Configuration and secrets Required
Keep secrets out of state
Pass secrets to resources in a way that never writes them into the state or plan files.
How to do it
State and plans store every attribute in plain text, so a password set as a normal argument leaks to anyone who can read them. Use write-only arguments, such as password_wo. They need Terraform 1.11 or OpenTofu 1.11 or later and a provider that offers them. Ephemeral resources read a secret from the store for one run only and never save it. A write-only value is sent again only when its version number changes. Pulumi marks values with secret(), which encrypts them in state. Better still, let the service create the secret itself.
Example
# The value lives in the secrets store. It is read for this run and never written to state or plan.
ephemeral "aws_secretsmanager_secret_version" "orders_db" {
secret_id = aws_secretsmanager_secret.orders_db.id
}
resource "aws_db_instance" "orders" {
identifier = "shop-orders"
password_wo = ephemeral.aws_secretsmanager_secret_version.orders_db.secret_string
password_wo_version = 1 # raise the number after the stored value changes
}
// Pulumi in TypeScript: the value is encrypted in state
import * as pulumi from '@pulumi/pulumi';
const config = new pulumi.Config();
export const paymentKey = config.requireSecret('paymentApiKey');
# Pulumi in Python: the same
import pulumi
payment_key = pulumi.Config().require_secret("paymentApiKey")
tofu state pull | gitleaks stdin --no-banner # exit 0 means nothing found
! tofu state pull | grep -qF "$STAGING_DB_PASSWORD"
How to check
Pull the state and scan it with a secret scanner such as gitleaks. It finds nothing. A search of the staging state for the staging database password finds no match.
For agents: if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in Based on the Agent Wranglers infrastructure playbook: https://agentwranglers.se/playbook/infrastructure/configuration-and-secrets/secrets-out-of-state.