














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 we’ll cover:
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:
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:
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.
The exact steps vary between backends. For example, for HashiCorp Consul, you can use a built-in certificate authority (CA) to generate the required certificates and distribute them to all servers and clients in your Consul cluster. Finally, you would add configuration similar to the following for the servers (and similarly for the clients):
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"Read the documentation for your self-managed backend to learn which steps are required to enable encryption in transit.
Encryption in transit should be end-to-end. Even if you have your own private network, you should still use encryption in transit inside it. This is part of the thinking behind a zero-trust network.
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.
This doesn’t mean you can’t adjust the backend’s encryption configuration, though. One example is Amazon S3, which automatically applies server-side encryption with keys managed by S3. You can configure your S3 bucket to use a custom AWS KMS key for object encryption.
A minimal example of configuring your own KMS key for your S3 state storage bucket looks like this:
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"
}
}
}You can configure similar encryption settings for other managed Terraform backends.
If you use a self-managed Terraform state backend, you could, in theory, configure it to not use encryption at rest. As you’d expect, that’s a bad idea.
Enabling encryption at rest for a self-managed backend most often means enabling encryption on the underlying storage medium (e.g., an SSD drive). How to do that is outside the scope of this post.
A self-managed backend requires more upfront setup and more ongoing administration on your side, for encryption and other details. This can be a deciding factor when you’re choosing between a self-managed backend and a managed cloud service for your Terraform state.
If you use HCP Terraform, your state files are encrypted at rest on the underlying managed state storage. If you run the premium tier, you can enable the hold-your-own key feature to encrypt state files and plan files with a key stored in a key management system (KMS) on AWS, Azure, GCP, or HashiCorp Vault.
With OpenTofu, you can explicitly encrypt state files and plan files on top of the encryption at rest you configure at the backend level.
OpenTofu supports a few different key providers for encryption at rest. Along with a key provider, you must select an encryption method. The only one currently supported is AES-GCM.
You can configure encryption settings using HCL (or JSON), or you can set them through an environment variable named TF_ENCRYPTION. The steps to enable state file encryption differ slightly between greenfield and brownfield projects.
The following code block shows an example of how to configure encryption for a greenfield project using the AWS KMS key provider and the AES-GCM encryption method:
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
}
}
}The state block specifies that the state file should be encrypted with the specified method. You can also encrypt the plan output by adding a plan block.
After applying a configuration with the above encryption configuration, you end up with a state file similar to the following (the output is truncated for brevity):
{
"serial": 1,
"lineage": "2c3e595d-105a-a54b-a56a-51d81df287ee",
"meta": {
"key_provider.aws_kms.default": "eyJja…SJ9"
},
"encrypted_data": "vYTCK7…M2",
"encryption_version": "v0"
}To enable state file encryption for a brownfield project with an existing unencrypted state file you need to add an unencrypted fallback to your configuration, allowing OpenTofu to read the unencrypted file during the migration to an encrypted state file.
An example of how you configure this is shown in the following code block:
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
}
}
}
}After applying the configuration with tofu apply you can remove the unencrypted method block and the fallback block from your configuration. You can follow the same steps to switch to another encryption method.
See the OpenTofu documentation for all the details on how to configure encryption for your state files.
Keep the following best practices in mind when working with Terraform state encryption.
This almost goes without saying, but you should always enable both types of encryption for your Terraform state.
You get this for free for many of the official state backend options: Amazon S3, Azure Storage, GCS, and more. You also get this for free if you use the managed state feature of an automation platform such as Spacelift.
If you manage your own Terraform state backend (e.g., HashiCorp Consul or PostgreSQL), you could, in theory, take a few shortcuts during backend setup and disable one or both of these encryption mechanisms. This is a bad idea unless you’re running an ephemeral Terraform experiment as a learning exercise and need a throwaway backend.
A good compromise when using the PostgreSQL or Kubernetes self-managed Terraform state backend is to use a managed service such as Amazon RDS for PostgreSQL or Google Kubernetes Engine.
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.
Anyone with the proper authentication and authorization to run terraform apply or tofu apply directly can access the sensitive data in your state file. Even if your users have no malicious intent, mistakes happen, and they can leak sensitive data.
Limit who can run apply commands for your infrastructure by centralizing your Terraform operations in a CI/CD pipeline or automation platform. Avoid granting individual users direct read and write permissions to state files and encryption keys
Use ephemeral values and ephemeral resources in your Terraform configurations to avoid storing sensitive information in the state file in the first place. This drastically reduces the impact of a leaked Terraform state file.
Support for ephemeral resources is still limited among providers, so check with yours to see what it supports.
Another option to avoid storing sensitive data in the state file is to configure short-lived dynamic credentials for any external system you interact with. This includes configuring federated credentials with workload identities for provider platforms. Use a service such as HashiCorp Vault to configure dynamic credentials for databases and third-party platforms.
Even though most managed backends support encryption at rest out of the box, it could be a good idea to manage the encryption key yourself.
A custom encryption key gives you several benefits:
Terraform is really powerful, but to achieve an end-to-end secure GitOps approach, you need to use a product that can run your Terraform workflows. Spacelift takes managing Terraform to the next level by giving you access to a powerful CI/CD workflow and unlocking features such as:
Spacelift enables you to create private workers inside your infrastructure, which helps you execute Spacelift-related workflows on your end. Read the documentation for more information on configuring private workers.
Watch the video below to learn how to manage Terraform at scale with Spacelift:

Your Terraform state file should be encrypted in transit and at rest. If you’re using a managed Terraform state backend (e.g., Amazon S3, Azure Storage, GCS), these encryption mechanisms are enabled by default and are managed for you.
Managed Terraform state backends offer additional encryption options that let you meet your organization’s security requirements, including managing the encryption keys yourself.
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.
A few best practices to keep in mind when managing Terraform state file encryption include:
If you are interested in learning more about Spacelift, create a free account today or book a demo with one of our engineers.
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, such as S3 server-side encryption, Azure Storage default encryption, or a managed backend like Spacelift, which stores state encrypted in Amazon S3 with access restricted to active runs.
OpenTofu ships native client-side encryption (GA since v1.7) through an encryption block that supports AWS KMS, GCP KMS, Vault, and PBKDF2 key providers, so state and plan files are encrypted before reaching any backend. Terraform’s open-source CLI has no equivalent and relies on backend-level encryption like S3 SSE-KMS or Azure Storage service encryption.
Yes, through server-side encryption offered by your existing backend, for example setting encrypt = true (optionally with kms_key_id) on an S3 backend, or relying on the default at-rest encryption in Azure Blob Storage and GCS. 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.
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。