How can I keep sensitive values out of Terraform state?
Terraform can write resource arguments into state and saved plans. HashiCorp's
Terraform state documentation warns that
state files can expose stored secrets. The sensitive flag redacts CLI and UI output, but Terraform can
still record the value in state.
With the atlas_schema resource, Terraform can pass connection metadata while Atlas resolves the
credential when it evaluates atlas.hcl.
Credential options
Pick one of three places for the credential:
| Option | How it works |
|---|---|
| IAM authentication | Atlas generates a short-lived database token from the runner's cloud identity. |
| Secret manager | Terraform passes a secret reference, and Atlas reads the secret with runtimevar. |
| Environment variable | The shell, CI runner, or HCP Terraform workspace injects DB_PASSWORD; Atlas reads it with getenv(). |
Terraform setup
In Terraform, pass only values you can store in state:
resource "atlas_schema" "app" {
env_name = "local"
config = file("${path.module}/atlas.hcl")
variables = jsonencode({
database_name = var.db_name
endpoint = "${var.db_host}:${var.db_port}"
username = var.db_user
})
hcl = file("${path.module}/schema.pg.hcl")
}
Terraform stores the config text and variables payload for the resource. Keep passwords, full database
URLs with passwords, and decoded secret payloads out of those fields.
IAM authentication
If the database supports IAM authentication, Atlas can use the runner's cloud identity instead of a
stored database password. Terraform can pass the endpoint, username, and region, while Atlas generates
a short-lived token with the aws_rds_token or gcp_cloudsql_token data source.
See the secrets guide for AWS RDS and Cloud SQL examples.
Secret manager
Teams that store database credentials in a secret manager can pass the reference through Terraform and have Atlas read the secret at runtime.
resource "atlas_schema" "app" {
env_name = "prod"
config = file("${path.module}/atlas.hcl")
variables = jsonencode({
database_name = var.db_name
endpoint = "${var.db_host}:${var.db_port}"
username = var.db_user
password_ref = "awssecretsmanager://prod/app/db-password?region=us-east-1"
})
hcl = file("${path.module}/schema.pg.hcl")
}
variable "password_ref" {
type = string
}
data "runtimevar" "password" {
url = var.password_ref
}
env "prod" {
url = "postgres://${var.username}:${urlescape(data.runtimevar.password)}@${var.endpoint}/${var.database_name}?sslmode=require"
}
Atlas supports secret stores such as AWS Secrets Manager, AWS Systems Manager Parameter Store, GCP Secret
Manager, and HashiCorp Vault through the runtimevar
data source. For setup details, see the secrets guide.
Environment variable
A local shell, a CI secret store, and an HCP Terraform workspace environment variable all use the same
pattern: the runner sets DB_PASSWORD, and Atlas reads it from the Terraform process environment.
variable "password" {
type = string
default = getenv("DB_PASSWORD")
}
env "local" {
url = "postgres://${var.username}:${urlescape(var.password)}@${var.endpoint}/${var.database_name}?sslmode=disable"
}
Atlas reads DB_PASSWORD when Terraform runs the atlas_schema resource. The password stays out of
atlas_schema.variables, url, and other persisted resource arguments.
Run the plan and apply with the password in the Terraform process environment:
export DB_PASSWORD='example-password'
terraform init
terraform plan -out=tfplan
terraform apply tfplan
Local demo
Start a disposable PostgreSQL instance to test the environment-variable option:
docker run --rm --name atlas-example-postgres \
-e POSTGRES_PASSWORD='example-password' \
-e POSTGRES_DB='appdb' \
-p 55432:5432 \
postgres:16-alpine
Then run Terraform with DB_PASSWORD set:
export DB_PASSWORD='example-password'
terraform init
terraform plan -out=tfplan
terraform apply tfplan
Remote state, HCP Terraform, and encrypted backends help protect Terraform state. Terraform still records
the values passed through persisted resource arguments. To keep a value out of state, keep it out of the
atlas_schema arguments and resolve it when Atlas runs.