複数アカウント環境において、1つのアカウントにデータを集約したいといったことがあると思います。
今回はインターネットと直接通信できないプライベートサブネット上のEC2から別アカウントのS3バケットにVPCエンドポイント経由でアクセスしてみます。
構成イメージ
簡単に説明するとアカウントAのアクセス元サーバが、アカウントBのS3バケットにアクセスできるRole BにAssumeRole(スイッチロール)することで実現できます。
AWS STSにより一時的にRoleBの認証情報を作成し、アクセス元サーバがその認証情報を使用してRoleBにAssumeRoleできる仕組みになっています。
STSやS3へVPCエンドポイント経由でアクセスしているため、インターネットに直接繋がっていないプライベートサブネットからでもアクセスできます。

手順の流れ
【事前準備】
STSのVPCエンドポイントに付けるセキュリティグループを作成しておきます。
ルールは下記のとおりです。
※セキュリティグループ名は「VPC-Endpoint」としておきます。

【全体の流れ】
- 【アカウントB】S3バケット作成
- 【アカウントB】Role Bの作成
- 【アカウントA】VPCエンドポイントの作成
- 【アカウントA】Role Aの作成
- 【アカウントA】アカウントBのs3バケットへアクセス
1. 【アカウントB】S3バケット作成
アカウントBのS3に新規バケットを作成していきます。




暗号化は必須ではないですが、今回はバケットを暗号化してみます。
キータイプについては「SSE-KMS」、キーは「AWS管理キー」を使用します。


作成後、バケットが作成されていることを確認。

2. 【アカウントB】Role Bの作成
アカウントBのバケットにアクセスするためのIAMロール(Role B)を作成します。
信頼されたエンティティタイプは「AWSアカウント」を選択。
AWSアカウントは別のAWSアカウントを選択し、アカウントAのAWSアカウントIDを入力します。

s3にアクセスするための許可ポリシーを設定。
今回はFullAccessを使用。

ロール名は「RoleB」として作成します。


RoleBが作成されたことを確認。(アカウントAのAWSアカウントIDが表示されます。)

3. 【アカウントA】VPCエンドポイントの作成
アカウントAでSTS/S3のVPCエンドポイントを作成します。
STSエンドポイント作成
サービスは「com.amazonaws.ap-northeast-1.sts」を選択。

VPCはアカウントAで使用しているものを選択。
サブネットはエンドポイントを配置するサブネットを選択。

セキュリティグループは事前に作成しておいたVPCエンドポイント用のものを使用します。

エンドポイントを作成。

S3エンドポイント作成
サービスは「com.amazonaws.ap-northeast-1.s3」を選択。

VPCはアカウントAで使用しているものを選択。
ルートテーブルはアクセス元サーバのサブネットに関連付けされているものを選択。

エンドポイントを作成。

4. 【アカウントA】Role Aの作成
STSを使用してアカウントBのRoleBにAssumeRoleするためのRoleAを新規作成します。
信頼されたエンティティタイプは「AWSのサービス」を選択。
ユースケースは「EC2を選択」。

許可ポリシーの追加で「ポリシーの作成」を選択。

ポリシーの作成はJSONタブに切り替えて下記をポリシーとして設定します。
ResourceにはアカウントBのAWSアカウントIDとRoleBを記述してます。
{ "Version": "2012-10-17", "Statement": { "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": "arn:aws:iam::[アカウントBのAWSアカウントID]:role/RoleB" } }

ポリシー作成後、RoleAに追加するポリシーとして先ほど作成したポリシー(ポリシー名はsts-accessとして作成。)が表示されるので
選択し、次へ。

ロール名は「RoleA」として作成。


RoleAが作成されたことを確認。

ここでRoleAをアクセス元サーバに設定します。
EC2の画面でアクセス元サーバを選択し、セキュリティ ⇒ IAMロールの変更を選択。

IAMロールにRoleAを選択し、保存します。

5. 【アカウントA】アカウントBのs3バケットへアクセス
以上で環境準備は整ったので実際にs3バケットへアクセスしてみます。
aws cliコマンドを使用してassume-roleしていきます。
–role-arnにはアカウントBのRoleB、–role-session-nameは任意のセッション名、
–endpointはstsのVPCエンドポイントのURL、–regionには東京リージョン(ap-northeast-1)をそれぞれ指定します。
[アカウントBのAWSアカウントID]:role/RoleB" --role-session-name "cross-account-test" --endpoint https://sts.ap-northeast-1.amazonaws.com --region ap-northeast-1
コマンド実行後、下記の様な認証情報が出力されます。
{ "Credentials": { "AccessKeyId": "アクセスキー", "SecretAccessKey": "シークレットアクセスキー", "SessionToken": "セッショントークン", "Expiration": "2022-05-15T09:44:57+00:00" }, "AssumedRoleUser": { "AssumedRoleId": "XXXXXXXXXXXXXX:cross-account-test", "Arn": "arn:aws:sts::XXXXXXXXXXX:assumed-role/RoleB/cross-account-test" } }
出力内容を環境変数に設定します。
# export AWS_ACCESS_KEY_ID="アクセスキー" # export AWS_SECRET_ACCESS_KEY="シークレットアクセスキー" # export AWS_SESSION_TOKEN="セッショントークン"
IAMの情報がアカウントBのRoleBになっていることを確認します。
# aws sts get-caller-identity --region ap-northeast-1 --endpoint https://sts.ap-northeast-1.amazonaws.com { "UserId": "XXXXXXXXXXXXX:cross-account-test", "Account": "XXXXXXXXXXXXX", "Arn": "arn:aws:sts::XXXXXXXXXXXXX:assumed-role/RoleB/cross-account-test" }
この状態でs3バケットにファイルをコピーしてみます。
# aws s3 cp /tmp/s3-put-test.txt s3://shimmy-cross-account-test/ upload: ../tmp/s3-put-test.txt to s3://shimmy-cross-account-test/s3-put-test.txt
lsでバケット内を確認するとコピーしたファイルが確認できました。
# aws s3 ls --region ap-northeast-1 s3://shimmy-cross-account-test 2022-05-15 09:00:20 0 s3-put-test.txt
補足事項
AWS STSによる認証情報を環境変数として設定していない場合、下記の様にアクセスが拒否されます。
# aws s3 ls --region ap-northeast-1 s3://shimmy-cross-account-test An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
以上で完了になります。
コメント