Bootstrapping - AWS Cloud Development Kit (AWS CDK)

Bootstrapping

Deploying AWS CDK apps into an AWS environment (a combination of an AWS account and region) may require that you provision resources the AWS CDK needs to perform the deployment. These resources include an Amazon S3 bucket for storing files and IAM roles that grant permissions needed to perform deployments. The process of provisioning these initial resources is called bootstrapping.

An environment needs to be bootstrapped if any of the following apply.

  • An AWS CDK stack being deployed uses Assets.

  • A AWS CloudFormation template generated by the app exceeds 50 kilobytes.

  • One or more of the stacks uses the DefaultSynthesizer. We will explain stack synthesizers in more detail shortly, but in brief, the DefaultSynthesizer is used if you have set the @aws-cdk/core:newStyleStackSynthesis feature flag in your app's cdk.json or if you explicitly create a DefaultSynthesizer and pass it to your stack. CDK Pipelines use the DefaultSynthesizer, so if your app uses CDK Pipelines, you must bootstrap the environments you will deploy into as well as the environment that contains the pipeline.

The required resources are defined in a AWS CloudFormation stack, called the bootstrap stack, which is usually named CDKToolkit. Just like any AWS CloudFormation stack, you can find it in the AWS CloudFormation console.

The AWS CDK supports two bootstrap templates. At this writing, the AWS CDK is transitioning from one of these templates to the other, but the original template (dubbed "legacy") is still the default. The newer template ("modern") is required by CDK Pipelines now and will become the default at some point in the future. For details, see Bootstrapping templates.

Environments are independent, so if you want to deploy to multiple environments (different AWS accounts or different regions in the same account), each environment must be bootstrapped separately.

Important

You may incur AWS charges for data stored in the bootstrapped resources.

If you attempt to deploy an AWS CDK application that requires bootstrap resources into an environment that does not have them, you receive an error message telling you that you need to bootstrap.

If you are using CDK Pipelines to deploy into another account's environment, and you receive a message like the following:

Policy contains a statement with one or more invalid principals

This error message means that the appropriate IAM roles do not exist in the other environment, which is most likely caused by a lack of bootstrapping.

How to bootstrap

Bootstrapping is the deployment of a AWS CloudFormation template to a specific AWS environment (account and region). The bootstrapping template accepts parameters that customize some aspects of the bootstrapped resources (see Customizing bootstrapping). Thus, you can bootstrap in one of two ways.

  • Use the AWS CDK Toolkit's cdk bootstrap command. This is the simplest method and works well if you have only a few environments to bootstrap.

  • Deploy the template provided by the AWS CDK Toolkit using another AWS CloudFormation deployment tool. This lets you use AWS CloudFormation Stack Sets or AWS Control Tower as well as the AWS CloudFormation console or the AWS CLI. You can even make small modifications to the template before deployment. This approach is more flexible and is suitable for large-scale deployments.

It is not an error to bootstrap an environmnt more than once. If an environment you bootstrap has already been bootstrapped, its bootstrap stack will be upgraded if necessary; otherwise, nothing happens.

Bootstrapping with the AWS CDK Toolkit

Use the cdk bootstrap command to bootstrap one or more AWS environments. In its basic form, this command bootstraps one or more specified AWS environments (two, in this example).

cdk bootstrap aws://ACCOUNT-NUMBER-1/REGION-1 aws://ACCOUNT-NUMBER-2/REGION-2 ...

The following examples illustrate bootstrapping of one and two environments, respectively. (Both use the same AWS account.) As shown in the second example, the aws:// prefix is optional when specifying an environment.

cdk bootstrap aws://123456789012/us-east-1 cdk bootstrap 123456789012/us-east-1 123456789012/us-west-1

If you do not specify at least one environment in the cdk bootstrap command, the AWS CDK Toolkit synthesizes the AWS CDK app in the current directory and bootstraps all the environments referenced in the app. If a stack is environment-agnostic (that is, it does not have an env property), the CDK's environment (for example, the one specified using --profile, or the default AWS environment otherwise) is applied to make the stack environment-specific, and that environment is then bootstrapped.

