Skip to content

Instantly share code, notes, and snippets.

@binarycrayon
Forked from pgolding/policy.md
Created February 14, 2018 01:32
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save binarycrayon/8b204baf765b33acbf287fb4b5812b77 to your computer and use it in GitHub Desktop.
Save binarycrayon/8b204baf765b33acbf287fb4b5812b77 to your computer and use it in GitHub Desktop.
s3 bucket policy for presigned URLs generated by serverless lambda functions

AWS Presigned URLs

Presigned URLs are useful for fine-grained access control to resources on s3.

For example, if storing larger text blocks than DynamoDB might allow with its 400KB size limits s3 is a useful option.

Ignoring various ACL methods and using presigned URLs, it's possible to create lambda functions that can generate the required upload and download URLs.

Using the default IAM roles and lambda proxy configuration of serverless, lambdas are assigned an IAM role for the application (so that a logical group of functions can share resources - e.g. for a CRUD REST API). Each function then assumes the IAM role via its own function name.

It is important that both of these are given the requisite access rights to the relevant bucket in order to avoid the dreaded:

<Error>
  <Code>AccessDenied</Code>
  <Message>Access Denied</Message>
  <RequestId>A37839BB23186F72</RequestId>
  <HostId>
yvKTN+CN1TTNk2tqoxxm3MPOGTUSMaRYtbbEFeCzGP7ou5IYf37Z9uBESwUQWDIUR1GUuPbZyuM=
  </HostId>
</Error>

The potential gotcha is that presigned URL functionality requires broader actions on the bucket than initially suspected. Therefore, wildcard actions on the bucket/path/* are insufficient. Permissions must also be granted on the bucket itself.

{
    "Version": "2012-10-17",
    "Id": "SomeID",
    "Statement": [
        {
            "Sid": "PresignedPermissions",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:sts::403511221862:assumed-role/serverless-app-lambdaRole/lambda-function-name",
                    "arn:aws:iam::403511221862:role/view-api-dev-us-west-2-lambdaRole"
                ]
            },
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::bucket-name",
                "arn:aws:s3:::bucket-name/*"
            ]
        }
    ]
}

Note the two resources: the bucket itself and the bucket's objects.

@yonixw
Copy link

yonixw commented Nov 14, 2022

Worked for me without putting in bucket policy, only in role. But I do know that the role of the lambda is short lived so the valid time = min(role_expire, sign_url_expire) and that on the aws side. But for cases of using the url right away, it is enough. For longer time, you need a user IAM or some "Assume role" architecture.

Any way this is the permission that worked for me in the lambda IAM:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::$BUCKET_NAME/*"
        }
    ]
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment