In this recipe, we will allow cross-account access to a bucket in one account (let's call this account A) to users in another account (let's call this account B), both through ACLs and bucket policies. Logging is a common use case for cross-account access. We can store our logs in a different account to provide access to an auditor or to secure them in case the account is compromised.
S3 cross-account access from the CLI
Getting ready
We need two working AWS accounts (let's call them account A and account B), configured as follows:
- Note down the canonical ID of account B: I have noted down mine as e280db54f21834544a8162b8fc5d23851972d31e1ae3560240156fa14d66b952.
- A bucket in account A with a file in it: I will be using a bucket name awsseccookbook, with a file named image-heartin-k.png. Replace them with your bucket name and filename.
- A user with administrator permission in account A and account B: We'll create profiles for these users in the CLI. I am using the awssecadmin and awschild1admin CLI profiles, respectively.
- A user or group with no permission in account B: I have created a group, testusergroup, and added the testuser user to the group. I will call this user's CLI profile child1_testuser.
Verify that both the administrator user and the non-administrator user from account B have no permission to upload to the bucket in account A.
How to do it...
We will implement cross-account access using CLI commands. You can follow the CLI commands and the tips provided within the following recipe to implement the cross-account access in the console or by using APIs.
Uploading to a bucket in another account
Perform the following steps to upload files as a user from account B to a bucket in account A:
- Create an access control policy document that grants access to account B and save it as acl-write-another-account.json:
{
"Owner": {
"DisplayName": "awsseccookbook",
"ID": "5df5b6014ae606808dcb64208aa09e4f19931b3123456e152c4dfa52d38bf8fd"
},
"Grants": [
{
"Grantee": {
"Type": "CanonicalUser",
"ID": "e280db54f21834544a8162b8fc5d23851972d31e1ae3560240156fa14d66b952"
},
"Permission": "WRITE"
}
]
}
The canonical ID of account A is provided under the Owner section, and the canonical ID of account B is provided under the Grants section.
- Update the ACL on the bucket owned by account A, as an administrator of account A:
aws s3api put-bucket-acl \
--bucket awsseccookbook \
--access-control-policy file://resources/acl-write-another-account.json \
--profile awssecadmin
We should now be able to upload objects to the bucket as an administrator from account B. However, a non-administrator from account B will not be able to upload files:
- Create a policy to delegate s3:PutObject access and the s3:PutObjectAcl action to administrator users in account B, and save this file as iam-policy-s3-put-obj-and-acl.json:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DelegateS3WriteAccess",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:PutObjectAcl"
],
"Resource": "arn:aws:s3:::awsseccookbook/*"
}
]
}
The s3:PutObjectAcl action is required to use canned ACLs later.
- Create a policy in account B using the preceding policy document as an administrator in account B:
aws iam create-policy \
--policy-name MyS3PutObjAndAclPolicy \
--policy-document file://resources/iam-policy-s3-put-obj-and-acl.json \
--profile awschild1admin
We should get a response as follows:
- Attach the preceding policy to the test user's group:
aws iam attach-group-policy \
--group-name testusergroup \
--policy-arn arn:aws:iam::380701114427:policy/MyS3PutObjAndAclPolicy \
--profile awschild1admin
We may also attach the policy directly to the user instead; however, using a group is a recommended practice.
- Upload the object to the bucket as a non-administrator user in account B:
aws s3 cp image-heartin-k.png s3://awsseccookbook/image-from-b-user.png \
--profile child1_testuser
We should be able to upload the file successfully.
If we try to download the object as an administrator in account A, the request will fail as follows:
- Upload the object to the bucket as a user in account B with the bucket-owner-full-control canned ACL:
aws s3 cp image-heartin-k.png s3://awsseccookbook/image-from-b-user.png \
--acl bucket-owner-full-control \
--profile child1_testuser
Account A should now be able to download the file successfully:
In the next section, we will learn to enforce the situation whereby account B should always give this permission to account A, with the bucket owner using bucket policies.
Uploading to a bucket in another account with a bucket policy
If you followed along with the previous section, remove the ACL granted on account A before proceeding with the following steps:
- Create a bucket policy that explicitly allows our non-administrator user, testuser, from account B to perform a PutObject action. Also, make sure that the user gives full control to the bucket owner through a canned ACL. Save the file as bucket-policy-write-another-account-user.json:
{
"Id": "SomeUniqueId1",
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllPutForOtherAccountUser",
"Action": [
"s3:PutObject"
],
"Effect": "Allow",
"Resource": "arn:aws:s3:::awsseccookbook/*",
"Condition": {
"StringEquals": {"s3:x-amz-acl":"bucket-owner-full-control"}
},
"Principal": {
"AWS": [
"arn:aws:iam::380701114427:user/testuser"
]
}
}
]
}
- Attach the bucket policy to the bucket:
aws s3api put-bucket-policy \
--bucket awsseccookbook \
--policy file://resources/bucket-policy-write-another-account-user.json \
--profile awssecadmin
- Attach a policy in account B to the non-administrator user, testuser, which allows the s3:PutObject and s3:PutObjectAcl actions. This step has already been performed in the previous section. If you haven't already done this in the previous section (or if you deleted the policy), work through the previous section to complete it.
- Upload image as testuser from account B to a bucket in account A with and without canned ACLs:
Here, we used a bucket policy to ensure that the user from account B provides full control to the bucket owner in account A using canned ACLs; otherwise the upload will fail.
How it works...
In the Uploading to a bucket in another account section, we first granted permissions to account B through a policy in account A. Later, the account B administrator delegated the permission to an administrator user through the user's group. We also saw that the account A administrator won't have access to an object uploaded by the user of account B, even though account A is the bucket owner, unless account B explicitly grants permission.
For account A to have access, the user of account B should grant permission while uploading the file, and this can be done using canned ACLs. An account B user with s3:PutObjectAcl permission can grant permission to account A, the bucket owner, using the bucket-owner-read or bucket-owner-full-control canned ACLs. With ACLs, there is no way to enforce a constraint, such as that account B should always give permission to account A, the bucket owner. This can, however, be enforced with bucket policies.
In the Uploading to a bucket in another account with a bucket policy section, we directly gave permission to the account B user through a bucket policy. We also added a Condition element to our bucket policy to ensure that the user in account B should always use the bucket-owner-full-control ACL to give complete control to account A, the bucket owner. The s3:PutObjectAcl permission is required for account B to specify a canned ACL.
There's more...
Account A can grant access to its S3 resources to account B in one of the following ways:
- The account A administrator grants access to account B through a bucket policy or ACL. The account B administrator delegates that permission to a user using a user policy. The user in account B can then access the S3 resources in account A according to the permissions granted to them. In this recipe, we followed this approach using ACL in the Uploading to a bucket in another account section, and the same is also possible with a bucket policy.
- The account A administrator grants access directly to a user in account B through a bucket policy. The account B administrator still has to delegate permission to the user using a policy. The user in account B can then access the S3 resources in account A according to the permissions granted to them. In this recipe, we followed this approach in the Uploading to a bucket in another account with a bucket policy section.
- The account A administrator creates a role with the required permissions to its S3 resources in account A. The role will have a trust relationship with account B as a trusted entity and account A as the trusting entity. The account B administrator delegates that permission to a user using user policy. The user in account B can then assume that role and access the S3 resources in account A in accordance with the permissions granted to them. We saw a variation of IAM role-based, cross-account access in Chapter 1, Managing AWS Accounts with IAM and Organizations, in the Switching role with AWS organizations recipe.
Let's quickly go through some scenarios to understand cross-account policies better:
- Account A created a bucket and gave PutObject ACL permissions to everyone (public access):
- Can a user from the same AWS account with no permissions (no policies attached) upload a file to that bucket from the AWS CLI? Yes.
- Can a user from another AWS account with no permissions (no policies attached) upload a file to that bucket from the AWS CLI? No.
- Can an administrator user from another AWS account upload a file to that bucket from the AWS CLI? Yes.
- Account A created a bucket and gave PutObject ACL permissions to account B using the account's canonical ID:
- Can a user with no permissions (no policies attached) from account B upload a file to that bucket from the AWS CLI? No.
- Can an administrator user from account B upload a file to that bucket from the AWS CLI? Yes.
- Account B uploaded a file to account A with cross-account access and no canned ACL (equivalent to the canned private ACL).
- Can a user with no permissions (no policies attached) from the bucket owner account read that object? No.
- Can an administrator user from the bucket owner account read that object? No.
- Can an administrator user from the bucket owner account delete that object? Yes.
- Account A created a bucket and gave the PutObject permission directly to a user, testuser, in account B through a bucket policy.
- Can testuser upload to a bucket in account A without additional permissions in account B? No, they still need to have the PutObject permission to the bucket assigned through a user policy within account B.
- Can an administrator in account B upload to a bucket in account A? No, we have explicitly granted permission to testuser.
- Can the account B administrator delegate more access to its users than it was granted by account A? This will not result in an error, but it will not have any impact as the permissions will be evaluated again from account A.
- Can we enforce the usage of canned ACL through a bucket policy? Yes, using a condition that checks the value of the s3:x-amz-acl condition key, for example, for the bucket-owner-full-control value.
See also
- We saw a variation of IAM role-based, cross-account access in Chapter 1, Managing AWS Accounts with IAM and Organizations, in the Switching Role with AWS Organizations recipe.