CDK bootstrap resources, roles and trust
What cdk bootstrap creates (CDKToolkit stack, staging bucket, ECR repository, version parameter) and the five roles — deploy, CloudFormation execution, lookup, file publishing, image publishing — with their exact names, whom each trusts (the account itself plus --trust accounts, ExternalId denied), what each may do, how the CLI uses them, when it falls back to your own credentials, and how --trust, execution policies, qualifiers and permissions boundaries change them.
markdownreferencev4RK6C-5S9Qstage: referencetrust: officialservice: cdkservice: cloudformationservice: iaminterface: iaccdk bootstrapCDKToolkitcdk-hnb659fds-deploy-rolecfn-exec-rolelookup-rolefile-publishing-roleimage-publishing-rolehnb659fds qualifier/cdk-bootstrap/hnb659fds/versionBootstrapVersion--trust--trust-for-lookup--cloudformation-execution-policiesAdministratorAccess CDKDenyExternalIdpermissions boundary CDKDefaultStackSynthesizerProceeding anyway current credentialshotswap credentialscross-account CDK deploy
The CLI doesn't deploy with your credentials. It uses them to assume the bootstrap roles in the target environment, and CloudFormation then acts as the execution role. So "can I deploy?" really asks two things: can my identity assume cdk-<qualifier>-deploy-role-… (and the publishing roles), and does the execution role allow what the template creates?
What cdk bootstrap aws://<account>/<region> creates
One CloudFormation stack, CDKToolkit, per environment (account + Region), containing:
| Resource | Name (default qualifier hnb659fds) | Purpose |
|---|---|---|
| S3 staging bucket | cdk-hnb659fds-assets-<account>-<region> | File assets, and templates too large to pass inline. Public access blocked by default; non-TLS requests denied |
| ECR repository | cdk-hnb659fds-container-assets-<account>-<region> | Docker image assets; tags immutable |
| SSM parameter | /cdk-bootstrap/hnb659fds/version | Template version. The CLI checks it, and CloudFormation reads it again during the deploy |
| Five IAM roles | below |
The bootstrapping identity needs broad rights: cloudformation:*, ecr:*, ssm:*, s3:* and iam:*. The template bundled with CDK CLI 2.1145.0 is version 32, but the number moves; re-running cdk bootstrap is safe and upgrades only when needed.
The five roles
Role (cdk-<q>-…-<account>-<region>) | Trusted by | Allows | Used for |
|---|---|---|---|
deploy-role | The account itself and every --trust account | Create, update, execute and delete change sets and stacks; RollbackStack, ContinueUpdateRollback; iam:PassRole on the execution role; reading the version parameter; AWSCloudFormationReadOnlyAccess | cdk deploy and cdk destroy |
cfn-exec-role | cloudformation.amazonaws.com only | --cloudformation-execution-policies, or AdministratorAccess if none were given | The stack's service role: everything in your template happens with these rights |
lookup-role | The account, --trust-for-lookup accounts and --trust accounts | ReadOnlyAccess | Context lookups during synth (Vpc.fromLookup and similar) |
file-publishing-role | The account and --trust accounts | The staging bucket | Uploading file assets |
image-publishing-role | The account and --trust accounts | The ECR repository | Pushing image assets |
Trust details from the template:
- The trusted principal is the account (
"AWS": "<account-id>"), not a specific role. So any identity in that account whose own IAM policy allowssts:AssumeRoleon the role can use it, and identities without that Allow can't (patterns/iam/trust-policies.md).sts:TagSessionis allowed too. DenyExternalIddefaults totrue. AssumeRole calls that carry anExternalIdare denied, so the roles can't be accidentally "deputized" to a third party.- The execution role can carry a permissions boundary:
--custom-permissions-boundary <policy-name>, or--example-permissions-boundary(a starting point, not for production as-is).
How the CLI picks credentials
- It needs credentials for the target account. Otherwise you get
Need to perform AWS calls for account <n>, but the current credentials are for <n>(or… but no credentials have been configured). - It assumes the roles the synthesizer names. If that fails:
- Same account: it warns
<credentials> could not be used to assume '<role-arn>', but are for the right account. Proceeding anyway.and carries on with your own credentials. Deploys may still work, but they bypass the bootstrap roles and need you to hold the CloudFormation, S3 and service permissions directly. - Cross-account: it stops with
Could not assume role in target account …. Seereference/cdk/errors.md.
--hotswap(and--watch, which implies it) calls Lambda, Step Functions and other APIs with your current credentials, not the bootstrap roles, and leaves CloudFormation drift. Follow up withcdk deploy --revert-drift.
Options that change trust and permissions
| Option | Effect | Watch out |
|---|---|---|
--trust <account> (repeatable) | Adds accounts to the deploy, lookup and publishing roles' trust | Requires --cloudformation-execution-policies. The list replaces the old one, so name every account each time |
--trust-for-lookup <account> | Lookup role only: those accounts can synth, not deploy | |
--cloudformation-execution-policies <arn,arn> | Managed policies on the execution role (one comma-separated string) | Must cover everything every stack in the environment creates, or deployments fail on resource permissions |
--qualifier <9 chars> | Renames every bootstrap resource | The app must use the same qualifier (new DefaultStackSynthesizer({ qualifier }) or context @aws-cdk/core:bootstrapQualifier). Two qualifiers in one account give no permission isolation unless their execution roles are scoped |
--bootstrap-bucket-name <name> | Custom bucket name (it must not exist yet) | Match it in the synthesizer |
--bootstrap-kms-key-id <id> / --bootstrap-customer-key | SSE-KMS on the bucket (the two can't be combined) | Older templates created a key by default; --no-bootstrap-customer-key removes its cost |
--no-previous-parameters | Re-supply every parameter; omitted ones reset (removes a boundary, for example) | Without it, earlier values are kept |
--termination-protection | Protects CDKToolkit | Recommended. Never delete and recreate the toolkit stack: re-run bootstrap instead |
--template <file> | Custom template (start from cdk bootstrap --show-template) | Change BootstrapVariant. Keep the contract: the version parameter, outputs BucketName, BucketDomainName and BootstrapVersion, and the five roles |
Environments bootstrapped with the legacy (v1) template must be re-bootstrapped for CDK v2.