Skip to content

Commit 440f848

Browse files
isadeksbgagent
andauthored
fix(cdk): grant lambda Tag/UntagResource on event-source-mappings (#407) (#408)
CDK event-source constructs (e.g. DynamoDBEventSource) tag the created event source mapping, so CloudFormation issues lambda:TagResource on event-source-mapping:* during deploy. The LambdaEventSourceMappings statement in the bootstrap policy grants Create/Delete/Update/Get on `*` but not the tagging actions — and the lambda:TagResource granted elsewhere is scoped to function:*/layer:*, which does not cover mappings. A fresh `mise //cdk:bootstrap` + deploy of current main therefore rolls back deep into the stack with: cdk-hnb659fds-cfn-exec-role is not authorized to perform lambda:TagResource on event-source-mapping:* Add lambda:TagResource and lambda:UntagResource to the LambdaEventSourceMappings statement (resources already `*`), regenerate bootstrap artifacts, and update the DEPLOYMENT_ROLES.md golden (+ Starlight mirror). Add a regression guard in policies.test.ts. Third instance of the same bootstrap-drift class as #402/#403 and #404/#405; root-cause CI gap tracked in #406. Fixes #407 Co-authored-by: bgagent <bgagent@noreply.github.com>
1 parent c81e079 commit 440f848

6 files changed

Lines changed: 33 additions & 3 deletions

File tree

cdk/bootstrap/bootstrap-template.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,6 +1019,8 @@ Resources:
10191019
- lambda:DeleteEventSourceMapping
10201020
- lambda:UpdateEventSourceMapping
10211021
- lambda:GetEventSourceMapping
1022+
- lambda:TagResource
1023+
- lambda:UntagResource
10221024
Effect: Allow
10231025
Resource: '*'
10241026
Sid: LambdaEventSourceMappings

cdk/bootstrap/policies/application.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@
7070
"lambda:CreateEventSourceMapping",
7171
"lambda:DeleteEventSourceMapping",
7272
"lambda:UpdateEventSourceMapping",
73-
"lambda:GetEventSourceMapping"
73+
"lambda:GetEventSourceMapping",
74+
"lambda:TagResource",
75+
"lambda:UntagResource"
7476
],
7577
"Effect": "Allow",
7678
"Resource": "*",

cdk/src/bootstrap/policies/application.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,12 @@ export function applicationPolicy(): iam.PolicyDocument {
106106
'lambda:DeleteEventSourceMapping',
107107
'lambda:UpdateEventSourceMapping',
108108
'lambda:GetEventSourceMapping',
109+
// CDK event-source constructs (e.g. DynamoDBEventSource) tag the
110+
// created mapping, so the exec role needs Tag/UntagResource on
111+
// event-source-mapping:* (the function:*/layer:*-scoped TagResource
112+
// grant elsewhere in this policy does not cover mappings).
113+
'lambda:TagResource',
114+
'lambda:UntagResource',
109115
],
110116
resources: ['*'],
111117
}),

cdk/test/bootstrap/policies.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,22 @@ describe('IaCRole-ABCA-Application', () => {
149149
);
150150
});
151151

152+
it('LambdaEventSourceMappings grants tagging (CDK event-source constructs tag the mapping)', () => {
153+
// Regression guard for #407: DynamoDBEventSource (and peers) tag the
154+
// created event source mapping, so the exec role needs Tag/UntagResource
155+
// on event-source-mapping:*. The TagResource granted elsewhere is scoped
156+
// to function:*/layer:* and does not cover mappings, so a fresh deploy
157+
// rolled back with AccessDenied on lambda:TagResource. Lock the contract.
158+
const resolvedDoc = stack.resolve(doc);
159+
const statements = resolvedDoc.Statement as Array<{ Sid: string; Action?: string | string[] }>;
160+
const esm = statements.find((s) => s.Sid === 'LambdaEventSourceMappings');
161+
expect(esm).toBeDefined();
162+
163+
const actions = Array.isArray(esm!.Action) ? esm!.Action : [esm!.Action];
164+
expect(actions).toContain('lambda:TagResource');
165+
expect(actions).toContain('lambda:UntagResource');
166+
});
167+
152168
it('SecretsManager statement allow-lists a secret pattern for every integration that creates a secret', () => {
153169
// Regression guard for #402: each integration construct that creates a
154170
// Secrets Manager secret (GitHub token, Slack, Linear, Jira, GitHub

docs/design/DEPLOYMENT_ROLES.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,9 @@ DynamoDB tables, Lambda functions, API Gateway, Cognito, WAFv2, EventBridge, SQS
339339
"lambda:CreateEventSourceMapping",
340340
"lambda:DeleteEventSourceMapping",
341341
"lambda:UpdateEventSourceMapping",
342-
"lambda:GetEventSourceMapping"
342+
"lambda:GetEventSourceMapping",
343+
"lambda:TagResource",
344+
"lambda:UntagResource"
343345
],
344346
"Resource": "*"
345347
},

docs/src/content/docs/architecture/Deployment-roles.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,9 @@ DynamoDB tables, Lambda functions, API Gateway, Cognito, WAFv2, EventBridge, SQS
343343
"lambda:CreateEventSourceMapping",
344344
"lambda:DeleteEventSourceMapping",
345345
"lambda:UpdateEventSourceMapping",
346-
"lambda:GetEventSourceMapping"
346+
"lambda:GetEventSourceMapping",
347+
"lambda:TagResource",
348+
"lambda:UntagResource"
347349
],
348350
"Resource": "*"
349351
},

0 commit comments

Comments
 (0)