1
votes

I am trying to get a pre-signed URL to upload files to the S3 bucket. Here is my workflow:

1. Invoke Lambda -> 2. Get pre-signed URL -> 3. Hit the URL (PUT) with file

1. Invoke Lambda

I made sure the AWS keys have the correct permission. In fact, it has full access. Here is the Source code:

AWS.config.update({
  accessKeyId: '*****************',
  secretAccessKey: '*****************',
  region: 'us-east-1',
  signatureVersion: 'v4'
});

let requestObject = JSON.parse(event["body"]);
let fileName = requestObject.fileName;
let fileType = requestObject.fileType;
const myBucket = 'jobobo-resumes';

s3.getSignedUrl('putObject', {
"Bucket": myBucket,
"Key": fileName,
"ContentType": fileType
}, function (err, url) {

  if (err) {    
  mainCallback(null, err);
  } else {    
  mainCallback(null, url);    
  }

}

So, I am getting the filename, file type(MIME) from the request and use that to create the signature.

2. Get pre-signed URL When I hit the Lambda I get the pre-signed URL. Now, I will use this URL to upload the file to S3.

Getting pre-signed URL

3. Hit the URL (PUT) with file

Now, I hit the URL with HTTP method and I add the file (binary), see my Postman request:

enter image description here

You can see that I hit the request with the PUT HTTP Method. I get the 403 error. Here are the headers in the request and you can see that the content-type is image/jpeg:

enter image description here

When I try the POST method, I get that the signature is invalid. I guess that is because of the signature is signed for the PUT method.

enter image description here

Here is the S3 bucket's settings:

Since I get access denied, I completely opened the bucket, I mean Block Public access: off.

enter image description here

What is wrong with the settings? Maybe S3?

1

1 Answers

2
votes

You have a service object in the variable s3 but you don't show, in your code, where that object was constructed... but it appears to be before you call AWS.config.update() which doesn't retroactively reconfigure your s3 object. The order of these operations is the problem.

Updates you make to the global AWS.config object don't apply to previously created service objects.

https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/global-config-object.html

If you observe your generated URL closely you can see that the Lambda Execution Role credentials are actually being used, which is why access is denied.

The giveaways are that the AWSAccessKeyId in the URL is not yours, it's a session key beginning with ASIA instead of AKIA like a normal Access Key ID. Also, there's a session token x-amz-security-token which wouldn't be there in a URL generated with static credentials. Also this URL is Signature V2, so when you correct the credential configuration issue, the format of the signed URL will change significantly. Signature V4 URLs have X-Amz-Credential instead of AWSAccessKeyId.