OpenTofu 1.7 introduced client-side state encryption—a feature the community requested from Terraform for years without success. For us, it solved a compliance problem that previously required workarounds.
The Problem
Terraform state contains secrets. Database passwords, API keys, and sensitive outputs all end up in plaintext within state files. S3 encryption helps, but the state is decrypted whenever accessed. Anyone with state file access sees everything.
Compliance frameworks flagged this repeatedly. “Your infrastructure state contains credentials in plaintext.” Our responses involved server-side encryption, access controls, and accepted risk documentation. None fully satisfied auditors.
State file leakage risks were real. Misconfigured bucket policies, overly broad IAM permissions, or backup systems could expose credentials. We mitigated but couldn’t eliminate the risk.
Meanwhile, state locking required DynamoDB tables alongside S3 buckets. More infrastructure to manage, more costs, more IAM policies to configure. A simple setup needed two AWS services when one should suffice.
Our Solution
OpenTofu state encryption encrypts state client-side before storage. The backend (S3, GCS, whatever) only ever sees ciphertext. Even with bucket access, the data is meaningless without encryption keys.
AWS KMS integration manages encryption keys. OpenTofu requests data encryption keys from KMS, uses them locally, and stores only encrypted state. Key rotation happens through KMS policies.
terraform {
encryption {
key_provider "aws_kms" "main" {
kms_key_id = "alias/opentofu-state"
region = "eu-west-1"
}
method "aes_gcm" "default" {
keys = key_provider.aws_kms.main
}
state {
method = method.aes_gcm.default
}
}
}
Migration from unencrypted state required a one-time conversion. OpenTofu handles this transparently—apply with encryption configured, and subsequent states are encrypted.
Plan file encryption completes the picture. Even plan outputs, which also contain sensitive values, get encrypted.
S3-native state locking arrived in the same release, eliminating DynamoDB entirely. OpenTofu uses S3’s conditional writes for locking—no separate table required. Our backend configuration simplified dramatically:
backend "s3" {
bucket = "company-opentofu-state"
key = "infrastructure/terraform.tfstate"
region = "eu-west-1"
use_lockfile = true # S3-native locking, no DynamoDB
}
The Benefits
Compliance satisfied genuinely rather than through workarounds. State encryption meets requirements that server-side encryption alone couldn’t. Auditors see actual cryptographic protection.
Defence in depth for credential exposure. Bucket misconfigurations still matter, but they don’t immediately expose secrets. The encryption provides a meaningful barrier.
Reduced blast radius from access compromises. An attacker with S3 read access sees ciphertext. They’d need KMS permissions to decrypt—a separate, audited permission.
Simplified infrastructure from S3-native locking. No DynamoDB tables to provision, monitor, or pay for. One fewer AWS service in the dependency chain. IAM policies simplified without cross-service permissions.
Cost reduction beyond just DynamoDB charges. Less infrastructure means less maintenance overhead, fewer things to go wrong, and simpler disaster recovery.
OpenTofu differentiation validates the fork’s value. Both features—encryption and S3-native locking—emerged because the community drives development. Features users need get prioritised over commercial considerations.
OpenTofu 1.7 represented a turning point. Two major features in one release, both addressing long-standing community requests. This is why we migrated.