Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 !

like image 929
user3163545 Avatar asked Feb 09 '18 15:02

user3163545


People also ask

Why am I getting an access denied error when I use lambda function to upload files to an Amazon S3 bucket?

If the permissions between a Lambda function and an Amazon S3 bucket are incomplete or incorrect, then Lambda returns an Access Denied error.

Does S3 bucket need to be public for Presigned URL?

All objects and buckets are private by default. However, you can use a presigned URL to optionally share objects or allow your customers/users to upload objects to buckets without AWS security credentials or permissions.

What is pre-signed URL in AWS?

A pre-signed URL allows you to grant temporary access to users who don't have permission to directly run AWS operations in your account. A pre-signed URL is signed with your credentials and can be used by any user.

How do I upload a pre-signed URL?

When you create a presigned URL, you must provide your security credentials and then specify a bucket name, an object key, an HTTP method (PUT for uploading objects), and an expiration date and time. The presigned URLs are valid only for the specified duration.


1 Answers

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

  1. The IAM policy of the Lambda function needs to have access to the S3 object in question (via arn:aws:s3:::BUCKET-NAME/*). If it doesn't have access, it will be able 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).
  2. Check that the URL hasn't expired.
  3. Check that the credentials used to sign the URL haven't expired. This is a common problem when using temporary credentials to pre-sign URLs where the credentials expire before the pre-signed URL expires.
  4. Check that the client is time-synced.
  5. Check that the URL hasn't been mangled in transit or encoded in some way.

** 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/fred. That will work and generate a pre-signed URL, but it will not actually be usable to retrieve that object.

like image 114
jarmod Avatar answered Oct 09 '22 13:10

jarmod