cdk bootstrapが何者なのか正面から向き合う

こんにちは!
昨年11月、37歳にしてやっと普通運転免許を取得してドライブにどハマりし、週2~3回のペースで首都高ドライブに挑んでいるnogusanです。
技術的な記事を執筆するのは今回が初めてなのですが、「初の技術記事にふさわしい内容はなんだろう?」と考えた結果、日々業務で触るAWS CDK(以下CDK)の「初めてコマンド」ともいえるcdk bootstrapについて調べてみることにしました!
概要
cdk bootstrap
は、CDKを使用してデプロイを行うにあたり必要になるリソースをデプロイするためのコマンドです。
このコマンドを実行すると、デフォルトでCDKToolkit
という名前のCloudFormation(以下Cfn)スタックが対象アカウントにデプロイされます。
当スタックには、S3やECR、IAMロールなど、CDKを使用してリソースをデプロイする際に、バックグラウンドで必要な基盤であるリソース群を1つのスタックとして自動的にデプロイしてくれます。
ブートストラップテンプレートbootstrap-template.yaml
にCDKToolkitの中身が記述されており、後述の方法で中身を確認すると、実体はあくまでもCfnスタックであることを再確認できます。
CDKToolkitではどんなリソースが作られるのか
まずはCDKToolkitでどのようなリソースが作られるのかを確認していきます。
1.構成図
CDKToolkitで作成されるリソースとそれを取り巻く環境について、構成図を作成しました。

