Cloud · Terraform · Security

Keeping secrets out of Terraform state: a checklist for platform teams

Most organisations using Terraform have database passwords, API keys or private keys sitting in state files, often in plaintext. For years that was simply how Terraform worked. Since versions 1.10 and 1.11 it doesn't have to be, but the fix needs deliberate migration.

ChecklistSumanta Mukhopadhyay7 min read6 sources
#cloud#terraform#security#platform
CHECKLIST · CLOUD · TERRAFORM · SECURITY28 Oct 2026 · 00:20 GST

Ask a platform team where their production database password lives and the answer is usually "in the secrets manager". Ask where else it lives and the honest answer is often "in the Terraform state file, in plaintext, readable by anyone with access to the state bucket". That was the default for years: a secret read through a data source or set on a resource ended up in both plan and state16.

What changed

VersionFeatureWhat it does
1.10Ephemeral values and resourcesFetch or generate values during a run without persisting them in plan or state14
1.11Write-only argumentsPass ephemeral values to managed resources; never stored in plan or state2

Together they close the gap: a secret can be read from a secrets manager ephemerally and handed to a resource through a write-only argument, without ever landing in state23. There is one catch. Because Terraform never stores the value, it can't detect when it changes. Write-only arguments are paired with a version argument that you increment to trigger an update, and only the version is stored2. Support also depends on each provider, resource by resource35.

"Sensitive" hides a value from your screen. "Ephemeral" and "write-only" keep it out of the file. Only the second protects you if the state bucket leaks.

1. Find the exposure

  • Inventory every state file and who can read it, including CI service accounts and old backends nobody uses.
  • Search state for secret-bearing attributes: passwords, private keys, tokens, connection strings.
  • List data sources that read from secrets managers; each one is copying a secret into state today.
  • Treat any secret that has ever been in state as potentially exposed to everyone with state access.

2. Upgrade the toolchain

  • Move to Terraform 1.11 or later so both features are available2.
  • Upgrade providers and check their documentation for ephemeral resources and write-only arguments on the resources you use.
  • If you run OpenTofu, check its equivalent features and version support separately; the choice is covered in OpenTofu or Terraform.

3. Migrate resource by resource

  • Replace secret-reading data sources with ephemeral resources where the provider offers them.
  • Switch resources to write-only arguments for passwords and keys, with a version argument for rotation.
  • Rotate the secret as part of the migration. Moving to write-only stops future storage; it doesn't undo past exposure.
  • Better still, let the platform generate and manage the secret itself, such as a managed database credential stored in the cloud's secrets manager, so Terraform never handles it.
  • Update shared modules first, using the patterns in Terraform module design, so every consumer benefits.

4. Harden state anyway

  • Encrypt state at rest with customer-managed keys and restrict decrypt permissions.
  • Limit state read access to the pipelines that need it; humans rarely do.
  • Enable versioning and access logging on the state backend, and alert on unusual reads.
  • Keep plan files out of CI artefacts and logs, or apply the same controls to them.

5. Keep it from regressing

  • Add a policy check in CI that flags secret-bearing attributes set through normal arguments, and secret-reading data sources.
  • Document the rotation process using version arguments, so it's routine rather than tribal knowledge.
  • Include state access in access reviews and in your SOC 2 evidence; it is often the broadest secret access in the company.

How I can help

I review and redesign infrastructure-as-code estates for security and maintainability, including secrets handling, state architecture and module standards. As a fractional CTO I can own that roadmap. Or analyse your challenge and bring the result to a call.

References
  1. 1
  2. 2
  3. 3
    Manage sensitive data in your configurationHashiCorp developer documentation
  4. 4
    Ephemerality in resourcesHashiCorp developer documentation
  5. 5
    Write-only arguments (Plugin Framework)HashiCorp developer documentation
  6. 6
FAQ

Common questions

Does marking a Terraform value as sensitive keep it out of state?

No. Marking a value as sensitive redacts it from plan and output display, but the value is still stored in the state file. To keep a secret out of state and plan files, use ephemeral resources and write-only arguments where providers support them.

What are Terraform ephemeral resources?

Introduced in Terraform 1.10, ephemeral resource blocks fetch or generate values, such as secrets, that are available during a run but are not persisted in plan or state files. Previously, reading a secret through a data source stored it in both.

What are write-only arguments?

Added in Terraform 1.11, write-only arguments on managed resources accept ephemeral values and are never stored in plan or state. Because Terraform can't see the stored value, a companion version argument is incremented to trigger an update.

Keep reading

Related

Open to advisory, fractional CTO & select builds

Let's talk about what you're building.

The fastest route is a free 30-minute call. Prefer to write? Send a message and I'll reply personally within two business days.

Start a conversation

How would you like to reach me?

Book a 30-min callFastest. Pick any open slot on my calendar.→ Write in GmailOpens a pre-filled draft in your browser.→ Use my email appOutlook, Apple Mail or your default client.→

I reply personally within two business days. Time zones from the Americas and Europe to the Middle East and Asia-Pacific.