How to Encrypt Terraform State Files
Terraform state file encryption relies on backend-level security, while OpenTofu introduces native client-side encryption for finer control.
Deep dive
- Terraform state files expose infrastructure metadata and sensitive secrets like database connection strings.
- Managed backends like S3 encrypt data at rest automatically, but this does not prevent access by users with read permissions to the bucket.
- OpenTofu's encryption block supports AWS KMS, GCP KMS, Vault, and PBKDF2 providers.
- Encryption in transit is handled by TLS/HTTPS; use managed cloud services to ensure this is enforced.
- Security best practices include using ephemeral credentials and restricting access to state files via automation platforms like Spacelift or Terraform Cloud.
Decoder
- State Backend: The storage location (e.g., S3, PostgreSQL) where Terraform keeps track of the mappings between real-world infrastructure and your configuration files.
- Client-side encryption: Encrypting data before it is transmitted to a storage provider, ensuring the provider never sees the plain-text file.
Original article
How to Encrypt Terraform State Files
Your Terraform state files contain the attributes and metadata of the resources and data sources that make up your Terraform configurations. This includes sensitive data such as passwords, database connection strings, certificate private keys, and more. By default, Terraform stores this information in plain text in your state file, so anyone with read access to that file can see it.
You can use ephemeral values and ephemeral resources to keep some of this sensitive data out of your state file in the first place. But even data that isn’t classified as sensitive is often something you’d rather not share in plain text. After all, the state file reveals a lot about your infrastructure.
In this post, we’ll explore how to encrypt your Terraform state file, both at rest and in transit. We’ll also look at an encryption feature that OpenTofu offers, and Terraform doesn’t.
What is Terraform state file encryption?
In simple terms, encryption turns a human-readable piece of information into something unintelligible using a secret key. With the same key (or a closely related one), you can reverse the transformation and turn the unintelligible data back into something readable.
In the context of Terraform state files, encryption means protecting the data they contain by rendering it unreadable to unauthorized users. If someone walked into a data center where you store your state files, pulled a hard drive out of a rack, and walked out with it, they still shouldn’t be able to read your state file.
The Terraform state file contains metadata, resource and data source attributes, check block results, and output values. Resource and data source attributes can include sensitive information such as API keys, certificate private keys, and passphrases. You can declare input variables and outputs as sensitive, which tells Terraform not to print them as plain text in logs. But this doesn’t change how Terraform stores those values in the state file.
This is why state file encryption matters: you need to protect the sensitive data inside the state file.
Two types of encryption matter here:
- Encryption in transit is when you encrypt the state file as it is transmitted over a network (e.g. during a Terraform operation in your CI/CD pipeline). This keeps the state file from moving in a readable format that someone could intercept.
- Encryption at rest is when you encrypt the state file data where it’s stored, usually the Terraform state backend (e.g., Amazon S3 or Google Cloud Storage).
How to encrypt Terraform state
In the following sections, we’ll cover how to encrypt Terraform state. If you’re worried about a complicated, math-heavy procedure, you will be glad to know that most of the work is handled for you.
Two important concepts used in the following sections are:
- A managed Terraform state backend is a backend based on a managed cloud service. Three popular examples are Amazon S3, Azure Storage, and Google Cloud Storage (GCS). This category also includes automation platforms that manage state storage for you, such as Spacelift and HCP Terraform.
- A self-managed Terraform state backend is a backend that you’re responsible for setting up and configuring. Examples include HashiCorp Consul, HTTP, Kubernetes, and PostgreSQL. Note that there could be managed offerings of these backends as well, e.g., Amazon RDS for PostgreSQL or Azure Kubernetes Service.
Encryption in transit
Encryption in transit protects against someone reading your data as it moves over a network, a threat known as eavesdropping. The standard way to encrypt data in transit is with TLS and HTTPS. Communicating over HTTPS doesn’t stop someone from listening in on the traffic, but the data they intercept will be unintelligible.
If you use a managed Terraform state backend, encryption in transit is managed for you.
There’s no setup to enable it, and no way to turn it off. Every interaction with the backend requires an HTTPS connection, whether from the CLI, Terraform, or a graphical user interface.
If you use a self-managed backend, you’re responsible for configuring encryption in transit. This means configuring TLS certificates and enabling all relevant encryption-in-transit settings for the selected backend.
verify_incoming = true
verify_outgoing = true
verify_server_hostname = true
ca_file = "consul-agent-ca.pem"
cert_file = "dc1-server-consul-0.pem"
key_file = "dc1-server-consul-0-key.pem"
Encryption at rest for state backends
All the officially supported Terraform state backends support encryption at rest in some form, but it may not be enabled by default.
For managed Terraform state backend services (Amazon S3, GCS, Azure Storage, etc.), encryption at rest is always enabled by default, and there is usually no option to disable it.
resource "aws_s3_bucket" "state" {
bucket_prefix = "terraform-state-"
}
resource "aws_kms_key" "state" {
description = "KMS key for Terraform state file encryption"
}
resource "aws_s3_bucket_server_side_encryption_configuration" "state" {
bucket = aws_s3_bucket.state.bucket
rule {
apply_server_side_encryption_by_default {
kms_master_key_id = aws_kms_key.state.arn
sse_algorithm = "aws:kms"
}
}
}
State file encryption at rest with OpenTofu
With OpenTofu, you can explicitly encrypt state files and plan files on top of the encryption at rest you configure at the backend level.
terraform {
encryption {
key_provider "aws_kms" "default" {
kms_key_id = "e6088080-95d4-4950-95d3-32a08225ee33"
region = "eu-north-1"
key_spec = "AES_256"
}
method "aes_gcm" "default" {
keys = key_provider.aws_kms.default
}
state {
method = method.aes_gcm.default
}
}
}
terraform {
encryption {
# configure your current encryption method (i.e. no encryption method)
method "unencrypted" "migrate" {}
key_provider "aws_kms" "default" {
kms_key_id = "e6088080-95d4-4950-95d3-32a08225ee33"
region = "eu-north-1"
key_spec = "AES_256"
}
method "aes_gcm" "default" {
keys = key_provider.aws_kms.default
}
state {
method = method.aes_gcm.default
fallback {
# reference the current encryption method in a fallback block
method = method.unencrypted.migrate
}
}
}
}
Core best practices for Terraform state file encryption
1. Always enable encryption at rest and encryption in transit
This almost goes without saying, but you should always enable both types of encryption for your Terraform state.
2. Implement network restrictions for state and encryption keys
Set up network protection mechanisms to restrict access to your state files and to the encryption keys you use to protect them. Never implicitly trust network traffic, even from within your private networks.
3. Limit access to state files and encryption keys
Anyone with the proper authentication and authorization to run terraform apply or tofu apply directly can access the sensitive data in your state file. Limit who can run apply commands for your infrastructure by centralizing your Terraform operations in a CI/CD pipeline or automation platform.
4. Keep sensitive data out of your encrypted state file
Use ephemeral values and ephemeral resources in your Terraform configurations to avoid storing sensitive information in the state file in the first place. Use a service such as HashiCorp Vault to configure dynamic credentials for databases and third-party platforms.
5. Use custom encryption keys if possible
A custom encryption key gives you several benefits: you can specify the encryption key type, set the cadence of key rotation, and configure access management for your keys at a more granular level.
How to manage Terraform state with Spacelift
Spacelift takes managing Terraform to the next level by giving you access to a powerful CI/CD workflow and unlocking features such as:
- Policies (based on Open Policy Agent)
- Multi-IaC workflows
- Build self-service infrastructure
- Integrations with any third-party tools
- Secure state management and locking
Key takeaways
Your Terraform state file should be encrypted in transit and at rest. If you’re using a managed Terraform state backend, these encryption mechanisms are enabled by default and are managed for you.
Terraform has no built-in support for state file encryption; instead, it relies entirely on the encryption built into your chosen state backend. This is one major feature that sets OpenTofu apart from Terraform: OpenTofu has built-in support for state file encryption.
Frequently asked questions
-
Does Terraform encrypt state files by default?
No. Terraform’s open-source CLI stores state in plaintext, both locally and when written to remote backends. Encryption at rest depends entirely on the backend you configure.
-
What's the difference between Terraform and OpenTofu state encryption?
OpenTofu ships native client-side encryption through an encryption block that supports AWS KMS, GCP KMS, Vault, and PBKDF2 key providers. Terraform’s open-source CLI has no equivalent and relies on backend-level encryption.
-
Can I encrypt Terraform state without changing my backend?
Yes, through server-side encryption offered by your existing backend, for example setting encrypt = true on an S3 backend. Terraform’s CLI itself has no native client-side encryption, so anything stronger requires switching to OpenTofu or wrapping the file with an external tool like SOPS.
Fresh dev news, AI-digested daily. Never miss a trend at devoured.fyi