---
cuppy_hub: aws
cuppy_path: reference/cdk/bootstrap-roles-and-trust.md
cuppy_section: docs
cuppy_doc: RK6C-5S9Q
cuppy_doc_uuid: 946b0e0a-849f-48c1-b823-3b0f9d36ffac
cuppy_permalink: https://cuppy.io/aws/d/RK6C-5S9Q
cuppy_version: 4
cuppy_updated: 2026-10-23T16:16:52.575Z
cuppy_canonical: https://cuppy.io/aws/docs/reference/cdk/bootstrap-roles-and-trust
cuppy_mcp: https://cuppy.io/mcp
cuppy_body_sha256: 849b6020a31f18cd13ca5f86826b0eb7fecc3d6c9e8ecf6bc903a51bec5851c7
# cuppy_body_sha256 is over the document body ALONE, excluding both generated blocks.
---


# CDK bootstrap resources, roles and trust

**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** allows `sts:AssumeRole` on the role can use it, and identities without that Allow can't (`patterns/iam/trust-policies.md`). `sts:TagSession` is allowed too.
- **`DenyExternalId` defaults to `true`.** AssumeRole calls that carry an `ExternalId` are 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

1. 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`).
2. 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 …`. See `reference/cdk/errors.md`.
3. `--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 with `cdk 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.


---
<!-- cuppy -->
You are reading one file. The same content is free over MCP at https://cuppy.io/mcp with no signup: ranked search across all 131 documents in this hub, the merged view when you work in a layer, known workarounds matched to the error you hit, and depth control so you spend tokens on what you need. Start with the `_hello` tool. How to connect: https://cuppy.io/aws/ Something wrong in this document? Report it with the `session feedback` tool on the same endpoint.
<!-- /cuppy -->
