[CDK] CloudFrontでCORSヘッダを設定する

2023.02.20

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

吉川@広島です。

今回はCDKでCloudFrontにCORSレスポンスヘッダを設定する方法を紹介します。

環境

  • aws-cdk-lib 2.46.0
  • constructs 10.1.43

コード

CloudFront ResponseHeadersPolicyを利用することで比較的簡単に設定できます。

import * as cdk from "aws-cdk-lib"
import { Construct } from "constructs"

export class CloudfrontStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props)

    const webBucket = new cdk.aws_s3.Bucket(this, "webBucket", {
      removalPolicy: cdk.RemovalPolicy.DESTROY,
    })

    const originAccessIdentity = new cdk.aws_cloudfront.OriginAccessIdentity(
      this,
      "originAccessIdentity"
    )

    const distribution = new cdk.aws_cloudfront.Distribution(
      this,
      "distribution",
      {
        defaultRootObject: "index.html",
        errorResponses: [
          {
            httpStatus: 404,
            responseHttpStatus: 200,
            responsePagePath: "/index.html",
            ttl: cdk.Duration.seconds(0),
          },
          {
            httpStatus: 403,
            responseHttpStatus: 200,
            responsePagePath: "/index.html",
            ttl: cdk.Duration.seconds(0),
          },
        ],
        defaultBehavior: {
          allowedMethods: cdk.aws_cloudfront.AllowedMethods.ALLOW_GET_HEAD,
          cachePolicy: cdk.aws_cloudfront.CachePolicy.CACHING_DISABLED,
          viewerProtocolPolicy:
            cdk.aws_cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
          origin: new cdk.aws_cloudfront_origins.S3Origin(webBucket, {
            originAccessIdentity,
          }),
          responseHeadersPolicy: new cdk.aws_cloudfront.ResponseHeadersPolicy(
            this,
            "responseHeadersPolicy",
            {
              corsBehavior: {
                accessControlAllowOrigins: ["https://example.com"],
                accessControlAllowHeaders: ["*"],
                accessControlAllowMethods: ["ALL"],
                accessControlAllowCredentials: false,
                originOverride: true,
              },
            }
          ),
        },
      }
    )

    new cdk.aws_s3_deployment.BucketDeployment(this, "webDeploy", {
      sources: [
        cdk.aws_s3_deployment.Source.data(
          "/index.html",
          "<html><body><h1>Hello World</h1></body></html>"
        ),
      ],
      destinationBucket: webBucket,
      distribution: distribution,
      distributionPaths: ["/*"],
    })
  }
}

ポイントとなるのは見たまんまで、

          responseHeadersPolicy: new cdk.aws_cloudfront.ResponseHeadersPolicy(
            this,
            "responseHeadersPolicy",
            {
              corsBehavior: {
                accessControlAllowOrigins: ["https://example.com"],
                accessControlAllowHeaders: ["*"],
                accessControlAllowMethods: ["ALL"],
                accessControlAllowCredentials: false,
                originOverride: true,
              },
            }
          ),

の箇所になります。

やってみる

それでは上記をデプロイします。

npx cdk deploy

curlコマンドで動作確認します。

curl -X OPTIONS -H "Origin: https://example.com" -H "Access-Control-Request-Method: GET" --dump-header - https://xxxxxxxxxxxxx.cloudfront.net
HTTP/2 200 
content-type: text/html
content-length: 46
date: Sun, 19 Feb 2023 09:42:46 GMT
last-modified: Sun, 19 Feb 2023 09:28:50 GMT
etag: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
x-amz-server-side-encryption: AES256
accept-ranges: bytes
server: AmazonS3
x-cache: Error from cloudfront
via: 1.1 xxxxxxxxxxxxxxxxxx.cloudfront.net (CloudFront)
x-amz-cf-pop: KIX50-P3
x-amz-cf-id: xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
access-control-allow-origin: https://example.com
vary: Origin

<html><body><h1>Hello World</h1></body></html>

access-control-allow-originが返ってくることが確認できました。

ハマった点

当初 accessControlAllowMethods に誤った値( ALL ではなく * )を設定していたせいで、

Stack Deployments Failed: Error: The stack named IacStack failed to deploy: UPDATE_ROLLBACK_COMPLETE: Internal error reported from downstream service during operation 'AWS::CloudFront::ResponseHeadersPolicy'.

というエラーが出ました。どのプロパティがNGなのか分からないメッセージで少しハマったのですが、ググった過程で類似のエラーに困っているIssueを発見し、

Issue creating AWS::CloudFront::ResponseHeadersPolicy · Issue #1156 · aws-cloudformation/cloudformation-coverage-roadmap

「この場合はCloudFormationでは内部エラーとしか出ないようだ。UIでは詳細なエラーが見れる」(要約)とのことだったので、マネコンから手動でリソース設定を試したところ間違いに気づくことができました。

このようにCloudFormation/CDKというかIaCツールはたまにエラーメッセージが分かりづらいことがある気がします。その際はIaC操作のみで原因究明することに固執せずマネコンからリソースを作ってデバッグしてみましょう。

参考