Terraform prevents accidental exposure of sensitive data by blocking outputs that reference sensitive values without explicit handling. This error occurs when you try to output a value derived from sensitive attributes (like passwords, API keys, or tokens) without marking the output as sensitive or stripping the sensitivity.
Terraform automatically marks certain resource attributes as sensitive (database passwords, API keys, tokens from providers like Okta or Datadog). When you reference these sensitive values in an output block, Terraform prevents the output unless you explicitly handle the sensitivity. This is a safety mechanism to prevent accidentally exposing secrets in CLI output, logs, or automation pipelines. Sensitivity propagates through operations: if you use a sensitive value in string interpolation, mathematical operations, or function calls, the result is also marked sensitive. Terraform requires you to either acknowledge this sensitivity with `sensitive = true` on the output block, or use the `nonsensitive()` function to explicitly strip the sensitive designation.
Add sensitive = true to your output block. This tells Terraform that you understand the output contains sensitive data and should be redacted in CLI output:
output "database_password" {
value = aws_db_instance.main.password
sensitive = true
}This is the recommended approach because it preserves security by masking the value in terraform plan, terraform apply, and terraform output commands.
When you need to access the actual value, use the -raw flag with terraform output to bypass the sensitive masking:
terraform output -raw database_passwordOr use JSON output to access the value programmatically:
terraform output -json database_passwordThis allows you to work with the value while keeping it redacted from normal CLI output.
If you are certain the value does not actually contain sensitive data (for example, a generated resource ID that happens to be derived from a sensitive attribute), you can use the nonsensitive() function:
output "public_endpoint" {
value = nonsensitive(aws_db_instance.main.endpoint)
}Warning: Only use nonsensitive() if you fully understand that the value is not a secret. Misusing this function can expose sensitive data in logs, state files, and CLI output.
Remember that marking an output as sensitive = true only hides it from CLI output. The actual value is still stored in plain text in your Terraform state file. Protect your state file by:
- Using a remote backend with encryption (S3 with encryption enabled, Terraform Cloud, Azure Storage with encryption)
- Restricting access to state files via IAM policies or file permissions
- Using Terraform Cloud or Enterprise for managed state with access controls
- Regularly auditing who has access to state files
Example S3 backend configuration with encryption:
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}When passing sensitive outputs from one module to another, the sensitivity propagates automatically. Make sure to declare module outputs that contain sensitive data as sensitive:
In child module outputs.tf:
output "api_key" {
value = sensitive(random_password.api_key.result)
sensitive = true
}In parent module, when using the output:
resource "example_resource" "main" {
api_key = module.child.api_key # Automatically marked sensitive
}
output "service_api_key" {
value = module.child.api_key
sensitive = true # Must declare as sensitive when outputting
}This ensures sensitive values are properly handled at every level of your module hierarchy.
Understanding Sensitivity Propagation: Terraform's type system treats sensitivity as a property that propagates through operations. If you perform any operation on a sensitive value (even simple ones like upper() or join()), the result becomes sensitive. This is intentional to prevent accidental exposure.
State File Encryption: The sensitive = true attribute is a CLI-level mask only. It does NOT encrypt the value in the state file. If you need actual encryption, use a secrets management tool (HashiCorp Vault, AWS Secrets Manager) instead of storing secrets directly in Terraform.
Conditional Sensitivity: You cannot conditionally mark outputs as sensitive based on runtime values. The sensitive argument must be a static boolean.
Sensitive Function vs. Attribute: The sensitive() function marks a specific value as sensitive within expressions:
locals {
api_key = sensitive(var.raw_api_key)
}
output "key" {
value = local.api_key
sensitive = true
}Provider-Specific Sensitivity: Different providers mark different attributes as sensitive. Check your provider documentation to understand which attributes are automatically sensitive (e.g., AWS RDS passwords, Datadog API keys, Kubernetes client certificates).
CI/CD Integration: In CI/CD pipelines, ensure you're using tools that respect Terraform's sensitive output masking. Some CI systems may log terraform output commands, exposing sensitive values. Use -raw carefully and always mask sensitive values in your CI/CD logs.
Error: Error installing helm release: cannot re-use a name that is still in use
How to fix "release name in use" error in Terraform with Helm
Error: Error creating GKE Cluster: BadRequest
BadRequest error creating GKE cluster in Terraform
Error: External program failed to produce valid JSON
External program failed to produce valid JSON
Error: Unsupported argument in child module call
How to fix "Unsupported argument in child module call" in Terraform
Error: network is unreachable
How to fix "network is unreachable" in Terraform