【AWS】自分以外のアカウントのS3へPutできないようにする。

## はじめに

:::note warn
本ブログに記載した内容は個人の見解であり、所属する会社、組織とは全く関係ありません。
:::

### 概要

本記事では、誤って自分以外のアカウントのS3バケットにデータをPutしないように設定する方法を説明します。

### 背景

初学者をターゲットとしていると思われる、悪意のある「your-s3-bucket-name」というS3バケットが以前話題となるなど、意図せず他のアカウントのバケットにデータをPutすることを防ぐための対策が必要です。
参考：[【注意】your-s3-bucket-nameというS3Bucketについて](https://qiita.com/mj69/items/87094a7fb5f492a0a97a)


## IAMの設定

自身のアカウント以外のS3バケットにオブジェクトをアップロードできないようなIAMポリシーを作成し、IAMユーザーに付与します。

### IAMポリシーの作成

`DenyPutExternalS3`というIAMポリシーを作成します。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Deny",
            "Action": "s3:PutObject",
            "Resource": "*",
            "Condition": {
                "StringNotEquals": {
                    "s3:ResourceAccount": "${aws:PrincipalAccount}"
                }
            }
        }
    ]
}
```

以下の部分で、S3が所属するアカウントと自身のアカウントが等しいかを比較し、

```json
"StringNotEquals": {
    "s3:ResourceAccount": "${aws:PrincipalAccount}"
}
```
自身のアカウントのバケットでない場合は、Putを拒否するようなポリシーになっています。  

:::note warn

なお、一部の AWS サービスは AWS マネージドバケットへのアクセスに依存していることに注意してください。アクセスできるS3バケットを絞ることはこれらのリソースへのアクセスにも影響する可能性があります。  
詳細は以下をご参照ください。
- [Restrict access to buckets in a specified AWS account](https://docs.aws.amazon.com/vpc/latest/privatelink/vpc-endpoints-s3.html#bucket-policies-s3)  in the AWS PrivateLink Guide

- [Restrict access to buckets that Amazon ECR uses](https://docs.aws.amazon.com/AmazonECR/latest/userguide/vpc-endpoints.html#ecr-minimum-s3-perms) in the Amazon ECR Guide

- [SSM Agent communications with AWS managed S3 buckets](https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent-technical-details.html#ssm-agent-minimum-s3-permissions) in the AWS Systems Manager Guide

:::

このIAMポリシーをIAMユーザーまたはユーザーが所属するIAMグループに付与します。

## 検証

### 前提

アカウントAに所属するIAMユーザーuser-Aから、アカウントBのS3バケットへ、オブジェクトをPutできるかを試してみます。  
user-AにはAdmin権限を付与しています。
また、アカウントBのS3バケットには、以下のバケットポリシーを設定しています。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::{アカウントAのID}:root"
            },
            "Action": "s3:PutObject",
            "Resource": [
                "arn:aws:s3:::{アカウントBのS3バケット名}",
                "arn:aws:s3:::{アカウントBのS3バケット名}/*"
            ]
        }
    ]
}
```

### Put拒否ポリシー無しの場合
user-Aに先ほど作成した`DenyPutExternalS3`が付与されていない場合、当然ですがアカウントBへのputは成功します。

```shell
$ aws s3 cp test.txt s3://{アカウントBのS3バケット名}/test/
upload: ./test.txt to s3://{アカウントBのS3バケット名}/test/test.txt
```

### Put拒否ポリシー有りの場合
user-Aに先ほど作成した`DenyPutExternalS3`が付与している場合、アカウントBへの`PutObject`はDenyポリシーにより失敗します。  

```shell
$ aws s3 cp test.txt s3://{アカウントBのS3バケット名}/test/
upload failed: ./test.txt to s3://{アカウントBのS3バケット名}/test/test.txt An error occurred (AccessDenied) when calling the PutObject operation: Access Denied
```

なお、自身のアカウントのS3バケットへの`PutObject`は問題なく成功します。

```shell
$ aws s3 cp test.txt s3://{アカウントAのS3バケット名}/test/
upload: ./test.txt to s3://{アカウントAのS3バケット名}/test/test.txt  
```

## まとめ

自分以外のアカウントのS3バケットにデータをPutしないように設定するIAMポリシーを紹介しました。 
生成AIの出力をコピペする等により、意図せず他アカウントへのputを行ってしまうインシデントを防ぐために、ガードレールとして設定しておくのも良いかもしれないです。

:::note warn
本ブログに記載した内容は個人の見解であり、所属する会社、組織とは全く関係ありません。
:::