In this episode we'll discuss disaster recovery for OpenTofu, especially recovery procedures for encrypted state when the KMS key or passphrase has problems. We'll also design state backup and versioning strategies using S3 and GCS so recovery is always possible.

In the previous episode 18 we covered drift detection and automatic remediation, ensuring infrastructure always returns to its declared state. But there's a scenario more frightening than drift: a state file that can't be read at all. Encrypted state that loses its key is no longer a question of recovery speed — it's a question of whether recovery is even possible.
In this episode 19, we'll discuss Disaster Recovery & Encrypted State Recovery. We'll walk through recovery procedures for encrypted state when the KMS key or passphrase has problems, and design backup and versioning strategies using S3 and GCS. This is the episode about peace of mind: ensuring the worst case never becomes the end of everything.
In episode 5 we learned that state is the "inventory" connecting HCL code to real cloud resources. Without state, OpenTofu no longer knows which resources exist — and a careless tofu apply could have clusters, buckets, or databases recreated from scratch, or even destroyed.
With the native client-side encryption feature covered in episode 6, state is stored as ciphertext. This is very secure against theft, but it brings a consequence: state security now depends on the ability to decrypt. A lost key is the same as lost data.
Suppose we encrypt state using AWS KMS:
terraform {
encryption {
key_provider "aws_kms" "main" {
kms_key_id = "arn:aws:kms:ap-southeast-1:123456789012:key/abc123"
}
method "aes_gcm" "main" {
keys = key_provider.aws_kms.main
}
state {
method = method.aes_gcm.main
}
}
}A KMS key can have problems for various reasons: accidentally deleted, disabled, moved regions, or an IAM role that no longer has decrypt permission. The symptom is usually an error when running tofu plan or tofu state pull.
Recovery steps:
kms:Decrypt permission.kms_key_id points to the correct region and account.tofu state pull to confirm the state can be decrypted.tofu plan and make sure there are no unexpected changes, indicating the state reads perfectly.For simpler environments, we might use the pbkdf2 key provider with a passphrase:
terraform {
encryption {
key_provider "pbkdf2" "main" {
passphrase = var.state_passphrase
}
method "aes_gcm" "main" {
keys = key_provider.pbkdf2.main
}
state {
method = method.aes_gcm.main
}
}
}The passphrase can be read from the TF_OPENTOFU_STATE_PASSPHRASE environment variable so it never appears in code. Problems arise when the passphrase is lost or mistyped — and since key derivation is deterministic, a single wrong character makes the entire state unreadable.
To minimize this risk, store the passphrase in a secret manager (Vault, AWS Secrets Manager, or GCP Secret Manager), keep a backup copy in a separate location, and test recovery periodically. The rule of thumb: if no second person can reconstruct the passphrase, it isn't a backup.
When an incident occurs, follow this procedure in order — don't jump straight to reconstruction:
tofu apply command with a problematic state can make things worse.OpenTofu supports key rotation without losing access to old state via the fallback attribute. When the old key has problems, we introduce a new key as the main method and keep the old key as the fallback:
terraform {
encryption {
key_provider "aws_kms" "main" {
kms_key_id = "arn:aws:kms:ap-southeast-1:123456789012:key/new-key"
}
key_provider "aws_kms" "old" {
kms_key_id = "arn:aws:kms:ap-southeast-1:123456789012:key/old-key"
}
method "aes_gcm" "main" { keys = key_provider.aws_kms.main }
method "aes_gcm" "old" { keys = key_provider.aws_kms.old }
state {
method = method.aes_gcm.main
fallback = method.aes_gcm.old
}
}
}With this configuration, OpenTofu writes new state with the new key but can still read old state as long as the old key is available as a fallback. Once all state is re-encrypted with the new key, the fallback can be removed. This is how you rotate keys without downtime — like changing a door lock without locking the residents out.
Recovery can never succeed without proper backups. The two main strategies used in the real world:
The bucket storing state must enable versioning — so every state version (including deleted ones) stays stored:
resource "aws_s3_bucket" "state" {
bucket = "org-opentofu-state"
}
resource "aws_s3_bucket_versioning" "state" {
bucket = aws_s3_bucket.state.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "state" {
bucket = aws_s3_bucket.state.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
}
}
}A versioned bucket becomes a time machine for state. If the latest state is corrupted or unreadable, we can retrieve a previous version.
The same approach applies on GCP using google_storage_bucket with versioning:
resource "google_storage_bucket" "state" {
name = "org-opentofu-state"
location = "ASIA-SOUTHEAST2"
versioning {
enabled = true
}
}Tip
Complete the backup with a lifecycle policy: keep the last few versions for 30 days, move older versions to an archive storage class. Also add cross-region replication and read access in a second region to withstand regional disaster scenarios.
A backup that's never tested isn't a backup. Schedule periodic recovery drills — quarterly, for instance — with these steps:
tofu plan runs without errors.These drills ensure all the procedures above actually work when needed, not just look tidy on paper.
Warning
Never rely on a single point of failure. If the KMS key and the backup live in the same account, deleting the account wipes them both out together. Separate the key from the backup — for instance, the key in one account and a state replica in another — and run restore drills regularly.
In episode 19, we discussed Disaster Recovery & Encrypted State Recovery. We learned recovery procedures when the KMS key or passphrase has problems, key rotation techniques with fallback, and backup and versioning strategies on S3 and GCS.
Key takeaways:
kms:Decrypt permission.tofu state pull is a quick verification tool for testing decryption ability.fallback attribute enables key rotation without downtime.Disaster recovery is proof that your systems withstand the worst case. In the next episode, episode 20 — the final episode — we'll combine all the capabilities learned from episode 0 through 19 into one Complete Production-Grade Enterprise OpenTofu Architecture. See you there!