Ivan Baranov
Ivan Baranov

Reputation: 355

s3 SignedUrl x-amz-security-token

const AWS = require('aws-sdk');

export function main (event, context, callback) {
  const s3 = new AWS.S3();
  const data = JSON.parse(event.body);`

  const s3Params = {
    Bucket: process.env.mediaFilesBucket,
    Key: data.name,
    ContentType: data.type,
    ACL: 'public-read',
  };

  const uploadURL = s3.getSignedUrl('putObject', s3Params);

  callback(null, {
    statusCode: 200,
    headers: {
      'Access-Control-Allow-Origin': '*'
    },
    body: JSON.stringify({ uploadURL: uploadURL }),
  })
}

When I test it locally it works fine, but after deployment it x-amz-security-token, and then I get access denied response. How can I get rid of this x-amz-security-token?

Upvotes: 11

Views: 18686

Answers (3)

Sugam Malviya
Sugam Malviya

Reputation: 59

I was facing the same issue, I'm creating a signed URL using library Boto3 in python3.7

All though this is not a recommended way to solve, it worked for me.

The request methods should be POST, content-type=['multipart/form-data']

Create a client in like this.

# Do not hard code credentials
client = boto3.client(
    's3',
    # Hard coded strings as credentials, not recommended.
    aws_access_key_id='YOUR_ACCESS_KEY',
    aws_secret_access_key='YOUR_SECRET_ACCESS_KEY'
)

Return response

bucket_name = BUCKET
acl = {'acl': 'public-read-write'}
file_path = str(file_name) //file you want to upload
response = s3_client.generate_presigned_post(bucket_name,
                                                 file_path,
                                                 Fields={"Content-Type": ""},
                                                 Conditions=[acl,
                                                    {"Content-Type": ""},
                                                    ["starts-with", "$success_action_status", ""],
                                                 ],
                                                 ExpiresIn=3600)

Upvotes: 0

Sean McMillan
Sean McMillan

Reputation: 341

I was having the same issue. Everything was working flawlessly using serverless-offline but when I deployed to Lambda I started receiving AccessDenied issues on the URL. When comparing the URLs returned between the serverless-offline and AWS deployments I noticed the only difference was the inclusion of the X-Amz-Security-Token in the URL as a query string parameter. After some digging I discovered the token being assigned was based upon the assumed role the lambda function had. All I had to do was grant the appropriate S3 policies to the role and it worked.

Upvotes: 17

delProfundo
delProfundo

Reputation: 110

I just solved a very similar, probably the same issue as you have. I say probably because you dont say what deployment entails for you. I am assuming you are deploying to Lambda but you may not be, this may or may not apply but if you are using temporary credentials this will apply.

I initially used the method you use above but then was using the npm module aws-signature-v4 to see if it was different and was getting the same error you are.

You will need the token, it is needed when you have signed a request with temporary credentials. In Lambda's case the credentials are in the runtime, including the session token, which you need to pass, the same is most likely true elsewhere as well but I'm not sure I haven't used ec2 in a few years.

Buried in the docs (and sorry I cannot find the place this is stated) it is pointed out that some services require that the session_token be processed with the other canonical query params. The module I'm using was tacking it on at the end, as the sig v4 instructions seem to imply, so I modified it so the token is canonical and it works.

We've updated the live version of the aws-signature-v4 module to reflect this change and now it works nicely for signing your s3 requests.

Signing is discussed here.

I would use the module I did as I have a feeling the sdk is doing the wrong thing for some reason.

usage example (this is wrapped in a multiPart upload thus the part number and upload Id):

function createBaseUrl( bucketName, uploadId, partNumber, objectKey ) {
  let url = sig4.createPresignedS3URL( objectKey, {
    method: "PUT",
    bucket: bucketName,
    expires: 21600,
    query: `partNumber=${partNumber}&uploadId=${uploadId}`
  });
  return url;
}

Upvotes: 3

Related Questions