I wrote a lambda function who return a pre-signed url for documents in S3 Buckets.
The code is really simple :
const url = s3.getSignedUrl('getObject', {
Bucket: BUCKET_NAME,
Key: myFile.Key,
Expires: 20
})
const response = {
statusCode: 200,
headers: {
"Access-Control-Allow-Origin": "*"
},
body: JSON.stringify({
"url": url
}),
};
The funny thing is when I call this function locally (with serverless framework) like this :
sls invoke local -f getEconomyFile -d '{ "queryStringParameters": { "key": "myfile.pdf" } }'
It's working ! I have a url which give me the file.
But when I deploy to AWS Lambda, the function return a URL which always says "access denied" on the file :
<Error>
<Code>AccessDenied</Code>
<Message>Access Denied</Message>
<RequestId>93778EA364B3506B</RequestId>
<HostId>
yqnPC0SeIVE3/Pl7/d+xHDJ78=
</HostId>
</Error>
Why is it working locally and not deployed ?
Thank you !
Here's a list of things to check when pre-signed URLs do not work:
s3:GetObject
permission on the relevant object ARN such as arn:aws:s3:::BUCKET-NAME/*
).arn:aws:s3:::BUCKET-NAME/*
or arn:aws:s3:::BUCKET-NAME/images/*
. It is a common mistake to indicate a bucket-level ARN such as arn:aws:s3:::BUCKET-NAME
but that will not work.Even if your IAM credentials do not permit access to the S3 object(s), it is possible to use those credentials to create a pre-signed URL (a purely local computation**) but that URL will not actually allow you to access the object because the credentials underpinning the pre-signed URL do not have access to the object.
** you can tell this is a local computation and does not involve any calls into AWS by pre-signing an object such as s3://notmybucket/cat.png
. That will work and generate a pre-signed URL, but it will not actually be usable to retrieve that object.