How to secure your S3 bucket from users with s3:* access
Tags: aws, s3, iam
Published: 2020-04-24 11:14:28

I recently worked on adding an extra layer of access control for some of the S3 buckets at work. This required me to allow only a specific group of employees to have direct access to the buckets. The problem is that a lot of them can assume an IAM role which gives them `s3:*` capabilities. In this post I will use an example of two users and IAM roles with read access to all buckets to show how we can restrict access for one user.

# Who is this post for?
This post is for you if you:
* Want to restrict access to certain S3 buckets **even if users have read access to all buckets through their IAM role**.

# Sections
- [Setup] (#chapter-1)
- [Bucket Policy] (#chapter-2)
- [Testing] (#chapter-3)

# Setup <a name="chapter-1"></a>
In this section we'll set up some mock data which will help us test our bucket policy. This includes creating new users, policies, groups, and roles. You may skip this section and move on to [Bucket Policy] (#chapter-2) if you already have this data.


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/58h3yevdexfyob8ppesh.png)
Let's start off by creating an S3 bucket. I used the default settings since we don't need the bucket to be public for this example.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/syeghbvlh06ltzqosedg.png)
Navigate to IAM and create two roles with *AmazonS3ReadOnlyAccess* policy. This policy will give the roles read only access to **all** buckets.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/vrdayhpunulg7fd9cvs2.png)
We will now create policies to allow our users to assume these roles. Go to *Policies* menu and create two policies. For both policies, select *STS* as the service and *AssumeRole* as the action. For resources, click on *Add ARN*.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/jhi34jcbtqxdo0alsvlc.png)
Type in each of the two role names for each policy as well as your AWS account ID.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/1atdfehjcoxj70xoaaax.png)
Navigate to *Groups* to create two groups. Attach one of the policies to each of these groups.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/8w3hrmoctsrg8kme1xxb.png)
Lastly, navigate to *Users*. As you may have guessed, we'll be creating two users. Make sure that *AWS Management Console access* is ticked.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/tfgfr80sgqqrkn3nb1dw.png)
Add each of the users to separate groups that you previously created.

If you've been following the post, you'll now have:
* Two roles with *AmazonS3ReadOnlyAccess* policy
* Two policies with *sts:AssumeRole* access to **one** of the two roles
* Two groups with **one** of the two policies above
* Two users in **one** of the two groups above

We now have all the data to write our S3 bucket policy.

# Bucket Policy <a name="chapter-2"></a>
In this section, we'll add a bucket policy which allows specific IAM roles to have read access.

Before we start with the bucket policy, we need to know the ID of the IAM role that **should** have access to our S3 bucket. We'll use <a href=https://aws.amazon.com/cli/>AWS CLI</a> to achieve this. If you don't have this set up, I recommend reading <a href=https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html>this</a> article from AWS.

Once you have AWS CLI set up, run the following command on your terminal:

```
> aws iam get-role --role-name YOUR_ROLE_NAME
{
    "Role": {
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17", 
            "Statement": [
                {
                    "Action": "sts:AssumeRole", 
                    "Effect": "Allow", 
                    "Condition": {}, 
                    "Principal": {
                        "AWS": "arn:aws:iam::12345678:root"
                    }
                }
            ]
        }, 
        "MaxSessionDuration": 3600, 
        "RoleId": "AROACHA7SAS77861CKA", 
        "CreateDate": "2020-04-24T08:23:30Z", 
        "RoleName": "access", 
        "Path": "/", 
        "Arn": "arn:aws:iam::12345678:role/access"
    }
}
```

Take note of the `RoleId`. We will need to use this information in our bucket policy.

Bucket policy is a JSON based IAM policy which can define entities that can/cannot access the content of your bucket. The bucket policy that we will add today looks like this:

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::${BUCKET_NAME}",
                "arn:aws:s3:::${BUCKET_NAME}/*"
            ],
            "Condition": {
                "StringNotLike": {
                    "aws:userId": "${ROLE_ID}:*"
                }
            }
        }
    ]
}
```
This policy denies all requests on the bucket if the requester is not using a specific IAM role. You'll need to manually fill out the `BUCKET_NAME` and `ROLE_ID`. The `:*` on the condition allows us to filter for any sessions that assume this role. This is because the `userId `includes random session identifiers when assuming a role.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/obofuuzj8qotv6ji80oc.png)

Head over to your S3 bucket and navigate to *Bucket Policy* under *Permissions*. Add your bucket policy and click *Save*.

If you've come this far, your bucket should now be accessible by only the IAM role that you've specified. Next section will show an example of how you can test this.

# Testing <a name="chapter-3"></a>

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ux5qwbzi32syg868ourg.png)
Head over to the <a href=https://console.aws.amazon.com/console/home>AWS Management Console Login page</a>. Select *IAM user* and enter your account number. Enter the credentials for the user that can assume the IAM role which *should not* have access to your bucket.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/gi2spklo0neuxprev8gb.png)
Open the menu on the top right corner and click *Switch Role*.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/v2ndlwjodxd0qz058wei.png)
Enter your account number again, and the name (not the ARN) of the IAM role that this user should be able to assume. Click `Switch Role`. Once you've successfully assumed the role, you'll see an indicator on the top right corner.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/dccaoibsskk56f1pa0ip.png)
Navigate to S3 and confirm that the user does not have access to your S3 bucket. This can be seen from the `Error` message under `Region`. You can also click on the bucket to confirm that the user cannot see the content of the bucket. Repeat this process for the user that *should* have access to your bucket.

# Conclusion
We've looked at how we can use bucket policies to prevent people from accessing your S3 bucket even if they have access to read from all S3 buckets. We use an explicit deny policy which is scalable, since we don't need to update the policy as new IAM roles are added to the AWS account.