S3バケットをOrganizations内全アカウントにアクセス許可

S3バケットをAWSアカウントを超えて共有したい、Organizatins内の全AWSアカウントに共有できるとなおよいとおもったので、方法を確認してみました。

# S3バケットのクロスアカウントアクセス

まず別のAWSアカウントの特定のIAMユーザーにアクセスを許すところから。

ここでは簡単な「[別の AWS アカウントのユーザーに、オブジェクトを S3 バケットにアップロードするアクセス権を与える](https://aws.amazon.com/jp/premiumsupport/knowledge-center/s3-cross-account-upload-access/?nc1=h_ls)」を試します。このドキュメントは下図のように、S3アクセスを実現するためにIAMポリシーとバケットポリシーを設定する、という内容になっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55718/f707c90d-963e-e3d4-76db-ab39f1ee35a8.png)

アカウントAでは、バケット名 `bucketname` への書込み操作をIAMユーザーに許可するために、IAMポリシーを作成してアタッチします。IAMポリシーの内容は以下のようになります。実施時は `bucketname` は実際のバケット名に合わせて置き換えます。

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::bucketname",
                "arn:aws:s3:::bucketname/*"
            ]
        }
    ]
}
```

これでIAMユーザー `UploadData` は `bucketname` に書込みに行けるようになりました。でも実際に書込みに行ってみると書き込む権限がないと断られる状況です。

そこで次に、アカウントBでバケット名 `bucketname` への書込みをIAMユーザー `UploadData` に許すために、バケットポリシーを作成してアタッチします。バケットポリシーの内容は以下のようになります。実施時は `bucketname` は実際のバケット名、`999999999999` は実際のAWSアカウントAのアカウントID、 `UploadData` は実際のIAMユーザー名で置き換えます。ドキュメント通りの手順でやるなら `arn:aws:iam::999999999999:user/UploadData` がまるごとIAMユーザーのARNで置き換えられます。

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "DelegateS3Access",
            "Effect": "Allow",
            "Principal": {"AWS": "arn:aws:iam::999999999999:user/UploadData"},
            "Action": ["s3:PutObject", "s3:ListBucket"],
            "Resource": [
                "arn:aws:s3:::bucketname",
                "arn:aws:s3:::bucketname/*"
            ]
        }
    ]
}
```

これで `UploadData` さんは無事にS3バケット `bucketname` にオブジェクトを保存（put）できるようになったはず、ということでこのドキュメントは終了。あとは、他アカウントのS3バケットへのアップロードはWebのAWSマネジメントコンソールからは試せないので、AWS CLIで確認します。

```
aws s3 cp ローカルファイル s3://bucketname/ 
```

本気で考えるなら「[S3 バケット内のオブジェクトへのクロスアカウントアクセスを許可する](https://aws.amazon.com/jp/premiumsupport/knowledge-center/cross-account-access-s3/)」で示されている以下の3つのアプローチから、どれがいいか選ぶところから検討することになるのでしょう。上の内容は、このうち最初のものに相当するはず。

* リソースベースのポリシーと IAM ポリシー
* リソースベースのアクセスコントロールリスト (ACL) と IAM ポリシー
* クロスアカウント IAM ロール

# 他AWSアカウントの全IAMユーザーにアクセス許可

次に別のAWSアカウントのすべてのIAMユーザーにアクセスを許したいと思います。バケットポリシーで読み書きを許可するユーザー名にワイルドカード `*` を指定したいところだけど、これはできません。

> Principal エレメント内でユーザーを指定する際に、"すべてのユーザー" の意味でワイルドカード (*) を使用することはできません。プリンシパルには、常に特定のユーザー（または複数の特定ユーザー）を指定する必要があります。
> ([AWS JSON ポリシーの要素: Principal - AWS Identity and Access Management](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_elements_principal.html))

そこで、AWSアカウントそのものを読み書きの許可対象に指定します。アカウントIDを指定する場合は、以下のどちらの書き方をしてもいいことになっています。

```
"Principal": { "AWS": "arn:aws:iam::123456789012:root" }
"Principal": { "AWS": "123456789012" }
```

バケットポリシーを以下のように書き換えます。ここでは上の1行目の書き方をしましたが、より簡素な2行目の書き方でもOKです。

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "DelegateS3Access",
            "Effect": "Allow",
            "Principal": {"AWS": "arn:aws:iam::999999999999:root"},
            "Action": ["s3:PutObject", "s3:ListBucket"],
            "Resource": [
                "arn:aws:s3:::bucketname",
                "arn:aws:s3:::bucketname/*"
            ]
        }
    ]
}
```

少し待ってからローカルファイルのアップロードを試します。

```
aws s3 cp ローカルファイル s3://bucketname/ 
```

# Organizations内の全AWSアカウントにアクセス許可

いよいよOrganizations内の全AWSアカウントへのアクセス許可を考えます。Organizations内のAWSアカウントには `arn:${Partition}:organizations::${MasterAccountId}:account/o-${OrganizationId}/${AccountId}` のようなOrganizations IDを含んだARNが付与されるので、これとワイルドカードを組合わせればできそうに思えますが、実際にはこのARNはPrincipalで利用できないようです。

> 以下のリソースタイプは、このサービスによって定義され、IAM アクセス許可ポリシーステートメントの Resource 要素で使用できます。
> [AWS Organizations のアクション、リソース、および条件キー - AWS Identity and Access Management](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/list_awsorganizations.html)


ここはPrincipalは完全にワイルドカード `*` にしてしまいます。その代わり、Organizations外からのアクセスができないように、Conditions（条件）を設定します。[aws:PrincipalOrgID](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_condition-keys.html#condition-keys-principalorgid)が利用できます。

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "DelegateS3Access",
            "Effect": "Allow",
            "Principal": "*",
            "Action": ["s3:PutObject", "s3:ListBucket"],
            "Resource": [
                "arn:aws:s3:::bucketname",
                "arn:aws:s3:::bucketname/*"
            ]
            "Condition": {"StringEquals":
                {"aws:PrincipalOrgID":["o-xxxxxxxxxxx"]}
            }
        }
    ]
}
```

少し待ってからローカルファイルのアップロードを試してみます。

```
aws s3 cp ローカルファイル s3://bucketname/ 
```

これでOrganizations内のどのAWSアカウントのIAMユーザーでも、このバケットへの読み書きが可能になったはずです。できればOrganizations外のAWSアカウントのIAMユーザーでは、バケットへの読み書きができないことも確認しておいた方がよいでしょう。

# 参考

本稿は以下のドキュメントを参考にまとめました。

* [別の AWS アカウントのユーザーに、オブジェクトを S3 バケットにアップロードするアクセス権を与える](https://aws.amazon.com/jp/premiumsupport/knowledge-center/s3-cross-account-upload-access/?nc1=h_ls)
* [S3 バケット内のオブジェクトへのクロスアカウントアクセスを許可する](https://aws.amazon.com/jp/premiumsupport/knowledge-center/cross-account-access-s3/)
* [AWS JSON ポリシーの要素: Principal - AWS Identity and Access Management](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_elements_principal.html)
* [AWS Organizations のアクション、リソース、および条件キー - AWS Identity and Access Management](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/list_awsorganizations.html)
* [aws:PrincipalOrgID](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_condition-keys.html#condition-keys-principalorgid)

触れていませんが、IAMユーザーとS3バケットにそれぞれポリシーを設定するというのは「アイデンティティベースのポリシーおよびリソースベースのポリシー」に該当します。

* [アイデンティティベースのポリシーおよびリソースベースのポリシー - AWS Identity and Access Management](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/access_policies_identity-vs-resource.html)