Introduction
Terraform state files contain everything Terraform needs to manage your infrastructure. That includes any cloud credentials you use to authenticate providers – AWS access keys, Azure service principals, GCP service account credentials.
This creates a security problem: anyone with access to your state file has access to your cloud credentials. Even when stored remotely in S3 or HCP Terraform, state files remain sensitive artifacts that require protection.
There’s a better approach: ephemeral resources in the Vault provider. They generate short-lived cloud credentials on demand, use them during your Terraform run, and ensure they never touch your state file.
The Old Way: Data Blocks
The traditional approach uses Vault’s data sources to retrieve credentials:
data "vault_aws_access_credentials" "creds" {
backend = "aws"
role = "terraform"
}
provider "aws" {
access_key = data.vault_aws_access_credentials.creds.access_key
secret_key = data.vault_aws_access_credentials.creds.secret_key
}
The problem: These credentials end up in your Terraform state file. The vault_aws_access_credentials data source returns credentials that Terraform persists to state like any other data source.
If your state file is compromised, those credentials are exposed. Even with a short TTL, you’ve created an unnecessary security risk.
The New Way: Ephemeral Resources
Terraform 1.10 introduced ephemeral resources – resources that exist only during plan and apply operations and are never written to state.
The Vault provider now supports ephemeral resources for AWS, Azure, and GCP credentials:
ephemeral "vault_aws_access_credentials" "creds" {
backend = "aws"
role = "terraform"
}
provider "aws" {
access_key = ephemeral.vault_aws_access_credentials.creds.access_key
secret_key = ephemeral.vault_aws_access_credentials.creds.secret_key
}
What’s different:
- Credentials are generated when Terraform needs them (during plan/apply)
- They’re used to configure your AWS provider
- They’re automatically revoked when Terraform finishes
- They never appear in your state file
Check your state after running this configuration – you won’t find the ephemeral resource or its credentials anywhere.
Note: Not all providers support ephemeral resources, so double-check the provider documentation for your targeted platform to validate. For example, here are the docs for one of Vault’s ephemeral resources. Look for the top-level Ephemeral Resources in the navigation pane.

How Terraform Should Authenticate to Vault
Before Terraform can retrieve credentials from Vault, it must first authenticate with Vault. The best approach: identity-based authentication.
For CI/CD systems, Terraform can authenticate using JWT tokens from your platform:
provider "vault" {
address = "https://vault.example.com"
auth_login_jwt {
role = "terraform"
jwt = var.jwt_token # From CI/CD platform
}
}
GitHub Actions, GitLab CI, and most modern CI/CD platforms can provide JWT tokens that Vault can validate. This eliminates the need for long-lived Vault tokens in your pipeline.
For local development, you can use your existing Vault token from environment variables:
provider "vault" {
address = "https://vault.example.com"
# Reads VAULT_TOKEN from environment variable
}
Identity-based authentication means Terraform never stores long-lived Vault credentials. Combined with ephemeral resources for cloud credentials, you’ve eliminated both credential storage problems.

Setting Up Vault
Before using ephemeral resources, you need to configure Vault’s secrets engine for your cloud provider.
For AWS:
# Enable the AWS secrets engine
vault secrets enable aws
# Configure with root credentials
vault write aws/config/root \
access_key=AKIA... \
secret_key=SECRET...
# Create a role that generates temporary credentials
vault write aws/roles/terraform \
credential_type=iam_user \
policy_document=-<<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["ec2:*", "s3:*"],
"Resource": "*"
}
]
}
EOF
For Azure:
Vault supports Azure through the Azure secrets engine, which generates service principals:
vault secrets enable azure
vault write azure/config \
subscription_id=... \
tenant_id=... \
client_id=... \
client_secret=...
Then use ephemeral "vault_azure_access_credentials" in your Terraform code.
For GCP:
Vault’s GCP secrets engine generates OAuth2 access tokens or service account keys:
vault secrets enable gcp
vault write gcp/config credentials=@credentials.json
Use ephemeral "vault_gcp_access_credentials" in Terraform.
Complete Example
Here’s a working example that authenticates Terraform to Vault using JWT, retrieves ephemeral AWS credentials, and deploys infrastructure:
terraform {
required_providers {
vault = {
source = "hashicorp/vault"
version = "~> 5.7.0"
}
aws = {
source = "hashicorp/aws"
version = "~> 6.0"
}
}
required_version = ">= 1.10"
}
provider "vault" {
address = "https://vault.example.com"
auth_login_jwt {
role = "terraform"
jwt = var.oidc_token
}
}
ephemeral "vault_aws_access_credentials" "aws" {
backend = "aws"
role = "terraform"
ttl = "1h"
}
provider "aws" {
region = "us-east-1"
access_key = ephemeral.vault_aws_access_credentials.aws.access_key
secret_key = ephemeral.vault_aws_access_credentials.aws.secret_key
}
resource "aws_instance" "example" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
}
During terraform plan and terraform apply:
- Terraform authenticates to Vault using the JWT token
- Terraform requests temporary AWS credentials from Vault
- Terraform uses those credentials to configure the AWS provider
- Terraform creates your infrastructure
- Vault automatically revokes the credentials after the TTL expires
The credentials never appear in plan output or state files.
Why This Matters
Security: Credentials aren’t stored in state files or plan artifacts. Even if someone gains access to your state, they don’t get cloud credentials.
Auditability: Vault logs every credential request. You know exactly when Terraform requested credentials and which role was used.
Compliance: Many security frameworks require credential rotation and time-limited access. Ephemeral credentials satisfy both requirements automatically.
Reduced blast radius: Compromised state files don’t expose valid cloud credentials. The credentials that existed during your last Terraform run expired hours or days ago.
Requirements
- Terraform 1.10 or later (when ephemeral resources were introduced)
- Vault provider 5.0 or later (when ephemeral resources were added)
- Vault configured with the appropriate secrets engine (AWS, Azure, or GCP)
- JWT authentication configured in Vault for your CI/CD platform
Migration Path
If you’re currently using data sources for Vault credentials:
- Upgrade to Terraform 1.10+ and Vault provider 5.0+
- Replace
data "vault_aws_access_credentials"withephemeral "vault_aws_access_credentials" - Update provider blocks to reference the ephemeral resource
- Test in a non-production environment first
- Verify credentials don’t appear in state after migration
The syntax is nearly identical – you’re mainly changing the resource type from data to ephemeral.
Final Thoughts
Storing cloud credentials in Terraform state has always been a necessary evil. Ephemeral resources eliminate that compromise.
If you’re using Vault to manage cloud credentials for Terraform, ephemeral resources should be your default approach. They provide the same functionality as data sources while keeping credentials out of state entirely.
The migration is straightforward, the security improvement is significant, and you’re finally using Terraform state the way it was meant to be used – for infrastructure metadata, not sensitive credentials.
Want to learn more about Terraform’s latest features? Check out my HashiCorp Certified Terraform Associate 004 course, which covers ephemeral resources, state management best practices, and everything you need to pass the certification exam.
Explore my latest courses



