michimani.net

AWS CLI で CloudFront の OAI を OAC に移行する

2022-08-30

CloudFront から S3 へのアクセスを制御する方法として Origin Access Identity (OAI) という機能がありましたが、それに代わる機能として Origin Access Control (OAC) という機能が発表されました。今回は、 AWS CLI を使って OAI を利用していたものを OAC に移行する方法について書きます。

移行方法

基本的には下記の公式ドキュメントに沿って移行していきます。

Restricting access to an Amazon S3 origin - Amazon CloudFront

具体的な手順としては、

  1. 対象の S3 Bucket の Bucket Policy に、 Origin Access Identity の Statement を残したまま Origin Access Control の Statement を追記する
  2. Origin Access Control のリソースを作成する
  3. 対象の Distribution に設定する
  4. 対象の S3 Bucket の Bucket Policy から Origin Access Identity の Statement を削除する
    1. 不要になった Origin Access Identity のリソースを削除する

となります。

AWS CLI でやっていく

今回は、上記の手順を AWS CLI を使ってやってみます。

必要な AWS CLI のバージョンは、 v1 は 1.25.60 以降、 v2 は 2.7.27 以降です。今回は v2 を使います。

❯ aws --version
aws-cli/2.7.27 Python/3.9.11 Darwin/21.6.0 exe/x86_64 prompt/off

作業するにあたっては、対象の S3 Bucket の名前と CloudFront の Distribution ID が必要なので、それぞれ環境変数に設定しておきます。

BUCKET_NAME='your-bucket-name'
DIST_ID='your-distribution-id'

1. 対象の S3 Bucket の Bucket Policy に、 Origin Access Identity の Statement を残したまま Origin Access Control の Statement を追記する

現在の Bucket Policy ドキュメントを取得する

aws s3api get-bucket-policy \
--bucket "${BUCKET_NAME}" \
--output text \
| jq . > bucket-policy.json

OAI による制御の Statement として下記のような設定がされています。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "OriginAccessIdentityStatement",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity your-distribution-id"
      },
      "Action": [
        "s3:GetObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::your-bucket-name/*",
        "arn:aws:s3:::your-bucket-name"
      ]
    }
  ]
}

Origin Access Control による制御の Statement を追記する

上記の JSON を下記のように編集します。(Distribution ARN のアカウント ID は読み替えてください)

 {
   "Version": "2012-10-17",
   "Statement": [
+     {
+       "Sid": "OriginAccessControlStatement",
+       "Effect": "Allow",
+       "Principal": {
+         "Service": "cloudfront.amazonaws.com"
+       },
+       "Action": [
+         "s3:GetObject",
+         "s3:ListBucket"
+       ],
+       "Resource": [
+         "arn:aws:s3:::your-bucket-name/*",
+         "arn:aws:s3:::your-bucket-name"
+       ],
+       "Condition": {
+         "StringEquals": {
+           "AWS:SourceArn": "arn:aws:cloudfront::000000000000:distribution/your-distribution-id"
+         }
+       }
+     },
      {
        "Sid": "OriginAccessIdentityStatement",
        "Effect": "Allow",
        "Principal": {
          "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity your-origin-access-identity-id"
        },
        "Action": [
          "s3:GetObject",
          "s3:ListBucket"
        ],
        "Resource": [
          "arn:aws:s3:::your-bucket-name/*",
          "arn:aws:s3:::your-bucket-name"
        ]
      }
    ]
  }

Bucket Policy を更新する

aws s3api put-bucket-policy \
--bucket "${BUCKET_NAME}" \
--policy file://bucket-policy.json

問題ないはずですが、一応この時点でちゃんとアクセスできることを確認します。

2. Origin Access Control のリソースを作成する

Origin Access Control リソースの作成には、新たに追加された cloudfront コマンドの create-origin-access-control サブコマンドを使います。

❯ aws cloudfront create-origin-access-control help

...

SYNOPSIS
            create-origin-access-control
          --origin-access-control-config <value>
          [--cli-input-json | --cli-input-yaml]
          [--generate-cli-skeleton <value>]
          [--debug]
          [--endpoint-url <value>]
          [--no-verify-ssl]
          [--no-paginate]
          [--output <value>]
          [--query <value>]
          [--profile <value>]
          [--region <value>]
          [--version <value>]
          [--color <value>]
          [--no-sign-request]
          [--ca-bundle <value>]
          [--cli-read-timeout <value>]
          [--cli-connect-timeout <value>]
          [--cli-binary-format <value>]
          [--no-cli-pager]
          [--cli-auto-prompt]
          [--no-cli-auto-prompt]
...

パラメータがいくつかありますが、今回は yaml ファイルを作って --cli-input-yaml で渡してリソースを作ってみます。

そのために、ベースとなる yaml を生成します。

aws cloudfront create-origin-access-control \
--generate-cli-skeleton yaml-input > oac.yaml

中身はこんな感じで、必須のパラメータのみ記載されています。

OriginAccessControlConfig:  # [REQUIRED] Contains the origin access control.
  Name: ''  # [REQUIRED] A name to identify the origin access control.
  Description: '' # [REQUIRED] A description of the origin access control.
  SigningProtocol: sigv4 # [REQUIRED] The signing protocol of the origin access control, which determines how CloudFront signs (authenticates) requests. Valid values are: sigv4.
  SigningBehavior: never # [REQUIRED] Specifies which requests CloudFront signs (adds authentication information to). Valid values are: never, always, no-override.
  OriginAccessControlOriginType: s3 # [REQUIRED] The type of origin that this origin access control is for. Valid values are: s3.

