Skip to content

Commit 367ff58

Browse files
authored
Add example for accessing S3 resources across different AWS accounts with IAM service enforced (#248)
* Add docs on how to share s3 resources to another account * Add test script, README and makefile targets
1 parent a20710d commit 367ff58

File tree

6 files changed

+172
-0
lines changed

6 files changed

+172
-0
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Enforce IAM to test cross-account cross-region access
2+
export ENFORCE_IAM=1
3+
export DEBUG=1
4+
5+
SHELL := /bin/bash
6+
7+
usage: ## Show this help
8+
@fgrep -h "##" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\\$$//' | sed -e 's/##//'
9+
10+
install: ## Install dependencies
11+
@which localstack || pip install localstack
12+
@which awslocal || pip install awscli-local
13+
14+
run: ## Run the cross-account cross-region experiment of copying data from one S3 bucket to another
15+
./run.sh
16+
17+
start: ## Start LocalStack
18+
localstack start -d
19+
20+
stop: ## Stop LocalStack
21+
@echo
22+
localstack stop
23+
24+
ready: ## Wait for LocalStack to be ready
25+
@echo Waiting on the LocalStack container...
26+
@localstack wait -t 30 && echo Localstack is ready to use! || (echo Gave up waiting on LocalStack, exiting. && exit 1)
27+
28+
logs: ## Retrieve logs from LocalStack
29+
@localstack logs > logs.txt
30+
31+
test-ci: ## Run CI test
32+
make start install ready run; return_code=`echo $$?`;\
33+
make logs; make stop; exit $$return_code;
34+
35+
.PHONY: usage install start run stop ready logs test-ci
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Localstack Demo: Access S3 resources from different account and different region
2+
3+
Simple demo script to showcase the accessing of S3 resources from a different AWS account using bucket policies and IAM users with specific IAM policies attached to their identities.
4+
The script uses a couple of AWS profiles to achieve that:
5+
6+
* Admin user of account A with account ID `000000000001`.
7+
8+
* Admin user of account B with account ID `000000000002`.
9+
10+
* Account A user that creates the S3 bucket and subsequent resources inside the bucket.
11+
12+
* Account B user that copies the resources from account A user's S3 bucket `source` into a bucket `target` it owns.
13+
14+
## Prerequisites
15+
16+
* LocalStack
17+
* Docker
18+
* Python 3.6+ / Python Pip
19+
* `make`
20+
21+
## Installing
22+
23+
To install the dependencies:
24+
25+
```shell
26+
make install
27+
```
28+
29+
## Starting LocalStack
30+
31+
Make sure that LocalStack is started:
32+
33+
```shell
34+
LOCALSTACK_AUTH_TOKEN=... make start
35+
```
36+
37+
## Running
38+
39+
Run the sample demo script:
40+
41+
```shell
42+
make run
43+
```
44+
45+
## License
46+
47+
This code is available under the Apache 2.0 license.
48+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package main
2+
3+
import "fmt"
4+
5+
func helloworld() string {
6+
return "Hello World!!"
7+
}
8+
9+
func main() {
10+
fmt.Println(helloworld())
11+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package main
2+
3+
import "testing"
4+
5+
func TestHelloWorld(t *testing.T) {
6+
if helloworld() != "Hello World!!" {
7+
t.Fatal("Test fail")
8+
}
9+
}
10+
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#!/bin/bash
2+
set -euxo pipefail
3+
export AWS_SECRET_ACCESS_KEY=test
4+
5+
# Create `ls-a` and `ls-b` IAM users using the root accounts of each user
6+
AWS_ACCESS_KEY_ID=000000000001 awslocal iam create-user --user-name ls-a
7+
AWS_ACCESS_KEY_ID=000000000002 awslocal iam create-user --user-name ls-b
8+
9+
# Create IAM policies for each of the IAM users using the root accounts of each user
10+
AWS_ACCESS_KEY_ID=000000000001 awslocal iam create-policy --policy-name pa --policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"s3:*","Resource":"*"}]}'
11+
AWS_ACCESS_KEY_ID=000000000002 awslocal iam create-policy --policy-name pb --policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"s3:*","Resource":"*"}]}'
12+
13+
# Attach the IAM policies to each IAM user using the root accounts of each user
14+
AWS_ACCESS_KEY_ID=000000000001 awslocal iam attach-user-policy --user-name ls-a --policy-arn arn:aws:iam::000000000001:policy/pa
15+
AWS_ACCESS_KEY_ID=000000000002 awslocal iam attach-user-policy --user-name ls-b --policy-arn arn:aws:iam::000000000002:policy/pb
16+
17+
# Create access keys for each user using the root accounts of each user
18+
CREDENTIALS_A=$(AWS_ACCESS_KEY_ID=000000000001 awslocal iam create-access-key --user-name ls-a)
19+
CREDENTIALS_B=$(AWS_ACCESS_KEY_ID=000000000002 awslocal iam create-access-key --user-name ls-b)
20+
21+
# Retrieve the access key id of each user
22+
# In LocalStack, the secret access key is not strictly enforced
23+
# But the access key id is
24+
USER_ACCESS_KEY_ID_A=`jq -r .AccessKey.AccessKeyId <<< $CREDENTIALS_A`
25+
USER_ACCESS_KEY_ID_B=`jq -r .AccessKey.AccessKeyId <<< $CREDENTIALS_B`
26+
27+
# Create `source` bucket in `ls-a` user's account
28+
AWS_ACCESS_KEY_ID=$USER_ACCESS_KEY_ID_A awslocal s3 mb s3://source
29+
AWS_ACCESS_KEY_ID=$USER_ACCESS_KEY_ID_A awslocal s3 sync ./bucket s3://source
30+
31+
# Attach a bucket policy so that user `ls-b` can access it
32+
AWS_ACCESS_KEY_ID=$USER_ACCESS_KEY_ID_A awslocal s3api put-bucket-policy --bucket source --policy file://source_bucket_policy.json
33+
34+
# Attempt to access bucket `source` using `ls-a` user
35+
AWS_ACCESS_KEY_ID=$USER_ACCESS_KEY_ID_B awslocal s3 ls s3://source
36+
AWS_ACCESS_KEY_ID=$USER_ACCESS_KEY_ID_B awslocal s3api list-object-versions --bucket source --prefix main.go
37+
38+
# Sync buckets `source` and `target` using `ls-b` user
39+
AWS_ACCESS_KEY_ID=$USER_ACCESS_KEY_ID_B awslocal s3 mb s3://target
40+
AWS_ACCESS_KEY_ID=$USER_ACCESS_KEY_ID_B awslocal s3 sync s3://source s3://target
41+
AWS_ACCESS_KEY_ID=$USER_ACCESS_KEY_ID_B awslocal s3api list-object-versions --bucket target --prefix main.go
42+
43+
# Fail the script if somehow user A can access the resources of bucket `target`
44+
echo "Check if s3api list-object-versions commnands fails as expected"
45+
if AWS_ACCESS_KEY_ID=$USER_ACCESS_KEY_ID_A awslocal s3api list-object-versions --bucket target --prefix main.go; then
46+
exit 1
47+
fi
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"Version": "2012-10-17",
3+
"Statement": [
4+
{
5+
"Effect": "Allow",
6+
"Action": [
7+
"s3:Get*"
8+
],
9+
"Principal": { "AWS": "arn:aws:iam::000000000002:user/ls-b" },
10+
"Resource": "arn:aws:s3:::source/*"
11+
},
12+
{
13+
"Effect": "Allow",
14+
"Action": [
15+
"s3:List*"
16+
],
17+
"Principal": { "AWS": "arn:aws:iam::000000000002:user/ls-b" },
18+
"Resource": "arn:aws:s3:::source"
19+
}
20+
]
21+
}

0 commit comments

Comments
 (0)