CloudFrontWebDistribution を Distribution に書き換えしたのでメモ

[CureApp Advent Calendar 2022](https://qiita.com/advent-calendar/2022/cureapp) 14日目の記事です。

私が携わってるプロダクトではインフラ構築に AWS CDK を採用しています。例えば静的なサイトやリソースのホスティングに CloudFront + S3 の構成で作成していますが、今回はその CloudFront についての小ネタを紹介します。

CDK で CloudFront を定義する API には

- CloudFrontWebDistribution
- Distribution

の二種類が存在します。
Distribtuion の方が新しいAPIであり新しい機能もこちらの方に優先的に入るっぽい、という話もあった[^2cf]のでプロダクトの中で CloudFrontWebDistribution で書かれていたものを Distribution に書き換えしました。その経過をメモとして残します。

[^2cf]:[CloudFront DistributionのCDK Constructの新しいクラスを使って静的サイトホスティング（Amazon S3）の配信を構築してみた | DevelopersIO](https://dev.classmethod.jp/articles/build-a-static-site-hosting-delivery-with-amaozn-s3-using-cloudfront-distributions-new-cdk-constrain/)

# TL;DR
- 書き換えは両者のAPIと睨めっこしてやっていけば多分わかる
- s3 の websiteIndexDocument の設定には注意
- 本番運用前ならリリース前にやっておいた方が色々考えなくて楽かも


# 環境
aws-cdk のバージョンは 2.30.0 でした。2020年にはリリースされていたよう[^2cf]なのでよっぽど古いものでなければ（一部APIがつかえないとかはあるかもしれませんが）適用可能そうです。

```ts
  "devDependencies": {
    "aws-cdk": "2.30.0",
    "aws-cdk-lib": "2.30.0",
    ...
  },
```

余談ですが cdk の v1 は 2023/6 にサポート終了が予定されているので[^cdkv1]、あまりにも古い場合はこっちの移行の方が急いだ方がいいかもしれないです。

[^cdkv1]:[AWS SDKs and Tools maintenance policy - AWS SDKs and Tools](https://docs.aws.amazon.com/sdkref/latest/guide/maint-policy.html)

## Distribution API に書き換え
まずは、aws_cloudfront.CloudFrontWebDistribution[^webdistribution] を aws_cloudfront.Distribution[^distribution] に書き換えます。Distribution も aws_cloudfront に生えてるのでインポートとかもとくに気にせず行けました。

その後内部のパラメータを書き換えていきます。 Migration guide 的なものは特に見つからなかったので API 仕様を見ながら適宜読み替えていきます。一番シンプルに書き換えできた部分を例示します。

[^webdistribution]:[class CloudFrontWebDistribution (construct) · AWS CDK](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_cloudfront.CloudFrontWebDistribution.html)
[^distribution]:[class Distribution (construct) · AWS CDK](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_cloudfront.Distribution.html)

```ts
// CloudFrontWebDistribution 書き換え前
const distribution = new CloudFrontWebDistribution(
  this,
  'HogeWebDistribution',
  {
    webACLId,
    originConfigs: [
      {
        s3OriginSource: {s3BucketSource: bucket, originAccessIdentity},
        behaviors: [{isDefaultBehavior: true}],
      },
    ],
    viewerCertificate: ViewerCertificate.fromAcmCertificate(certificate, {
      aliases: [domainName],
      securityPolicy: SecurityPolicyProtocol.TLS_V1,
      sslMethod: SSLMethod.SNI,
    }),
  },
);
```

```ts
// Distribution 書き換え後
const distribution = new Distribution(this, 'HogeDistribution', {
  webAclId,
  defaultBehavior: {
    origin: new S3Origin(bucket, {
      originAccessIdentity,
    }),
  },
  // s3 bucket 側で設定していた websiteIndexDocument の設定を移動した
  defaultRootObject: 'index.html',
  domainNames: [domainName],
  certificate,
  minimumProtocolVersion: SecurityPolicyProtocol.TLS_V1,
  sslSupportMethod: SSLMethod.SNI,
});
```


### s3 bucket 側の websiteIndexDocument 設定の削除

ここが一番ハマりました。元々は s3 bucket の設定に websiteIndexDocument を設定していたのですが、その状態のまま Distribution に移行しても期待した挙動になっていませんでした。色々調べた結果以下記述に辿り着き[^2cf]ました（最初に見てた記事なのに気づくのにだいぶ時間がかかりました）。こちらが悪さをしてそうです。

> 注意点として、「Distribution」を使用する場合は、S3 Bucket側でwebsiteIndexDocumentを設定して静的ウェブサイトホスティングを有効化すると、Distribution側でカスタムオリジンが優先して設定されてしまうようです。

bucket の宣言部分から websiteIndexDocument を削除し、前述の Distribution の defaultRootObject での宣言に変更したところ、意図通りの挙動になりました。

```ts
  // s3 bucket の宣言
    const bucket = new Bucket(this, 'HogeBucket', {
      bucketName: `hoge-bucket`,
-     websiteIndexDocument: 'index.html',
      publicReadAccess: false,
      blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
    });
```

## デプロイ前に古いスタックを一旦削除する
コード変更後にももう1つやることがありました。既に一度でも CloudFrontWebDistribution で構築してしまった Stack を Distribution で書きかえた場合、そのままの状態ではデプロイ時にCNAMEの重複エラーが発生[^override]しました。回避方法としては

- Logical IDをオーバーライドする
- ダウンタイムを設けて一度古い Stack を削除し、再デプロイする

の二択がありそうです。

今回は移行するプロダクトは本番運用前のプロダクトであったこと、Logical ID オーバーライドの記述は消さずに残しておく必要があるため実害はないと言ってもちょっと気になるなぁと思ったことから、古い Stack を一旦削除し再デプロイする後者の選択を取りました。

既に本番運用中の場合は Logical ID をオーバーライドする記述を書くか、メンテナンス時間の間に削除するなどの選択になりそうです。この書き換えをやりたいと考えている本番運用前のプロダクトがあれば、リリース前にやっておいた方が色々気にしなくて良いかもしれないです。

[^override]:[CNAMEを設定したCloudFront DistributionのCDK Constructを「CloudFrontWebDistribution」から「Distribution」にダウンタイムなしで置き換えたい場合は、Logical IDのオーバーライドが選択肢になりそう | DevelopersIO](https://dev.classmethod.jp/articles/change-the-cdk-constract-of-cloudfront-distribution-with-cname-set-from-cloudfront-webdistribution-to-distribution-distribution-override-the-logical-id-when-replacing-it-with/)


# 終わりに
DevelopersIOと公式APIのリンク集になってしまいましたが、何かの足しになれば幸いです