Overview
This lab demonstrates where secrets enter Terraform state, which supported resources can use write-only or ephemeral values, and how to scan state safely during migration.
The website intentionally does not mirror this repository. The GitHub repository is the canonical, versioned lab so its Terraform, scanner, workflow, and tests cannot drift into a second downloadable copy here.
Requirements
- Terraform 1.11+ for write-only managed-resource arguments
- Random provider 3.7.0+ for ephemeral
random_password - AWS provider 5.88.0+ for
secret_string_wo - AzureRM provider 4.23.0+ for
value_wo - Python 3.8+, Bash, and authenticated AWS or Azure tooling only for the examples you choose to apply
The reviewed repository revision pins Terraform 1.14.9 through
.terraform-version and commits provider locks for AWS 5.100.0, AzureRM
4.25.0, and Random 3.7.2. Initialize with -lockfile=readonly so a normal lab
run cannot silently rewrite those selections.
For either Azure example, set ARM_SUBSCRIPTION_ID to the exact disposable
subscription you intend to use and confirm it with az account show before
planning. AzureRM 4.x requires an explicit subscription selection.
Both Azure examples use the same deny-by-default Key Vault firewall policy and
accept exactly one canonical, globally routable public IPv4 /32. They reject
private, shared, loopback, link-local, documentation, benchmarking, multicast,
reserved, IPv6, and broad ranges. Use a private endpoint or virtual-network
design for private addressing rather than putting a private address in an IP
rule. Keeping both network policies identical isolates the intended comparison:
traditional value versus write-only value_wo state behavior.
Start Here
- Read the companion article for the state-security model and supported-resource caveats.
- Open the reviewed repository revision.
- Follow the README through isolated setup, state inspection, the write-only comparison, validation, and cleanup.
Use disposable test secrets only. Treat every state file as sensitive even when the exercise is complete.
Use the repository’s scripts/leak-check.sh instead of printing state values to
the terminal. It reports only resource and attribute names and always redacts
matched values. Exit code 0 means no obvious match, 1 means a potential leak,
and 2 means the scan could not make a trustworthy decision because a tool or
state was missing, empty, unreadable, or could not be pulled. CI must treat both
1 and 2 as failures, not as a skipped/pass result.
