In my current project, my team was instructed to create a signed URL for an s3 object created programmatically so that they were able to download the s3 object without any AWS account.
Writing The Code
We created a lambda function. This lambda function used typescript and javascript aws sdk v3.
import { Context } from "aws-lambda";
import {
GetObjectCommand,
PutObjectCommand,
S3Client,
S3ClientConfig,
} from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
export const lambdaHandler = async (event: object, context: Context) => {
const maxExpireTime = 604800; //7 days maximum expire time
const region = "us-west-2";
const s3client = new S3Client({
region,
} as S3ClientConfig);
const bucketName = "my-bucket-name";
const key = "my-key";
const body = "my-body";
const putObjectCommand = new PutObjectCommand({
Bucket: bucketName,
Key: key,
Body: body,
});
await s3client.send(putObjectCommand);
const getObjectCommand = new GetObjectCommand({
Bucket: bucketName,
Key: key,
});
const signedURL = await getSignedUrl(s3client, getObjectCommand, {
expiresIn: maxExpireTime,
});
return {
statusCode: 200,
body: {
signedURL,
},
};
};
According to this link, the max expiration time is 604800 seconds which means 7 days.
The Problem
So far so good. Lambda worked properly and gave us the signed URL but after 12 hours the signed URL for the s3 object expired and threw an error like below.
After investigating, we found out that if the token expires the signed URL expires.
The Solution
We created IAM user access keys using the AWS console and implemented these keys with signature version 4 in our lambda function.
import { Context } from "aws-lambda";
import {
GetObjectCommand,
PutObjectCommand,
S3Client,
S3ClientConfig,
} from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
export const lambdaHandler = async (event: object, context: Context) => {
const maxExpireTime = 604800; //7 days maximum expire time
const region = "us-west-2";
const accessKeyId = "MY_ACCESS_KEY_ID";
const secretAccessKey = "MY_SECRET_ACCESS_KEY";
const s3client = new S3Client({
region,
credentials: {
accessKeyId,
secretAccessKey,
},
signatureVersion: "v4",
} as S3ClientConfig);
const bucketName = "my-bucket-name";
const key = "my-key";
const body = "my-body";
const putObjectCommand = new PutObjectCommand({
Bucket: bucketName,
Key: key,
Body: body,
});
await s3client.send(putObjectCommand);
const getObjectCommand = new GetObjectCommand({
Bucket: bucketName,
Key: key,
});
const signedURL = await getSignedUrl(s3client, getObjectCommand, {
expiresIn: maxExpireTime,
});
return {
statusCode: 200,
body: {
signedURL,
},
};
};
The Result
After using the IAM user access keys with signature version 4, the generated signed URL didn't expire after 12 hours as expected.
The Sources
- https://docs.aws.amazon.com/AmazonS3/latest/userguide/ShareObjectPreSignedURL.html
- https://repost.aws/knowledge-center/presigned-url-s3-bucket-expiration
- https://elasticscale.cloud/why-do-your-s3-presigned-urls-expire-after-12-hours-even-if-youve-set-a-longer-time/#:~:text=This%20means%20that%20if%20the,will%20stop%20working%20as%20well
Contact me:
Top comments (0)