1

I'm trying to delete a number of objects in an S3 bucket like so (Lambda / Node.js):

exports.handler =  async function(event, context) {
  const s3Params = {
    Bucket: 'my-bucket',
    Delete: {
      Objects: [ 'my-bucket/dir/file1.json', 'my-bucket/dir/file2.json' ],
      Quiet: False
    }
  }
  const result = await s3.deleteObjects(s3Params).promise()
  return result
}

But I get:

{ 
  result: { 
    Deleted: [],
    Errors: [ 
        {Key: "my-bucket/dir/file1.json", Code: "AccessDenied", Message: "Access Denied"},
        {Key: "my-bucket/dir/file1.json", Code: "AccessDenied", Message: "Access Denied"}
    ]
  }
}  

Here is my role policy:

{
    "RoleName": "S3CleanupRole", 
    "PolicyDocument": {
        "Version": "2012-10-17", 
        "Statement": [
            {
                "Action": [
                    "s3:ListBucket", 
                    "s3:DeleteObject"
                ], 
                "Resource": [
                    "arn:aws:s3:::my-bucket"
                ], 
                "Effect": "Allow"
            }, 
            {
                "Action": [
                    "DynamoDB:Query"
                ], 
                "Resource": [
                    "arn:aws:dynamodb:us-east-1:514141358776:table/buckets-to-clean-out"
                ], 
                "Effect": "Allow"
            }
        ]
    }, 
    "PolicyName": "S3CleanupPolicy"
}

What's the problem?

Aurelia Peters
  • 2,169
  • 1
  • 20
  • 34

1 Answers1

2

(Kudos to Ravi Ramanujam for this - his answer to AWS S3 Access Denied on delete helped me solve this problem.)

My policy is wrong. The permission for s3:DeleteObject applies only to the bucket arn:aws:dynamodb:us-east-1:514141358776:table/buckets-to-clean-out and not any of its contents. The correct policy allows s3:DeleteObject on the bucket contents, viz:

{
    "RoleName": "S3CleanupRole", 
    "PolicyDocument": {
        "Version": "2012-10-17", 
        "Statement": [
            {
                "Action": [
                    "s3:ListBucket"
                ], 
                "Resource": [
                    "arn:aws:s3:::my-bucket"
                ], 
                "Effect": "Allow"
            }, 
            {
                "Action": [
                    "s3:DeleteObject"
                ], 
                "Resource": [
                    "arn:aws:s3:::my-bucket/*"
                ], 
                "Effect": "Allow"
            }, 
            {
                "Action": [
                    "DynamoDB:Query"
                ], 
                "Resource": [
                     "arn:aws:dynamodb:us-east-1:514141358776:table/buckets-to-clean-out"
                ], 
                "Effect": "Allow"
            }
        ]
    }, 
    "PolicyName": "S3CleanupPolicy"
}

The crucial piece is below. Note that the "Resource" section contains arn:aws:s3:::my-bucket/* rather than just arn:aws:s3:::my-bucket

 {
     "Action": [
         "s3:DeleteObject"
     ], 
     "Resource": [
          "arn:aws:s3:::my-bucket/*"
     ], 
     "Effect": "Allow"
 } 
Aurelia Peters
  • 2,169
  • 1
  • 20
  • 34
  • 1
    Yes, most people see this issue when creating policies with `GetObject`. It can be a time-consuming lesson. See similar: [AWS STS to list buckets gives access denied](https://stackoverflow.com/a/60291852/174777) – John Rotenstein Feb 20 '20 at 23:13