10

I created a new S3 bucket, and left all defaults in place. I am trying to write an object to the bucket from a lambda function using the PutObject method. No matter what policies I attach or what I do, I get "access denied" on the action, unless I edit the bucket ACL and make it fully public. Obviously this isn't a very good solution. I really don't know what's going on: I know I've done this before without any special settings. The lambda and S3 bucket are both in the same account, and the role assigned to the lambda has the AWSLambdaFullAccess policy attached. I'm going crazy, any help would be appreciated.

5 Answers 5

11

Unfortunately "s3:PutObject" is not enough to make it running - you will keep getting 403 Access denied error.

You should add "s3:PutObjectAcl" policy to your Lambda role.

Sign up to request clarification or add additional context in comments.

1 Comment

That really helped, thanks! The question is how would one know which permissions are needed for an operation?
2

I was having this exact issue.

SOLUTION

The way I resolved it was with the policy below:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PetsS3Write",
            "Effect": "Allow",
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::<bucket name or wildcard if you want all buckets writable>/*"
        }
    ]
}

Comments

If you have a look at the actual policy in the IAM console you'll see this will give the lambda write access to the bucket AND any object. This is what it looks like in IAM view under the resources heading:

BucketName | string like | auth0-test-hucket, ObjectPath | string like | All.

Without the wildcard on the end it'll give no access to write any object to the bucket because it cannot name that object as there's no permission to do it. If you edit the policy you'll see you'll be able to specify the Bucket name and Object name.

So, I'm assuming the wildcard can be replaced with a string and it'll limited write access to that particular string. Like if you replaced the wildcard with "oneObject" then you'll only be able to create an object in the bucket named "oneObject". I've not tried this, but it seems to follow from the rules above.

Comments

0

Based on the permission sets you have assigned to your Lambda function, AWSLambdaFullAccess wont give you access to your S3 bucket. What you need in addition to those permissions is allowing access to S3. If PutObject is the only permission you need, then the following policy can be added to your Lambda role. Keep in mind, these permissions can be further locked down to the resource level but you can start with these:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1546988882992",
      "Action": [
        "s3:PutObject"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}

You can add or remove more S3 permissions based on your requirements.

5 Comments

I copied the above into an inline policy for my lambda role, but I'm still getting "access denied." Thoughts?
Unfortunately, "access denied" is the full error message in the CloudWatch logs
I don't think it's best practice to use the wildcard (*) for the "Resource" key, it's way to permissive. I had this exact same issue. My solution is below.
@codeinaire If you read my answer, it states that the OP can 'start' with that and once he gets his function working, he can 'lock it down' to the specific resource.
@captainblack yeah, I understand what you are saying. The solution you provide is applicable and flexible more generally but doesn't specifically answer the question. The OP stated the only resource they want it apply the action to is a bucket which make the solution you provided to general. I believe the answer I provided was more specific to the OP's question although not as generalisable or flexible as your solution. Does that make sense?
0

I had this error and I know this is a strange answer but the root cause of my problem was that the encryption type had to be set.

In NodeJS, I had to do something like:

    const filePath = path.join(__dirname, "../..", file);
    const fileData = fs.readFileSync(filePath);

    let result = await axios.put(s3Url, fileData, {
      headers: {
        "x-amz-server-side-encryption": "aws:kms:dsse",
        "x-amz-server-side-encryption-aws-kms-key-id": "alias/MyS3KMSKey",
// Or this if you don't have a custom KMS key
//      "x-amz-server-side-encryption-aws-kms-key-id":
//          "alias/S3KMSMultiRegionKey",
      },
    });

Comments

-1

You should change a policy for the s3 bucket. So you can use following code.

  iamRoleStatements:
    - Effect: 'Allow'
      Action:
        - 's3:PutObject'
        - 's3:GetObject'
      Resource: "arn:aws:s3:::*/*"
    - Effect: 'Allow'
      Action:
        - 's3:ListBucket'
      Resource: "arn:aws:s3:::*"

Note: you should put the s3:PutObjecct into Action. Wish help for you.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.