S3 Buckets and Changes to Cross-account Access

Published on 02 December 2021

Introduction

It is not unusual to have a requirement to grant cross-account access to S3. Normally you would do this via an IAM policy on the user, and a bucket policy. There is a change announced at re:Invent though that helps a lot here.

Granting Access

To illustrate this, here is an IAM policy for a user in one of my accounts. This has been created as a managed policy, and attached to the user, testuser1:

        {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Action": [
                        "s3:GetObject",
                        "s3:PutObject",
                        "s3:PutObjectAcl"
                    ],
                    "Resource": "arn:aws:s3:::heywoodstuff/*"

                }
            ]
        }

At that point, we have given testuser1 permission to access the bucket called "heywoodstuff". S3 names are unique, so we don't need to specify anything other than the bucket name. We are not done yet though.

If we try and view the bucket (aws s3 ls), it won't show the bucket contents, because we also need to do some work in the account where the bucket actually exists. There, we can create this bucket policy, in the properties of bucket itself:

        {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {
                        "AWS": "arn:aws:iam::912461xxxx39:user/testuser1"
                    },
                    "Action": [
                        "s3:GetObject",
                        "s3:PutObject",
                        "s3:PutObjectAcl"
                    ],
                    "Resource": [
                        "arn:aws:s3:::heywoodstuff/*"
                    ]
                }
            ]
        }

So by doing that, we have then given the user from the first account, permissions to access the bucket in the second account. In the second account, we have put a policy on the bucket to say that the user can access it. Notice that here we specified the account where the user comes from, as well as the username.

Those permissions should then allow you to upload a file, which we can do from the command line:

        PS C:\stuff> aws s3 cp variables.tf s3://heywoodstuff --profile testuser1
        upload: .\variables.tf to s3://heywoodstuff/variables.tf

That indicates that the upload was successful, and I have uploaded a file called variables.tf, as a user called testuser1.

Object Ownership

But you will see that because you don't have permissions to read what is in the bucket, you won't be able to actually see the file using this user (testuser1), which is expected given the permissions granted. If we use a different profile for a user with access though (a user called gregcli here), we can see the file in the bucket (variables.tf):

        PS C:\stuff> aws s3 ls s3://heywoodstuff --profile gregcli
                                PRE Unsaved/
        2021-01-11 21:48:07       4028 CWConfig_Linux.json
        2021-05-09 19:34:16        886 org_inventory.json
        2021-05-09 20:22:36       1037 org_inventory2.json
        2021-12-02 11:04:00        445 variables.tf

Success! So the next thing to do, is see if we can download that file using the "gregcli" account.

        PS C:\stuff> aws s3 cp s3://heywoodstuff/variables.tf variables2.tf --profile gregcli
        fatal error: An error occurred (403) when calling the HeadObject operation: Forbidden

We can't, even though the user has S3FullAccess. If we jump back to the console for a second and check using a user with full access, we will see that we can't even see the ACLs for that object, variables.tf, even though it is in our bucket in our account.

s3_1

This is to be expected though. The profile for the user I am using to view the bucket, gregcli, has full access to S3, but the file we uploaded, by a user in a different account, and therefore belongs to the user in the other account. The gregcli user doesn't have rights.

There are some scenarios where this is fine, somewhere it is a real issue, and in general it can just be quite confusing.

What's New? Disabling S3 Bucket ACLs

To get around this, we can edit the bucket properties. So go to the bucket Properties, go to Object Ownership, and disable ACLs.

s3_2

When we then try again to download the file using gregcli, it works, because we now own the object (great, since it is in our bucket in our account!):

        PS C:\stuff> aws s3 cp s3://heywoodstuff/variables.tf variables2.tf --profile gregcli
        download: s3://heywoodstuff/variables.tf to .\variables2.tf

Problem solved! What is good though, is that we can set the Ownership property back to "ACLs enabled" and choose to restore the pre-existing ACLs, so this is not a one-way change. Once we re-enable ACLs, we are back to where we were.

        PS C:\stuff> aws s3 cp s3://heywoodstuff/variables.tf variables2.tf --profile gregcli
        fatal error: An error occurred (403) when calling the HeadObject operation: Forbidden

Personally, I think this is really good change as it will reduce some of the complexity and confusion around permissions when accessing buckets across account. You can read more about it here.

comments powered by Disqus