2.リソース一覧
図中のCDKToolkit
のピンクの太枠線内にあるリソースがブートストラップによって作成されるリソース群です。
それでは、各リソースはどのような役割を担っているのでしょうか?下表にそれぞれを解説します。
論理ID | タイプ | 説明 |
---|---|---|
CdkBootstrapVersion | AWS::SSM::Parameter | ブートストラップのバージョン番号を格納したSSMパラメータ。ブートストラップテンプレートはCDKの開発チームによって定期的に更新されるため、更新後は再度cdk bootstrap することでバージョンアップすることが推奨される |
CloudFormationExecutionRole | AWS::IAM::Role | Cfnがスタックの作成・削除・更新を行うためのロール。Cfnのサービスプリンシパルに対してAdministrator権限を渡している |
ContainerAssetsRepository | AWS::ECR::Repository | ECSなどを使用する場合、作成したDockerイメージが格納されるECR。ECSを使用しない場合は特に何も格納されない |
DeploymentActionRole | AWS::IAM::Role | CDKコマンドを実行する際に使用されるロール。信頼関係にはデフォルトでアカウントのルートユーザが指定されており、S3やCfnに対する各種権限が許可されている |
FilePublishingRole | AWS::IAM::Role | StatgingBucketに各種ファイルをアップロードするためのロール。信頼関係にはデフォルトでアカウントのルートユーザが指定されている |
FilePublishingRoleDefaultPolicy | AWS::IAM::Policy | FilePublishingRoleにアタッチするロール。S3に関する各種権限と、KMSの権限が付与されている |
ImagePublishingRole | AWS::IAM::Role | ContainerAssetsRepositoryにDockerイメージをPushするためのロール。信頼関係にはデフォルトでアカウントのルートユーザが指定されている |
ImagePublishingRoleDefaultPolicy | AWS::IAM::Policy | ImagePublishingRoleにアタッチするロール。ECRに関する各種権限が付与されている |
LookupRole | AWS::IAM::Role | fromLookup()などのメソッドを実行するためのロール。信頼関係にはデフォルトでアカウントのルートユーザが指定されている。また、ReadOnlyAccessポリシーがアタッチされている |
StagingBucket | AWS::S3::Bucket | CDKでデプロイされる際に生成される、Cfnテンプレート等のアセットが格納されるバケット。CfnはこのバケットにあるCfnテンプレート等を参照することでデプロイを行う。Cfnテンプレート以外では、Zipファイル化されたLambdaコード等が格納される |
StagingBucketPolicy | AWS::S3::BucketPolicy | StagingBucketにSSL通信以外を禁止するためのポリシー |
ブートストラップテンプレートの中身を覗いてみる
CDKToolkitのイメージがだいぶ湧いてきましたね!
今度は、冒頭で述べたCDKToolkitの「実体はあくまでもCfnスタックであること」を体感するために、ブートストラップテンプレートの中身を下記コマンドで確認してみます。
# CDKプロジェクトディレクトリの直下にいることを確認
$ pwd
/Users/nogusan/cdk-boostrap-revealing
# ブートストラップテンプレートの中身を確認
# 2通りのコマンドがありますが、2つ目のほうがテンプレートファイルの在処がわかり、実体を体感しやすいかもしれませんね。
$ npx cdk bootstrap --show-template
$ cat ./node_modules/aws-cdk/lib/api/bootstrap/bootstrap-template.yaml
上記のコマンドを実行すると、下記のようにCDKToolkitの正体であるブートストラップのテンプレートファイルを確認できました!(長いため一部のみ抜粋して表示します)
先ほどお示しした一覧表の中にあったStagingBucket
がCfnテンプレートとして定義されていますね。
Resources:
# 一部省略
StagingBucket:
Type: AWS::S3::Bucket
Properties:
BucketName:
Fn::If:
- HasCustomFileAssetsBucketName
- Fn::Sub: "${FileAssetsBucketName}"
- Fn::Sub: cdk-${Qualifier}-assets-${AWS::AccountId}-${AWS::Region}
AccessControl: Private
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: aws:kms
KMSMasterKeyID:
Fn::If:
- CreateNewKey
- Fn::Sub: "${FileAssetsBucketEncryptionKey.Arn}"
- Fn::If:
- UseAwsManagedKey
- Ref: AWS::NoValue
- Fn::Sub: "${FileAssetsBucketKmsKeyId}"
# これ以降も省略
StagingBucketに保存されるファイルを覗いてみる
CDKToolkitで作成されるStagingBucket
には、Cfnテンプレートなどデプロイ時に使用する様々なアセットが格納されます。
こちらを体感するために、以下の手順で実際に検証していきたいと思います。
- CDKでサンプルのS3バケットをデプロイする
StagingBucket
に格納されるテンプレートの中身を覗き見る- Cfnコンソール画面で表示されるテンプレートを目視確認し、手順②のファイルと照らし合わせる
【手順①】CDKでサンプルのS3バケットをデプロイする
まずはS3バケット生成用のCDKコードを書きます。今回はTypeScriptで記述します。
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as s3 from 'aws-cdk-lib/aws-s3';
export class S3SampleStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// S3 バケットを作成
new s3.Bucket(this, 'SampleBucket', {
bucketName: 'nogusan-sample-bucket',
});
}
}
const app = new cdk.App();
new S3SampleStack(app, 'S3SampleStack');
デプロイします。
npx cdk deploy S3SampleStack
✨ Synthesis time: 3.52s
S3SampleStack: start: Building bee2ac2695adc44e1a951e90fdaf020f5ebd61163862402307d569f1418934cf:current_account-current_region
S3SampleStack: success: Built bee2ac2695adc44e1a951e90fdaf020f5ebd61163862402307d569f1418934cf:current_account-current_region
S3SampleStack: start: Publishing bee2ac2695adc44e1a951e90fdaf020f5ebd61163862402307d569f1418934cf:current_account-current_region
S3SampleStack: success: Published bee2ac2695adc44e1a951e90fdaf020f5ebd61163862402307d569f1418934cf:current_account-current_region
S3SampleStack: deploying... [1/1]
S3SampleStack: creating CloudFormation changeset...
S3SampleStack | 0/3 | 18:19:56 | REVIEW_IN_PROGRESS | AWS::CloudFormation::Stack | S3SampleStack User Initiated
S3SampleStack | 0/3 | 18:20:02 | CREATE_IN_PROGRESS | AWS::CloudFormation::Stack | S3SampleStack User Initiated
S3SampleStack | 0/3 | 18:20:04 | CREATE_IN_PROGRESS | AWS::S3::Bucket | SampleBucket (SampleBucket7F6F8160)
S3SampleStack | 0/3 | 18:20:04 | CREATE_IN_PROGRESS | AWS::CDK::Metadata | CDKMetadata/Default (CDKMetadata)
S3SampleStack | 0/3 | 18:20:05 | CREATE_IN_PROGRESS | AWS::CDK::Metadata | CDKMetadata/Default (CDKMetadata) Resource creation Initiated
S3SampleStack | 1/3 | 18:20:05 | CREATE_COMPLETE | AWS::CDK::Metadata | CDKMetadata/Default (CDKMetadata)
S3SampleStack | 1/3 | 18:20:06 | CREATE_IN_PROGRESS | AWS::S3::Bucket | SampleBucket (SampleBucket7F6F8160) Resource creation Initiated
S3SampleStack | 2/3 | 18:20:19 | CREATE_COMPLETE | AWS::S3::Bucket | SampleBucket (SampleBucket7F6F8160)
S3SampleStack | 3/3 | 18:20:20 | CREATE_COMPLETE | AWS::CloudFormation::Stack | S3SampleStack
✅ S3SampleStack
✨ Deployment time: 28.76s
Stack ARN:
arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:stack/S3SampleStack/05339d10-eb7e-11ef-abe7-0e65a27aa8bd
✨ Total time: 32.28s
【手順②】StagingBucket
に格納されるテンプレートの中身を覗き見る
サンプルS3バケットのデプロイに成功しました。StagingBucket
(物理IDではcdk-hnb659fds-assets-${accountID}-ap-northeast-1
)を確認すると、何やらCDKデプロイに伴って生成されたと思われるファイルが入っています。

