diff --git a/multi-account-multi-region-s3-access/Makefile b/multi-account-multi-region-s3-access/Makefile new file mode 100644 index 0000000..d63acd8 --- /dev/null +++ b/multi-account-multi-region-s3-access/Makefile @@ -0,0 +1,35 @@ +# Enforce IAM to test cross-account cross-region access +export ENFORCE_IAM=1 +export DEBUG=1 + +SHELL := /bin/bash + +usage: ## Show this help + @fgrep -h "##" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\\$$//' | sed -e 's/##//' + +install: ## Install dependencies + @which localstack || pip install localstack + @which awslocal || pip install awscli-local + +run: ## Run the cross-account cross-region experiment of copying data from one S3 bucket to another + ./run.sh + +start: ## Start LocalStack + localstack start -d + +stop: ## Stop LocalStack + @echo + localstack stop + +ready: ## Wait for LocalStack to be ready + @echo Waiting on the LocalStack container... + @localstack wait -t 30 && echo Localstack is ready to use! || (echo Gave up waiting on LocalStack, exiting. && exit 1) + +logs: ## Retrieve logs from LocalStack + @localstack logs > logs.txt + +test-ci: ## Run CI test + make start install ready run; return_code=`echo $$?`;\ + make logs; make stop; exit $$return_code; + +.PHONY: usage install start run stop ready logs test-ci diff --git a/multi-account-multi-region-s3-access/README.md b/multi-account-multi-region-s3-access/README.md new file mode 100644 index 0000000..d5ff161 --- /dev/null +++ b/multi-account-multi-region-s3-access/README.md @@ -0,0 +1,48 @@ +# Localstack Demo: Access S3 resources from different account and different region + +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. +The script uses a couple of AWS profiles to achieve that: + +* Admin user of account A with account ID `000000000001`. + +* Admin user of account B with account ID `000000000002`. + +* Account A user that creates the S3 bucket and subsequent resources inside the bucket. + +* Account B user that copies the resources from account A user's S3 bucket `source` into a bucket `target` it owns. + +## Prerequisites + +* LocalStack +* Docker +* Python 3.6+ / Python Pip +* `make` + +## Installing + +To install the dependencies: + +```shell +make install +``` + +## Starting LocalStack + +Make sure that LocalStack is started: + +```shell +LOCALSTACK_AUTH_TOKEN=... make start +``` + +## Running + +Run the sample demo script: + +```shell +make run +``` + +## License + +This code is available under the Apache 2.0 license. + diff --git a/multi-account-multi-region-s3-access/bucket/main.go b/multi-account-multi-region-s3-access/bucket/main.go new file mode 100644 index 0000000..d78aad9 --- /dev/null +++ b/multi-account-multi-region-s3-access/bucket/main.go @@ -0,0 +1,11 @@ +package main + +import "fmt" + +func helloworld() string { + return "Hello World!!" +} + +func main() { + fmt.Println(helloworld()) +} diff --git a/multi-account-multi-region-s3-access/bucket/main_test.go b/multi-account-multi-region-s3-access/bucket/main_test.go new file mode 100644 index 0000000..c9952bb --- /dev/null +++ b/multi-account-multi-region-s3-access/bucket/main_test.go @@ -0,0 +1,10 @@ +package main + +import "testing" + +func TestHelloWorld(t *testing.T) { + if helloworld() != "Hello World!!" { + t.Fatal("Test fail") + } +} + diff --git a/multi-account-multi-region-s3-access/run.sh b/multi-account-multi-region-s3-access/run.sh new file mode 100755 index 0000000..7a38ebf --- /dev/null +++ b/multi-account-multi-region-s3-access/run.sh @@ -0,0 +1,47 @@ +#!/bin/bash +set -euxo pipefail +export AWS_SECRET_ACCESS_KEY=test + +# Create `ls-a` and `ls-b` IAM users using the root accounts of each user +AWS_ACCESS_KEY_ID=000000000001 awslocal iam create-user --user-name ls-a +AWS_ACCESS_KEY_ID=000000000002 awslocal iam create-user --user-name ls-b + +# Create IAM policies for each of the IAM users using the root accounts of each user +AWS_ACCESS_KEY_ID=000000000001 awslocal iam create-policy --policy-name pa --policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"s3:*","Resource":"*"}]}' +AWS_ACCESS_KEY_ID=000000000002 awslocal iam create-policy --policy-name pb --policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"s3:*","Resource":"*"}]}' + +# Attach the IAM policies to each IAM user using the root accounts of each user +AWS_ACCESS_KEY_ID=000000000001 awslocal iam attach-user-policy --user-name ls-a --policy-arn arn:aws:iam::000000000001:policy/pa +AWS_ACCESS_KEY_ID=000000000002 awslocal iam attach-user-policy --user-name ls-b --policy-arn arn:aws:iam::000000000002:policy/pb + +# Create access keys for each user using the root accounts of each user +CREDENTIALS_A=$(AWS_ACCESS_KEY_ID=000000000001 awslocal iam create-access-key --user-name ls-a) +CREDENTIALS_B=$(AWS_ACCESS_KEY_ID=000000000002 awslocal iam create-access-key --user-name ls-b) + +# Retrieve the access key id of each user +# In LocalStack, the secret access key is not strictly enforced +# But the access key id is +USER_ACCESS_KEY_ID_A=`jq -r .AccessKey.AccessKeyId <<< $CREDENTIALS_A` +USER_ACCESS_KEY_ID_B=`jq -r .AccessKey.AccessKeyId <<< $CREDENTIALS_B` + +# Create `source` bucket in `ls-a` user's account +AWS_ACCESS_KEY_ID=$USER_ACCESS_KEY_ID_A awslocal s3 mb s3://source +AWS_ACCESS_KEY_ID=$USER_ACCESS_KEY_ID_A awslocal s3 sync ./bucket s3://source + +# Attach a bucket policy so that user `ls-b` can access it +AWS_ACCESS_KEY_ID=$USER_ACCESS_KEY_ID_A awslocal s3api put-bucket-policy --bucket source --policy file://source_bucket_policy.json + +# Attempt to access bucket `source` using `ls-a` user +AWS_ACCESS_KEY_ID=$USER_ACCESS_KEY_ID_B awslocal s3 ls s3://source +AWS_ACCESS_KEY_ID=$USER_ACCESS_KEY_ID_B awslocal s3api list-object-versions --bucket source --prefix main.go + +# Sync buckets `source` and `target` using `ls-b` user +AWS_ACCESS_KEY_ID=$USER_ACCESS_KEY_ID_B awslocal s3 mb s3://target +AWS_ACCESS_KEY_ID=$USER_ACCESS_KEY_ID_B awslocal s3 sync s3://source s3://target +AWS_ACCESS_KEY_ID=$USER_ACCESS_KEY_ID_B awslocal s3api list-object-versions --bucket target --prefix main.go + +# Fail the script if somehow user A can access the resources of bucket `target` +echo "Check if s3api list-object-versions commnands fails as expected" +if AWS_ACCESS_KEY_ID=$USER_ACCESS_KEY_ID_A awslocal s3api list-object-versions --bucket target --prefix main.go; then + exit 1 +fi diff --git a/multi-account-multi-region-s3-access/source_bucket_policy.json b/multi-account-multi-region-s3-access/source_bucket_policy.json new file mode 100644 index 0000000..de3efad --- /dev/null +++ b/multi-account-multi-region-s3-access/source_bucket_policy.json @@ -0,0 +1,21 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "s3:Get*" + ], + "Principal": { "AWS": "arn:aws:iam::000000000002:user/ls-b" }, + "Resource": "arn:aws:s3:::source/*" + }, + { + "Effect": "Allow", + "Action": [ + "s3:List*" + ], + "Principal": { "AWS": "arn:aws:iam::000000000002:user/ls-b" }, + "Resource": "arn:aws:s3:::source" + } + ] +}