Keep Secrets Out of the State: Terraform's Ephemeral Resources

Securing Sensitive Data in Terraform with Ephemeral Resources
Terraform state files contain detailed information about your infrastructure, including sensitive data like passwords, API keys, and authentication tokens.
While Terraform offers various methods to manage this sensitive information, the introduction of ephemeral resources in version 1.10+ provides a powerful new approach to keeping secrets out of your state files entirely.
In this post, we'll explore how ephemeral resources work, why they're important for security, and provide a practical example using AWS RDS database creation with automatic password rotation.
Consider this, you've misconfigured the S3 bucket that holds your Terraform state, allowing for anonymous access, now everyone can see your sensitive data.
If you've configured your state S3 bucket with anonymous access you have bigger problems to worry about than what is written here.
Your first priority with dealing with Terraform is securing your state file, you can use a well-protected S3 bucket, Terraform Cloud, Consul, and more.
Ephemeral resources are a kind of resource that is made to keep one-time data outside of the Terraform state, this is perfect for sensitive material – though there are some factors to consider.
Documentation


Theephemeral
block defines resources that are essentially temporary. Ephemeral resources have a unique lifecycle, and Terraform does not store information about ephemeral resources in state or plan files. Eachephemeral
block describes one or more ephemeral resources, such as a temporary password or connection to another system.
Practical Example
Creating a database with RDS is a common enough pattern, so let's use that to show how to use ephemeral blocks to create a password with Terraform while avoiding having the secret stored in the Terraform state and allowing us to rotate the secret with a simple version bump (or a time_rotating resource).
provider "aws" {}
terraform {
required_version = ">= 1.10"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.0"
}
random = {
source = "hashicorp/random"
version = "~> 3.0"
}
time = {
source = "hashicorp/time"
version = "~> 0.3"
}
}
}
versions.tf
ephemeral "random_password" "database" {
length = 16
}
resource "time_rotating" "password" {
rotation_minutes = 10
}
resource "aws_db_instance" "this" {
allocated_storage = 10
db_name = "awesome_db"
engine = "mysql"
instance_class = "db.t3.micro"
password_wo = ephemeral.random_password.database.result
password_wo_version = time_rotating.password.unix
skip_final_snapshot = true
username = "awesome_username"
}
main.tf
Let's break down the example, first, the ephemeral resource is declared, it behaves exactly the same as a standard resource, the only difference is that its value is not known after apply by Terraform.
Instead, it uses a foo_version
property to track if the ephemeral value needs to change – once you change the version there's no way of getting the old value back.
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_db_instance.this will be created
+ resource "aws_db_instance" "this" {
+ allocated_storage = 10
+ copy_tags_to_snapshot = false
+ db_name = "awesome_db"
+ engine = "mysql"
+ instance_class = "db.t3.micro"
+ password_wo = (write-only attribute)
+ password_wo_version = (known after apply)
+ region = "us-east-1"
+ skip_final_snapshot = true
+ username = "awesome_username"
}
# time_rotating.password will be created
+ resource "time_rotating" "password" {
+ rotation_minutes = 10
+ unix = (known after apply)
}
Plan: 2 to add, 0 to change, 0 to destroy.
terraform plan -out planfile (trimmed some data out of the output)
After the instance is created it won't detect changes for ten minutes (how we defined it in the time_rotating resource).
No changes. Your infrastructure matches the configuration.
Terraform has compared your real infrastructure against your configuration
and found no differences, so no changes are needed.
terraform plan -out planfile
Now, we'll let the time_rotating resource lapse by waiting ten minutes and check again with a new speculative plan.
Note: Objects have changed outside of Terraform
Terraform detected the following changes made outside of Terraform since the
last "terraform apply" which may have affected this plan:
# time_rotating.password has been deleted
- resource "time_rotating" "password" {
id = "2025-06-27T22:23:36Z"
- unix = 1751063616 -> null
# (9 unchanged attributes hidden)
}
Unless you have made equivalent changes to your configuration, or ignored the
relevant attributes using ignore_changes, the following plan may include
actions to undo or respond to these changes.
─────────────────────────────────────────────────────────────────────────────
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
+ create
~ update in-place
Terraform will perform the following actions:
# aws_db_instance.this will be updated in-place
~ resource "aws_db_instance" "this" {
~ password_wo_version = 1751063616 -> (known after apply)
# (72 unchanged attributes hidden)
}
# time_rotating.password will be created
+ resource "time_rotating" "password" {
+ rotation_minutes = 10
}
Plan: 1 to add, 1 to change, 0 to destroy.
terraform plan -out planfile
We can then apply the plan to rotate the database password with a new random one, terraform apply -auto-approve planfile
, rotating static db credentials is one way of using it, maybe not the most useful but it's one of the only resources that support write-only
attributes at the moment, but now you know how to use them, other providers might have better support.
Limitations and Considerations for Ephemeral Resources
While ephemeral resources offer significant security benefits, there are some important limitations to keep in mind:
1. Limited Provider Support: Currently, only certain providers and resources support write-only attributes, which are necessary for ephemeral resources to function properly. Always check provider documentation for compatibility.
2. Debugging Challenges: Since values aren't stored in state, debugging can be more difficult when issues arise with ephemeral resources.
3. State Recovery: If you need to import or recover infrastructure, ephemeral resources add complexity since their values aren't available in state backups.
4. Team Coordination: When multiple team members work with infrastructure containing ephemeral resources, additional coordination may be needed since values can't be referenced from the state.
5. Requires Terraform 1.10+: Older Terraform versions don't support this feature, so you'll need to ensure your environment is updated.
Despite these limitations, ephemeral resources provide a valuable security enhancement for handling sensitive data in Terraform when implemented appropriately.
Further reading:
Ephemeral resources also bring ephemeral variables and outputs to the table, allowing you to pass ephemeral values to other modules or as a one-off variable when creating resources.


Also consider, that with ephemeral resources you are able to read from secret stores, configure some resource and "forgetting" the actual secret, think about the example we just did but instead of generating a random password we bring a new one from AWS Secrets Manager.
Member discussion