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
sensitiveargument tovariableandoutputblocks - Use Terraform 1.10 or later to add the
ephemeralargument to variables and child module outputs, or add theephemeralblock - 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
ephemeralargument on variables and child module outputs - The
ephemeralblock - 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
ephemeralargument on variables and child module outputs - The
ephemeralblock - 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
localsblock - In
variableblocks with theephemeralargument - In child module
outputblocks with theephemeralargument - In a managed resource write-only argument
- The
ephemeralblock - Configuring providers in the
providerblock - 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
encryptoption, and protects state with TLS in transit - The GCS backend supports using customer-supplied or customer-managed encryption keys