State has historically held every secret in plain text; modern Terraform can avoid that.
sensitive = true on variables and outputs, and sensitive attributes in provider schemas, only redact display: plans and logs show (sensitive value), but the value is still written to state and to saved plan files. So state and plan files must be treated as secrets: encrypted storage, tight access, no uploading plan files to public CI artifacts.
Newer features keep values out of artifacts entirely:
- Ephemeral variables and outputs (
ephemeral = true, 1.10+): available during the run, never persisted in state or plan. They can only flow into places that accept ephemeral values. - Ephemeral resources (
ephemeral "aws_secretsmanager_secret_version" "db" {...}): fetch a secret or a temporary credential for the duration of the run, e.g. to configure a provider, without saving it. - Write-only arguments (1.11+): resource arguments like
password_wo(with a companionpassword_wo_versionto signal changes) that are sent to the API but never stored. Support depends on the provider and resource.
Other options: have the service generate and own the secret (RDS manage_master_user_password = true stores it in Secrets Manager), or pass references (an ARN) rather than values.
Avoid random_password resources whose result lands in state, unless state is protected accordingly. OpenTofu additionally offers client-side state encryption.
Example
variable "db_password" {
type = string
sensitive = true
ephemeral = true # never stored in state or plan
}
ephemeral "aws_secretsmanager_secret_version" "api_key" {
secret_id = "prod/api-key" # read during the run only
}
resource "aws_db_instance" "main" {
identifier = "shop-prod"
engine = "postgres"
instance_class = "db.t4g.medium"
allocated_storage = 50
username = "shop"
password_wo = var.db_password # write-only: sent, not stored
password_wo_version = 2 # bump to rotate
}
# State records password_wo_version, never the password itself.Remember
- sensitive hides output but values still land in state and plans
- ephemeral variables/resources are never persisted
- Write-only arguments send secrets without storing them; bump the version to change
Watch out for
- Believing sensitive = true keeps a password out of the state file.