AWS CDK で CloudFront + S3 環境を構築してみよう!
はじめに
AWS リソース(CloudFront や S3)をアプリと同じように管理したいと思い「CloudFormation より簡単!?AWS CDK で楽々 IaC 実践」を参考に CDK で CloudFront + S3 環境を構築してみました。
対象読者
- AWS CDK の導入を検討している方
- CloudFormation を利用しているが、より柔軟な管理をしたい方
AWS CDK の基本概念
この記事を参考にしてください。
さっそく環境構築から
以降は Windows11 向けの解説です。その他の OS 利用者はダウンロード先やコマンドは必要に応じて読み替えて実行してください。
ステップ1:Node.js のインストール
> node -v && npm -v
v20.16.0
10.8.1
ステップ2:AWS CLIのインストール
> aws --version
aws-cli/2.15.15 Python/3.11.6 Windows/10 exe/AMD64 prompt/off
ステップ3:AWS認証情報の設定
3-1. IAMユーザーの作成とアクセスキーの設定
- AWSマネジメントコンソールにログイン
- IAMサービスにアクセス
- 「ユーザー」→「ユーザーを追加」をクリック
- ユーザー名欄に任意のユーザー名を入力し、「次へ」をクリック
- 「ポリシーを直接アタッチする」を選択し、許可ポリシーで「AdministratorAccess」を検索してチェックし「次へ」をクリック
- 「ユーザーの作成」をクリック
- 作成したユーザーを選択して、「セキュリティ認証情報」タブの「アクセスキーを作成」をクリック
- ユースケースから「コマンドラインインターフェイス (CLI)」を選択して、下部の確認マークをチェックして「次へ」をクリック
- 「アクセスキーを作成」をクリック
- アクセスキーが作成されました!
3-2. AWS CLIの設定
ターミナルで下記コマンドを実行し、認証情報を設定します
> aws configure
- AWS Access Key ID: 先ほど作成したアクセスキー
- AWS Secret Access Key: 先ほど作成したシークレットアクセスキー
- Default region name: リージョン指定 東京 (ap-northeast-1) にしました。
- Default output format: 出力結果の形式 初期値の json にしました。
ステップ4:CDK のインストール
> npm install -g aws-cdk
> cdk --version
2.1100.1 (build db19110)
ステップ5:CDK環境の初期化(ブートストラップ)
> cdk bootstrap aws://ACCOUNT-NUMBER/REGION
ACCOUNT-NUMBER と REGION は、自分のAWSアカウント番号とリージョンに置き換えてください。
成功すると以下の通り CloudFormation で「CDKToolkit」という名前のスタックが作成されます。

ステップ6:CDK プロジェクトの作成
1. 作業ディレクトリの作成
my-cdk-app というディレクトリを作成しています。
お好きな名前に変更してください。
> mkdir my-cdk-app && cd my-cdk-app
my-cdk-app>
2. CDK プロジェクトの作成
my-cdk-app> cdk init app --language=typescript
※成功すると my-cdk-app 内にいろいろファイルが作られます。
テンプレートの作成
以下 my-cdk-app で作成した場合の例です。該当の ts ファイルを修正してください。
必要に応じて読み替えて変更してください。
スタック(Stack)
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import {
aws_s3 as s3,
aws_cloudfront as cloudfront,
aws_cloudfront_origins as cloudfront_origins,
} from 'aws-cdk-lib';
export class S3CloudfrontStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const s3Bucket = new s3.Bucket(this, 'WebSiteBucket', {
bucketName: `s3-bucket-${cdk.Aws.ACCOUNT_ID}-${cdk.Aws.REGION}`,
autoDeleteObjects: true,
removalPolicy: cdk.RemovalPolicy.DESTROY,
// S3バケットのパブリックアクセスを拒否(デフォルト)
publicReadAccess: false,
websiteIndexDocument: 'index.html',
// S3へのパブリックアクセスを全て拒否(デフォルト)
blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
});
const oac = new cloudfront.S3OriginAccessControl(this, 'OAC', {
originAccessControlName: `${id}-oac`,
// 認証の設定
// SIGV4:認証プロトコル(現状唯一)
// ALWAYS/NO_OVERRIDE:CloudFrontが認証するリクエストの選定
signing: cloudfront.Signing.SIGV4_ALWAYS,
});
const distribution = new cloudfront.Distribution(this, 'Distribution', {
// CloudFrontディストリビューションのデフォルト動作を各種設定
defaultBehavior: {
// オリジンの指定
origin: cloudfront_origins.S3BucketOrigin.withOriginAccessControl(
s3Bucket,{
originAccessLevels: [cloudfront.AccessLevel.READ],
},
),
},
// S3からではなくCloudFrontから配信するのでこちらでルートオブジェクトを指定
defaultRootObject: 'index.html',
});
const url = new cdk.CfnOutput(this, 'URL', {
value: distribution.domainName,
description: 'Website URL'
});
}
}
アプリ(App)
#!/usr/bin/env node
import * as cdk from 'aws-cdk-lib';
import { S3CloudfrontStack } from '../lib/my-cdk-app-stack';
const app = new cdk.App();
new S3CloudfrontStack(app, 'S3CloudfrontStack', {
});
デプロイ
my-cdk-app> cdk deploy
時間がかかりますので気長に待ちましょう!
成功すると以下の通り CloudFormation で「S3CloudfrontStack」という名前のスタックが作成されます。

S3 バケットの確認と index.html の作成
-
AWSマネジメントコンソールで S3 サービスにアクセスし「s3-bucket-XXXXX-リージョン」のバケットが作成されていることを確認します。

-
そのバケットに index.html をアップロードします。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>TEST</title>
</head>
<body>
<h1>TEST</h1>
<p>テストページです。</p>
</body>
</html>
動作確認
OAC の確認
-
AWSマネジメントコンソールで S3 サービスにアクセスし、対象バケットの「プロパティ」→「静的ウェブサイトホスティング」から「バケットウェブサイトエンドポイント」をコピーします。

-
ご利用のブラウザで「バケットウェブサイトエンドポイント」にアクセスすると「403 Forbidden」が表示されます。(成功)

CloudFront 経由でアクセス
-
AWSマネジメントコンソールで CloudFront サービスにアクセスし、対象ディストリビューションの「ディストリビューションドメイン名」をコピーします。

-
ご利用のブラウザで「ディストリビューションドメイン名」にアクセスすると作成したテストページが表示されます。(成功)

片付け
作成したリソースは cdk destroy で削除可能です。
S3 バケット内にファイルがあってもリソースは削除されました。
my-cdk-app> cdk destroy
まとめ
環境構築にてこずりましたが、先人たちの知恵に助けられました。
(参考サイトの方々、ありがとうございました。🙇♂️)
不要になった際、コマンド1つで削除できるのは、やっぱり便利ですね!
また yaml とは違い、条件分岐やループを活用できるそうなので、今後チャレンジしてみようと思います。
この記事が、誰かのお役に立てば幸いです。
Discussion