このファイルの中身を確認してみましょう。今回はaws s3 cp
コマンドを使用して、ターミナルの標準出力にファイルの中身を出直して確認してみます。
$ aws s3 cp s3://cdk-hnb659fds-assets-XXXXXXXXXXXX-ap-northeast-1/bee2ac2695adc44e1a951e90fdaf020f5ebd61163862402307d569f1418934cf.json - | jq
{
"Resources": {
"SampleBucket7F6F8160": {
"Type": "AWS::S3::Bucket",
"Properties": {
"BucketName": "nogusan-sample-bucket"
},
"UpdateReplacePolicy": "Retain",
"DeletionPolicy": "Retain",
"Metadata": {
"aws:cdk:path": "S3SampleStack/SampleBucket/Resource"
}
},
# これ以降の出力は省略
}
Resouces
キーの中身がCfnテンプレートの中身のようですね🤔
【手順③】Cfnコンソール画面で表示されるテンプレートを目視確認し、手順②のファイルと照らし合わせる
今度は、CloudFormationマネジメントコンソール画面で、デプロイしたS3SampleStack
のテンプレートが使用されていることを確かめます。

見事に、手順②で確認したファイルと一致していますね!
スクリーンショットでは途中まで表示していますが、その後のJSONも一致しておりました。
素朴な疑問:物理IDにつくhnb659fds
とは何か
最後に素朴な疑問について確認します。
StagingBucket
や他のCDKToolkit内のリソースに、物理IDとしてつくリソース名にhnb659fds
という文字列があり、これがランダムに生成される文字列なのかどうか気になったので調べてみました。私の環境では、作成されたS3バケットの名称はcdk-hnb659fds-assets-${accountID}-ap-northeast-1
となっていました。
cdk bootstrap
によって作成されるS3バケットStagingBucket
につけられる物理IDは、ブートストラップテンプレートで下記のように指定されています(一部抜粋)。
Parameters:
Qualifier:
Description: An identifier to distinguish multiple bootstrap stacks in the same environment
Default: hnb659fds
Resouces:
StagingBucket:
Type: AWS::S3::Bucket
Properties:
BucketName:
Fn::If:
- HasCustomFileAssetsBucketName
- Fn::Sub: "${FileAssetsBucketName}"
- Fn::Sub: cdk-${Qualifier}-assets-${AWS::AccountId}-${AWS::Region}
Parameters
セクションにQualifier
としてhnb659fds
がデフォルト指定されていました!
AWSのデベロッパーズガイドを確認してみると、この文字列に特に意味は無いことがわかりました。

リソース名の中の文字列
https://docs.aws.amazon.com/ja_jp/cdk/v2/guide/customize-synth.htmlhnb659fds
は、修飾子と呼ばれます。デフォルト値に特別な意味はありません。
この修飾子と呼ばれる文字列はカスタマイズが可能です。修飾子をカスタマイズしてcdk bootstrap
することで、同一アカウント・同一リージョンに複数のブートストラップを実行することも可能です。
まとめ
cdk bootstrap
は、CDKでAWSリソースをデプロイする際、バックグラウンドで必要になるリソース群をデプロイするコマンド- ブートストラップを実行すると、デフォルトでは
CDKToolkit
というスタックが作成され、そのスタックに必要なリソース群がデプロイされる StagingBucket
にCfnテンプレートなどのアセットが格納され、Cfnはそれを参照してスタックをデプロイする。Cfnテンプレートのアセットは、ローカルではCDKプロジェクトディレクトリのcdk.out
ディレクトリに出力される- CDKToolkit配下のリソースの物理IDに付与される
hnb659fds
は修飾子と呼ばれ、同一アカウント内でのブートストラップを一意に保つために存在する。この文字列そのものに特別な意味は無く、カスタマイズすることも可能。
今までCDKプロジェクトを開始するときに漫然と使用していたcdk bootstrap
について深掘りすることで、自分の中での理解度をグッと高め、調べる過程で知らなかった機能を知見として得ることができました。
普段何気なく使用しているコマンドや機能、ツールについて、ときには「その正体がなんなのか」と正面から向き合い、調べていくのもよいかと思いました!
参考資料
