AWS CDK v2でS3 CloudFrontを使った静的ホスティングを作成 (OAC)


検証等で静的サイトをAWSにデプロイする際にコンソール上でS3、CloudFrontを作っていましたが、コンソールから作成するのは意外と手間なのでCDKで作成していきます。
今回の構成はS3、CloudFrontを使ったシンプルなものとなっています。

今回作成するサービスの構成図

AWS diagram

CDKの作成

コード全文 (Github)

CDKプロジェクト

typescriptを利用します。(AWS CDK)

mkdir s3-cloudfront-sample
cd s3-cloudfront-sample
cdk init app --language typescript

普段 pnpm を利用しているため変更します。(npmの場合は不要)

rm -rf node_modules package-lock.json
pnpm install

リソースの作成

リソース作成用のコードはs3-cloudfront-sample/lib/s3-cloudfront-sample-stack.tsに記述していきます。

S3 バケットの作成

静的サイトを配置するためのS3バケットを作成します。(S3 CDK docs)

import * as s3 from "aws-cdk-lib/aws-s3";
...
const bucket = new s3.Bucket(this, "S3Bucket", {
    removalPolicy: cdk.RemovalPolicy.DESTROY,
});

スタック削除時にバケットが削除されるようにremovalPolicyを設定しています。(バケット内は空でないといけない)

CloudFront ディストリビューションの作成

CloudFront CDK docs

import * as cloudfront from "aws-cdk-lib/aws-cloudfront";
import * as origins from "aws-cdk-lib/aws-cloudfront-origins";
...
const distribution = new cloudfront.Distribution(
    this,
    "CloudfrontDistribution",
    {
        defaultBehavior: { origin: new origins.S3Origin(bucket) },
        defaultRootObject: "index.html",
    }
);

上記で作成したバケットとアクセス時に読み込むhtmlファイルを指定します。

OAC (Origin access control)の設定

CloudFront

CloudFrontのOACの設定がL2 コンストラクトではできないため、L1を利用して設定していきます。(AWS コンストラクト)

const cfnOriginAccessControl = new cloudfront.CfnOriginAccessControl(
    this,
    "OriginAccessControl",
    {
        originAccessControlConfig: {
            name: "OriginAccessControlForS3",
            originAccessControlOriginType: "s3",
            signingProtocol: "sigv4",
            signingBehavior: "always",
        },
    }
);
cfnDistribution.addPropertyOverride(
    "DistributionConfig.Origins.0.S3OriginConfig.OriginAccessIdentity",
    ""
);
cfnDistribution.addPropertyOverride(
    "DistributionConfig.Origins.0.OriginAccessControlId",
    cfnOriginAccessControl.attrId
);

OAIの設定を削除し、OACを設定しています。 OAIの設定を削除しないとデプロイ時にCannot use both Origin Acc ess Control and Origin Access Identity on an originのエラーが発生しました。

S3

CloudFront OACに対して読み取り許可を与えるバケットポリシーをバケットに設定します。

import * as iam from "aws-cdk-lib/aws-iam";
...
const oacPolicy = new iam.PolicyStatement({
    sid: "AllowGetObjectForCloudFront",
    principals: [new iam.ServicePrincipal("cloudfront.amazonaws.com")],
    effect: iam.Effect.ALLOW,
    actions: ["s3:GetObject"],
    resources: [bucket.bucketArn + "/*"],
    conditions: {
    StringEquals: {
        "AWS:SourceArn": `arn:aws:cloudfront::${
        cdk.Stack.of(this).account
        }:distribution/${distribution.distributionId}`,
    },
    },
});
  • バケットポリシーの初期化と上記で作成したポリシーの付与
const bucketPolicy = new s3.BucketPolicy(
    this,
    "BucketPolicy",
    {
    bucket: bucket,
    }
);

bucketPolicy.document.addStatements(oacPolicy);

デプロイ

  1. CDKの作成ができたので、AWSにデプロイします。
cdk deploy
  1. 作成されたs3にindex.htmlをアップロードします。
<!DOCTYPE html>
<html lang="en">
	<body>
	    <h1>Hello, World!</h1>
	</body>
</html>
  1. CloudFrontにアクセスし、表示されることを確認します。
    xxxxxxxxxxxxxx.cloudfront.net cloudfront

ソースコード

aws-cdk-s3-cloudfront (Github)

参考サイト