S3 Bucket Policy - NotPrincipal and Lambda Functions

AWS S3 bucket policies have a handy NotPrincipal element that allows you restrict actions to specific principals. For example, the following allows you only allow deletes from two specified roles:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "DenyObjectDeleteWithWhitelist",
            "Effect": "Deny",
            "NotPrincipal": {
                "AWS": [
                    "arn:aws:iam::123456789012:role/SuperRoleOne",
                    "arn:aws:iam::123456789012:role/SuperRoleTwo"
                ]
            },
            "Action": "s3:DeleteObject",
            "Resource": "arn:aws:s3:::mybucket/*"
        }
    ]
}

But what if you want to restrict it to an assumed role? While working on a Serverless Framework project, I wanted to open up a S3 bucket to allow deletes from a Lambda function (and only that Lambda function).

Surprisingly, the following S3 bucket policy didn’t work:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "DenyObjectDeleteWithWhitelist",
            "Effect": "Deny",
            "NotPrincipal": {
                "AWS": [
                    "arn:aws:iam::123456789012:role/my-lambda-role"
                ]
            },
            "Action": "s3:DeleteObject",
            "Resource": "arn:aws:s3:::mybucket/*"
        }
    ]
}

With a bit of digging and troubleshooting, I realized that the Lambda function assumes the role you provide, and that assumed role must also be added to the S3 bucket policy:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "DenyObjectDeleteWithWhitelist",
            "Effect": "Deny",
            "NotPrincipal": {
                "AWS": [
                    "arn:aws:iam::123456789012:role/my-lambda-role",
                    "arn:aws:sts::123456789012:assumed-role/my-lambda-role/my-lambda-function"
                ]
            },
            "Action": "s3:DeleteObject",
            "Resource": "arn:aws:s3:::mybucket/*"
        }
    ]
}

This will prevent any entity from deleting from the S3 bucket except for your Lambda function.

If this isn’t your exact scenario, and/or you’re looking for more details, check out How to Restrict Amazon S3 Bucket Access to a Specific IAM Role by AWS.

Software Developer | Lifelong Learner. neverendingqs.com