S3 Access Pointsによるクロスアカウントアクセスを検証してみた

# はじめに
「S3 Access Points」が2022年のre:Inventでクロスアカウントにおける共有先側でアクセス権を付与する事ができるようになったのでどんなものなのか試してみようと思います。

# S3 Access Pointsとは
- アクセスポイントごとに固有のアクセスコントロールポリシーを作成する事で共有データセットへのアクセスをコントロール
- 各アプリケーション用にカスタマイズした名前とアクセス許可によってアクセスポイントを個別化して作成
- VPCからのアクセスのみに制限することで、プライベートネットワーク内で完結も可能
- 追加料金なし

S3 Access Pointsを使わない場合、例えば1つのS3バケットに対して複数のアプリケーション(ロール)やユーザからアクセスを想定すると1つのバケットポリシーに何処から、どんなアクションを、何処まで(Prefix)許可するかを対応する分だけ記述していく事になり、1対多のような関係性になります。

S3 Access Pointsを使用する場合、アクセス元のS3バケットポリシーにはアクセスポイントからのアクセス許可を記述するだけでよくなります。代わりにアクセスポイン上でポリシーを設定する必要があります。

アクセスポイント上のポリシーに対するバケットポリシーはガードレールの様な関係性があり、バケットポリシーが許可する範囲内であればアクセスポイント上で設定するポリシーに対してアクションが許可されます。

バケットポリシーで集中的に定義していた権限管理を、特定のアプリケーション向けに用意されたポリシーを使用してアクセスポイント側に委譲させる事で負荷を抑える事ができるようになるので、使いようによっては運用が楽になるかもしれませんね。

# クロスアカウントアクセス
これまではS3バケットに対して同一アカウント内に作成されたアクセスポイントからの権限管理が可能でしたが、今回のアップデートにより別アカウントに作成されたアクセスポイントにてS3バケットへのアクセス権管理とデータセットアクセスが可能になりました。

ポイントとしてはアクセスポイントはS3バケットを所有するアカウントとは別のアカウント側で作成する点ですね。

# アクセスポイント作成
## アクセス元
- S3バケットの作成
    - sample-test-s3-2022-12
- バケットポリシー設定

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": [
                "s3:GetObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::sample-test-s3-2022-12",
                "arn:aws:s3:::sample-test-s3-2022-12/*"
            ],
            "Condition": {
                "StringEquals": {
                    "s3:DataAccessPointAccount": "xxxxxxxxxxxx"
                }
            }
        }
    ]
}
```

## アクセス先
- アクセスポイント作成
    - CLI、AWS SDK、Amazon S3 RESTAPIに対応

```sh
[cloudshell-user@ ~]$ aws s3control create-access-point --name sample-test --account-id xxxxxxxxxxxx --bucket sample-test-s3-2022-12 --bucket-account-id △△△△△△△△△△△△
{
    "AccessPointArn": "arn:aws:s3:ap-northeast-1:xxxxxxxxxxxx:accesspoint/sample-test-accesspoint",
    "Alias": "sample-test-accesspoint-xxxxxxxxxxxxxxxxxxxxx-s3alias"
}
```

コンソールを見るとアクセスポイントが作成されています。
![スクリーンショット 2022-12-31 21.54.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354022/41f276a5-c4c5-b38d-6673-02b4376353ee.png)

試しにバケット名をクリックしてみましょう
![スクリーンショット_2022-12-31_21_54_58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354022/75b27032-0089-e6d9-23e2-2a821d61c29c.png)

すると、アクセスポイント>**sample-test-accesspoint**画面に遷移しバケット内にはオブジェクトが何もない状態であることが分かります。

# オブジェクトのアップロード
- アクセス元よりオブジェクトをアップロードした場合に、アクセスポイント側からオブジェクトが表示されるか確認

## アクセス元
- オブジェクトのアップロード
    - test.png

バケット>**sample-test-s3-2022-12**配下に**test.png**が配置された事を確認
![スクリーンショット_2022-12-31_22_02_11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354022/def13862-d97a-fd2a-ca43-d3776c022732.png)

## アクセス先
- アクセスポイントでオブジェクト確認

アクセスポイント>**sample-test-accesspoint**配下に**test.png**が配置された事を確認
![スクリーンショット_2022-12-31_22_04_11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354022/dfa42bd0-1d1f-7a54-61f1-ab001e3aa58f.png)

アクセス元にアップロードされたオブジェクトがアクセス先アカウントのアクセスポイント上で確認する事が出来ました。

# オブジェクトの削除パターン1
- バケットポリシーにDeleteObject権限を付与した場合に、アクセスポイントからオブジェクトを削除できるか確認

- **test.png**の削除確認
アクセス先アカウントコンソールで通常通りオブジェクトの削除を実施しようとすると削除に失敗します。
![スクリーンショット 2022-12-31 22.07.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354022/5c92f506-7364-804c-4056-07f1f7d9e66d.png)

## アクセス元
- バケットポリシーに削除権限を追加

```diff_json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": [
                "s3:GetObject",
                "s3:ListBucket",
+               "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::sample-test-s3-2022-12",
                "arn:aws:s3:::sample-test-s3-2022-12/*"
            ],
            "Condition": {
                "StringEquals": {
                    "s3:DataAccessPointAccount": "xxxxxxxxxxxx"
                }
            }
        }
    ]
}
```

## アクセス先
- 再度**test.png**の削除確認
![スクリーンショット 2022-12-31 22.11.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354022/584048c1-9804-5259-0dda-13a960be1697.png)

今度はちゃんと削除されました。

# オブジェクトの削除パターン2
- バケットポリシーからDeleteObject権限を削除して、アクセスポリシーにDeleteObjectを付与した場合にアクセスポイントからオブジェクトを削除できるか確認

## アクセス元
- オブジェクトのアップロード
    - test2.png
- バケットポリシーに削除権限の削除

```diff_json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": [
                "s3:GetObject",
                "s3:ListBucket"
-               "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::sample-test-s3-2022-12",
                "arn:aws:s3:::sample-test-s3-2022-12/*"
            ],
            "Condition": {
                "StringEquals": {
                    "s3:DataAccessPointAccount": "xxxxxxxxxxxx"
                }
            }
        }
    ]
}
```

## アクセス先
- アクセスポリシーの設定
    - DeleteObject権限の付与

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::xxxxxxxxxxxx:root"
            },
            "Action": "s3:DeleteObject",
            "Resource": "arn:aws:s3:ap-northeast-1:xxxxxxxxxxxx:accesspoint/sample-test-accesspoint/object/*"
        }
    ]
}
```

- **test2.png**の削除確認

![スクリーンショット_2022-12-31_22_52_04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354022/fb4e165a-08fb-90aa-df6b-6644b8a52ffa.png)

削除が失敗したことが分かります。
大元であるアクセス元バケットポリシーでDeleteObjectの権限を付与していない事から起きた事象で、これによりアクセスポイントはあくまでもバケットポリシーの範囲内でアクションが可能であることが確認出来ました。

# さいごに
当初のイメージでは権限周りの管理に閉じた機能と考えていましたが、アップロード時にリアルタイムでアクセスポイント側からオブジェクトが確認できたところからS3 Access Pointsは機能名から察するにマウントポイントのそれだなと感じました。

検証段階では大きなメリットを感じる事は正直ありませんでしたが、機能コンセプトにあるように大規模な共有データアセットを持つS3に対するバケットポリシー管理からの開放、VPCへのアクセスを制限、新しいポリシーのテストなど幾つかのシーンでは活用の場面がありそうなので覚えておいて損はないかなと思います。