terraform-aws-modules/terraform-aws-iam examples/iam-policy

Source: https://github.com/terraform-aws-modules/terraform-aws-iam.git at v6.8.0.

Set: core. Lane: terraform-popular.

Why it is in the core set: a most-downloaded terraform-aws-modules example, pinned by tag; the shape most people deploy

Not clear yet.

StageVerdictDetail
Cold deploypassApply complete! Resources: 2 added, 0 changed, 0 destroyed.; 0 objects carry tofu-estate=iam-policy-crossing before migration
Migratepass2 of 2 stamped, both carrying tofu-slot=0/0 read back through IAM (choudoufu #372); Apply complete! Resources: 0 added, 0 changed, 0 destroyed. - nothing left to converge
Replan from nothingpassno resource change proposed, nothing foreign; identity re-check (via the AWS CLI) both unchanged
No-op applypassgenuine no-op: 2 objects before, 2 after, no state file either time
Drift and reconvergepassone object tampered (arn:aws:iam::000000000000:policy/example_from_data_source’s Example tag), plan proposed fixing exactly one object, apply changed 1 and reconverged the tag
Renamepassmoved block: module.iam_policy_from_data_source renamed with zero churn (0 add, 1 change, 0 destroy), marker rewritten in place; live-mv: module.iam_policy renamed with zero churn, marker rewritten in place (found and fixed live-mv’s own missing issue #266 tag-index fallback and the arnJoinTable’s missing iam:policy entry to get here); stock oracle over the same two-module rename on cold_deploy’s own state also shows zero churn (0 add, 0 change, 0 destroy); both ARNs unchanged, read via the AWS CLI
Remove a blockpasschoudoufu: deleting module.iam_policy_renamed’s block proposed exactly one destroy (0 add, 0 change, 1 destroy), applied cleanly (0 added, 0 changed, 1 destroyed), the object is genuinely gone from the live account (iam get-policy on the old ARN now returns NoSuchEntity, read via the AWS CLI, not choudoufu’s own report), and the next plan proposes no resource action; stock oracle on cold_deploy’s own state (STAGE 1.5.5) also proposes exactly one destroy for the same object; classifyOrphans did not withhold the destroy even though module.iam_policy_renamed2’s policy shares the same block key, because that surviving instance is bound, not unclaimed
Change count (planned)not run
Replace with create_before_destroynot run
Crash between create and destroy (planned)not run
Teardown (planned)not run
Plan, review, apply (planned)not run
Greenfield applypass2 resources from nothing (both aws_iam_policy), markers verified via the AWS CLI, 2 records in the local record store (#364 A2), replan empty both with and without the local record store, both policies’ documents and paths match stock’s cold-deploy container (STAGE 1, untouched) object by object, marker tags never compared
Strict profile (planned)not run

Last run at commit a2b7eb7f4c on 2026-08-25T17:28:43Z, exit code 0.

Upgraded from a real but pre-#274-pipeline predecessor script (choudoufu apply from a live block present from the start, delete state, replan empty twice) to the current five-stage shape, following corpus-vpc-complete/corpus-lambda-simple’s structure. Verified for real in a fresh isolated worktree off local main (ff106e63a7), Docker/floci/AWS CLI throughout, not read from the predecessor’s prior notes. All five stages pass cleanly: cold_deploy (plain terraform apply, “Apply complete! Resources: 2 added”, confirmed 0 objects tagged before migration), migrate (live-import dry run verifies “2 of 2 resource instance(s) are eligible for stamping”, -approve reports “2 resource(s) newly stamped, 0 already stamped, 0 failed, 0 skipped”, both tofu-address/tofu-estate tags read directly through the AWS CLI: module.iam_policy.aws_iam_policy.policy:0 and module.iam_policy_from_data_source.aws_iam_policy.policy:0), test_plan (live-plan genuinely empty, both identities re-read unchanged after the state file’s only copy was deleted), test_apply (“0 added, 0 changed, 0 destroyed”, object count unchanged at 2), and drift_reconverge (one policy’s Example tag tampered directly against floci, live-plan proposes fixing exactly that object, apply reconverges it to “0 added, 1 changed, 0 destroyed”). BREAK=1 verified twice, independently, against each stage it targets: run as committed it fails stage 3’s identity check (expects the real policy’s tofu-address on a module that was never created); run separately with stage 3’s corruption disabled, it correctly fails stage 5 by tampering a second object and proving the “exactly one object” count assertion is load-bearing (both objects flagged, not silently 1). NEW FINDING, not previously documented in any real crossing that reached this deep: live-import -approve deliberately writes only tofu-estate and tofu-address, never tofu-slot (internal/live/stamp/doc.go’s own “tofu-slot comes in from outside” - a slot is minted from a monotonic counter over the live set that a read-only, one-state-file view cannot compute). Both of this estate’s aws_iam_policy resources declare count = var.create ? 1 : 0, exactly the shape that needs one, so the FIRST live-plan straight after live-import -approve is not empty - it proposes adding tofu-slot=“0” to both, and nothing else. Folded into stage 2 as one ordinary choudoufu apply (“0 added, 2 changed, 0 destroyed”) before stage 3 is attempted; every replan after is genuinely empty. This is real, deliberate, already-documented product behavior, not a defect - but it will recur on any count-based resource crossing that reaches this far and had not yet been noticed in one that actually got here. Also caught and fixed while verifying: a self-authored bug where stage 5’s negative drift assertion compared a live-plan diff header’s address (bracket form, “policy[0]”) against the escaped tag-value form (“policy:0”) and could never have matched - a vacuous check that a stricter assertion in the sibling script (see corpus-iam-read-only-policy) surfaced; fixed here by keeping both forms as separate variables.

Reproduce it#

go run ./tools/gauntlet run corpus-iam-policy

Needs Docker (the emulator is pulled at the pinned digest), the AWS CLI, and a stock terraform or tofu binary on PATH for the cold deploy. The script is live/e2e/corpus-iam-policy/run.sh; BREAK=1 corrupts its assertions to show they are load-bearing.