Skip to content

fix(iac/aws): reconcile IAM action drift and add CFN/TF parity gate#1219

Merged
cristim merged 3 commits into
mainfrom
fix/inf-02-aws-iam-parity
Jul 16, 2026
Merged

fix(iac/aws): reconcile IAM action drift and add CFN/TF parity gate#1219
cristim merged 3 commits into
mainfrom
fix/inf-02-aws-iam-parity

Conversation

@cristim

@cristim cristim commented Jun 11, 2026

Copy link
Copy Markdown
Member

Problem

Closes #1163 (review finding INF-02, P2).

The CloudFormation stack, the Terraform lambda/fargate modules, and the federation CFN/TF/CLI templates each encode their own copy of the IAM action list for the same application code, and the copies drifted:

  • The CFN stack lacked savingsplans:DescribeSavingsPlansOfferings (called in the Savings Plans purchase pre-flight, so CFN deployments 403 there) and the EC2 RI exchange-quote actions.
  • The TF lambda/fargate modules lacked ce:GetReservationCoverage / ce:GetSavingsPlansCoverage (coverage-targeted sizing silently degrades to "assume zero existing coverage"), ec2:DescribeRegions, and rds:DescribeDBInstances.
  • The federation cross-account CFN template lacked the org-discovery statement its Terraform sibling carries, and the newer federation templates (both flavors, CFN, TF, and the embedded CLI onboarding scripts) lost the Cost Explorer statement the legacy CUDly-CrossAccount template grants, breaking CE-based recommendation flows for federated accounts.
  • Azure has a CI parity gate (check-azure-role-parity.sh); AWS had none.

