Terraform
Manage sensitive data in your configuration
Terraform may require access to sensitive data, such as cloud provider credentials, API tokens, and other secrets to provision your infrastructure. If you add secret values directly to your configuration, Terraform stores those secrets in its state and plan files. Learn about the different options for securing sensitive data in your configuration, and the tradeoffs of each approach.
Background
Terraform state and plan files contain detailed information about your infrastructure, including resource attributes and metadata that can contain sensitive values, such as initial database passwords or API tokens.
If you are developing with Terraform locally, Terraform stores your state in a plaintext file, which includes any secret values you defined in your configuration. Treat your state file as sensitive data by excluding it from Git workflows and following our recommendations to secure your state file.
You can also configure Terraform to store your state and plan files in a remote location. When you configure Terraform to use remote state storage, it only holds state in memory when actively using it. You can encrypt your state at rest, but the encryption method depends on your specific backend. For example, HCP Terraform automatically encrypts state at rest and protects it with TLS in transit.
Requirements
The following requirements are tied to specific blocks and arguments you can use to handle sensitive values in your Terraform configuration:
- Use Terraform 0.15 or later to add the
sensitive
argument tovariable
andoutput
blocks - Use Terraform 1.10 or later to add the
ephemeral
argument to variables and child module outputs, or add theephemeral
block - Use Terraform 1.11 or later to use a write-only argument on a managed resource
Each provider defines any available ephemeral
blocks and write-only arguments on their managed resources. Reference the Terraform registry to learn more about what your provider supports.
Determine how to handle your sensitive data
To decide how to handle sensitive values in your configuration, start by determining whether you want to hide values from the Terraform CLI and HCP Terraform UI, or prevent Terraform from storing those values entirely.
You can add the sensitive
argument to variable
or output
blocks so that Terraform redacts those values from CLI output and in the HCP Terraform UI. Terraform also treats any expressions that reference a sensitive variable or output as inherently sensitive. Refer to Hide sensitive variables and outputs for instructions on hiding sensitive data in variables and outputs.
Ephemeral values are available at runtime, but Terraform omits them from state and plan files entirely. Terraform provides four ways to define ephemeral values in your configuration:
- The
ephemeral
argument on variables and child module outputs - The
ephemeral
block - A write-only argument on a managed resource
For more information about ephemeral values and their restrictions, refer to Omit values from state and plan files.
You can also add both the ephemeral
and sensitive
arguments to variable
and child module output
blocks to prevent Terraform from storing their values. Doing so redacts those values in the Terraform CLI and HCP Terraform UI. Learn more about hiding values in the CLI without storing them.
Hide sensitive variables and outputs
Hands-on: Try the Protect Sensitive Input Variables tutorial.
Use the sensitive
argument on variable
and output
blocks when you want to redact those values from Terraform CLI log output and the HCP Terraform UI. Terraform also treats any expressions that reference a sensitive variable or output as inherently sensitive.
Add the sensitive
argument to variable
blocks that contain sensitive data:
variable "database_password" {
description = "Password for the database instance"
type = string
sensitive = true
}
You can also add sensitive
to output
blocks that contain sensitive data:
output "connection_string" {
description = "Database connection string"
value = "postgresql://${var.db_username}:${var.database_password}@${aws_db_instance.main.endpoint}/mydb"
sensitive = true
}
Terraform then redacts sensitive variables and outputs in the operation log of the Terraform CLI. For example, the connection_string
output is redacted in the following apply summary:
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Outputs:
connection_string = (sensitive value)
Terraform also automatically treats any expression that references a sensitive variable or output as sensitive. In the following example, the password
argument references the sensitive var.database_password
in another resource:
resource "aws_db_instance" "main" {
identifier = "my-database"
engine = "postgres"
username = var.db_username
password = var.database_password
}
Terraform redacts the password
argument from the main
resource in plan and apply operations:
# aws_db_instance.main will be created
+ resource "aws_db_instance" "main" {
+ password = (sensitive value)
+ username = "admin"
}
Terraform stores values with the sensitive
argument in both state and plan files, and anyone who can access those files can access your sensitive values. Additionally, if you use the terraform output
CLI command with the -json
or -raw
flags, Terraform displays sensitive variables and outputs in plain text.
If you do not want to store the values of your sensitive variables and outputs, refer to Omit values from state and plan files. If you have sensitive values in your state and plan files, we recommend securing your state.
Hide values without storing them
You can add the sensitive
argument to variables and child module outputs that have the ephemeral
argument to combine their benefits. The following database_password
variable is omitted from state and plan files, and the value is redacted in the Terraform CLI and the HCP Terraform UI:
variable "database_password" {
description = "Password for the database instance"
type = string
sensitive = true
ephemeral = true
}
To learn more about the ephemeral
argument, refer to Omit values from state and plan files.
Omit values from state and plan files
Ephemeral values are available at the run time of an operation, but Terraform omits them from state and plan files. Because Terraform does not store ephemeral values, you must capture any generated values you want to preserve in another resource or output in your configuration.
You can use the following methods ways to define ephemeral values in your configuration:
- The
ephemeral
argument on variables and child module outputs - The
ephemeral
block - A write-only argument on a managed resource
Terraform restricts where you can reference ephemeral values in your configuration. You can only refer to ephemeral values in the following contexts:
- In the
locals
block - In
variable
blocks with theephemeral
argument - In child module
output
blocks with theephemeral
argument - In a managed resource write-only argument
- The
ephemeral
block - Configuring providers in the
provider
block - In provisioner and connection blocks
Add the ephemeral
argument to a variable or output
Set the ephemeral
argument to true
in a variable
block containing temporary sensitive data to omit that value from state and plan files:
variable "api_token" {
description = "Short-lived API token for provider authentication"
type = string
sensitive = true
ephemeral = true
}
You can reference a variable
block with the ephemeral
argument in other ephemeral contexts. For example, you can use the api_token
variable in a provider
block to configure a provider:
provider "example" {
api_token = var.api_token
}
You can also add the ephemeral
argument in the output
block in child modules to pass data between modules without persisting that data to state or plan files. You cannot add the ephemeral
argument to outputs in the root module.
output "session_token" {
value = ephemeral.auth_provider.main.token
ephemeral = true
sensitive = true
}
Passing output values between child modules and the root module is useful for managing credentials, tokens, and other temporary values that you do not want to store in state.
You can also add the sensitive
argument to variable
and output
blocks to hide their values in the CLI and HCP Terraform UI. Learn more about using the ephemeral
argument alongside the sensitive
argument.
Use the ephemeral
block
The ephemeral
block declares a temporary ephemeral resource that only exists during the current Terraform operation. Terraform does not store ephemeral resources in state or plan files, making them ideal for managing sensitive or temporary data that you do not want to persist, such as temporary passwords or connections to other systems. Each provider defines any available ephemeral resources. Reference the Terraform registry to learn more about what your provider supports.
For example, you can use the random_password
ephemeral resource to generate a temporary password:
ephemeral "random_password" "db_password" {
length = 16
override_special = "!#$%&*()-_=+[]{}<>:?"
}
You can only reference an ephemeral
block in other ephemeral contexts, such as a write-only argument in a managed resource. Write-only arguments let you securely pass temporary values to managed resources during an operation without persisting those resource values. For example, you can reference the db_password
in the password_wo
write-only argument:
#...
ephemeral "random_password" "db_password" {
length = 16
override_special = "!#$%&*()-_=+[]{}<>:?"
}
resource "aws_db_instance" "example" {
instance_class = "db.t3.micro"
allocated_storage = "5"
engine = "postgres"
username = "example"
skip_final_snapshot = true
publicly_accessible = true
db_subnet_group_name = aws_db_subnet_group.example.name
password_wo = ephemeral.random_password.db_password.result
password_wo_version = 1
}
Neither write-only arguments nor ephemeral
blocks persist outside of the current Terraform run. This ensures that the ephemeral.random_password.db_password.result
value is completely omitted from state and plan files.
Terraform does not store the generated value of ephemeral.random_password.db_password.result
, but you can capture it in another resource to ensure the value is not lost. For an example of generating, storing, retrieving, and using an ephemeral password, refer to write-only arguments.
To learn about ephemeral resources, refer to the ephemeral
block reference.
Use write-only arguments
Write-only arguments let you securely pass temporary values to Terraform's managed resources during an operation without persisting those values to state or plan files. Each provider defines any available write-only arguments on their managed resources. Reference the Terraform registry to learn more about what your provider supports.
Write-only arguments typically end with _wo
and have corresponding _wo_version
arguments. For example, the aws_db_instance
has a password_wo
write-only argument:
resource "aws_db_instance" "main" {
instance_class = "db.t3.micro"
allocated_storage = "20"
engine = "postgres"
username = "admin"
skip_final_snapshot = true
password_wo = ephemeral.random_password.db_password.result
password_wo_version = 1
}
During a Terraform operation, the aws
provider uses the password_wo
value to create the database instance, and then Terraform discards that value without storing it in the plan or state file. To learn more about write-only arguments, including how to update them with versions and store their values, refer to write-only arguments.
State security best practices
If you store sensitive values in a state file, we recommend implementing additional security measures to keep your state safe:
- Store your state remotely
- Encrypt your state at rest
- Use access controls to limit who has access to your state
- Use audit logs to track state access over time
Storing your state remotely can provide better security by letting you encrypt your state when it's at rest. For example, the following backends support state encryption:
- HCP Terraform encrypts state at rest, lets you supply your own encryption keys, and protects state with TLS in transit
- The S3 backend can encrypt state at rest if you enable the
encrypt
option, and protects state with TLS in transit - The GCS backend supports using customer-supplied or customer-managed encryption keys