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.
| Stage | Verdict | Detail |
|---|---|---|
| Cold deploy | pass | Apply complete! Resources: 2 added, 0 changed, 0 destroyed.; 0 objects carry tofu-estate=iam-policy-crossing before migration |
| Migrate | pass | 2 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 nothing | pass | no resource change proposed, nothing foreign; identity re-check (via the AWS CLI) both unchanged |
| No-op apply | pass | genuine no-op: 2 objects before, 2 after, no state file either time |
| Drift and reconverge | pass | one 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 |
| Rename | pass | moved 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 block | pass | choudoufu: 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_destroy | not run | |
| Crash between create and destroy (planned) | not run | |
| Teardown (planned) | not run | |
| Plan, review, apply (planned) | not run | |
| Greenfield apply | pass | 2 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-policyNeeds 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.