Ephemeral values are not stored in state
One of the most critical security challenges in infrastructure-as-code is keeping sensitive data out of your Terraform state file. When you store secrets, API keys, or temporary credentials in state, you create a persistent record that can leak through logs, backups, version control accidents, or compromised state backends. Ephemeral resources and values offer a solution: data that Terraform uses during a run but deliberately refuses to persist in state.
In Terraform, ephemeral values are outputs or local values marked with the ephemeral keyword. They exist only during the current apply or plan operation. Once the operation completes, Terraform discards them entirely—they never touch your state file. This is fundamentally different from regular outputs or locals, which Terraform preserves for future operations.
Consider a scenario where you're provisioning a database and need to configure an application with temporary admin credentials. Without ephemeral values, those credentials would sit in state indefinitely, creating an attack surface. With ephemeral values, you generate them, pass them to your application, and they vanish from Terraform's memory once the operation finishes.
# Bad: credentials stored in state forever
resource "random_password" "db_admin" {
length = 32
special = true
}
output "db_admin_password" {
value = random_password.db_admin.result
description = "Database admin password"
}
# Better: ephemeral output, not stored in state
resource "random_password" "db_admin" {
length = 32
special = true
}
output "db_admin_password" {
value = random_password.db_admin.result
description = "Database admin password (ephemeral)"
ephemeral = true
}The difference is subtle but powerful. When you mark an output as ephemeral = true, Terraform still computes and displays the value during your run, but it refuses to save it to terraform.tfstate. This means each subsequent apply will regenerate or re-fetch the value, which is exactly what you want for temporary credentials.
Useful for temporary credentials
Temporary credentials are the canonical use case for ephemeral values. In cloud environments, it's a best practice to issue short-lived tokens rather than long-term secrets. AWS STS temporary credentials, Azure managed identities, or Kubernetes service account tokens all follow this pattern. Terraform should facilitate this pattern, not undermine it by storing credentials permanently in state.
Imagine you're using AWS STS to assume a role and generate temporary credentials for a deployment process. You want those credentials to be used immediately—passed to an application, written to a secure configuration, or injected into a deployment—but you never want them sitting in state where they could be compromised weeks later.
data "aws_sts_caller_identity" "current" {}
resource "aws_sts_assumed_role_credentials" "deploy_role" {
role_arn = aws_iam_role.deploy.arn
role_session_name = "terraform-deploy-${formatdate("YYYY-MM-DD-hhmm-ss", timestamp())}"
duration_seconds = 3600
}
# Use the credentials immediately in the same run
resource "kubernetes_secret" "deploy_creds" {
metadata {
name = "deploy-aws-creds"
namespace = "default"
}
data = {
access_key = aws_sts_assumed_role_credentials.deploy_role.access_key
secret_access_key = aws_sts_assumed_role_credentials.deploy_role.secret_access_key
session_token = aws_sts_assumed_role_credentials.deploy_role.session_token
}
}
# These credentials are ephemeral and should not persist in state
output "deploy_credentials_used" {
value = "Credentials generated and injected; not stored in state"
ephemeral = true
}This pattern keeps your state file clean and compliant. The credentials are generated, used to configure infrastructure, and then discarded. On the next run, new credentials are generated. This aligns with the principle of least privilege: credentials exist only as long as they're needed.
Another practical scenario: bootstrapping a new environment where you need to generate an initial API key for a service, store it in a secrets manager, and then discard it from Terraform. The ephemeral value ensures that even though you used the secret to configure something, it doesn't linger in state as a potential leak vector.
Write-only arguments for secrets
Beyond ephemeral outputs, Terraform also supports write-only arguments for resource inputs. These are configuration values that Terraform accepts but refuses to store in state. This is useful for secrets that you pass to resources but don't need to track or read back later.
A write-only argument is typically used for initial setup: think database root passwords, API keys, or bootstrap tokens. You provide them once during resource creation, and Terraform stores them in the resource itself (or passes them to the underlying system), but the state file doesn't preserve them.
# Example: database with write-only root password
resource "aws_db_instance" "main" {
identifier = "mydb"
engine = "mysql"
engine_version = "8.0"
instance_class = "db.t3.micro"
allocated_storage = 20
storage_type = "gp2"
# This is sensitive and write-only
password = var.db_root_password # Not stored in state
# These are stored normally
username = "admin"
skip_final_snapshot = true
}
variable "db_root_password" {
type = string
sensitive = true
description = "Root password for database (write-only)"
}When you mark a variable as sensitive = true and use it for a write-only argument, Terraform redacts it from logs and output but still passes it to the resource during creation. The resource provider stores it where it needs to be—often encrypted at rest in the cloud—but Terraform's state doesn't contain it.
This is different from regular sensitive outputs, which Terraform still stores in state (just marked as sensitive in the UI). Write-only arguments never enter state at all. This distinction matters for compliance and security audits: if an auditor reviews your state file, they won't find the secret there.
However, it's crucial to understand that write-only doesn't mean "secret from the cloud provider." The resource still stores and manages the secret according to its own logic. For databases, that password is stored by the database engine. For APIs, the key is stored by the API service. Terraform is just refusing to cache it.
Requires recent Terraform versions
Ephemeral values and write-only arguments are relatively new features in Terraform. Ephemeral outputs landed in Terraform 1.8 (released March 2024), and support has been expanding in subsequent releases. If you're using an older version, these features won't be available, and you'll need to upgrade.
Before planning infrastructure that relies on ephemeral values, verify your Terraform version:
terraform {
required_version = ">= 1.8"
}This constraint in your configuration ensures that anyone on the team—or any CI/CD pipeline—uses a compatible version. It prevents silent failures where ephemeral settings are simply ignored.
The broader ecosystem is catching up too. Provider versions matter: if you're using ephemeral values with AWS, Azure, or Kubernetes providers, ensure those providers support the feature. Most major providers have added support in recent releases, but older provider versions may not recognize the ephemeral keyword and will throw validation errors.
Consider this version check in your provider configuration:
terraform {
required_version = ">= 1.8"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.38" # Supports ephemeral values
}
}
}
provider "aws" {
region = var.aws_region
}If you're managing a large infrastructure and can't upgrade everything at once, consider a gradual rollout: use ephemeral values in new modules or greenfield projects, and leave existing state-managed secrets in place. This avoids disruption while moving toward better practices incrementally.
Common mistakes
- Assuming ephemeral = invisible to users: Ephemeral outputs still display their values in plan and apply output. If you're passing them to CI/CD logs, they're visible there. Use output filtering in your pipeline if needed.
- Using ephemeral for stateful data: Ephemeral values should only be used for transient data like credentials or temporary tokens. If you need to track something across runs, it must be stored in state.
- Forgetting to mark variables as sensitive: Even if you use write-only arguments, always mark the input variables as
sensitive = true. This prevents Terraform from logging or displaying them unexpectedly. - Not updating provider and Terraform versions: If your infrastructure code uses ephemeral values but your CI/CD environment has an older Terraform version, deployments will fail. Sync versions across all environments.
- Mixing ephemeral outputs with downstream references: You can't reference an ephemeral output in a subsequent module or a separate Terraform workspace. They exist only during the current run. Design your modules to pass ephemeral values directly to resources, not through intermediate outputs.
Key takeaways
- Ephemeral values are computed during Terraform runs but never stored in state, making them ideal for temporary credentials and sensitive data.
- Mark outputs with
ephemeral = trueto keep secrets out of state while still making them available during deployment. - Write-only arguments for resource inputs accept sensitive values but refuse to persist them, adding another layer of protection.
- Upgrade to Terraform 1.8 or later and ensure your providers support ephemeral values before relying on them in production.
- Combine ephemeral values with the principle of least privilege: issue temporary credentials with short lifetimes and let Terraform discard them immediately after use.
- Use sensitive = true on all variables that feed into ephemeral or write-only arguments to prevent accidental logging or display.
- Remember that ephemeral doesn't mean "invisible to cloud providers"—the resource still manages the secret. Terraform is just declining to cache it.






Comments
Loading comments…