Why does the presigned URL for my Amazon S3 bucket expire before the expiration time that I specified?

2 minute read
3

I used a temporary token to create a presigned URL for an Amazon Simple Storage Service (Amazon S3) bucket. The URL expired before the expiration time that I specified. I want to create a presigned URL that's valid for a longer time.

Resolution

Important: Presigned URLs grant Amazon S3 bucket access to anyone with the URL. For security, it's a best practice to limit the capabilities of presigned URLs.

When you use a temporary token to create a presigned URL, the URL expires when the token expires. This is true even when you create the URL with a later expiration time than the temporary token.

For more information about expiration times, see Expiration time for presigned URLs.

For information about the types of credentials that you can use and their associated expiration time, see Who can created a presigned URL.

Note: Services that assume an AWS Identity and Access Management (IAM) role, such as the AWS Lambda execution role, don't always comply with the role's session duration settings.

To grant users access to the objects in your Amazon S3 bucket for longer than 7 days, choose one of the following options:

Related information

Sharing objects with presigned URLs

GetSessionToken

Retrieve security credentials from instance metadata

Authenticating requests: Using query parameters (AWS Signature Version 4)

AWS OFFICIAL
AWS OFFICIALUpdated 5 months ago
6 Comments

I use the following approach (AWS sdk v3 Javascript) in my lambda function:

import { GetObjectCommand, S3Client } from "@aws-sdk/client-s3";
const client = new S3Client({ region });  // perhaps we can pass here credentials of IAM user
const command = new GetObjectCommand({ Bucket: bucket, Key: key });
const url = await getSignedUrl(client, command, { expiresIn: 4320000 }); // I expect that link will expire in 5 days

But the problem is the link expires in ~12-14hours. Here is the fragment of cloudformation template:

Resources:
  LambdaFunctionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Action: "sts:AssumeRole"
    Path: "/"

  GetPresignedUrlFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub "get-presigned-url-${EnvName}"
      Handler: getPresignedUrl.handler
      Role: !GetAtt LambdaFunctionRole.Arn

Should I use credentials of IAM user for S3Client constructor options like:

const client = new S3Client({ region, credentials: { accessKeyId: 'test', secretAccessKey: 'test' }});
replied a year ago

Thank you for your comment. We'll review and update the Knowledge Center article as needed.

profile pictureAWS
EXPERT
replied a year ago

I am having the same issue when using S3.getSignedUrl in a lambda function (I am using aws sdk v2) . Although I specify the "Expires" parameter as a value that equals 1 year , the signed URL is no longer accessible after about 12 hours or so. The lambda function uses an IAM role that has GetObject permissions on the bucket. The error received upon accessing the URL after 12 hours or so, is : <Code>ExpiredToken</Code><Message>The provided token has expired.</Message>

The post above says "If you created a presigned URL using a temporary token, then the URL expires when the token expires. This is true even if the URL was created with a later expiration time." Although the signed URL contains an AccessKeyID in the URL, I did not generate it or any temporary token explicitly, just simply used the SDK in a lambda that assumes a role. However , the default expiry for the "session" that generated the URL is not 7 days, it is not even 24 hrs. How do I change that.

replied a year ago

Thank you for your comment. We'll review and update the Knowledge Center article as needed.

profile pictureAWS
MODERATOR
replied a year ago

I could not believe that the solution was to create an IAM user therefore I wanted an alternative approach.

I have "fixed" this problem by creating a Lambda with a function url. The lambda function listens to HTTP GET requests.

When executed it creates a pre-signed url in real time and then redirects the requester to the pre-signed url using a 302 status code and location header. The lambda function has a querystring that has expiry, object key and a salted hash of the key. The expiry date is also signed to ensure it cannot be tampered with. Before the pre-signed url is created the code verifies the signatures and ensures the querystring parameters have not been altered.

replied 6 months ago

Thank you for your comment. We'll review and update the Knowledge Center article as needed.

profile pictureAWS
MODERATOR
replied 6 months ago