DEV Community

Daniel Kim
Daniel Kim

Posted on

How to secure your S3 bucket from users with s3:* access

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

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 if you already have this data.

Alt Text
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
Navigate to IAM and create two roles with AmazonS3ReadOnlyAccess policy. This policy will give the roles read only access to all buckets.

Alt Text
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
Type in each of the two role names for each policy as well as your AWS account ID.

Alt Text
Navigate to Groups to create two groups. Attach one of the policies to each of these groups.

Alt Text
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
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

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 AWS CLI to achieve this. If you don't have this set up, I recommend reading this 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 userIdincludes random session identifiers when assuming a role.

Alt Text

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

Alt Text
Head over to the AWS Management Console Login page. 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
Open the menu on the top right corner and click Switch Role.

Alt Text
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
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.

Top comments (0)