CDKでCloudFrontのMulti Originを設定する

2021.08.27

吉川@広島です。

掲題の通り、CDKでCloudFrontのMulti Originを設定する方法についてです。

想定シチュエーション

マルチオリジンをしたい場合の一例として、今回は以下のシチュエーションを想定してやっていきます。

  • SPAリソース(HTML/CSS/JS)+固定画像などのフロントエンドリソースをフロントエンド用バケットに置く
  • 特定の画像(キャンペーン訴求など)を時期によって運用側で変更する必要があるため、これらの画像専用のバケットを別に作成したい(運用者はフロントエンド用バケットを触りたくない)
  • 両方とも同一ドメイン下に配置したい

環境

  • aws-cdk 1.119.0
  • typescript 4.3.5

CDKコード

フロントエンドリソース用バケット

フロントエンド用バケットです。ここにビルドしたSPAリソースを aws sync コマンドなどでデプロイする想定です。

    /**
     * フロントエンドリソース用
     */
    const frontBucket = new s3.Bucket(this, 'front-bucket', {
      websiteIndexDocument: 'index.html',
    })

    const frontOai = new cloudfront.OriginAccessIdentity(this, 'front-oai')

    new iam.PolicyStatement({
      effect: iam.Effect.ALLOW,
      actions: ['s3:GetObject'],
      principals: [
        new iam.CanonicalUserPrincipal(
          frontOai.cloudFrontOriginAccessIdentityS3CanonicalUserId
        ),
      ],
      resources: [frontBucket.bucketArn + '/*'],
    })

画像用バケット

フロントエンド用とほぼ一緒です。バケットを分けたいという運用上の都合に対応する形です。

    /**
     * 画像用
     */
    const imageBucket = new s3.Bucket(this, 'image-bucket', {})

    const imageOai = new cloudfront.OriginAccessIdentity(this, 'image-oai')

    new iam.PolicyStatement({
      effect: iam.Effect.ALLOW,
      actions: ['s3:GetObject'],
      principals: [
        new iam.CanonicalUserPrincipal(
          imageOai.cloudFrontOriginAccessIdentityS3CanonicalUserId
        ),
      ],
      resources: [imageBucket.bucketArn + '/*'],
    })

CloudFront Distribution

originConfigsが配列になっているので、ここにoriginSourceとbehaviorsのセットを2つ以上指定するとマルチオリジンが実現できるということになります。

    /**
     * CloudFront Distribution
     */
    new cloudfront.CloudFrontWebDistribution(this, 'my-distribution', {
      viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
      httpVersion: cloudfront.HttpVersion.HTTP2,
      originConfigs: [
        {
          s3OriginSource: {
            s3BucketSource: frontBucket,
            originAccessIdentity: frontOai,
          },
          behaviors: [
            {
              isDefaultBehavior: true,
              compress: true,
            },
          ],
        },
        {
          s3OriginSource: {
            s3BucketSource: imageBucket,
            originAccessIdentity: imageOai,
          },
          behaviors: [
            {
              isDefaultBehavior: false,
              compress: true,
              pathPattern: 'images/*', // URLのパスが/images/*の時はこのOriginを見る
            },
          ],
        },
      ],
      errorConfigurations: [
        {
          errorCode: 403,
          responseCode: 200,
          responsePagePath: '/',
        },
        {
          errorCode: 404,
          responseCode: 200,
          responsePagePath: '/',
        },
      ],
    })

一点注意として、S3バケット内の構造を上で指定したpathPatternと合わせる必要があります。CloudFront側で images/* と設定しているので、S3バケットに画像を配置する際は images/example.png のように、imagesプレフィックスの下にアップロードしないといけません。

参考