Skip to content

Commit 61fa63c

Browse files
krokokobgagentcursoragent
authored
fix(cdk): refresh bootstrap policies for current stack deploy (#350) (#351)
Least-privilege bootstrap v1.2.0 was missing IAM for integration secrets, SQS DLQs, CloudFront OAC, Lambda layers, event-source mappings, and app S3 buckets — causing mid-deploy AccessDenied on custom bootstrap. Adds a resource-action map and synth-coverage test, updates DEPLOYMENT_ROLES.md, and documents the check in review_pr. Co-authored-by: bgagent <bgagent@noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 373bce5 commit 61fa63c

15 files changed

Lines changed: 672 additions & 35 deletions

File tree

.abca/commands/review_pr.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,28 @@ Then apply principal-architect judgment over the diff:
7171
together and parity fixtures were refreshed.
7272
- **Security & least privilege** — IAM scoping, Cedar HITL gates, secrets handling, path-
7373
traversal guards, input validation. Fail closed.
74+
- **Bootstrap policy coverage (CDK deploy IAM)** — When the PR adds or changes constructs,
75+
stacks, or handlers that introduce new CloudFormation resource types (new AWS services,
76+
`AWS::SQS::Queue`, `AWS::CloudFront::*`, `AWS::SecretsManager::Secret`, Lambda layers,
77+
application S3 buckets, etc.), verify the least-privilege bootstrap bundle was updated in
78+
the **same PR**:
79+
1. `cdk/src/bootstrap/policies/*.ts` — new actions and resource ARN patterns on the
80+
CloudFormation execution role.
81+
2. `cdk/src/bootstrap/resource-action-map.ts` — entry for each new CFN type (minimum
82+
create-time IAM actions).
83+
3. `BOOTSTRAP_VERSION` bumped in `cdk/src/bootstrap/version.ts` (minor when adding
84+
permissions) and artifacts regenerated (`mise //cdk:bootstrap:generate` → committed
85+
`cdk/bootstrap/policies/*.json`, `bootstrap-template.yaml`, `BOOTSTRAP_HASH`).
86+
4. `docs/design/DEPLOYMENT_ROLES.md` golden baseline updated (required by
87+
`cdk/test/bootstrap/golden-baseline.test.ts`).
88+
5. `cdk/test/bootstrap/synth-coverage.test.ts` passes — run
89+
`mise //cdk:test -- test/bootstrap/synth-coverage` or the full bootstrap suite.
90+
**Flag as blocking** if constructs changed but bootstrap policies, the action map, or
91+
version/artifacts were not updated. Missing ARN patterns (action present but resource
92+
too narrow) are a common gap — check secret/queue/bucket naming against the patterns
93+
in `application.ts` / `observability.ts`, not just action presence.
94+
See [ADR-002](../../docs/decisions/ADR-002-least-privilege-bootstrap-policies.md) and
95+
issue #350 for the failure mode this prevents.
7496
- **AWS / CDK quality** — Prefer L2 constructs, sane removal policies, no hardcoded ARNs/account
7597
IDs, cdk-nag clean. Watch for cost and operational footguns.
7698
- **Tests** — Are unit tests added/updated under the matching `*/test/` tree? Do they cover the
@@ -126,7 +148,8 @@ Summarize as a principal architect would in a PR review. Structure the output:
126148
3. **Blocking issues** — Numbered, each with `file:line`, the risk, and a suggested fix.
127149
4. **Non-blocking suggestions / nits** — Clearly separated.
128150
5. **Documentation** — What was updated, what is missing, mirror-sync status.
129-
6. **Tests & CI** — Coverage assessment and check status.
151+
6. **Tests & CI** — Coverage assessment and check status. For CDK construct/stack changes,
152+
explicitly note bootstrap synth-coverage status (pass / not applicable / missing updates).
130153
7. **Review agents run** — List each plugin/agent you invoked (Stage 3) and, for any in-scope
131154
agent you omitted, the one-line reason. This section is required — its absence means the
132155
mandatory plugin step was skipped.

cdk/bootstrap/BOOTSTRAP_HASH

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
a24d14dde94c546fdf94c7839492e92f612ae91def4660aaacab48d8e8da3146
1+
b0501c8a57f20e4b5bf50d6fe8bbb934310adc4b64480228565d8392a19d1503

cdk/bootstrap/BOOTSTRAP_VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.1.0
1+
1.2.0

cdk/bootstrap/bootstrap-template.yaml

Lines changed: 70 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# GENERATED FILE - DO NOT EDIT DIRECTLY
22
# This template is generated by: npx tsx scripts/generate-bootstrap-template.ts
3-
# ABCA Bootstrap Policy Version: 1.1.0
4-
# ABCA Bootstrap Policy Hash: a24d14dde94c546fdf94c7839492e92f612ae91def4660aaacab48d8e8da3146
3+
# ABCA Bootstrap Policy Version: 1.2.0
4+
# ABCA Bootstrap Policy Hash: b0501c8a57f20e4b5bf50d6fe8bbb934310adc4b64480228565d8392a19d1503
55
#
66
# Based on the default CDK bootstrap template with the following modifications:
77
# - BootstrapVariant set to "ABCA: Least-Privilege Bootstrap"
@@ -626,14 +626,11 @@ Resources:
626626
Policies:
627627
- PolicyDocument:
628628
Statement:
629-
- Sid: CloudFormationPermissions
629+
- Sid: DeployPermissions
630630
Effect: Allow
631631
Action:
632632
- cloudformation:CreateChangeSet
633633
- cloudformation:DeleteChangeSet
634-
- cloudformation:DescribeChangeSet
635-
- cloudformation:DescribeStacks
636-
- cloudformation:DescribeEvents
637634
- cloudformation:ExecuteChangeSet
638635
- cloudformation:CreateStack
639636
- cloudformation:UpdateStack
@@ -673,12 +670,9 @@ Resources:
673670
Effect: Allow
674671
- Sid: CliPermissions
675672
Action:
676-
- cloudformation:DescribeStackEvents
677-
- cloudformation:GetTemplate
678673
- cloudformation:DeleteStack
679674
- cloudformation:UpdateTerminationProtection
680675
- sts:GetCallerIdentity
681-
- cloudformation:GetTemplateSummary
682676
Resource: '*'
683677
Effect: Allow
684678
- Sid: CliStagingBucket
@@ -701,14 +695,12 @@ Resources:
701695
Effect: Allow
702696
Action:
703697
- cloudformation:CreateStackRefactor
704-
- cloudformation:DescribeStackRefactor
705698
- cloudformation:ExecuteStackRefactor
706-
- cloudformation:ListStackRefactorActions
707-
- cloudformation:ListStackRefactors
708-
- cloudformation:ListStacks
709699
Resource: '*'
710700
Version: '2012-10-17'
711701
PolicyName: default
702+
ManagedPolicyArns:
703+
- Fn::Sub: arn:${AWS::Partition}:iam::aws:policy/AWSCloudFormationReadOnlyAccess
712704
RoleName:
713705
Fn::Sub: cdk-${Qualifier}-deploy-role-${AWS::AccountId}-${AWS::Region}
714706
Tags:
@@ -794,7 +786,7 @@ Resources:
794786
Type: String
795787
Name:
796788
Fn::Sub: /cdk-bootstrap/${Qualifier}/version
797-
Value: '30'
789+
Value: '32'
798790
IaCRoleABCAInfrastructure:
799791
Type: AWS::IAM::ManagedPolicy
800792
Properties:
@@ -1013,11 +1005,23 @@ Resources:
10131005
- lambda:GetRuntimeManagementConfig
10141006
- lambda:ListVersionsByFunction
10151007
- lambda:InvokeFunction
1008+
- lambda:PublishLayerVersion
1009+
- lambda:DeleteLayerVersion
1010+
- lambda:GetLayerVersion
10161011
Effect: Allow
10171012
Resource:
10181013
- arn:aws:lambda:*:*:function:backgroundagent-dev-*
10191014
- arn:aws:lambda:*:*:function:backgroundagent-dev-AWS*
1015+
- arn:aws:lambda:*:*:layer:*
10201016
Sid: Lambda
1017+
- Action:
1018+
- lambda:CreateEventSourceMapping
1019+
- lambda:DeleteEventSourceMapping
1020+
- lambda:UpdateEventSourceMapping
1021+
- lambda:GetEventSourceMapping
1022+
Effect: Allow
1023+
Resource: '*'
1024+
Sid: LambdaEventSourceMappings
10211025
- Action:
10221026
- apigateway:POST
10231027
- apigateway:GET
@@ -1080,6 +1084,33 @@ Resources:
10801084
Effect: Allow
10811085
Resource: arn:aws:events:*:*:rule/backgroundagent-dev-*
10821086
Sid: EventBridge
1087+
- Action:
1088+
- sqs:CreateQueue
1089+
- sqs:DeleteQueue
1090+
- sqs:GetQueueAttributes
1091+
- sqs:SetQueueAttributes
1092+
- sqs:TagQueue
1093+
- sqs:UntagQueue
1094+
- sqs:GetQueueUrl
1095+
- sqs:ListQueueTags
1096+
Effect: Allow
1097+
Resource: arn:aws:sqs:*:*:backgroundagent-dev-*
1098+
Sid: SQS
1099+
- Action:
1100+
- cloudfront:CreateDistribution
1101+
- cloudfront:UpdateDistribution
1102+
- cloudfront:DeleteDistribution
1103+
- cloudfront:GetDistribution
1104+
- cloudfront:TagResource
1105+
- cloudfront:UntagResource
1106+
- cloudfront:ListTagsForResource
1107+
- cloudfront:CreateOriginAccessControl
1108+
- cloudfront:UpdateOriginAccessControl
1109+
- cloudfront:DeleteOriginAccessControl
1110+
- cloudfront:GetOriginAccessControl
1111+
Effect: Allow
1112+
Resource: '*'
1113+
Sid: CloudFront
10831114
- Action:
10841115
- secretsmanager:CreateSecret
10851116
- secretsmanager:DeleteSecret
@@ -1096,6 +1127,10 @@ Resources:
10961127
Resource:
10971128
- arn:aws:secretsmanager:*:*:secret:backgroundagent-*
10981129
- arn:aws:secretsmanager:*:*:secret:GitHubTokenSecret*
1130+
- arn:aws:secretsmanager:*:*:secret:SlackIntegration*
1131+
- arn:aws:secretsmanager:*:*:secret:LinearIntegration*
1132+
- arn:aws:secretsmanager:*:*:secret:GitHubScreenshot*
1133+
- arn:aws:secretsmanager:*:*:secret:bgagent/*
10991134
Sid: SecretsManager
11001135
- Action: secretsmanager:GetRandomPassword
11011136
Effect: Allow
@@ -1180,6 +1215,24 @@ Resources:
11801215
- arn:aws:s3:::cdk-hnb659fds-assets-*
11811216
- arn:aws:s3:::cdk-hnb659fds-assets-*/*
11821217
Sid: S3CDKAssets
1218+
- Action:
1219+
- s3:CreateBucket
1220+
- s3:DeleteBucket
1221+
- s3:PutBucketPolicy
1222+
- s3:DeleteBucketPolicy
1223+
- s3:PutBucketPublicAccessBlock
1224+
- s3:GetBucketPublicAccessBlock
1225+
- s3:PutEncryptionConfiguration
1226+
- s3:PutLifecycleConfiguration
1227+
- s3:GetBucketLocation
1228+
- s3:ListBucket
1229+
- s3:PutBucketTagging
1230+
- s3:GetBucketTagging
1231+
Effect: Allow
1232+
Resource:
1233+
- arn:aws:s3:::backgroundagent-dev-*
1234+
- arn:aws:s3:::backgroundagent-dev-*/*
1235+
Sid: S3ApplicationBuckets
11831236
- Action:
11841237
- kms:CreateGrant
11851238
- kms:Decrypt
@@ -1304,13 +1357,13 @@ Outputs:
13041357
Fn::Sub: ${ContainerAssetsRepository}
13051358
BootstrapVersion:
13061359
Description: The version of the bootstrap resources that are currently mastered in this stack
1307-
Value: '30'
1360+
Value: '32'
13081361
BootstrapPolicyVersion:
13091362
Description: The version of the ABCA bootstrap policy bundle
1310-
Value: 1.1.0
1363+
Value: 1.2.0
13111364
BootstrapPolicyHash:
13121365
Description: SHA-256 hash of the ABCA bootstrap policy bundle for drift detection
1313-
Value: a24d14dde94c546fdf94c7839492e92f612ae91def4660aaacab48d8e8da3146
1366+
Value: b0501c8a57f20e4b5bf50d6fe8bbb934310adc4b64480228565d8392a19d1503
13141367
BootstrapPolicySet:
13151368
Description: Comma-separated list of active ABCA bootstrap policy names
13161369
Value:

cdk/bootstrap/policies/application.json

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,30 @@
5252
"lambda:GetProvisionedConcurrencyConfig",
5353
"lambda:GetRuntimeManagementConfig",
5454
"lambda:ListVersionsByFunction",
55-
"lambda:InvokeFunction"
55+
"lambda:InvokeFunction",
56+
"lambda:PublishLayerVersion",
57+
"lambda:DeleteLayerVersion",
58+
"lambda:GetLayerVersion"
5659
],
5760
"Effect": "Allow",
5861
"Resource": [
5962
"arn:aws:lambda:*:*:function:backgroundagent-dev-*",
60-
"arn:aws:lambda:*:*:function:backgroundagent-dev-AWS*"
63+
"arn:aws:lambda:*:*:function:backgroundagent-dev-AWS*",
64+
"arn:aws:lambda:*:*:layer:*"
6165
],
6266
"Sid": "Lambda"
6367
},
68+
{
69+
"Action": [
70+
"lambda:CreateEventSourceMapping",
71+
"lambda:DeleteEventSourceMapping",
72+
"lambda:UpdateEventSourceMapping",
73+
"lambda:GetEventSourceMapping"
74+
],
75+
"Effect": "Allow",
76+
"Resource": "*",
77+
"Sid": "LambdaEventSourceMappings"
78+
},
6479
{
6580
"Action": [
6681
"apigateway:POST",
@@ -137,6 +152,39 @@
137152
"Resource": "arn:aws:events:*:*:rule/backgroundagent-dev-*",
138153
"Sid": "EventBridge"
139154
},
155+
{
156+
"Action": [
157+
"sqs:CreateQueue",
158+
"sqs:DeleteQueue",
159+
"sqs:GetQueueAttributes",
160+
"sqs:SetQueueAttributes",
161+
"sqs:TagQueue",
162+
"sqs:UntagQueue",
163+
"sqs:GetQueueUrl",
164+
"sqs:ListQueueTags"
165+
],
166+
"Effect": "Allow",
167+
"Resource": "arn:aws:sqs:*:*:backgroundagent-dev-*",
168+
"Sid": "SQS"
169+
},
170+
{
171+
"Action": [
172+
"cloudfront:CreateDistribution",
173+
"cloudfront:UpdateDistribution",
174+
"cloudfront:DeleteDistribution",
175+
"cloudfront:GetDistribution",
176+
"cloudfront:TagResource",
177+
"cloudfront:UntagResource",
178+
"cloudfront:ListTagsForResource",
179+
"cloudfront:CreateOriginAccessControl",
180+
"cloudfront:UpdateOriginAccessControl",
181+
"cloudfront:DeleteOriginAccessControl",
182+
"cloudfront:GetOriginAccessControl"
183+
],
184+
"Effect": "Allow",
185+
"Resource": "*",
186+
"Sid": "CloudFront"
187+
},
140188
{
141189
"Action": [
142190
"secretsmanager:CreateSecret",
@@ -154,7 +202,11 @@
154202
"Effect": "Allow",
155203
"Resource": [
156204
"arn:aws:secretsmanager:*:*:secret:backgroundagent-*",
157-
"arn:aws:secretsmanager:*:*:secret:GitHubTokenSecret*"
205+
"arn:aws:secretsmanager:*:*:secret:GitHubTokenSecret*",
206+
"arn:aws:secretsmanager:*:*:secret:SlackIntegration*",
207+
"arn:aws:secretsmanager:*:*:secret:LinearIntegration*",
208+
"arn:aws:secretsmanager:*:*:secret:GitHubScreenshot*",
209+
"arn:aws:secretsmanager:*:*:secret:bgagent/*"
158210
],
159211
"Sid": "SecretsManager"
160212
},

cdk/bootstrap/policies/observability.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,28 @@
8080
],
8181
"Sid": "S3CDKAssets"
8282
},
83+
{
84+
"Action": [
85+
"s3:CreateBucket",
86+
"s3:DeleteBucket",
87+
"s3:PutBucketPolicy",
88+
"s3:DeleteBucketPolicy",
89+
"s3:PutBucketPublicAccessBlock",
90+
"s3:GetBucketPublicAccessBlock",
91+
"s3:PutEncryptionConfiguration",
92+
"s3:PutLifecycleConfiguration",
93+
"s3:GetBucketLocation",
94+
"s3:ListBucket",
95+
"s3:PutBucketTagging",
96+
"s3:GetBucketTagging"
97+
],
98+
"Effect": "Allow",
99+
"Resource": [
100+
"arn:aws:s3:::backgroundagent-dev-*",
101+
"arn:aws:s3:::backgroundagent-dev-*/*"
102+
],
103+
"Sid": "S3ApplicationBuckets"
104+
},
83105
{
84106
"Action": [
85107
"kms:CreateGrant",

0 commit comments

Comments
 (0)