Skip to content

Commit 899ab79

Browse files
committed
fix(iam): limit runtime additions to supported CE and EC2 calls
Keep the six runtime grants backed by existing CE and EC2 requests. Remove reserved-resource tag grants whose API contracts do not support the claimed fix, and narrow the source-action guard to its actual scope. OpenSearch tagging is tracked in #1204; Redshift support is tracked separately in #2092. Neither is repaired by widening runtime IAM.
1 parent c337080 commit 899ab79

4 files changed

Lines changed: 17 additions & 48 deletions

File tree

‎cloudformation/stacks/CUDly/template.yaml‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,6 @@ Resources:
480480
- es:DescribeReservedInstanceOfferings
481481
- es:DescribeReservedInstances
482482
- es:PurchaseReservedInstanceOffering
483-
- es:AddTags
484483
Resource: "*"
485484

486485
# Redshift Reserved Nodes
@@ -490,8 +489,6 @@ Resources:
490489
- redshift:DescribeReservedNodeOfferings
491490
- redshift:DescribeReservedNodes
492491
- redshift:PurchaseReservedNodeOffering
493-
- redshift:DescribeTags
494-
- redshift:CreateTags
495492
Resource: "*"
496493

497494
# MemoryDB Reserved Nodes

‎terraform/modules/compute/aws/fargate/main.tf‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -366,13 +366,10 @@ resource "aws_iam_role_policy" "ri_exchange" {
366366
"es:DescribeReservedInstances",
367367
"es:DescribeReservedInstanceOfferings",
368368
"es:PurchaseReservedInstanceOffering",
369-
"es:AddTags",
370369
# Redshift reserved nodes
371370
"redshift:DescribeReservedNodes",
372371
"redshift:DescribeReservedNodeOfferings",
373372
"redshift:PurchaseReservedNodeOffering",
374-
"redshift:DescribeTags",
375-
"redshift:CreateTags",
376373
# MemoryDB reserved nodes
377374
"memorydb:DescribeReservedNodes",
378375
"memorydb:DescribeReservedNodesOfferings",

‎terraform/modules/compute/aws/lambda/main.tf‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -374,13 +374,10 @@ resource "aws_iam_role_policy" "ri_exchange" {
374374
"es:DescribeReservedInstances",
375375
"es:DescribeReservedInstanceOfferings",
376376
"es:PurchaseReservedInstanceOffering",
377-
"es:AddTags",
378377
# Redshift reserved nodes
379378
"redshift:DescribeReservedNodes",
380379
"redshift:DescribeReservedNodeOfferings",
381380
"redshift:PurchaseReservedNodeOffering",
382-
"redshift:DescribeTags",
383-
"redshift:CreateTags",
384381
# MemoryDB reserved nodes
385382
"memorydb:DescribeReservedNodes",
386383
"memorydb:DescribeReservedNodesOfferings",

‎terraform/modules/compute/aws/runtime_iam_coverage_test.go‎

Lines changed: 17 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,8 @@
1-
// Guards the class of defect behind #1967 and #1968: an AWS action the
2-
// application calls under the runtime role that no runtime IaC flavor grants.
3-
// check-aws-iam-parity.sh cannot see this class because it only compares the
4-
// three runtime flavors with each other, so a gap present in all three passes.
5-
// This derives the called-action set straight from the SDK request structs
6-
// under the scanned roots and asserts each flavor grants every one.
7-
//
8-
// Two limits are deliberate. The guard is one-way: it catches an action the
9-
// code calls that a flavor does not grant, never a grant no code uses. Dead
10-
// grants are #1322's subject. And it covers only the reservation-related
11-
// service prefixes below, matching check-aws-iam-parity.sh's scope; platform
12-
// namespaces (sns, ses, secretsmanager, lambda, kms, logs) are out of reach
13-
// and have known gaps of their own, tracked on #1204.
1+
// Detects CE/EC2 action names missing from runtime IaC, including gaps shared
2+
// by all three flavors that check-aws-iam-parity.sh cannot detect (#1967/#1968).
3+
// This is source/action-presence coverage, not IAM evaluation: Effect, resource
4+
// scope, role attachment, and inline comments require separate review. Unused
5+
// grants (#1322) and other service namespaces are outside this guard's scope.
146
package aws_test
157

168
import (
@@ -25,22 +17,13 @@ import (
2517
"testing"
2618
)
2719

28-
// sdkServiceToIAMPrefix maps an aws-sdk-go-v2 service package name to the IAM
29-
// action prefix it authorizes against. Two services rename: Cost Explorer's
30-
// package is costexplorer but its actions are ce:*, and OpenSearch's package
31-
// is opensearch but its actions (for historical reasons) are es:*. sts is
32-
// deliberately absent: GetCallerIdentity requires no IAM permission at all,
33-
// so a call to it must never enter the derived set.
20+
// sdkServiceToIAMPrefix maps the CE/EC2 aws-sdk-go-v2 service package names to
21+
// the IAM action prefixes they authorize against. Cost Explorer's package is
22+
// costexplorer but its actions are ce:*. sts is deliberately absent:
23+
// GetCallerIdentity requires no IAM permission and must never enter the set.
3424
var sdkServiceToIAMPrefix = map[string]string{
35-
"costexplorer": "ce",
36-
"ec2": "ec2",
37-
"rds": "rds",
38-
"elasticache": "elasticache",
39-
"opensearch": "es",
40-
"redshift": "redshift",
41-
"memorydb": "memorydb",
42-
"savingsplans": "savingsplans",
43-
"organizations": "organizations",
25+
"costexplorer": "ce",
26+
"ec2": "ec2",
4427
}
4528

4629
// requiredDerivedActions is the floor from #1967/#1968: actions the code is
@@ -54,9 +37,6 @@ var requiredDerivedActions = []string{
5437
"ec2:CancelReservedInstancesListing",
5538
"ec2:DescribeInstanceTypes",
5639
"ec2:CreateTags",
57-
"redshift:DescribeTags",
58-
"redshift:CreateTags",
59-
"es:AddTags",
6040
}
6141

6242
// scanRoots are walked, relative to the repo root, for SDK call sites.
@@ -250,19 +230,17 @@ func sdkImportAliases(file *ast.File) map[string]string {
250230
return aliases
251231
}
252232

253-
// grantedActionPattern is check-aws-iam-parity.sh's extraction regex,
254-
// rewritten with a capture group so the match includes only the action
255-
// itself, not the boundary byte before it.
256-
var grantedActionPattern = regexp.MustCompile(`(?:^|[^A-Za-z])((?:ce|ec2|rds|elasticache|es|redshift|memorydb|savingsplans|organizations):[A-Z][A-Za-z]+)`)
233+
// grantedActionPattern is the CE/EC2 subset of check-aws-iam-parity.sh's
234+
// extraction regex, rewritten with a capture group so the match includes only
235+
// the action itself, not the boundary byte before it.
236+
var grantedActionPattern = regexp.MustCompile(`(?:^|[^A-Za-z])((?:ce|ec2):[A-Z][A-Za-z]+)`)
257237

258238
// hashCommentLinePattern matches a whole line whose first non-blank byte is
259239
// #, the comment style both Terraform and CloudFormation YAML use here.
260240
var hashCommentLinePattern = regexp.MustCompile(`(?m)^[ \t]*#.*$`)
261241

262-
// grantedActions reads path (relative to this package's directory, matching
263-
// how go test sets its working directory) and returns the set of IAM actions
264-
// it grants. Comment lines are stripped first, so a comment naming an action
265-
// cannot satisfy the guard.
242+
// grantedActions extracts action names from path after stripping whole-line
243+
// # comments. It does not parse policy semantics or other comment forms.
266244
func grantedActions(t *testing.T, path string) map[string]bool {
267245
t.Helper()
268246

0 commit comments

Comments
 (0)