Is Your Terraform State Secure? A 5-Minute Audit for `terraform_data` Usage in v1.16
How do you ensure sensitive data is not accidentally exposed in your Terraform state? The introduction of `terraform_data` in Terraform 1.
Run this audit in 5 minutes. The introduction of terraform_data in Terraform 1.16 natively handles arbitrary values, but replacing null_resource does not automatically secure your state files. Passing sensitive strings into this resource without explicit protection leaves them in plaintext right on your disk.
TL;DR: Upgrading to Terraform v1.16 and swapping
null_resourceforterraform_dataleaves private values exposed in plaintext state if you miss thesensitiveflag. Unencrypted state files are a primary attack vector for credential theft in deployment pipelines. This post provides a 5-minute audit checklist usingterraform show -jsonandgrepto hunt down unprotected secrets across your workspaces.
What you’ll walk away with:
- A copy-pasteable command sequence to extract all
terraform_datainputs from a live state file. - A strict scoring rubric to evaluate your workspace’s security posture.
- The exact
grepsyntax required to parse HashiCorp’s standardized JSON outputs.
How Do You Find Unprotected Secrets in Terraform State?
You find unprotected secrets in Terraform state by exporting the deployment data to JSON using terraform show -json and querying the text. Because Terraform v1.16 serializes all non-sensitive terraform_data attributes directly, parsing this output instantly reveals any hardcoded credentials stored without explicit cryptographic masking.
Terraform state is a JSON-formatted mapping file that tracks the metadata and attributes of all deployed infrastructure resources. According to the HashiCorp internal JSON format specification, the output uses format version 1.2, which guarantees stable parsing across minor releases. When developers map the Aicademy database passwords to standard inputs, the state file captures them entirely unredacted.
flowchart LR
A["Terraform config<br/>(v1.16)"] --> B["terraform_data"]
B --> C{"Marked sensitive?"}
C -->|"No"| D["Plaintext state file"]
C -->|"Yes"| E["Masked in CLI outputs"]
E -->|"Still stored as"| D
Always run
terraform initand fetch the latest state from your remote backend before running local JSON exports.
How Do You Audit Terraform Data Bindings for Data Leaks?
You audit terraform_data bindings by running a three-step terminal sequence that extracts, filters, and inspects local state JSON for plaintext inputs. This process identifies every instance where a developer passed private infrastructure details into a standard input attribute instead of securely masking them.
Execute the following checklist to evaluate your configuration.
- Export the active state to a local JSON file.
1
terraform show -json > state.json
1
# No output; creates state.json in the current directory
- Scan the JSON for
terraform_dataconfigurations.1
grep -A 5 -B 2 '"type": "terraform_data"' state.json
1 2 3 4 5 6 7 8 9 10 11 12
{ "address": "terraform_data.api_token", "mode": "managed", "type": "terraform_data", "name": "api_token", "provider_name": "registry.terraform.io/hashicorp/terraform", "schema_version": 0, "values": { "id": "2d8f9a2b", "input": "super-secret-aicademy-token-991" } }
View a full unredacted state JSON response
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
"format_version": "1.2",
"terraform_version": "1.16.0",
"values": {
"root_module": {
"resources": [
{
"address": "terraform_data.api_token",
"mode": "managed",
"type": "terraform_data",
"name": "api_token",
"provider_name": "registry.terraform.io/hashicorp/terraform",
"schema_version": 0,
"values": {
"id": "2d8f9a2b",
"input": "super-secret-aicademy-token-991",
"output": "super-secret-aicademy-token-991",
"triggers_replace": null
},
"sensitive_values": {}
}
]
}
}
}
- Score your workspace based on the
grepresults.- 0 findings = Healthy. No plaintext variables exposed.
- 1-2 findings = Warning. Review inputs for potential hardcoded IDs.
- 3+ findings = Critical. Immediate credential rotation required.
Use
terraform state pullinstead ofterraform showif you need the raw state file without the standardized JSON formatting wrapper.
What Is the Difference Between Standard and Sensitive Inputs?
The difference between standard and sensitive inputs is that Terraform explicitly redacts sensitive values from CLI output and logs, whereas standard inputs display openly during every apply. Both types still write to the backend state file in plaintext, which makes remote state encryption mandatory for security.
Default to standard inputs unless the string acts as an authentication credential. For a comprehensive look at how this replaces legacy methods, read The Terraform null_resource Anti-Pattern terraform_data Finally Replaces for Private Data.
| Input Method | Console Output | State File Storage | Best For |
|---|---|---|---|
input = "val" |
Plaintext | Plaintext | Public IDs, resource tags |
input = sensitive("val") |
Redacted | Plaintext | Passwords, API tokens |
| Ephemeral block | Redacted | Never Stored | Short-lived IAM roles |
To understand why standard inputs persist indefinitely across applies, review Is Your Terraform State Hiding Sensitive Data? The Power of terraform_data in v1.16.
Avoid storing long-lived credentials in
terraform_dataentirely; fetch them at runtime using provider data sources instead.
How Do You Remediate Plaintext State Leaks?
You remediate plaintext state leaks by wrapping the assigned variables in the sensitive() function or migrating temporary credentials out of the configuration entirely. Once you update the resource block, you must rotate the exposed credentials immediately because the historical plaintext values remain permanently accessible in remote backends.
Update your configuration files to wrap the vulnerable Aicademy token variable.
1
2
3
4
resource "terraform_data" "aicademy_token" {
- input = var.api_token
+ input = sensitive(var.api_token)
}
To enforce this behavior across your organization automatically, implement code reviews as discussed in Manual Policy Reviews vs. Automated tfpolicy Guardrails: Accelerate Compliance by 90%.
Rotating credentials is non-negotiable after a leak; removing a variable from Terraform state does not erase it from AWS S3 or Terraform Cloud history.
Bottom Line
Relying on terraform_data in version 1.16 removes unnecessary provider dependencies, but it does not inherently encrypt your inputs. Audit your state JSON today to identify leaked Aicademy tokens or database passwords sitting in plaintext. Action this immediately if your deployment pipelines store state in unencrypted storage buckets or accessible network shares.
FAQ
How do you encrypt Terraform state files?
You encrypt state by configuring a remote backend like AWS S3 or Azure Blob Storage with server-side encryption enabled. Terraform does not support native client-side encryption for the state file itself.
Does terraform_data store variables in plaintext?
Yes, terraform_data writes all standard and sensitive inputs to the state file in plaintext. The sensitive function only hides the value from console output, not from the physical state tracking file.
What is the format_version for Terraform state JSON?
As of Terraform 1.16, the terraform show -json command produces format version 1.2. This specific schema version ensures backward compatibility for external parsing and auditing tools.
How do you mask sensitive output in Terraform?
Wrap the output value in the sensitive() function within your configuration files. This prevents the CLI from printing the value to the console during a plan or apply operation.
Can you parse Terraform state without converting it to JSON?
Yes, using terraform state pull, but it is highly discouraged for automation. The raw state file structure changes frequently, whereas the JSON output guarantees a stable contract.
In the next part of the tf-1-16-private-data series, we examine strategies for wiping historical plaintext secrets from remote backend version control.
Part of the series: tf-1-16-private-data
- Is Your Terraform State Hiding Sensitive Data? The Power of `terraform_data` in v1.16
- The Terraform `null_resource` Anti-Pattern `terraform_data` Finally Replaces for Private Data
- Is Your Terraform State Secure? A 5-Minute Audit for `terraform_data` Usage in v1.16 (you are here)
Further Reading
- https://developer.hashicorp.com/terraform/cli/commands/show
- https://developer.hashicorp.com/terraform/internals/json-format
🚀 Ready to get hands-on? Spin up an interactive AI or Kubernetes Sandbox at Aicademy Labs for free.
