Skip to content

Commit

Permalink
Add example for accessing S3 resources across different AWS accounts …
Browse files Browse the repository at this point in the history
…with IAM service enforced (#248)

* Add docs on how to share s3 resources to another account

* Add test script, README and makefile targets
  • Loading branch information
robertlcx authored Jun 28, 2024
1 parent a20710d commit 367ff58
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 0 deletions.
35 changes: 35 additions & 0 deletions multi-account-multi-region-s3-access/Makefile
Original file line number Diff line number Diff line change
@@ -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
48 changes: 48 additions & 0 deletions multi-account-multi-region-s3-access/README.md
Original file line number Diff line number Diff line change
@@ -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.

11 changes: 11 additions & 0 deletions multi-account-multi-region-s3-access/bucket/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package main

import "fmt"

func helloworld() string {
return "Hello World!!"
}

func main() {
fmt.Println(helloworld())
}
10 changes: 10 additions & 0 deletions multi-account-multi-region-s3-access/bucket/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package main

import "testing"

func TestHelloWorld(t *testing.T) {
if helloworld() != "Hello World!!" {
t.Fatal("Test fail")
}
}

47 changes: 47 additions & 0 deletions multi-account-multi-region-s3-access/run.sh
Original file line number Diff line number Diff line change
@@ -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
21 changes: 21 additions & 0 deletions multi-account-multi-region-s3-access/source_bucket_policy.json
Original file line number Diff line number Diff line change
@@ -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"
}
]
}

0 comments on commit 367ff58

Please sign in to comment.