CloudFront のオリジンに S3 アクセスポイントを設定する

試してみたらできたので共有します。

なお、S3 バケットへのパブリックアクセスはブロックされており、CloudFront からは Origin Access Identity (OAI) を利用してアクセスするものとします。

https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html

## OAI の作成

OAI はオリジンの作成時ではなく事前に作成しておきます。

CloudFront コンソールでメニューから「オリジンアクセスアイデンティティ」を選択し、「オリジンアクセスアイデンティティを作成」します。

![image1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586035/34c46545-dc58-a0ba-d4d2-32cb92a54c2c.png)

名前は適当にわかりやすいものをつけておきます。

作成できたら、OAI の ID を控えておきます。

![image2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586035/0c0b456f-979a-571a-3a7b-ff096afc0d41.png)

## S3 アクセスポイントの作成

S3 コンソールで対象のバケットを選択し、「アクセスポイント」タブから「アクセスポイントの作成」を行います。

![image3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586035/8a2e7313-3885-abfa-c66e-0ebe7afebfc1.png)

ネットワークオリジンには「インターネット」、ブロックパブリックアクセス設定は「パブリックアクセスをすべてブロック」に設定します。

また、アクセスポイントポリシーは次のように設定します。
※ `${OAI_ID}` は先ほど控えておいた OAI の ID に、`${ACCESSPOINT_ARN}` は作成している S3 アクセスポイントの ARN に置き換えてください

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${OAI_ID}"
            },
            "Action": "s3:GetObject",
            "Resource": "${ACCESSPOINT_ARN}/object/*"
        }
    ]
}
```

このアクセスポイントポリシーにより、バケット内のすべてのオブジェクトの取得を OAI に許可しています。

作成できたら、アクセスポイントエイリアスを控えておきます。

![image4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586035/1d71db2c-3d45-8d91-7fb2-e06e458a74fb.png)

## バケットポリシーの設定

アクセスポイントポリシーでアクセス許可を設定した場合、基になるバケット側でも同じアクセスを許可する必要があります。

ここでアクセスポイントポリシーと同等の内容のバケットポリシーを設定してしまうと S3 アクセスポイントを使っている意味があまりなくなってしまうので、「アクセスポイントにアクセスコントロールを委任」する設定を行います。
これにより、アクセスポイントポリシーで許可されたアクセスがバケット側でも許可されます。

https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-points-policies.html#access-points-delegating-control

対象の S3 バケットに次のようなバケットポリシーを設定します。
※ `${BUCKET_ARN}` は S3 バケットの ARN に、`${AWS_ACCOUNT_ID}` は AWS アカウントの ID に置き換えてください

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": "*",
            "Resource": [
                "${BUCKET_ARN}",
                "${BUCKET_ARN}/*"
            ],
            "Condition": {
                "StringEquals": {
                    "s3:DataAccessPointAccount": "${AWS_ACCOUNT_ID}"
                }
            }
        }
    ]
}
```

## CloudFront オリジンの作成

CloudFront コンソールで新規にディストリビューションを作成します。
（作成済みの場合は対象のディストリビューションを選択し、「オリジン」タブから「オリジンを作成」します)

![image5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586035/4ffaa1a4-45db-5c2a-25e5-4dd264663363.png)

ここが一番重要なのですが、「オリジンドメイン」の選択肢には S3 アクセスポイントは表示されません(2021 年9 月現在)。
そこで、次のような値を手動で入力します。
※ `${ACCESSPOINT_ALIAS}` は先ほど控えておいたアクセスポイントエイリアスに、`${BUCKET_REGION}` は対象の S3 バケットのリージョンに置き換えてください

```
${ACCESSPOINT_ALIAS}.s3.${BUCKET_REGION}.amazonaws.com
```

このような値を入力することで、OAI の設定も可能となります。
図のように OAI の使用を有効化し、作成した OAI を選択してください(バケットポリシーは更新しないようにします)。

![image6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586035/c1177bad-2882-29f1-f233-2b6b1ab73426.png)

後は適当に設定してディストリビューション (オリジン) を作成すれば完了です。