29

I have the following policy on an S3 bucket created with the AWS policy generator to allow a lambda, running with a specific role, access to the files in the bucket. However, when I execute the Lambda, I get 403 permission denied:

"errorMessage": "Access Denied (Service: Amazon S3; Status Code: 403; Error Code: AccessDenied; Request ID: <requestId>)",
  "errorType": "com.amazonaws.services.s3.model.AmazonS3Exception",

The Policy on the S3 bucket:

{
"Version": "2012-10-17",
"Id": "Policy<number>",
"Statement": [
    {
        "Sid": "Stmt<number>",
        "Effect": "Allow",
        "Principal": {
            "AWS": "arn:aws:iam::<account>:role/<roleName>"
        },
        "Action": "s3:*",
        "Resource": "arn:aws:s3:::<bucketName>/*"
    }
]
}

What is wrong with the policy? The Lamba is running with the role configured in the policy.

FiguringThisOut
  • 810
  • 2
  • 9
  • 18
  • I will start with firstly modifying this policy to give all permissions to all .. basically removing Principal and bucketname.. That will tell you if problem is in your s3 policy or with lambda. – Deepak Singhal Jul 24 '17 at 16:44
  • 2
    Why not add the S3 bucket permissions to the IAM Role assigned to the Lambda function, instead of trying to do this through a bucket policy? – Mark B Jul 24 '17 at 17:01
  • What are you doing to the bucket, from Lambda? Some actions require the resource to exclude the `/*` at the end, others need it included: `"Resource": [ "arn:aws:s3:::", "arn:aws:s3:::/*" ]` – Michael - sqlbot Jul 24 '17 at 19:54

3 Answers3

40

A role assigned to an AWS Lambda function should be created with an AWS Lambda role (that is selected when creating a Role in the IAM console).

Roles do not have a Principal since the permissions are assigned to whichever service (in this case, Lambda function) is using the role.

Also, you should assign permissions on the bucket itself (e.g. to list contents) and on the contents of the bucket (e.g. to GetObject).

It would be something like this:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowS3Access",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::123XXX:role/service-role/LAMBDA_ROLE_NAME"
            },
            "Action": [
                "s3:*"
            ],
            "Resource": [
                "arn:aws:s3:::my-bucket",
                "arn:aws:s3:::my-bucket/*"
            ]
        }
    ]
}
Neoheurist
  • 3,183
  • 6
  • 37
  • 55
John Rotenstein
  • 241,921
  • 22
  • 380
  • 470
  • 2
    Thanks for the reply. The policy I had setup on the bucket itself was correct. What was missing was that the roll itself needed to have the AmazonS3FullAccess policy attached to it via the IAM. – FiguringThisOut Aug 01 '17 at 15:49
  • @FiguringThisOut: Attaching the AmazonS3FullAccess policy to the role worked for me too. Please post your own answer and mark it as the accepted answer! – Syed Waqas Feb 13 '19 at 07:47
15

After looping for I while i could make it work, the process is:

  1. create the s3 bucket.
  2. create the IAM policy (bucket name needed)
  3. Create IAM role (IAM policy needed)
  4. Create lambda Function (IAM Role needed)
  5. Create s3 bucket policy (lambda function name needed)

IAM Policy:

 {
"Version": "2012-10-17",
"Statement": [
    {
        "Sid": "Stmt*******",
        "Effect": "Allow",
        "Action": [
            "s3:PutObject",
            "s3:PutObjectAcl",
            "s3:PutObjectTagging",
            "s3:PutObjectVersionAcl",
            "s3:PutObjectVersionTagging"
        ],
        "Resource": [
            "arn:aws:s3:::<bucket-name>"
        ]
    }
]
}

and I use this policy on the s3 Bucket

{
"Id": "Policy************",
"Version": "2012-10-17",
"Statement": [
{
  "Sid": "Stmt********",
  "Action": [
    "s3:PutObject",
    "s3:PutObjectAcl",
    "s3:PutObjectTagging",
    "s3:PutObjectVersionAcl",
    "s3:PutObjectVersionTagging"
  ],
  "Effect": "Allow",
  "Resource": "arn:aws:s3:::<bucket-name>/*",
  "Principal": {
    "AWS": [
      "arn:aws:iam::*********:role/<lambda-function-name>"
          ]
          }
        }
     ]
}
Cristian Sepulveda
  • 1,572
  • 1
  • 18
  • 25
  • 14
    I think this should not be the ``, but the role name, or in other words, just the full role arn. – udondan Dec 06 '18 at 14:39
  • I was able to get this to work with just steps 2 and 3. That assumes, of course, that you have an existing bucket (step 1) and existing function (step 4). I don't believe Step 5 is needed if the execution role has been given permissions to the bucket. For my use case I need both read and write to the bucket so I had two statements, one with "Action": ["s3:ListBucket"] and one with "Action": "s3:*Object" to allow both Get and Put actions. – Carson Evans Jun 16 '21 at 21:42
0

I faced a similar issue and tried many different bucket policies and most of them either failed to do the job (got Access Denied as explained in the question) or needed me to go extra mile and add some bits and pieces. Below is the simplest way to get it working without having to add any new resource or define a new role for your Lambda.

You just need to find your Lambda execution role from AWS console: enter image description here

Let's assume the role name is 'MyLambdaRoleName-1234' Then find the role id using AWS CLI or AWS CloudShell:

aws iam get-role --role-name MyLambdaRoleName-1234

you will find the role id from the result:

enter image description here

Copy the RoleId and use it in below bucket policy. Let's assume it is 'ARARARARARARARARARARA'

{
    "Version": "2008-10-17",
    "Statement": [
        {
            "Sid": "Deny everything for any service but Lambda",
            "Effect": "Deny",
            "Principal": "*",
            "Action": [
                "s3:*"
            ],
            "Resource": "arn:aws:s3:::<bucketName>/*",
            "Condition": {
                "StringNotLike": {
                    "aws:userId": [
                        "ARARARARARARARARARARA:*",
                        "ARARARARARARARARARARA"
                    ]
                }
            }
        }
    ]
}

I wanted to allow only my Lambda to perform actions on the bucket and stop any other role/services to run any action. If this is not your case and you just want to add a policy to give access to your Lambda, of course you just need to replace Deny with Allow and StringNotLike with StringLike.

Amir Chatrbahr
  • 2,260
  • 21
  • 31