user3163545
user3163545

Reputation: 245

Lambda / Pre-signed url access denied

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 !

Upvotes: 7

Views: 12911

Answers (2)

jarmod
jarmod

Reputation: 78898

Here's a list of things to check when pre-signed URLs do not work:

  1. Check that the IAM policy of the signing credentials (the Lambda function IAM role in this case) permits access to download the S3 object in question (via s3:GetObject permission on the relevant object ARN such as arn:aws:s3:::BUCKET-NAME/*).
  2. Make sure that your IAM policy actually includes the appropriate object-level ARN such as 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.
  3. Check that the URL hasn't expired.
  4. Check that the credentials used to sign the URL haven't expired. This is a common problem when using temporary STS credentials to pre-sign URLs where the credentials expire before the pre-signed URL expires.
  5. Check that the client is time-synced.
  6. Check that the URL hasn't been mangled in transit or encoded in some way.

Note on IAM credentials

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.

Upvotes: 22

phyatt
phyatt

Reputation: 19152

https://aws.amazon.com/premiumsupport/knowledge-center/s3-bucket-owner-full-control-acl/

As access to a bucket is given to other accounts, if they put an object in the bucket, the account owner doesn't get automatic access to those put files. To fix this you need to add this to your commands:

--acl bucket-owner-full-control

Such as

aws s3api put-object --bucket accountB-bucket --key example.txt --acl bucket-owner-full-control

or

aws s3 cp s3://accountA-bucket/test.txt s3://accountB-bucket/test2.txt --acl bucket-owner-full-control

Otherwise you leave the ACL for the object hyper specific to the other account and user that pushed the file.

Hope that helps.

Upvotes: 0

Related Questions