Bucket Policy Example Statements

So I recently posted about AWS S3 Bucket security and all the way AWS makes it easy for your to mess things up.

This post contains some example Bucket Policies I like to use for various needs.

Bucket Policies are pretty powerful. You can specify specific AWS accounts who can access your bucket. You can apply specific conditions around Source IP or Encryption settings. You can limit the access by object prefix. The Danger here is that if you specify Principal: * in your policy, you’ve just authorized Any AWS Customer to access your bucket.

S3 Bucket Policies contain five key elements. Effect, Action, Resource and Condition are the same as in IAM. Principal is used by Resource Policies (SNS, S3 Buckets, SQS, etc) to define who the policy applies to. In most cases the Principal is the root user of a specific AWS account. That AWS account can then delegate permission (via IAM) to users or roles. That means when you trust the root of another AWS Account, you’re trusting all the IAM or federated users in that account.

For example, this bucket policy statement allows anonymous access (via http or https), but will limit where the request is coming from:

    {
        "Sid": "IPAllowGetFromOffice",
        "Effect": "Allow",
        "Principal": "*",
        "Action": "s3:GetObject",
        "Resource": "arn:aws:s3:::horrible-insecure-bucket/*",
        "Condition": {
            "IpAddress": {
                "aws:SourceIp": "123.234.128.0/24"
            }
        }
    }

To really secure this bucket require AWS Authentication. Use this as your policy statement:

    {
        "Sid": "IPAllowGetFromOffice",
        "Effect": "Allow",
        "Principal": {
            "AWS": "arn:aws:iam::1234567890:root"
        },
        "Action": "s3:GetObject",
        "Resource": "arn:aws:s3:::horrible-insecure-bucket/*",
        "Condition": {
            "IpAddress": {
                "aws:SourceIp": "123.234.128.0/24"
            }
        }
    }

Now, only users that have 1) Authenticated to AWS as your account (1234567890), AND have IAM permissions for s3:GetObject, AND who are coming from the 123.234.128.0/24 subnet will be able to download the content.

You can also use bucket polices to enforce encryption. This policy will deny any upload that didn’t specify the right encryption:

    {
        "Sid": "DenyIncorrectEncryptionHeader",
        "Effect": "Deny",
        "Principal": "*",
        "Action": "s3:PutObject",
        "Resource": "arn:aws:s3:::my-more-secure-bucket/*",
        "Condition": {
            "StringNotEquals": {
                "s3:x-amz-server-side-encryption": "AES256"
            }
        }
    },
    {
        "Sid": "DenyUnEncryptedObjectUploads",
        "Effect": "Deny",
        "Principal": "*",
        "Action": "s3:PutObject",
        "Resource": "arn:aws:s3:::my-more-secure-bucket/*",
        "Condition": {
            "Null": {
                "s3:x-amz-server-side-encryption": "true"
            }
        }
    }

(You might notice the use of “Principal”: “*” in the above. In this case, that’s probably ok since the Effect is Deny)

Now here is a bucket policy you DON’T want:

    {
        "Sid": "AllowAnyone",
        "Effect": "Allow",
        "Principal": "*",
        "Action": "s3:GetObject",
        "Resource": "arn:aws:s3:::horrible-insecure-bucket/*"
    }

This Bucket Policy has the same effect as All Users Read.

And this policy will grant anyone full control to your bucket. Never do this:

    {
        "Sid": "AllowAnyone",
        "Effect": "Allow",
        "Principal": "*",
        "Action": "*",
        "Resource": [
        	"arn:aws:s3:::horrible-insecure-bucket/*"
        	"arn:aws:s3:::horrible-insecure-bucket"
        ]
    }