- AWS
AWS CDK入門|TypeScriptでS3とLambdaを作りsynthまで
AWS CDK(Cloud Development Kit)は、AWS のリソースを TypeScript などのプログラムで書き、CloudFormation のテンプレートに変換して作る道具です。 この記事では、S3 バケットと Lambda 関数を約30行の TypeScript で書き、cdk synth で変換したところ、241行の CloudFormation テンプレートになりました。
TypeScript(約30行) ──cdk synth──▶ CloudFormation(241行) ──cdk deploy──▶ AWS に作成
| コマンド | 何をするか | AWS の認証情報 |
|---|---|---|
cdk init app --language typescript |
プロジェクトのひな形を作る | 要らない |
cdk synth |
CloudFormation テンプレートに変換する | 要らない(環境を指定しない場合) |
npm test |
テンプレートの中身をテストする | 要らない |
cdk bootstrap |
デプロイの準備(アカウント・リージョンごとに1回) | 要る |
cdk diff |
AWS にある状態との差分を見る | 要る |
cdk deploy |
AWS に作る | 要る |
確認環境:AWS CDK CLI 2.1145.0、aws-cdk-lib 2.273.0、Node.js 22.22.2(Linux)。AWS の認証情報を外した状態で、init・synth・テストまでを確かめました(確認日 2026年10月12日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「AWS CDK入門|TypeScriptでS3とLambdaを作りsynthまで」
1. CDK CLI を入れて、プロジェクトを作る
AWS のドキュメントでは、CDK CLI は npm でグローバルに入れる手順です。
npm install -g aws-cdk
cdk --version # 2.1145.0 (build 13877dc)
mkdir hello && cd hello
cdk init app --language typescript
cdk init は、空のフォルダで実行します。 フォルダ名(hello)がプロジェクト名とスタック名(HelloStack)になりました。作られた主なファイルです。
| ファイル | 役割 |
|---|---|
bin/hello.ts |
入口。どのスタックを作るかを書く |
lib/hello-stack.ts |
スタックの中身(作るリソース)を書く場所 |
test/hello.test.ts |
テスト(jest) |
cdk.json |
CDK の設定。"app" に実行方法、"context" に機能フラグ |
package.json |
aws-cdk-lib・constructs などの依存 |
作られた bin/hello.ts です(コメントは一部省略)。
#!/usr/bin/env node
import * as cdk from 'aws-cdk-lib/core';
import { HelloStack } from '../lib/hello-stack';
const app = new cdk.App();
new HelloStack(app, 'HelloStack', {
// env を指定しないと、どのアカウント・リージョンにもデプロイできる「環境に依存しない」スタックになる
// env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
});
CDK CLI 2.1145.0 のひな形では、import が aws-cdk-lib/core になっていました。 import * as cdk from 'aws-cdk-lib' で読み込んだ App・Stack と同じものか確かめると、どちらも同じでした(true)。
2. S3 バケットと Lambda を書く
lib/hello-stack.ts に、S3 バケットと、そのバケットの一覧を返す Lambda 関数を書きます。
import * as cdk from 'aws-cdk-lib/core';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { Construct } from 'constructs';
export class HelloStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// S3 バケット
const bucket = new s3.Bucket(this, 'FilesBucket', {
versioned: true,
blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
enforceSSL: true,
removalPolicy: cdk.RemovalPolicy.RETAIN,
});
// Lambda 関数(lambda フォルダの中身を zip にして登録)
const fn = new lambda.Function(this, 'ListFiles', {
runtime: lambda.Runtime.PYTHON_3_13,
handler: 'index.handler',
code: lambda.Code.fromAsset('lambda'),
timeout: cdk.Duration.seconds(10),
environment: { BUCKET_NAME: bucket.bucketName },
});
// Lambda にバケットを読む権限を付ける
bucket.grantRead(fn);
new cdk.CfnOutput(this, 'BucketName', { value: bucket.bucketName });
}
}
Lambda のコードは lambda/index.py に置きます。
import os
import boto3
s3 = boto3.client("s3")
def handler(event, context):
res = s3.list_objects_v2(Bucket=os.environ["BUCKET_NAME"], MaxKeys=10)
return {"keys": [o["Key"] for o in res.get("Contents", [])]}
| 書いたこと | 意味 |
|---|---|
versioned: true |
上書き・削除しても前の版が残る |
blockPublicAccess: BLOCK_ALL |
公開を4項目すべてブロック |
enforceSSL: true |
HTTPS 以外のアクセスを拒否する |
removalPolicy: RETAIN |
スタックを消しても、バケットは消さずに残す |
bucket.bucketName |
作られるバケットの名前(デプロイ時に決まる)を環境変数に渡す |
bucket.grantRead(fn) |
読み取りに要る IAM ポリシーを作って Lambda のロールに付ける |
3. cdk synth で CloudFormation に変換する
cdk synth
AWS の認証情報が無い状態でも、synth は約5秒で終わりました。 出力された YAML は241行で、次のリソースが含まれていました。
| 論理ID(一部) | 種類 | どこから作られたか |
|---|---|---|
FilesBucket16450113 |
AWS::S3::Bucket |
new s3.Bucket |
FilesBucketPolicy8CA19688 |
AWS::S3::BucketPolicy |
enforceSSL: true |
ListFilesServiceRoleC64590F9 |
AWS::IAM::Role |
Lambda の実行ロール(自動) |
ListFilesServiceRoleDefaultPolicyF4ED98CC |
AWS::IAM::Policy |
bucket.grantRead(fn) |
ListFilesA068FBAF |
AWS::Lambda::Function |
new lambda.Function |
ListFilesLogGroup233735BF |
AWS::Logs::LogGroup |
Lambda のロググループ(自動) |
grantRead の1行から、次の IAM ポリシーが作られていました。 バケット本体と、その中のオブジェクト(/*)の両方が対象です。
ListFilesServiceRoleDefaultPolicyF4ED98CC:
Type: AWS::IAM::Policy
Properties:
PolicyDocument:
Statement:
- Action:
- s3:GetBucket*
- s3:GetObject*
- s3:List*
Effect: Allow
Resource:
- Fn::GetAtt: [FilesBucket16450113, Arn]
- Fn::Join: ["", [Fn::GetAtt: [FilesBucket16450113, Arn], "/*"]]
enforceSSL: true からは、HTTPS でないアクセスを拒否するバケットポリシーが作られました。
- Action: s3:*
Condition:
Bool:
aws:SecureTransport: "false"
Effect: Deny
Principal:
AWS: "*"
Lambda のコードは、cdk.out フォルダに asset.<ハッシュ> として置かれ、テンプレートでは cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region} というバケットから読む形になっていました。このバケットが、次の bootstrap で作られるものです。
Code:
S3Bucket:
Fn::Sub: cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}
S3Key: a5a0ad9750d22505fa748cc0dccf965b3c9eb545757e77a3077d1c59a356464e.zip
IAM ポリシーの読み方は、関連記事「IAMポリシーの書き方|JSONの読み方と最小権限の作り方【例文つき】」で扱っています。
4. テストを書く(認証情報なしで動く)
CDK のテストは、synth したテンプレートの中身を確かめるものです。 AWS には接続しません。aws-cdk-lib/assertions の Template を使います。
import * as cdk from 'aws-cdk-lib/core';
import { Template, Match } from 'aws-cdk-lib/assertions';
import { HelloStack } from '../lib/hello-stack';
test('バケットはバージョニングあり・公開ブロック', () => {
const app = new cdk.App();
const template = Template.fromStack(new HelloStack(app, 'TestStack'));
template.resourceCountIs('AWS::S3::Bucket', 1);
template.hasResourceProperties('AWS::S3::Bucket', {
VersioningConfiguration: { Status: 'Enabled' },
PublicAccessBlockConfiguration: {
BlockPublicAcls: true, BlockPublicPolicy: true,
IgnorePublicAcls: true, RestrictPublicBuckets: true,
},
});
});
test('Lambda は Python 3.13・タイムアウト10秒', () => {
const app = new cdk.App();
const template = Template.fromStack(new HelloStack(app, 'TestStack'));
template.hasResourceProperties('AWS::Lambda::Function', {
Runtime: 'python3.13',
Timeout: 10,
Environment: { Variables: { BUCKET_NAME: Match.anyValue() } },
});
});
$ npm test
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
「公開ブロックを外してしまう」「タイムアウトを変えてしまう」ような変更を、デプロイ前に止められます。
5. bootstrap → diff → deploy(ここから認証情報が要る)
認証情報が無いとき
認証情報が無い状態で cdk diff を実行すると、次のメッセージで止まりました。
Unable to resolve AWS account to use. It must be either configured when you define your CDK Stack, or through the environment
aws configure などで認証情報を設定してから進めます。設定方法は関連記事「AWS CLI設定|aws configureとprofile切り替え・優先順位」で扱っています。
bootstrap(アカウント・リージョンごとに1回)
CDK でデプロイする前に、デプロイ先のアカウント・リージョンを bootstrap します。 AWS のドキュメントでは、Lambda のコードなどを置く S3 バケット、Docker イメージ用の ECR リポジトリ、デプロイに使う IAM ロールが、CDKToolkit というスタックで作られると説明されています。
cdk bootstrap aws://123456789012/ap-northeast-1
# プロファイルを使うなら
cdk bootstrap --profile prod
diff と deploy
cdk diff # AWS にある状態との差分を表示
cdk deploy # 作成・更新
cdk destroy # スタックを削除(RETAIN のバケットは残る)
| 流れ | 習慣にしたいこと |
|---|---|
| 書いたら | cdk synth で変換できるか、npm test でテスト |
| デプロイ前 | cdk diff で、消えるリソース・置き換わるリソースが無いか見る |
| 消したくないデータ | removalPolicy: RETAIN(バケット・テーブル) |
CloudFormation・Terraform との違い
| CloudFormation(YAML) | AWS CDK | Terraform | |
|---|---|---|---|
| 書くもの | YAML・JSON | TypeScript・Python・Java など | HCL |
| 実際に作るもの | CloudFormation | CloudFormation(synth で変換) | Terraform が直接 API を呼ぶ |
| 権限・関連の作り込み | 自分で書く | grantRead などで自動 |
自分で書く(モジュールで補える) |
| 状態の管理 | CloudFormation のスタック | CloudFormation のスタック | state ファイル |
CloudFormation の書き方は関連記事「CloudFormationテンプレートの書き方と組み込み関数一覧」、Terraform は「Terraform入門|基本の流れからstate管理・既存リソースの取り込みまで」で扱っています。
よくある質問
Q. TypeScript 以外の言語でも書けますか。
A. cdk init --list で確かめると、app のひな形は TypeScript・JavaScript・Python・Java・C#・F#・Go が選べました(cdk init app --language python など)。ただし CDK CLI 自体は npm で入れるので、Node.js は要ります。
Q. 論理ID の末尾の 16450113 のような文字は何ですか。
A. コードの中の場所(HelloStack/FilesBucket)から CDK が付けるものです。new s3.Bucket(this, 'FilesBucket', …) の 'FilesBucket' を変えると論理IDも変わり、CloudFormation から見ると「別のリソース」になります。デプロイ後に ID を変えるときは、cdk diff で置き換えにならないか確かめます。
Q. cdk synth で 1 feature flags are not configured と出ました。
A. cdk.json の context に書かれていない機能フラグがある、という案内でした。synth 自体は成功しています。メッセージどおり cdk flags --unstable=flags で一覧を見られます。
Q. SAM とどちらを使えばいいですか。 A. Lambda と API が中心の小さな構成なら SAM、S3・VPC・RDS などを含めて組むなら CDK が書きやすい、という使い分けがあります。SAM は関連記事「AWS SAM入門」で扱っています。
まとめ
- CDK は TypeScript などで書き、
cdk synthで CloudFormation に変換して作る - 約30行の TypeScript が 241行の CloudFormation になった。IAM ロール・ポリシー・ロググループは自動
bucket.grantRead(fn)の1行で、最小限の読み取りポリシーができるsynthとテストは認証情報なしで動く。bootstrap・diff・deployは要る- デプロイ前は
cdk diff、消したくないデータはRETAIN
参考・出典
確認日はいずれも 2026年10月12日です。
- AWS CDK v2 デベロッパーガイド「Getting started with the AWS CDK」:https://docs.aws.amazon.com/cdk/v2/guide/getting-started.html
- AWS CDK v2 デベロッパーガイド「AWS CDK bootstrapping」:https://docs.aws.amazon.com/cdk/v2/guide/bootstrapping.html
- AWS CDK v2 デベロッパーガイド「Bootstrap your environment for use with the AWS CDK」:https://docs.aws.amazon.com/cdk/v2/guide/bootstrapping-env.html
- AWS CDK CLI 2.1145.0・aws-cdk-lib 2.273.0(
cdk init・cdk synth・cdk diffの出力、jest の結果)
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「AWS CDK入門|TypeScriptでS3とLambdaを作りsynthまで」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。