terraform-aws-modules/terraform-aws-security-group examples/complete (tag v6.0.0), its flagship example

Source: https://github.com/terraform-aws-modules/terraform-aws-security-group.git at v6.0.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 deploypass67 resources (DELTA 2, lex00/floci#57)
Migratepass58 of 67 stamped, 67 identities recorded (#364 unit A2)
Replan from nothingpassthe plan is genuinely empty: every choudoufu wall (#305, #307, #313 A and B, #321, #332) and both confirmed floci gaps (#102, #104) are fixed or absent this run; default route table identities asserted by value against the AWS CLI in step 3a
No-op applypassno-op apply (0 added, 0 changed, 0 destroyed); tofu-estate-tagged object count unchanged at 58 objects, read through resourcegroupstaggingapi
Drift and reconvergepassone object tampered (DriftProbe tag on the main security group), exactly module.security_group.aws_security_group.this[0] proposed, apply changed 1 and the tag is gone, confirmed via the AWS CLI
Renamepassmoved block: module.postgresql renamed to module.postgresql_renamed with zero churn (0 add, 4 change, 0 destroy) - the rule-children case, its own SG plus ingress/egress rules and rules_exclusive all moving under one moved block; live-mv: aws_security_group.app renamed with zero churn, marker rewritten in place; stock oracle over the same two-object rename on cold_deploy’s own state also shows zero churn (0 add, 0 change, 0 destroy); both live ids unchanged, read via the AWS CLI
Remove a blockpasschoudoufu: deleting module.postgresql_renamed’s block proposed exactly 5 destroys (0 add, 0 change, 5 destroy: SG + 2 ingress + 1 egress + 1 untaggable rules_exclusive), applied cleanly (0 added, 0 changed, 5 destroyed), the security group is genuinely gone from the live account (0 matches on describe-security-groups for the old id, read via the AWS CLI, not choudoufu’s own report), and the next plan proposes nothing; stock oracle on cold_deploy’s own state (D-ORACLE remove) also proposes exactly 5 destroys for the same 5 objects; classifyOrphans did not withhold the untaggable rules_exclusive destroy even though module.security_group’s and module.consul’s own rules_exclusive instances share its block key, because both surviving instances are 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 applypass67 resources from nothing, all markers verified via the AWS CLI, 67 records in the local record store (#364 A2), replan empty, 6 tagged security groups (4 named + 2 default adopters) and every named one’s rule shape matches $PLAIN_EST’s own stage-1 apply object by object, tags stripped
Strict profile (planned)not run

Last run at commit 8f904b06dc on 2026-08-25T17:39:23Z, exit code 0.

Landed c876435875 (2026-08-18), 67 real resources. The brief expected this crossing to hit #304 (a static lookup()-keyed count-index) directly, since a prior crossing found #304 through this same module as a dependency - checked, not assumed, and refuted: v6.0.0 rewrote the module from the classic single-aws_security_group-with-dynamic-blocks shape #304 lives in to a for_each-over-a-map shape emitting aws_vpc_security_group_ingress_rule/egress_rule per rule key, so that whole pattern is gone from this version’s own example. migrate genuinely passes (52 of 67 eligible and stamped: 35 VERIFIED + 17 DRIFTED; 15 skipped - 6 untaggable by design, 9 unadmitted). test_plan blocked by two real, distinct, filed gaps: #305 (6 sites, the familiar default_* adopter trio, doubled since this estate nests two terraform-aws-vpc calls) and a NEW one, filed as #307: aws_vpc_security_group_rules_exclusive is unadmitted (3 sites) - no CFN counterpart and the pinned provider ships no identity schema for it, but its own import docs are unambiguous that security_group_id (required, ForceNew, always a direct parent reference) is its whole identity, the same shape aws_vpc_security_group_vpc_association’s already-admitted row has. Also found and filed a real floci gap (lex00/floci#57: EC2 AssociateSecurityGroupVpc has no handler at all), worked around with a documented delta removing the estate’s one vpc_associations block (67 of 68 resources still stand up for real). One open, honestly-unresolved observation: 17 of the DRIFTED resources show referenced_security_group_id read back as “000000000000/sg-xxx” from floci where config computes a bare “sg-xxx” - doesn’t block stamping, but live-plan never got past #305/#307’s hard refusals to reveal whether the real provider’s diff-suppression absorbs this cleanly or would surface as an 18th change. Not filed separately; the next crossing attempt (once #305/#307 land) will show it for real. Follow-up pass 2026-08-19 (#313’s data-source fix, c636ab20f7/0284d8c408): re-verified for real against the current pin (67 cold-deployed, 58 stamped, state deleted). test_plan diagnostics dropped from 239 to 19 - #313’s canonical data.aws_availability_zones cause (50 sites) is fully gone, the module-output/resource-attribute variant (2 sites) still correctly refuses (out of scope by the maintainer’s own ruling), and the 187-site cascade collapsed to 5. The remaining 12 sites are a NEW, newly-reached class (previously masked behind #313’s hard refusal): element([].id, count.index) in the vpc module’s aws_route_table_association.private - both operands are tagged resources, the obstacle is the splat-through-function-call shape, not an admission gap. Filed as #321, not attempted (scouting slot). test_plan therefore stays fail, but the estate’s real remaining blocker is now #321 (a derivable, no-design-call-needed gap) rather than #313 (an architecture question) - #321 is the clear next step toward this estate’s five-of-five and the core set’s last gap. Follow-up pass 2026-08-19 (#321 fixed and merged, c33a47288a/626ca84739): element([].attr, idx) over a splat of tagged resources now resolves generically - it names the same live object a direct indexed traversal already resolves, via element()’s own modulo wraparound. Re-verified for real: test_plan diagnostics 19 -> 7. The 12 splat-through-element sites are confirmed cleared by their absence from real live-plan output; the remaining 7 are #313’s own deliberately-out-of-scope resource-attribute root cause (root cause B), a maintainer scope boundary, not a bug. test_plan stays fail - the core set does NOT reach five-of-five from this fix alone. Generalizes beyond this estate: refusal-probe over terraform-aws-modules/vpc’s own examples, 21 -> 8 sites, zero regressions - three configs (ipam, ipv6-only, outpost) fully cleared. A related but distinct lint-side wall (RuleCountIndex, 32 sites/6 configs, a genuine unresolved composite-vs-per-argument injectivity design question) stays independently blocking and was left open, documented rather than attempted. Follow-up pass 2026-08-19 (#191 fixed and merged, 312acbbb61/75ef0a6a78): internal/live/identity/partialargs.go’s tolerant rebuild now composes across more than one module call and evaluates a call the caller wrote (merge(), not a bare constructor) through an evaluator whose own var.* closure is already tolerant, one module up. module.consul’s ingress_referenced_security_group_id map no longer poisons the 22 ingress rules it seeds two module calls down - the map’s KEYS (eleven preset names crossed with one caller key) were always written down; only the VALUE under one key was ever unknowable, and it still is. Re-verified for real against floci, script exit 0, BREAK=1 negative control correctly fails: test_plan diagnostics 7 -> 4, and every analysis-layer refusal this estate has ever hit is now 0 and asserted by absence (#305, #307, #313 root causes A and B both, #321). What newly reached PROJECTION and blocks the estate now is #332 (not #313 - the old ‘Unable to use aws_security_group.app in static context’ framing is confirmed gone): aws_default_route_table imports by the VPC’s id, not its own, and the ratified row says otherwise - 2 ‘Cannot import for projection’ + 2 ’empty result’, one pair per nested vpc module call, both traced to the same type. #332 is filed, not fixed here; it is now the sole remaining blocker on this estate and on the core set’s last five-of-five gap. #332 fixed 2026-08-19 (859c1ad747/ff1f6bcdea/c1197befc7): the ratified row claimed aws_default_route_table imports by the route table’s own rtb-… id; the real provider imports it by the VPC’s id, read off the vpc_id ATTRIBUTE (not argument) the discovered object already carries - settled by running stock terraform 1.15.8 + hashicorp/aws 6.59.0 (Error: empty result for rtb-…, Import successful! for vpc-…). Reach stated honestly: one type today (defaultAdopterSiblings/sameRatifiedIdentity in internal/live/discovery/discovery.go split “same live object” from “same import identity” generically, off each type’s own ratified IdentityAttrs/ImportSyntax, no type name in the control flow - #302’s aws_iam_service_linked_role/aws_iam_role pair already exercises the same recomposition path; aws_default_route_table is simply the only aws_default_* row that currently diverges from its plain sibling at aws 6.59.0). Re-verified independently 2026-08-20 with a fresh real crossing against floci (ghcr.io/lex00/floci@sha256:120b6783c7fb48d3d78245056251492b7d9246cdc3b397c98db2659cdc78d94a, the currently pinned image): STAGE 1 PASS, STAGE 2 PASS, STAGE 3 BLOCKED at exactly 1 site (was 239, then 19, then 7, then 4) - every choudoufu-layer refusal this estate has ever hit (#305, #307, #313 root causes A and B, #321, #332) confirmed absent, and step 3a re-derives each nested VPC’s default route table import identity from AWS directly (module.vpc: vpc-9eceebf0 -> rtb-7a9e0d017620e163c; module.vpc_secondary: vpc-91d40754 -> rtb-b66d5dc82e63b6e38) and asserts it BY VALUE, not by absence. The 1 remaining site is the AWS provider answering “Provider produced invalid plan” on its own requires-replacement path for module.security_group.aws_vpc_security_group_ingress_rule.this[“dns-from-prefix-list”] (cty.Path{cty.GetAttrStep{Name:""}}), explicitly a provider bug per the error’s own text - filed upstream as #335, genuinely outside this fork’s code (the diagnostic names no choudoufu path). test_plan stays “fail” in this table’s pass/fail/not_run vocabulary since the plan is not clean, but the estate’s own blocker has moved entirely off this fork: #332 was the core set’s last derivable gap, and #335 (an AWS-provider defect) is what now stands between this estate and five-of-five.

Reproduce it#

go run ./tools/gauntlet run corpus-security-group-complete

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-security-group-complete/run.sh; BREAK=1 corrupts its assertions to show they are load-bearing.