Eric Widmann
Eric Widmann

Reputation: 106

S3 Signed Url's expiring before argument passed

I am trying to generate a signed URL for S3 bucket objects with the maximum expiration of 604800 seconds or 7 days. However, after testing I discovered that the links expire in under 24hrs. Doing some digging I came across this article claiming that the 7 day expiration is only available if the aws-sdk is authorized with an IAM user and the s3 library is making use of AWS Signature v4.

I am definitely using v4: exports.getS3 = () => new AWS.S3({region : 'us-east-1', signatureVersion: 'v4'})

Additionally, as far as I can tell, the lambdas deployed via serverless should default to my IAM user credentials when making use of the sdk without any other manipulation: const AWS = require('aws-sdk')

Here is the aforementioned article : https://aws.amazon.com/premiumsupport/knowledge-center/presigned-url-s3-bucket-expiration/

I also defined the IAM role delegated to my user to enable access to s3 iamRoleStatements: - Effect: Allow Action: - dynamodb:* Resource: "*" - Effect: Allow Action: - ssm:* Resource: "*" - Effect: Allow Action: - s3:* Resource: "*"

I've verified that it is not something as asinine as passing the wrong argument exports.getSignedURL = (key,bucket,method,expiration) =>{ console.log(`GETTING SIGNED URL WITH EXPIRATION ${expiration}`) return new Promise((resolve, reject) => { exports.getS3().getSignedUrl(method,{ Bucket: bucket, Key : key, Expires : expiration },(err,url)=>err?reject(err):resolve(url)) }); }

Has anybody encountered this issue or have any ideas what may be causing my problem? Is there some configuration I am missing?

Upvotes: 3

Views: 3571

Answers (1)

jarmod
jarmod

Reputation: 78803

Lambda functions deployed with serverless do not default to your IAM user credentials, as far as I know. They use the IAM role/policy that you supply in serverless.yml, plus basic CloudWatch Logs permissions which are auto-generated by serverless

The problem is that your Lambda function is using temporary credentials from STS (via an assumed IAM role) to generate the pre-signed URL. The URL will expire when the temporary session token expires (or earlier if you explicitly indicate an earlier timeout).

If you use IAM user credentials, rather than temporary credentials via an IAM role, you can extend the expiration to 7 days (with signature v4) or end of epoch (with the potentially deprecated signature v2). So, you need to supply your Lambda function with IAM user credentials, possibly through environment variables or AWS Parameter Store or AWS Secrets Manager.

For more, see Why is my presigned URL for an Amazon S3 bucket expiring before the expiration time that I specified?

Also, there are a couple of minor coding issues here:

  • all AWS methods have a .promise() option to return a promise, so no need to use callbacks and no need to manually create Promise objects
  • while the getSignedUrl method offers an asynchronous option, the operation itself is synchronous so you should simply run const url = s3.getSignedUrl(...)

Upvotes: 7

Related Questions