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

2 minute read
2

I created a presigned URL for an Amazon Simple Storage Service (Amazon S3) bucket using a temporary token. However, the URL expired before the expiration time that I specified. Why did this happen? How can I create a presigned URL that's valid for a longer time?

Resolution

If you created a presigned URL using a temporary token, then the URL expires when the token expires. The URL expires even if the URL was created with a later expiration time.

The credentials that you can use to create a presigned URL include:

  • AWS Identity and Access Management (IAM) instance profile: Valid up to six hours.
  • AWS Security Token Service (STS): Valid up to 36 hours when signed by an AWS Identity and Access Management (IAM) user, or valid up to one hour when signed by the root user.
  • IAM user: Valid up to seven days when using AWS Signature Version 4.

To create a presigned URL that's valid up to seven days, designate IAM user credentials (the access key and secret access key) to your SDK. Then, generate a presigned URL using AWS Signature Version 4. For examples, see Signature calculations in AWS Signature Version 4.

When creating a presigned URL, keep the following points in mind:

  • Services that assume a role, such as the AWS Lambda execution role, don't necessarily comply with the role's session duration settings.
  • Because presigned URLs grant Amazon S3 bucket access to whoever has the URL, it's a best practice to protect them appropriately.
  • 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.

To allow users access to the objects in your Amazon S3 bucket for longer than seven days, consider using one of these options:


Related information

Sharing objects using presigned URLs

GetSessionToken

Retrieve security credentials from instance metadata

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

Boto 3 Docs: S3

AWS OFFICIAL
AWS OFFICIALUpdated 2 years ago
3 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 23 days ago

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

profile pictureAWS
MODERATOR
replied 22 days 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 4 hours ago