Fix

  • Reconciled every list to a single canonical set per deployment role:
    • CFN stack: + savingsplans:DescribeSavingsPlansOfferings, + ec2:GetReservedInstancesExchangeQuote, + ec2:AcceptReservedInstancesExchangeQuote, + organizations:DescribeOrganization.
    • TF lambda + fargate: + ce:GetReservationCoverage, + ce:GetSavingsPlansCoverage, + ec2:DescribeRegions, + rds:DescribeDBInstances, + organizations:DescribeAccount; legacy es:*ReservedElasticsearch* actions replaced with the new-style es:* actions the OpenSearch SDK calls require (overlaps INF-01: Terraform runtime IAM grants legacy es:*ReservedElasticsearch* actions; code calls the OpenSearch API, breaking OpenSearch RI flows on TF deployments #1149, which tracks the same TF-side gap); dropped savingsplans:DescribeSavingsPlanRates, which has no caller anywhere in the repo.
    • Federation: restored the 6-action Cost Explorer statement in aws-cross-account and aws-target CFN + TF templates and in both embedded CLI onboarding templates; added an opt-in EnableOrgDiscovery parameter + conditional OrganizationsDiscovery statement to the cross-account CFN template, mirroring the Terraform module's enable_org_discovery (default false in both).
  • Added scripts/check-aws-iam-parity.sh, the AWS sibling of check-azure-role-parity.sh. It extracts the application-owned IAM namespaces (ce, ec2, rds, elasticache, es, redshift, memorydb, savingsplans, organizations) and asserts parity across: the runtime trio (CFN stack vs TF lambda vs TF fargate), the federation cross-account CFN/TF pair (including org discovery), and the federation core set across both flavors plus the CLI templates.
  • Added scripts/test-aws-iam-parity.sh self-tests and wired both into ci.yml as a gating aws-iam-parity job (added to ci-success needs).

Test evidence

  • scripts/check-aws-iam-parity.sh against a pristine origin/main checkout: exit 1, reporting exactly the drift instances from the finding (CE Coverage, exchange quotes, DescribeSavingsPlansOfferings, legacy/new es names, federation org statement). Against this branch: exit 0.
  • scripts/test-aws-iam-parity.sh: 4/4 pass. The drift fixtures replicate the real pre-fix failure shapes (TF lambda missing the CE Coverage actions; federation CFN missing the org statement) and the check fails on them; a missing compared file fails loud with exit 2.
  • cfn-lint on all three touched CFN templates: findings identical to the pre-existing baseline on main (no new findings).
  • terraform fmt -check -recursive clean; actionlint .github/workflows/ci.yml clean.
  • go build ./... and go test ./internal/iacfiles/... ./internal/api/ -run "Federation|Template|Iac|IaC": 71 tests pass (covers the edited embedded templates).

Notes

  • The silent degradation in the coverage caller ("sizing will assume zero existing coverage" on CE errors) noted by the verifier is a fail-loud concern in Go code, intentionally not addressed in this IaC-parity PR.
  • README.md contains an illustrative minimal CLI policy that is not an IaC artifact and is not covered by the gate.

Summary by CodeRabbit

  • New Features

    • Expanded IAM permissions for AWS Cost Explorer, Reserved Instances, and Savings Plans management.
    • Added optional AWS Organizations account discovery capability across federation templates.
    • Extended EC2 and database reserved-instance exchange support.
  • Tests

    • Added automated IAM permission parity validation in CI pipeline to ensure consistency across infrastructure templates.
  • Chores

    • Updated CI workflow with new validation checks.

@cristim cristim added triaged Item has been triaged priority/p2 Backlog-worthy severity/high Significant harm urgency/this-quarter Within the quarter impact/many Affects most users effort/m Days type/bug Defect labels Jun 11, 2026
@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 5 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: adf91163-65dd-4cd7-a216-76b76e8a0d27

📥 Commits

Reviewing files that changed from the base of the PR and between 06820db and d45ffc5.

📒 Files selected for processing (9)
  • .github/workflows/ci.yml
  • CHANGELOG.md
  • cloudformation/stacks/CUDly/template.yaml
  • iac/federation/aws-cross-account/cloudformation/template.yaml
  • iac/federation/aws-cross-account/terraform/main.tf
  • iac/federation/aws-target/cloudformation/template.yaml
  • iac/federation/aws-target/terraform/main.tf
  • internal/iacfiles/templates/aws-cross-account-cli.sh.tmpl
  • internal/iacfiles/templates/aws-wif-cli.sh.tmpl
📝 Walkthrough

Walkthrough

IAM action lists across CloudFormation, Terraform, and CLI IaC templates are reconciled to close permission drift identified in INF-02: compute modules (lambda/fargate) gain CE coverage actions and corrected OpenSearch API names; federation and CUDly templates add CostExplorer statements; a new check-aws-iam-parity.sh script with a test harness enforces future consistency in CI.

Changes

AWS IAM Drift Fix and Parity Gate

Layer / File(s) Summary
Lambda and Fargate IAM permission expansion
terraform/modules/compute/aws/lambda/main.tf, terraform/modules/compute/aws/fargate/main.tf
ri_exchange policies gain ec2:DescribeRegions, corrected OpenSearch reserved-instances action names (dropping Elasticsearch-specific variants), and new CE coverage actions; org_discovery policies add organizations:DescribeAccount.
CUDly CloudFormation stack IAM expansion
cloudformation/stacks/CUDly/template.yaml
Lambda execution role gains ec2:GetReservedInstancesExchangeQuote, ec2:AcceptReservedInstancesExchangeQuote, savingsplans:DescribeSavingsPlansOfferings, and organizations:DescribeOrganization to match the Terraform module.
Federation cross-account and target IAM expansion
iac/federation/aws-cross-account/cloudformation/template.yaml, iac/federation/aws-cross-account/terraform/main.tf, iac/federation/aws-target/cloudformation/template.yaml, iac/federation/aws-target/terraform/main.tf, internal/iacfiles/templates/aws-cross-account-cli.sh.tmpl, internal/iacfiles/templates/aws-wif-cli.sh.tmpl
All federation template variants receive a new CostExplorer statement; the cross-account CloudFormation template also introduces an EnableOrgDiscovery parameter and a conditional OrganizationsDiscovery statement omitted via AWS::NoValue when disabled.
Parity check script
scripts/check-aws-iam-parity.sh
New script implementing extract_actions() with optional organizations: exclusion and hard-error on missing files, compare_pair() using process-substitution diff, and three comparison sets covering runtime and federation templates; exits 1 on any drift.
Parity test harness and CI wiring
scripts/test-aws-iam-parity.sh, .github/workflows/ci.yml
Test harness seeds fixtures from real repo files, mutates them to reproduce INF-02 drift shapes, and runs four cases with expected exit codes; CI adds an aws-iam-parity job running both scripts and registers it as a ci-success dependency.

Sequence Diagram(s)

sequenceDiagram
  participant CI as CI Job (aws-iam-parity)
  participant Check as check-aws-iam-parity.sh
  participant Test as test-aws-iam-parity.sh
  participant Files as IaC Source Files

  CI->>Check: run (REPO_ROOT)
  Check->>Files: extract_actions(CFN runtime template)
  Check->>Files: extract_actions(TF lambda template)
  Check->>Files: extract_actions(TF fargate template)
  Check->>Check: compare_pair runtime sets
  Check->>Files: extract_actions(cross-account CFN, exclude orgs)
  Check->>Files: extract_actions(cross-account TF, exclude orgs)
  Check->>Check: compare_pair federation cross-account
  Check->>Files: extract_actions(target CFN/TF/CLI x4, exclude orgs)
  Check->>Check: compare_pair federation target variants
  Check-->>CI: exit 0 (no drift) or exit 1 (drift found)
  CI->>Test: run self-tests (fixture trees)
  Test->>Check: run_case real repo (expect 0)
  Test->>Check: run_case TF CE drift fixture (expect 1)
  Test->>Check: run_case CFN CE drift fixture (expect 1)
  Test->>Check: run_case missing file fixture (expect 2)
  Test-->>CI: exit 0 (all cases passed)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested labels

priority/p1, urgency/now, impact/internal

Poem

🐇 Hopping through the IAM fields so wide,
Where CFN and Terraform walked side by side,
The actions now match — no more silent 403s,
CE Coverage granted, the coverage agrees!
A parity script guards the gate with a diff,
No more permission drift to give devs a sniff! 🌿

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(iac/aws): reconcile IAM action drift and add CFN/TF parity gate' directly describes the main objective of the PR: reconciling IAM permission drift and adding a CI parity check across CloudFormation and Terraform templates.
Linked Issues check ✅ Passed The PR fully addresses all coding objectives from issue #1163: reconciles IAM action drift across CFN/TF/federation templates, implements a parity check script equivalent to the Azure one, and adds CI integration as a gating job.
Out of Scope Changes check ✅ Passed All changes are directly scoped to issue #1163: IAM permission reconciliation across templates and the parity check implementation. No unrelated modifications to application logic or other systems are present.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/inf-02-aws-iam-parity

Comment @coderabbitai help to get the list of available commands.

@cristim

cristim commented Jun 11, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim

cristim commented Jun 11, 2026

Copy link
Copy Markdown
Member Author

Rebased onto main to pick up the CI fixes from #1220 (lint MinSavingsUSD rename, govulncheck, e2e/integration test repairs). The previous Lint/Security/E2E/Integration failures were inherited from the old base, none touched files in this PR.

Known remaining breakage on main itself: the pre-commit gocyclo hook fails on recEffectiveSavingsPct (complexity 12, introduced by #1206), tracked in #1222. That failure is unrelated to this PR and will show up on any branch until #1222 is fixed.

Local verification on the rebased head:

  • scripts/check-aws-iam-parity.sh passes on this tree, and exits 1 against the pre-fix tree (detects the exact CFN/TF drifts from INF-02)
  • scripts/test-aws-iam-parity.sh: 4/4 self-tests pass
  • actionlint on ci.yml: clean
  • cfn-lint on the three touched templates: only findings already present on main
  • go build ./... and go test ./internal/iacfiles/...: pass

@cristim

cristim commented Jun 11, 2026

Copy link
Copy Markdown
Member Author

Correction to the previous comment: the rebase did not clear Lint, Security Scanning, or Integration Tests, because main's own CI on its current HEAD (4108e51, post #1220) still fails those same three jobs (run 27325319311). Filed #1223 to track that breakage; the pre-commit gocyclo failure remains tracked in #1222. None of the failures involve files touched by this PR.

PR-relevant checks on the rebased head are green: AWS IAM actions parity (the new gate), Azure role parity, Validate Terraform (aws/azure), Unit Tests, Docker build, Snyk, both sanity workflows, CodeRabbit. E2E (Docker Buildx setup) and Validate Terraform (gcp) (Setup Terraform step) failed in runner setup before reaching any code; re-ran both.

@cristim
cristim force-pushed the fix/inf-02-aws-iam-parity branch from 7a16435 to 06820db Compare June 19, 2026 15:08
@cristim

cristim commented Jun 19, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/check-aws-iam-parity.sh`:
- Around line 45-49: The --root flag handling in the case statement does not
validate that a value is provided after the flag. When --root is passed without
a value, accessing $2 results in an unbound variable error and exit code 1. Add
a check in the --root case to verify that $2 exists (not empty or unset), and if
it does not, echo a usage error message to stderr and exit with code 2 before
attempting to assign REPO_ROOT="$2".
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 11a73212-eaa9-4d84-8422-1a02d0d76a00

📥 Commits

Reviewing files that changed from the base of the PR and between 451a70f and 06820db.

📒 Files selected for processing (12)
  • .github/workflows/ci.yml
  • cloudformation/stacks/CUDly/template.yaml
  • iac/federation/aws-cross-account/cloudformation/template.yaml
  • iac/federation/aws-cross-account/terraform/main.tf
  • iac/federation/aws-target/cloudformation/template.yaml
  • iac/federation/aws-target/terraform/main.tf
  • internal/iacfiles/templates/aws-cross-account-cli.sh.tmpl
  • internal/iacfiles/templates/aws-wif-cli.sh.tmpl
  • scripts/check-aws-iam-parity.sh
  • scripts/test-aws-iam-parity.sh
  • terraform/modules/compute/aws/fargate/main.tf
  • terraform/modules/compute/aws/lambda/main.tf

Comment thread scripts/check-aws-iam-parity.sh
@cristim
cristim force-pushed the fix/inf-02-aws-iam-parity branch from 06820db to c89eae6 Compare June 19, 2026 21:40
@cristim

cristim commented Jun 19, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

cristim added a commit that referenced this pull request Jun 26, 2026
… fix

PR #1219 reconciles the AWS IAM action lists between the CloudFormation
stack, the Terraform lambda/fargate modules, and the federation CFN/TF/CLI
templates -- but existing customer deployments do not auto-update. Bundles
deployed before this PR continue to silently degrade until re-applied:
federation roles lack the CE Get*Coverage actions (coverage-targeted sizing
assumes zero coverage), the cross-account CFN flavor lacks the optional
EnableOrgDiscovery parameter and the legacy CE statement, and runtime
deployments lack the new EC2 RI exchange actions and the new-style es:*
OpenSearch actions.

Add a Notices entry mirroring the existing 2026-04-22 federation-bundle
precedent so the operational impact is visible to upgrading customers.
@cristim

cristim commented Jun 26, 2026

Copy link
Copy Markdown
Member Author

Adversarial review (PR #1219)

Reviewed against the INF-02 finding (#1163) and the risk surfaces in the brief: CFN/TF IAM action drift, action additions vs removals, customer migration impact, parity gate implementation, least-privilege regressions, CI tool pinning, and tests. The fix is solid; one in-scope CHANGELOG entry pushed (b3fa9791b); one minor follow-up filed.

Verified

  • Runtime trio in parity: scripts/check-aws-iam-parity.sh extracts and sorts every ce|ec2|rds|elasticache|es|redshift|memorydb|savingsplans|organizations:<Action> token from cloudformation/stacks/CUDly/template.yaml, terraform/modules/compute/aws/lambda/main.tf, and terraform/modules/compute/aws/fargate/main.tf, then diffs them pairwise. Locally clean (exit 0). Pre-fix shape replicated by test-aws-iam-parity.sh Case 2 (strip ce:Get*Coverage from the TF lambda module) -> exit 1, confirming the gate FAILS on the original INF-02 drift. ✓
  • Federation cross-account pair in parity (incl. opt-in org-discovery): iac/federation/aws-cross-account/cloudformation/template.yaml now carries the 6-action CostExplorer statement that its TF sibling already had, plus a new EnableOrgDiscovery parameter / OrgDiscoveryEnabled condition / OrganizationsDiscovery statement (organizations:ListAccounts + organizations:DescribeOrganization) mirroring the TF module's var.enable_org_discovery. Both default to false. Pre-fix shape replicated by Case 3 (strip the org-discovery statement from the CFN template) -> exit 1. ✓
  • Federation core (across all 6 flavors) in parity with org-discovery excluded: aws-target CFN + TF and both CLI templates (aws-cross-account-cli.sh.tmpl, aws-wif-cli.sh.tmpl) now carry the 6-action CostExplorer statement that the legacy CUDly-CrossAccount template grants. Org-discovery legitimately excluded from this comparison group (target/CLI flavors intentionally don't offer it). ✓
  • No wildcard ACTIONS added (no s3:*, ec2:*, *:*). Resource: "*" is unchanged where present and load-bearing -- AWS doesn't support resource-level restrictions on the CE / Describe* / Organizations / Savings Plans actions used here (the lambda module's comment "Organizations API does not support resource-level restrictions" confirms intent). ✓
  • SDK-level rename correct, not just renamed for cosmetics: providers/aws/services/opensearch/client.go:24-26,89-94,188-194,222-229,391-397,502-507 calls DescribeReservedInstances / DescribeReservedInstanceOfferings / PurchaseReservedInstanceOffering -- the post-OpenSearch (es:*ReservedInstance*) action names, never the legacy (es:*ReservedElasticsearch*) names. Dropping the legacy names is safe; the new names are now granted everywhere. ✓
  • Dropped action savingsplans:DescribeSavingsPlanRates is genuinely dead: grep -rnE 'DescribeSavingsPlanRates' providers/aws/ internal/ cmd/ returns nothing in production code. Confirmed dropped only from the TF modules (where it was the only file that ever granted it). Removal is a real least-privilege win. ✓
  • CR's only --root finding addressed: commit c89eae696 adds the [[ $# -lt 2 || -z "${2:-}" ]] guard plus a self-test case for the bare-flag shape -> exit 2 with the explicit "--root requires a path value" message. Verified locally. ✓
  • CI gate wired correctly: aws-iam-parity runs under CI - Build & Test, gates on actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 (SHA-pinned per feedback_sha_pin_current_major.md / feedback_ci_tool_version_pin.md), added to ci-success needs list. The job ran green on this PR (AWS IAM actions parity (CFN vs TF) = SUCCESS). Pre-fix shape would have failed: the runtime drift (TF missing CE Coverage) and federation drift (CFN missing org statement) both reproduce cleanly via test-aws-iam-parity.sh Cases 2 + 3. ✓
  • No silent / log-and-continue path in the gate: a missing source file fails loud with exit 2 (extract_actions checks -f and emits a path); an empty extraction (regex match zero) fails loud with "no IAM actions extracted ... did the policy move or change format?". feedback_no_silent_fallbacks.md satisfied. ✓
  • Migration-collision shape from project_migration_number_collisions.md cleared: the branch was rebased onto main's migration renumber commit (5894580f3, merge 451a70f73), so 000074_audit_actor_stamps -> 000077_audit_actor_stamps on the PR head; only 000074_repair_partial_migration_058_067 remains at slot 74. No duplicate-number collision left to fail CI's full-history pre-commit. ✓

Fix pushed

b3fa9791b -- docs(changelog): note federation re-apply needed for IAM action drift fix. The repo's CHANGELOG.md already has a "Notices" precedent for the exact same shape ("Federation IaC bundles downloaded before 2026-04-22 need to be re-downloaded ..."): silent degradation persists on customer-deployed bundles until they re-apply. This PR's reconciliation has the same blast radius -- federated customers' roles continue to lack the CE Get*Coverage actions until they redeploy the federation template, so coverage-targeted sizing keeps assuming zero existing coverage; the cross-account CFN flavor's customers also miss the new EnableOrgDiscovery parameter and the legacy CE statement. Mirrored the existing 2026-04-22 Notice format to make the operational impact visible to upgrading customers. In-scope (mirrors the PR's own description, just rendered in the canonical "Notices" location) -- no scope creep.

Follow-up filed

  • fix(iac/aws): drop dead organizations:Describe{Account,Organization} grants from runtime trio #1322 (label priority/p3, severity/low, urgency/eventually, impact/internal, effort/xs, type/chore, triaged): runtime trio's organizations:DescribeAccount and organizations:DescribeOrganization grants are dead -- providers/aws/provider.go:43,283 and internal/accounts/org_discovery.go:24,42 only call ListAccounts. The PR took the union of pre-existing CFN-side and TF-side grants to reconcile the drift, which is the right choice while the rename ships (revoking would have been a customer-impacting change in the same PR). Tracked as a least-privilege cleanup so the unused actions can be dropped from both the CFN stack and the TF lambda/fargate modules once the parity gate is in place. Out of scope for INF-02.

UNSTABLE state

Three failing checks (Lint Code, Integration Tests, Security Scanning, plus the CI Success aggregator) are pre-existing on main: the latest CI - Build & Test on main (27833571269 on 451a70f7) fails the identical three jobs (Lint Code on errcheck in cmd/cleanup-lambda/..., internal/api/handler*, etc.; Integration Tests on TestPostgresStore_PurchaseExecutions/Get_execution_by_ID_-_not_found in internal/config/store_postgres_test.go; Security Scanning on frontend npm audit -- 44 vulns from picomatch / postcss / serialize-javascript / svgo / webpack / ws). None touch the 13-file diff in this PR (12 IaC + 1 CHANGELOG). Not blocking.

Verdict

LGTM. CR re-ping below.

@cristim

cristim commented Jun 26, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

cristim added a commit that referenced this pull request Jul 10, 2026
… fix

PR #1219 reconciles the AWS IAM action lists between the CloudFormation
stack, the Terraform lambda/fargate modules, and the federation CFN/TF/CLI
templates -- but existing customer deployments do not auto-update. Bundles
deployed before this PR continue to silently degrade until re-applied:
federation roles lack the CE Get*Coverage actions (coverage-targeted sizing
assumes zero coverage), the cross-account CFN flavor lacks the optional
EnableOrgDiscovery parameter and the legacy CE statement, and runtime
deployments lack the new EC2 RI exchange actions and the new-style es:*
OpenSearch actions.

Add a Notices entry mirroring the existing 2026-04-22 federation-bundle
precedent so the operational impact is visible to upgrading customers.
@cristim
cristim force-pushed the fix/inf-02-aws-iam-parity branch from b3fa979 to dba4f96 Compare July 10, 2026 13:51
@cristim

cristim commented Jul 10, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

cristim added a commit that referenced this pull request Jul 16, 2026
… fix

PR #1219 reconciles the AWS IAM action lists between the CloudFormation
stack, the Terraform lambda/fargate modules, and the federation CFN/TF/CLI
templates -- but existing customer deployments do not auto-update. Bundles
deployed before this PR continue to silently degrade until re-applied:
federation roles lack the CE Get*Coverage actions (coverage-targeted sizing
assumes zero coverage), the cross-account CFN flavor lacks the optional
EnableOrgDiscovery parameter and the legacy CE statement, and runtime
deployments lack the new EC2 RI exchange actions and the new-style es:*
OpenSearch actions.

Add a Notices entry mirroring the existing 2026-04-22 federation-bundle
precedent so the operational impact is visible to upgrading customers.
@cristim
cristim force-pushed the fix/inf-02-aws-iam-parity branch from dba4f96 to e582d60 Compare July 16, 2026 18:17
@cristim

cristim commented Jul 16, 2026

Copy link
Copy Markdown
Member Author

Rebased onto origin/main (2448a02, which merged #1217).

es: rename conflict resolved: #1217 already applied the es:*ReservedElasticsearch* -> es:*ReservedInstance* rename to both terraform files. Git applied the rebase cleanly with no manual conflict resolution needed -- the rename hunks from this PR became no-ops and were dropped automatically, so the PR's terraform diff is now the additive-only set: ec2:DescribeRegions, rds:DescribeDBInstances, ce:GetReservationCoverage, ce:GetSavingsPlansCoverage, removal of savingsplans:DescribeSavingsPlanRates, and organizations:DescribeAccount -- no legacy es: names re-introduced.

Parity gate re-verified:

  • bash scripts/check-aws-iam-parity.sh: exit 0 (OK)
  • bash scripts/test-aws-iam-parity.sh: 5/5 passed (exit 0)
  • Drift detection confirmed: temporarily removing ce:GetReservationCoverage from lambda/main.tf caused exit 1 with diff output; restore => exit 0.

Terraform gates: terraform fmt -check exit 0; terraform validate exit 0 on lambda, fargate, federation/aws-cross-account, federation/aws-target modules.

New head: e582d60

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

@cristim Thanks for the rebase details and verification. I’ll review the updated PR head, including the additive Terraform IAM changes and parity-gate coverage.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

cristim added a commit that referenced this pull request Jul 16, 2026
… fix

PR #1219 reconciles the AWS IAM action lists between the CloudFormation
stack, the Terraform lambda/fargate modules, and the federation CFN/TF/CLI
templates -- but existing customer deployments do not auto-update. Bundles
deployed before this PR continue to silently degrade until re-applied:
federation roles lack the CE Get*Coverage actions (coverage-targeted sizing
assumes zero coverage), the cross-account CFN flavor lacks the optional
EnableOrgDiscovery parameter and the legacy CE statement, and runtime
deployments lack the new EC2 RI exchange actions and the new-style es:*
OpenSearch actions.

Add a Notices entry mirroring the existing 2026-04-22 federation-bundle
precedent so the operational impact is visible to upgrading customers.
@cristim

cristim commented Jul 16, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@cristim
cristim force-pushed the fix/inf-02-aws-iam-parity branch from e582d60 to 13cb361 Compare July 16, 2026 18:35
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

cristim added 3 commits July 16, 2026 21:55
The CloudFormation stack, the Terraform lambda/fargate modules, and the
federation CFN/TF/CLI templates each granted a different, partially
insufficient IAM action set for the same application code:

- CFN stack lacked savingsplans:DescribeSavingsPlansOfferings (called in
  the purchase pre-flight) and the EC2 RI exchange-quote actions.
- TF lambda/fargate lacked ce:GetReservationCoverage and
  ce:GetSavingsPlansCoverage (coverage-targeted sizing silently degraded
  to zero existing coverage), ec2:DescribeRegions, and
  rds:DescribeDBInstances; they also still granted the legacy
  es:*ReservedElasticsearch* actions instead of the new-style es:*
  actions the OpenSearch SDK calls require (overlaps #1149).
- The federation cross-account CFN template lacked the optional
  org-discovery statement its Terraform sibling has, and all newer
  federation templates lost the Cost Explorer statement the legacy
  CUDly-CrossAccount template grants, breaking CE-based recommendations
  for federated accounts.
- savingsplans:DescribeSavingsPlanRates was granted by TF only and has
  no caller anywhere in the repo; dropped.

Reconcile all lists to a single canonical set per deployment role and
add scripts/check-aws-iam-parity.sh, the AWS sibling of
check-azure-role-parity.sh, wired into ci.yml as a gating job. The
check compares the application-owned IAM namespaces across the runtime
trio (CFN stack vs TF lambda vs TF fargate), the federation
cross-account CFN/TF pair (including org discovery), and the federation
core set across both flavors plus the embedded CLI onboarding
templates. scripts/test-aws-iam-parity.sh replicates the pre-fix drift
shapes in fixture trees and asserts the check fails on them; the check
was also verified to fail against the pre-fix tree and pass after
reconciliation.

Closes #1163
Under set -euo pipefail, passing --root without a following path value
hit `$2` as an unbound variable, exiting 1 with a bash error instead of
the intended exit 2 plus a usage message. Guard the argument before
dereferencing it and emit an explicit "--root requires a path value"
error. Add a self-test case asserting exit 2 for the bare --root flag.
… fix

PR #1219 reconciles the AWS IAM action lists between the CloudFormation
stack, the Terraform lambda/fargate modules, and the federation CFN/TF/CLI
templates -- but existing customer deployments do not auto-update. Bundles
deployed before this PR continue to silently degrade until re-applied:
federation roles lack the CE Get*Coverage actions (coverage-targeted sizing
assumes zero coverage), the cross-account CFN flavor lacks the optional
EnableOrgDiscovery parameter and the legacy CE statement, and runtime
deployments lack the new EC2 RI exchange actions and the new-style es:*
OpenSearch actions.

Add a Notices entry mirroring the existing 2026-04-22 federation-bundle
precedent so the operational impact is visible to upgrading customers.
@cristim
cristim force-pushed the fix/inf-02-aws-iam-parity branch from 13cb361 to d45ffc5 Compare July 16, 2026 18:55
@cristim

cristim commented Jul 16, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim
cristim merged commit 1391680 into main Jul 16, 2026
19 checks passed
@cristim
cristim deleted the fix/inf-02-aws-iam-parity branch July 16, 2026 19:11
@cristim

cristim commented Jul 16, 2026

Copy link
Copy Markdown
Member Author

Merged to main after pre-merge adversarial review (rebase-then-merge through #1217/#1364/#1389): additive read-only CE/RI-exchange IAM actions (no new wildcards, Resource=* only where the API lacks resource scoping) plus a hermetic CFN-vs-TF IAM parity gate proven to catch injected drift. terraform validate + parity gate green.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/m Days impact/many Affects most users priority/p2 Backlog-worthy severity/high Significant harm triaged Item has been triaged type/bug Defect urgency/this-quarter Within the quarter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

INF-02: IAM drift between CloudFormation and Terraform deployments of the same Lambda image; no AWS parity gate

1 participant