なので、中身を埋めます。

OriginAccessControlConfig:
  Name: 'OriginAccessControlForMyBlog'
  Description: 'Origin Access Control for my blog.'
  SigningProtocol: sigv4
  SigningBehavior: always
  OriginAccessControlOriginType: s3

Name, Description については任意の文字列を入れます。

SigningProtocol にはそのまま sigv4 を、 OriginAccessControlOriginType にもそのまま s3 を入れます。

SigningBehavior については、下記公式ドキュメントの Advanced settings for origin access control の部分を確認し、 always, never, no-override のいずれかを入れます。

Restricting access to an Amazon S3 origin | Advanced settings for origin access control - Amazon CloudFront

それぞれの設定について、公式ドキュメントの内容を要約してみます。

always (推奨設定)

CloudFront が Origin (S3 Bucket) に送信するすべてのリクエストに署名します。

never

CloudFront が Origin (S3 Bucket) に送信するすべてのリクエストに署名しません。これはつまり、この Origin Access Control を使用する Distribution のすべての Origin に対して アクセスコントロールをオフにします。

この設定をする場合、 Originとなる S3 Bucket には Public に公開されている必要があります。公開されていない Bucket に対してこの設定を行うと、 CloudFront は Origin にアクセスできず、 Viewer にはエラーを返します。

no-override

Viewer リクエストに Authorization ヘッダが存在する場合はそれを Origin リクエストに使用し、含まれていない場合は CloudFront が署名します。

この設定を使用する場合、 Viewer からの Authorization ヘッダを Origin リクエストで使用するためにキャッシュポリシーで Authorization ヘッダを許可する必要があります。


以上から、基本的には always で設定しておけば良さそうです。

作った yaml をもとに、 Origin Access Control のリソースを作成します。作成結果として ID が後に必要になるので控えておきます。

aws cloudfront create-origin-access-control \
--cli-input-yaml file://oac.yaml \
--query 'OriginAccessControl.Id' \
--output text

3. 対象の Distribution に設定する

続いて、作成した Origin Access Control を Distribution に設定します。 これは cloudfrontupdate-distribution という、どデカイ更新を行うサブコマンドで実施します。

まずは現状の Distribution の設定を yaml で取得し、中身を変更して update-distribution で投げます。

aws cloudfront get-distribution-config \
--id "${DIST_ID}" \
--output yaml \
> dist-config.yaml

100 行を超える yaml が生成されるので、その中の Origins の設定を下記のように変更します。このとき、 Origin Access Identity のリソースは後に削除するので、 your-oai-id の部分を環境変数に設定しておきます。 (OAI_ID='your-oai-id')

+  OriginAccessControlId: your-oac-id
   S3OriginConfig:
-    OriginAccessIdentity: origin-access-identity/cloudfront/your-oai-id
+    OriginAccessIdentity: ''

また、 ETag フィールドの 値はそのままで フィールド名を IfMatch に変更します。

- ETag: HOGEHOGEVALUE
+ IfMatch: HOGEHOGEVALUE

下記コマンドで更新します。

aws cloudfront update-distribution \
--id "${DIST_ID}" \
--cli-input-yaml file://dist-config.yaml

この時点でアクセスできていれば、既に Origin Access Control による制御への移行は成功しています。

4. 対象の S3 Bucket の Bucket Policy から Origin Access Identity の Statement を削除する

Bucket Policy 内の Origin Access Identity の Statement は不要になったので削除します。

1 の手順で使った bucket-policy.json を下記のように変更し、 put-bucket-policy で更新します。

 {
   "Version": "2012-10-17",
   "Statement": [
      {
        "Sid": "OriginAccessControlStatement",
        "Effect": "Allow",
        "Principal": {
          "Service": "cloudfront.amazonaws.com"
        },
        "Action": [
          "s3:GetObject",
          "s3:ListBucket"
        ],
        "Resource": [
          "arn:aws:s3:::your-bucket-name/*",
          "arn:aws:s3:::your-bucket-name"
        ],
        "Condition": {
          "StringEquals": {
            "AWS:SourceArn": "arn:aws:cloudfront::000000000000:distribution/your-distribution-id"
          }
        }
-     },
-     {
-       "Sid": "OriginAccessIdentityStatement",
-       "Effect": "Allow",
-       "Principal": {
-         "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity your-origin-access-identity-id"
-       },
-       "Action": [
-         "s3:GetObject",
-         "s3:ListBucket"
-       ],
-       "Resource": [
-         "arn:aws:s3:::your-bucket-name/*",
-         "arn:aws:s3:::your-bucket-name"
-       ]
      }
    ]
  }
aws s3api put-bucket-policy \
--bucket "${BUCKET_NAME}" \
--policy file://bucket-policy.json

5. 不要になった Origin Access Identity のリソースを削除する

不要になった Origin Access Identity のリソースは cloudfront コマンドの delete-cloud-front-origin-access-identity コマンドで削除します。

aws cloudfront delete-cloud-front-origin-access-identity \
--id "${OAI_ID}" \
--if-match $(
  aws cloudfront get-cloud-front-origin-access-identity \
  --id ${OAI_ID} \
  --query 'ETag' \
  --output text)

まとめ

Amazon CloudFront の新しいアクセスコントロール機能である Origin Access Control への移行を AWS CLI でやってみた話でした。

Terraform も次の 4.29.0 で対応されそうなので、対応されたら試してみます。


comments powered by Disqus