別アカウントのS3にファイルを置く方法

# 環境
アカウントA：111122223333
アカウントB：777788889999
リージョン：東京
EC2：AmazonLinux 2023

構成としては以下です。
![スクリーンショット 2025-04-02 170105.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3860847/1e46528f-eee3-4764-ba65-19a0cd307c49.png)

EC2にアタッチしたIAMロールでアカウントBのロールをAssumeRole出来るようにし、
アカウントBのロールでAssumeRoleの許可と、S3バケットへPut出来る権限を付与します。

簡単に言うと、**アカウントAのEC2でアカウントBのロールを使ってS3にファイルを置く**ということです。
たびたび出てくるAssumeRoleの意味が分からなければ、脳内で**AssumeRoleする=借りる**と変換してください。

# やってみた
EC2は作成されている前提で進めます。
今回はパブリックサブネットに配置されている前提ですが、プライベートにある場合はSTSとS3のエンドポイントが必要になります。
S3エンドポイント：com.amazonaws.ap-northeast-1.s3
STSエンドポイント：com.amazonaws.ap-northeast-1.sts

### アカウントAの作業

まずはポリシーを作成します。
以下JSONに記載します。
アカウントBのロール（S3を操作するための権限）をAssumeRole先として記載します。
```JSON
{
    "Version": "2012-10-17",
    "Statement": {
        "Effect": "Allow",
        "Action": "sts:AssumeRole",
        "Resource": "arn:aws:iam::777788889999:role/S3-trance-role"
    }
}
```

ここでは仮に、「accountA-S3-Policy」とします。

続いて作ったポリシーを使うためにロールも作成します。

ロールでは、使用するのがEC2のため、「信頼するエンティティタイプ」にはEC2を選択します。
![スクリーンショット 2025-04-02 173828.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3860847/c4182f6a-8d34-498e-b3d3-f2f4d8384295.png)

アタッチするポリシーは先ほど作成した「accountA-S3-Policy」です。

ロール名は「accountA-S3-Role」とします。

あとはこの作成した「accountA-S3-Role」をEC2にアタッチしてあげます。

### アカウントBの作業

続いてアカウントBの作業です。
アカウントBでは、先ほどのアカウントAで作成した「accountA-S3-Role」を受け入れてあげて、S3にファイルを置くための権限を許可してあげます。

まずはポリシーを作成します。
ファイルを置くための権限として「s3:PutObject」を許可。
ターゲットとするS3バケットは「test-s3-backet」とします。
```JSON
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::test-s3-backet/*"
            ]
        }
    ]
}
```
ポリシー名は「accountB-S3-Policy」とします。

続いて「accountB-S3-Policy」を使うためにロールも作成します。

先ほどは「信頼するエンティティタイプ」にEC2を指定しましたが、ここでは「accountA-S3-Role」を指定します。
アカウントAが「accountA-S3-Role」を使ってアカウントBのロールを借りてS3を使おうとしているため、「accountA-S3-Role」を信頼してあげる設定をします。
カスタム信頼ポリシーを選択して、以下のように記述します。
```JSON
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Statement1",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::111122223333:role/accountA-S3-Role"
                ]
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
```

そして、先ほど作成した「accountB-S3-Policy」をアタッチして作成します。

ロール名は、アカウントAのポリシーで書いた「S3-trance-role」にします。

**ここまでで、アカウントAがアカウントBの「S3-trance-role」を使ってS3にファイルを置く権限を持つことが出来るようになりました。**

ただもう一つ設定しなければいけないのが**S3のバケットポリシー**です。
普段自分のアカウントのS3を使用する時は、IAMかバケットポリシーのどちらかが許可されていればいいのですが、**他のアカウント**から**S3**へアクセスする時は、**IAMの許可とS3のバケットポリシーの許可の両方が必要**です。

S3のバケットポリシーにも許可を書いてあげます。

```JSON
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::7777788889999:role/S3-trance-role"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::test-s3-backet/*"
        }
    ]
}
```
:::note warn
※注意
記載するロールはアカウントBのロールです。
アカウントAの「accountA-S3-Role」はアカウントBの「S3-trance-role」を借りるために使用しているので、実際にS3にアクセスするのはアカウントAが借りている「S3-trance-role」になります。
:::

Put以外にも操作したい権限がある場合は、「accountB-S3-Policy」とS3バケット両方に記載を増やしてください。

# S3にファイルを置くためのEC2内での操作
EC2でアカウントBの「S3-trance-role」を使うためには、必要な作業があるのでまとめておきます。
```
ls -l ~/.aws
# ディレクトリがなければ「mkdir ~/.aws」で作成
vi ~/.aws/config
# 以下を記載
================================
[profile ToS3-Role]
role_arn = arn:aws:iam::777788889999:role/S3-trance-role
credential_source = Ec2InstanceMetadata
================================

## UserIdやAccountなどの情報が出力されることを確認
aws sts get-caller-identity --profile ToS3-Role

## ファイルを作成してアカウントBのS3にtest.txtファイルを置く
cd /tmp
touch test.txt
aws s3 cp /tmp/test.txt s3://test-s3-backet --profile ToS3-Role
```
:::note info
「ToS3-Role」は任意なのでどんな名前でもいいです。
変更する場合は、S3にファイルを置くコマンドで指定する--profileの後の部分も変えて下さい。
role_arnは借りるロールを記載します。
credential_sourceは、変える必要はありません。
:::

読んでくださってありがとうございました！
誰かのためになれば幸いです。

以上！！