Skip to content

Commit 0174e2a

Browse files
docs: ADR-002 least-privilege CDK bootstrap policies
Records the design decisions from RFC #120: why policies as code, why triple-layer versioning, why two-layer preflight validation, and why cdk/src/bootstrap/ as the location. Refs #121 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 39053e3 commit 0174e2a

2 files changed

Lines changed: 146 additions & 0 deletions

File tree

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# ADR-002: Least-privilege CDK bootstrap policies as code
2+
3+
**Status:** accepted
4+
**Date:** 2026-05-19
5+
**References:** ADR-001 (delivery methodology)
6+
7+
## Context
8+
9+
CDK bootstrap creates five roles per account/region. The **CloudFormation execution role** (cdk-hnb659fds-cfn-exec-role) receives `AdministratorAccess` by default — CloudFormation assumes it to create, modify, and delete stack resources. This violates least-privilege and may conflict with organizational SCPs or compliance gates.
10+
11+
The ABCA project documented three scoped policies in `docs/design/DEPLOYMENT_ROLES.md` (PR #46), validated against a live deployment through 7 iterations and 36 CloudTrail-discovered actions. However, these policies exist only as JSON blobs in a Markdown file — unversioned, untested, and manually applied.
12+
13+
**Failure mode without automation:** When a new release adds a resource type (e.g., SQS queue), operators who pull and deploy hit a mid-rollback CloudFormation failure because their bootstrap policy predates the new permissions. The deploy fails 15 minutes in with no prior warning.
14+
15+
**Constraints:**
16+
- IAM managed policies have a 6,144-character limit — hence the three-policy split (Infrastructure, Application, Observability).
17+
- Bootstrap must exist before the CDK app can deploy — circular dependency prevents managing bootstrap from within the app stack.
18+
- The four other bootstrap roles (deploy, lookup, file-publishing, image-publishing) are already scoped by the default template and don't need modification.
19+
20+
## Decision
21+
22+
### Policies as typed TypeScript code in `cdk/src/bootstrap/`
23+
24+
Rationale for location:
25+
- **Agent routing**`AGENTS.md` routes CDK/IAM changes to `cdk/`. An agent modifying a construct that adds a DynamoDB table naturally looks here for the policy it must update.
26+
- **Testability** — Jest tests can assert policy size limits, validate structure, and verify coverage against the synthesized template.
27+
- **Co-location** — the CDK app defines what resources exist (and therefore what permissions are needed); both live in the same package.
28+
- **Self-contained**`cdk/` has its own `mise.toml`, build, and test pipeline.
29+
30+
### Triple-layer versioning
31+
32+
| Layer | Purpose |
33+
|-------|---------|
34+
| **Semver** | Quick operator answer: "do I need to re-bootstrap?" Major = breaking. |
35+
| **SHA256 hash** | Detects console drift — manual IAM edits that diverge from code. |
36+
| **Action-set comparison** | Precise gap reporting: exactly which actions are missing. |
37+
38+
Semver and hash are emitted as CloudFormation outputs on the CDKToolkit stack, enabling automated preflight checks.
39+
40+
### Two-layer preflight validation
41+
42+
1. **CDK Aspect (synth-time)** — runs during `mise //cdk:synth`, visits every `CfnResource`, looks up required actions in a resource-action-map, compares against declared policy. Catches issues at dev time.
43+
2. **Live-account validator (deploy-time)**`mise //cdk:preflight` reads CDKToolkit stack outputs, compares version/hash against requirements. Fails fast with an actionable "re-bootstrap required" message before CloudFormation starts.
44+
45+
### Custom bootstrap template
46+
47+
Generated from the policy source code (not hand-maintained). Operators run `mise //cdk:bootstrap` to provision least-privilege roles in a single command. The template replaces `AdministratorAccess` with the three managed policies while retaining all other default bootstrap resources.
48+
49+
### Delivery via stacked PRs (ADR-001)
50+
51+
The implementation is decomposed into 8 sub-issues, each independently reviewable and deployable. See RFC #120 for the full stack.
52+
53+
## Consequences
54+
55+
- (+) Policies are diffable in PRs — IAM changes are code-reviewed like any other code
56+
- (+) Tests enforce the 6,144-char limit and structural validity on every commit
57+
- (+) Preflight prevents the "deploy, wait 15 minutes, fail, rollback" loop
58+
- (+) Single `mise //cdk:bootstrap` command replaces the multi-step manual process
59+
- (+) Agents can automatically update policies when they add new resource types
60+
- (-) Resource-action-map requires maintenance when new AWS resource types are added
61+
- (-) Rebase complexity from the 8-PR stack
62+
- (!) Bootstrap template drift — CDK upstream may change defaults; requires rebase on CDK major upgrades
63+
- (!) Operators with existing deployments must re-bootstrap (documented upgrade path provided)
64+
65+
## References
66+
67+
- RFC #120 — parent issue with full design and sub-issue breakdown
68+
- `docs/design/DEPLOYMENT_ROLES.md` — current documentation (will become generated)
69+
- PR #46 — original policy derivation and validation methodology
70+
- [CDK default bootstrap template](https://github.com/aws/aws-cdk/blob/main/packages/aws-cdk/lib/api/bootstrap/bootstrap-template.yaml)
71+
- [IAM managed policy size limit](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-quotas.html)
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
---
2+
title: 002 least privilege bootstrap policies
3+
---
4+
5+
# ADR-002: Least-privilege CDK bootstrap policies as code
6+
7+
**Status:** accepted
8+
**Date:** 2026-05-19
9+
**References:** ADR-001 (delivery methodology)
10+
11+
## Context
12+
13+
CDK bootstrap creates five roles per account/region. The **CloudFormation execution role** (cdk-hnb659fds-cfn-exec-role) receives `AdministratorAccess` by default — CloudFormation assumes it to create, modify, and delete stack resources. This violates least-privilege and may conflict with organizational SCPs or compliance gates.
14+
15+
The ABCA project documented three scoped policies in `docs/design/DEPLOYMENT_ROLES.md` (PR #46), validated against a live deployment through 7 iterations and 36 CloudTrail-discovered actions. However, these policies exist only as JSON blobs in a Markdown file — unversioned, untested, and manually applied.
16+
17+
**Failure mode without automation:** When a new release adds a resource type (e.g., SQS queue), operators who pull and deploy hit a mid-rollback CloudFormation failure because their bootstrap policy predates the new permissions. The deploy fails 15 minutes in with no prior warning.
18+
19+
**Constraints:**
20+
- IAM managed policies have a 6,144-character limit — hence the three-policy split (Infrastructure, Application, Observability).
21+
- Bootstrap must exist before the CDK app can deploy — circular dependency prevents managing bootstrap from within the app stack.
22+
- The four other bootstrap roles (deploy, lookup, file-publishing, image-publishing) are already scoped by the default template and don't need modification.
23+
24+
## Decision
25+
26+
### Policies as typed TypeScript code in `cdk/src/bootstrap/`
27+
28+
Rationale for location:
29+
- **Agent routing**`AGENTS.md` routes CDK/IAM changes to `cdk/`. An agent modifying a construct that adds a DynamoDB table naturally looks here for the policy it must update.
30+
- **Testability** — Jest tests can assert policy size limits, validate structure, and verify coverage against the synthesized template.
31+
- **Co-location** — the CDK app defines what resources exist (and therefore what permissions are needed); both live in the same package.
32+
- **Self-contained**`cdk/` has its own `mise.toml`, build, and test pipeline.
33+
34+
### Triple-layer versioning
35+
36+
| Layer | Purpose |
37+
|-------|---------|
38+
| **Semver** | Quick operator answer: "do I need to re-bootstrap?" Major = breaking. |
39+
| **SHA256 hash** | Detects console drift — manual IAM edits that diverge from code. |
40+
| **Action-set comparison** | Precise gap reporting: exactly which actions are missing. |
41+
42+
Semver and hash are emitted as CloudFormation outputs on the CDKToolkit stack, enabling automated preflight checks.
43+
44+
### Two-layer preflight validation
45+
46+
1. **CDK Aspect (synth-time)** — runs during `mise //cdk:synth`, visits every `CfnResource`, looks up required actions in a resource-action-map, compares against declared policy. Catches issues at dev time.
47+
2. **Live-account validator (deploy-time)**`mise //cdk:preflight` reads CDKToolkit stack outputs, compares version/hash against requirements. Fails fast with an actionable "re-bootstrap required" message before CloudFormation starts.
48+
49+
### Custom bootstrap template
50+
51+
Generated from the policy source code (not hand-maintained). Operators run `mise //cdk:bootstrap` to provision least-privilege roles in a single command. The template replaces `AdministratorAccess` with the three managed policies while retaining all other default bootstrap resources.
52+
53+
### Delivery via stacked PRs (ADR-001)
54+
55+
The implementation is decomposed into 8 sub-issues, each independently reviewable and deployable. See RFC #120 for the full stack.
56+
57+
## Consequences
58+
59+
- (+) Policies are diffable in PRs — IAM changes are code-reviewed like any other code
60+
- (+) Tests enforce the 6,144-char limit and structural validity on every commit
61+
- (+) Preflight prevents the "deploy, wait 15 minutes, fail, rollback" loop
62+
- (+) Single `mise //cdk:bootstrap` command replaces the multi-step manual process
63+
- (+) Agents can automatically update policies when they add new resource types
64+
- (-) Resource-action-map requires maintenance when new AWS resource types are added
65+
- (-) Rebase complexity from the 8-PR stack
66+
- (!) Bootstrap template drift — CDK upstream may change defaults; requires rebase on CDK major upgrades
67+
- (!) Operators with existing deployments must re-bootstrap (documented upgrade path provided)
68+
69+
## References
70+
71+
- RFC #120 — parent issue with full design and sub-issue breakdown
72+
- `docs/design/DEPLOYMENT_ROLES.md` — current documentation (will become generated)
73+
- PR #46 — original policy derivation and validation methodology
74+
- [CDK default bootstrap template](https://github.com/aws/aws-cdk/blob/main/packages/aws-cdk/lib/api/bootstrap/bootstrap-template.yaml)
75+
- [IAM managed policy size limit](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-quotas.html)

0 commit comments

Comments
 (0)