I am using NodeJs to upload files to AWS S3. I want the client to be able to download the files securely. So I am trying to generate signed URLs, that expire after one usage. My
Your code looks good but I think you are missing the signatureVersion: 'v4'
parameter while creating the s3bucket
object. Please try the below updated code.
const s3bucket = new AWS.S3({
signatureVersion: 'v4',
accessKeyId: 'my-access-key-id',
secretAccessKey: 'my-secret-access-key',
Bucket: 'my-bucket-name',
})
const uploadParams = {
Body: file.data,
Bucket: 'my-bucket-name',
ContentType: file.mimetype,
Key: `files/${file.name}`,
}
s3bucket.upload(uploadParams, function (err, data) {
// ...
})
const url = s3bucket.getSignedUrl('getObject', {
Bucket: 'my-bucket-name',
Key: 'file-key',
Expires: 300,
})
For more about signatureVersion: 'v4'
see the below links
https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html
https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html
You can also try out the below nodejs
library that create presigned url
https://www.npmjs.com/package/aws-signature-v4
I had the same issue when i'm locally testing my lambda function its works but after deploy it didn't work. once i add the s3 full access to lambda function it worked.
If your s3 files are encrypted than make sure that your policy also access to encryption key and related actions.
Your code is correct, double check the following things:
Your bucket access policy.
Your bucket permission via your API key.
Your API key and secret.
Your bucket name and key.
For bucket policy you can use the following:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::bucket/*"
}
]
}
Change bucket with your bucket name.
For users and access key permission (#2), you should follow these steps:
1-Goto AWS Identity and Access Management (IAM) and click on Policies link and click on "Create policy" button.
2-Select the JSON tab.
3-Enter the following statement, make sure change the bucket name and click on "review policy" button.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor1",
"Effect": "Allow",
"Action": "s3:*",
"Resource": "arn:aws:s3:::YOURBUCKETNAME"
}
]
}
4-Enter a name for your policy and click on "Create policy" button.
5-Click on Users link, and find your current username (You already have the access key and secret for that)
6-Click on "add permission" button.
7-Add the policy we created in the previous step and save.
Finally, make sure your bucket not accessible from Public, add the correct content type to your file and set signatureVersion: 'v4'
The final code should be like this, thanks @Vaisakh PS:
const s3bucket = new AWS.S3({
signatureVersion: 'v4',
accessKeyId: 'my-access-key-id',
secretAccessKey: 'my-secret-access-key',
Bucket: 'my-bucket-name',
})
const uploadParams = {
Body: file.data,
Bucket: 'my-bucket-name',
ContentType: file.mimetype,
Key: `files/${file.name}`,
}
s3bucket.upload(uploadParams, function (err, data) {
// ...
})
const url = s3bucket.getSignedUrl('getObject', {
Bucket: 'my-bucket-name',
Key: 'file-key',
Expires: 300,
})
I kept having a similar problem but mine were due to region settings. In our back end we had some configuration settings for the app.
One of which was "region": "us-west-2"
so the presigned url was created with this region but when it was called on the front end the region was set to "us-west-1"
.
Changing it to be the same fixed the issue.
I saw this problem recently when moving from a bucket that was created a while ago to one created recently.
It appears that v2 pre-signed links (for now) continue to work against older buckets while new buckets are mandated to use v4.
Revised Plan – Any new buckets created after June 24, 2020 will not support SigV2 signed requests, although existing buckets will continue to support SigV2 while we work with customers to move off this older request signing method.
Even though you can continue to use SigV2 on existing buckets, and in the subset of AWS regions that support SigV2, I encourage you to migrate to SigV4, gaining some important security and efficiency benefits in the process.
https://docs.amazonaws.cn/AmazonS3/latest/API/sigv4-query-string-auth.html#query-string-auth-v4-signing-example
Our solution involved updating the AWS SDK to use this by default; I suspect newer versions probably already default this setting.
https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/net-dg-config-other.html#config-setting-aws-s3-usesignatureversion4