For example, the following command synthesizes the current AWS CDK app using the prod AWS profile, then bootstraps its environments.

cdk bootstrap --profile prod

Bootstrapping from the AWS CloudFormation template

AWS CDK bootstrapping is performed by an AWS CloudFormation template. To get a copy of this template in the file bootstrap-template.yaml, run the following command.

cdk bootstrap --show-template > bootstrap-template.yaml

The template is also available in the AWS CDK GitHub repository.

Deploy this template using your preferred deployment mechanism for AWS CloudFormation templates. For example, the following command deploys the template using the AWS CLI:

Mac OS X/Linux
aws cloudformation create-stack \ --stack-name CDKToolkit \ --template-body file://bootstrap-template.yaml
Windows
aws cloudformation create-stack ^ --stack-name CDKToolkit ^ --template-body file://bootstrap-template.yaml

Bootstrapping templates

At this writing, the AWS CDK is transitioning from one set of bootstrap resources to another. The original bootstrap template, which shipped with the very first version of the AWS CDK, is called the legacy template. A newer version of the template with additional resources was added in version 1.25.0. This newer template is called the modern template.

The legacy template is fully supported by the AWS CDK and is in fact the template that is selected by default when you issue cdk bootstrap. The modern template is required primarily by the CDK Pipelines module, which can be used to set up a continuous delivery pipeline for your CDK applications. More precisely, the modern template is required if you use the DefaultSynthesizer (see Stack synthesizers),

The main differences between the templates are as follows.

Feature Legacy Modern
Cross-account deployments Not allowed Allowed
AWS CloudFormation Permissions Deploys using current user's permissions (determined by AWS profile, environment variables, etc.) Deploys using the permissions specified when the bootstrap stack was provisioned
Versioning Only one version of bootstrap stack is available Bootstrap stack is versioned; new resources can be added in future versions, and AWS CDK apps can require a minimum version
Resources* Amazon S3 bucket Amazon S3 bucket
AWS KMS key
IAM roles
Amazon ECR repository
SSM parameter for versioning
Resource naming Automatically generated Deterministic
Bucket encryption Default key Customer-managed key

* We will add additional resources to the modern template as needed.

At some point in the future, the modern template will become the default bootstrapping template. Until then, you must manually select the modern template when bootstrapping by setting the CDK_NEW_BOOTSTRAP environment variable.

Mac OS X/Linux
export CDK_NEW_BOOTSTRAP=1 cdk bootstrap
Windows
set CDK_NEW_BOOTSTRAP=1 cdk bootstrap

The modern template is also selected when you issue cdk bootstrap in an AWS CDK app directory where the @aws-cdk/core:newStyleStackSynthesis feature flag is set in the app's cdk.json file.

