So you want to restrict access to a bucket to only certain users or sets of users, or roles. There are three main ways of doing this, which can work together.

  1. The first is to give a user or a role permission to access named buckets, and only those buckets. This can be dangerous, and isn’t covered by this guide, because a slight misconfiguration that allows a user to access s3:* without restrictions to certain buckets will give them access to s3:* on all buckets. This is very easy to do.
  2. The second way is to encrypt your bucket, and to give access to the key to named users. There are many guides on this online, so that isn’t covered here either.
  3. The third is to set a policy on the bucket to allow access from only certain users, certain roles, or certain sets of users.

The following general scheme gives access to only users or roles where their ARNs meet certain criteria. This policy can be put under the Permissions tab of the bucket, under Amazon S3 > Buckets > bucket-name. The <Conditions> bit should be replaced by ARNs or conditions, that allow you to specify who has access to the bucket. This works well with bucket encryption and key management as a safety net, but for low sensitivity data, this is fine on its own. That’s your call.

{
    "Version": "2012-10-17",
    "Id": "DenyAllButThese",
    "Statement": [
        {
            "Sid": "1",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::bucket-name",
                "arn:aws:s3:::bucket-name/*"
            ],
            "Condition": {
                "ArnNotLike": {
                    "aws:PrincipalArn": [
                        <Conditions>
                    ]
                }
            }
        }
    ]
}

Named users

Users can be named on the policy directly, by grabbing their user ARN from their IAM entry.

"arn:aws:iam::123456789012:user/userOne"
"arn:aws:iam::123456789012:user/userTwo"

Sets of users with the same prefix can be named as below. This obviously needs to be done with care, as subsequent users with the same prefix will have the same access to this bucket. Name your new users carefully.

"arn:aws:iam::123456789012:user/userSeries*"

Roles

Roles can be named as below. The role itself needs access to the bucket, but roles are passed from entity to entity, so there needs to be a way of entities which have had a role passed to them to access the bucket. assumed-role ARNs with the same role name as the role ARN allow E.G.: an EC2 instance that has assumed the role to have the same access as the role itself.

"arn:aws:sts::123456789012:assumed-role/roleName/*"
"arn:aws:iam::123456789012:role/roleName/*"

Putting this all together

Once you have chosen your conditions and modified the bucket-name, your policy should look something like this.

{
    "Version": "2012-10-17",
    "Id": "DenyAllButThese",
    "Statement": [
        {
            "Sid": "1",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::bucket-name",
                "arn:aws:s3:::bucket-name/*"
            ],
            "Condition": {
                "ArnNotLike": {
                    "aws:PrincipalArn": [
                        "arn:aws:iam::123456789012:user/userOne",
                        "arn:aws:iam::123456789012:user/userTwo",
                        "arn:aws:sts::123456789012:assumed-role/roleName/*",
                        "arn:aws:iam::123456789012:role/roleName/*"
                    ]
                }
            }
        }
    ]
}