{ // ... "context": { "@aws-cdk/core:newStyleStackSynthesis": "true" } }
Tip

We recommend always setting CDK_NEW_BOOTSTRAP when you want to bootstrap using the modern template. The context key is supported to make sure you bootstrap correctly if your app uses the DefaultStackSynthesizer, but relies on you being in an app's directory when bootstrapping.

These two ways to specify the modern template also apply to cdk bootstrap --show-template, which will display the modern template if one or the other of these flags is present.

If the environment you are bootstrapping with the modern template has already been bootstrapped with the legacy template, the environment is upgraded to the modern template. The Amazon S3 bucket from the legacy stack is orphaned in the process. Re-deploy all AWS CDK applications in the environment at least once before deleting the legacy bucket.

Customizing bootstrapping

There are two ways to customize the bootstrapping resources.

  • Use command-line parameters with the cdk bootstrap command. This lets you modify a few aspects of the template.

  • Modify the default bootstrap template and deploy it yourself. This gives you unlimited control over the bootstrap resources.

The following command-line options, when used with CDK Toolkit's cdk bootstrap, provide commonly-needed adjustments to the bootstrapping template..

  • --bootstrap-bucket-name overrides the name of the Amazon S3 bucket. May require changes to your CDK app (see Stack synthesizers).

  • --bootstrap-kms-key-id overrides the AWS KMS key used to encrypt the S3 bucket.

  • --tags adds one or more AWS CloudFormation tags to the bootstrap stack.

  • --termination-protection prevents the bootstrap stack from being deleted (see Protecting a stack from being deleted in the AWS CloudFormation User Guide)

The following additional switches are available only with the modern bootstrapping template.

  • --cloudformation-execution-policies specifies the ARNs of managed policies that should be attached to the deployment role assumed by AWS CloudFormation during deployment of your stacks. At least one policy is required; otherwise, AWS CloudFormation will attempt to deploy without permissions and deployments will fail.

  • --trust lists the AWS accounts that may deploy into the environment being bootstrapped. Use this flag when bootstrapping an evironment that a CDK Pipeline in another environment will deploy into. The account doing the bootstrapping is always trusted.

  • --qualifier a string that is added to the names of all resources in the bootstrap stack. A qualifier lets you avoid name clashes when you provision two bootstrap stacks in the same environment. The default is hnb659fds (this value has no significance). Changing the qualifier will require changes to your AWS CDK app (see Stack synthesizers).

Customizing the template

When you need more customization than the AWS CDK Toolkit switches can provide, you can modify the bootstrap template to suit your needs. Remember that you can obtain the template by using the --show-template flag. Optionally, set the CDK_NEW_BOOTSTRAP environment variable to get the modern template (otherwise, you'll get the legacy template).

Mac OS X/Linux
export CDK_NEW_BOOTSTRAP=1 cdk bootstrap
Windows
set CDK_NEW_BOOTSTRAP=1 cdk bootstrap

Any modifications you make must adhere to the bootstrapping template contract.

You can deploy your modified template as described in Bootstrapping from the AWS CloudFormation template, or using cdk bootstrap.

cdk bootstrap --template bootstrap-template.yaml

Stack synthesizers

Your AWS CDK app needs to know about the bootstrapping resources available to it in order to successfully synthesize a stack that can be deployed. The stack synthesizer is an AWS CDK class that controls how the stack's template is synthesized, including how it uses bootstrapping resources (for example, how it refers to assets stored in the bootstrap bucket).

The AWS CDK includes two stack synthesizers:

  • LegacyStackSynthesizer can be used with either bootstrap template. (It requires only an Amazon S3 bucket, and both templates include one.)

  • DefaultStackSynthesizer requires the modern bootstrap template. It includes capabilities for cross-account deployments and CDK Pipelines deployments.

You can pass a stack synthesizer to a stack when you instantiate it using the synthesizer property.

TypeScript
new MyStack(this, 'MyStack', { // stack properties synthesizer: new DefaultStackSynthesizer({ // synthesizer properties }), });
JavaScript
new MyStack(this, 'MyStack', { // stack properties synthesizer: new DefaultStackSynthesizer({ // synthesizer properties }), });
Python
MyStack(self, "MyStack", # stack properties synthesizer=DefaultStackSynthesizer( # synthesizer properties ))
Java
new MyStack(app, "MyStack", StackProps.builder() // stack properties .synthesizer(DefaultStackSynthesizer.Builder.create() // synthesizer properties .build()) .build();
C#
new MyStack(app, "MyStack", new StackProps // stack properties { Synthesizer = new DefaultStackSynthesizer(new DefaultStackSynthesizerProps { // synthesizer properties }) });

If you don't provide the synthesizer property, the default behavior depends on whether the context key @aws-cdk/core:newStyleStackSynthesis is set, either in the AWS CDK app's source code or in cdk.json. If it is set, synthesis uses a DefaultStackSynthesizer; otherwise, a LegacyStackSynthesizer is used. This is the usual way of choosing a synthesizer unless you have customized the bootstrap template.

The most important differences between the two built-in stack synthesizers are summarized here.

Feature LegacyStackSynthesizer DefaultStackSynthesizer
Bootstrap stack Both legacy and modern bootstrap stack Modern bootstrap stack only
Deployments AWS CDK Toolkit deployments only AWS CDK Toolkit and CDK Pipelines deployments
Assets Uses AWS CloudFormation parameters to reference assets Expects assets to be in a predictable location
Docker image assets Creates Amazon ECR repository on demand Pushes images to Amazon ECR repository provisioned by bootstrapping
Roles Uses AWS CDK Toolkit's current permissions to deploy Uses roles and permissions provisioned by bootstrapping to deploy
Versioning Not supported Confirms versions of bootstrapping resources via embedded AWS CloudFormation rule

Customizing synthesis

Depending on the changes you made to the bootstrap template, you may also need to customize synthesis. The DefaultStackSynthesizer can be customized using the properties described below. If none of these properties provide the customizations you require, you can write your synthesizer as a class that implements IStackSynthesizer (perhaps deriving from DefaultStackSynthesizer).

Note

The LegacyStackSynthesizer does not offer any customization properties.

Changing the qualifier

The qualifier is added to the name of bootstrap resources to distinguish the resources in separate bootstrap stacks. To deploy two different versions of the bootstrap stack in the same environment (AWS account and region), then, the stacks must have different qualifiers. This feature is intended for name isolation between automated tests of the CDK itself. Unless you can very precisely scope down the IAM permissions given to the AWS CloudFormation execution role, there are no privilege isolation benefits to having two different bootstrap stacks in a single account, so there is usually no need to change this value.

To change the qualifier, configure the DefaultStackSynthesizer either by instantiating the synthesizer with the property:

TypeScript
new MyStack(this, 'MyStack', { synthesizer: new DefaultStackSynthesizer({ qualifier: 'MYQUALIFIER', }), });
JavaScript
new MyStack(this, 'MyStack', { synthesizer: new DefaultStackSynthesizer({ qualifier: 'MYQUALIFIER', }), })
Python
MyStack(self, "MyStack", synthesizer=DefaultStackSynthesizer( qualifier="MYQUALIFIER" ))
Java
new MyStack(app, "MyStack", StackProps.builder() .synthesizer(DefaultStackSynthesizer.Builder.create() .qualifier("MYQUALIFIER") .build()) .build();
C#
new MyStack(app, "MyStack", new StackProps { Synthesizer = new DefaultStackSynthesizer(new DefaultStackSynthesizerProps { Qualifier = "MYQUALIFIER" }) });

Or by configuring the qualifier as a context key in cdk.json.

{ "app": "...", "context": { "@aws-cdk/core:bootstrapQualifier": "MYQUALIFIER" } }

Changing the resource names

All the other DefaultStackSynthesizer properties relate to the names of the resources in the modern bootstrapping template. You only need to provide any of these properties if you modified the bootstrap template and changed the resource names or naming scheme.

All properties accept the special placeholders ${Qualifier}, ${AWS::Partition}, ${AWS::AccountId}, and ${AWS::Region}. These placeholders are replaced with the values of the qualifier parameter and with the values of the AWS partition, account ID, and region for the stack's environment, respectively.

The following example shows all the available properties for DefaultStackSynthesizer along with their default values, as if you were instantiating the synthesizer.

TypeScript
new DefaultStackSynthesizer({ // Name of the S3 bucket for file assets fileAssetsBucketName: 'cdk-${Qualifier}-assets-${AWS::AccountId}-${AWS::Region}', // Name of the ECR repository for Docker image assets imageAssetsRepositoryName: 'cdk-${Qualifier}-container-assets-${AWS::AccountId}-${AWS::Region}', // ARN of the role assumed by the CLI and Pipeline to deploy here deployRoleArn: 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-${Qualifier}-deploy-role-${AWS::AccountId}-${AWS::Region}', // ARN of the role used for file asset publishing (assumed from the deploy role) fileAssetPublishingRoleArn: 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-${Qualifier}-file-publishing-role-${AWS::AccountId}-${AWS::Region}', fileAssetPublishingExternalId: '', // ARN of the role used for Docker asset publishing (assumed from the deploy role) imageAssetPublishingRoleArn: 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-${Qualifier}-image-publishing-role-${AWS::AccountId}-${AWS::Region}', imageAssetPublishingExternalId: '', // ARN of the role passed to CloudFormation to execute the deployments cloudFormationExecutionRole: 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-${Qualifier}-cfn-exec-role-${AWS::AccountId}-${AWS::Region}', })
JavaScript
new DefaultStackSynthesizer({ // Name of the S3 bucket for file assets fileAssetsBucketName: 'cdk-${Qualifier}-assets-${AWS::AccountId}-${AWS::Region}', // Name of the ECR repository for Docker image assets imageAssetsRepositoryName: 'cdk-${Qualifier}-container-assets-${AWS::AccountId}-${AWS::Region}', // ARN of the role assumed by the CLI and Pipeline to deploy here deployRoleArn: 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-${Qualifier}-deploy-role-${AWS::AccountId}-${AWS::Region}', // ARN of the role used for file asset publishing (assumed from the deploy role) fileAssetPublishingRoleArn: 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-${Qualifier}-file-publishing-role-${AWS::AccountId}-${AWS::Region}', fileAssetPublishingExternalId: '', // ARN of the role used for Docker asset publishing (assumed from the deploy role) imageAssetPublishingRoleArn: 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-${Qualifier}-image-publishing-role-${AWS::AccountId}-${AWS::Region}', imageAssetPublishingExternalId: '', // ARN of the role passed to CloudFormation to execute the deployments cloudFormationExecutionRole: 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-${Qualifier}-cfn-exec-role-${AWS::AccountId}-${AWS::Region}', })
Python
DefaultStackSynthesizer( # Name of the S3 bucket for file assets file_assets_bucket_name="cdk-${Qualifier}-assets-${AWS::AccountId}-${AWS::Region}", # Name of the ECR repository for Docker image assets image_assets_pepository_name="cdk-${Qualifier}-container-assets-${AWS::AccountId}-${AWS::Region}", # ARN of the role assumed by the CLI and Pipeline to deploy here deploy_role_arn="arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-${Qualifier}-deploy-role-${AWS::AccountId}-${AWS::Region}", # ARN of the role used for file asset publishing (assumed from the deploy role) file_sset_publishing_role_arn="arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-${Qualifier}-file-publishing-role-${AWS::AccountId}-${AWS::Region}", file_asset_publishing_external_id="", # ARN of the role used for Docker asset publishing (assumed from the deploy role) image_asset_publishing_role_arn="arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-${Qualifier}-image-publishing-role-${AWS::AccountId}-${AWS::Region}", image_asset_publishing_external_id="", # ARN of the role passed to CloudFormation to execute the deployments cloud_formation_execution_role="arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-${Qualifier}-cfn-exec-role-${AWS::AccountId}-${AWS::Region}" )
Java
DefaultStackSynthesizer.Builder.create() // Name of the S3 bucket for file assets .fileAssetsBucketName("cdk-${Qualifier}-assets-${AWS::AccountId}-${AWS::Region}") // Name of the ECR repository for Docker image assets .imageAssetsRepositoryName("cdk-${Qualifier}-container-assets-${AWS::AccountId}-${AWS::Region}") // ARN of the role assumed by the CLI and Pipeline to deploy here .deployRoleArn("arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-${Qualifier}-deploy-role-${AWS::AccountId}-${AWS::Region}") // ARN of the role used for file asset publishing (assumed from the deploy role) .fileAssetPublishingRoleArn("arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-${Qualifier}-file-publishing-role-${AWS::AccountId}-${AWS::Region}") .fileAssetPublishingExternalId("") // ARN of the role used for Docker asset publishing (assumed from the deploy role) .imageAssetPublishingRoleArn: "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-${Qualifier}-image-publishing-role-${AWS::AccountId}-${AWS::Region}", .imageAssetPublishingExternalId: "", // ARN of the role passed to CloudFormation to execute the deployments .cloudFormationExecutionRole("arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-${Qualifier}-cfn-exec-role-${AWS::AccountId}-${AWS::Region}") .build()
C#
new DefaultStackSynthesizer(new DefaultStackSynthesizerProps { // Name of the S3 bucket for file assets FileAssetsBucketName = "cdk-${Qualifier}-assets-${AWS::AccountId}-${AWS::Region}", // Name of the ECR repository for Docker image assets ImageAssetsRepositoryName = "cdk-${Qualifier}-container-assets-${AWS::AccountId}-${AWS::Region}", // ARN of the role assumed by the CLI and Pipeline to deploy here DeployRoleArn = "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-${Qualifier}-deploy-role-${AWS::AccountId}-${AWS::Region}", // ARN of the role used for file asset publishing (assumed from the deploy role) FileAssetPublishingRoleArn = "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-${Qualifier}-file-publishing-role-${AWS::AccountId}-${AWS::Region}", FileAssetPublishingExternalId = "", // ARN of the role used for Docker asset publishing (assumed from the deploy role) ImageAssetPublishingRoleArn = "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-${Qualifier}-image-publishing-role-${AWS::AccountId}-${AWS::Region}", ImageAssetPublishingExternalId = "", // ARN of the role passed to CloudFormation to execute the deployments CloudFormationExecutionRole = "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-${Qualifier}-cfn-exec-role-${AWS::AccountId}-${AWS::Region}" })

The bootstrapping template contract

The requirements of the bootstrapping stack depend on the stack synthesizer being used. If you write your own stack synthesizer, you have complete control of the bootstrap resources that your synthesizer requires and how the synthesizer finds them. This section describes the expectations that the DefaultStackSynthesizer has of the bootstrapping template.

Versioning

The template should contain a resource to create an SSM parameter with a well-known name and an output to reflect the template's version.

Resources: CdkBootstrapVersion:` Type: AWS::SSM::Parameter Properties: Type: String Name: Fn::Sub: '/cdk-bootstrap/${Qualifier}/version' Value: 4 Outputs: BootstrapVersion: Value: Fn::GetAtt: [CdkBootstrapVersion, Value]

Versioning

The DefaultStackSynthesizer requires four IAM roles for four different purposes. If you are not using the default roles, the synthesizer needs to be told the ARNs for the roles you want to use. The roles are:

  • The deployment role is assumed by the AWS CDK Toolkit and by AWS CodePipeline to deploy into an environment. Its AssumeRolePolicy controls who can deploy into the environment. The permissions this role needs can be seen in the template.

  • The file publishing role and the image publishing role are assumed by the AWS CDK Toolkit and by AWS CodeBuild projects to publish assets into an environment: that is, to write to the S3 bucket and the ECR repository, respectively. These roles require write access to these resources.

  • The AWS CloudFormation execution role is passed to AWS CloudFormation to perform the actual deployment. Its permissions are the permissions that the deployment will execute under. The permissions are passed to the stack as a parameter that lists managed policy ARNs.

Versioning

The AWS CDK Toolkit requires that the following CloudFormation outputs exist on the bootstrap stack.

  • BucketName: the name of the file asset bucket

  • BucketDomainName: the file asset bucket in domain name format

  • BootstrapVersion: the current version of the bootstrap stack

Help us help you

Did you find what you were looking for? We recently added this topic and are keenly interested in hearing about how it's working for you. Please click Provide feedback at the bottom of the page and let us know! Providing your e-mail address is optional, but very helpful if we have further questions. (We'll keep it to ourselves.)