State file menyimpan data rahasia seperti password dan API key dalam bentuk plaintext di remote backend. Episode ini membahas fitur eksklusif OpenTofu: enkripsi state di sisi client sebelum dikirim ke storage, lengkap dengan key provider AWS KMS, GCP KMS, dan PBKDF2 passphrase.

Di episode 5 sebelumnya kita membahas remote state management dan state locking — bagaimana state file dipindahkan dari laptop ke penyimpanan terpusat seperti S3, GCS, atau backend HTTP, lengkap dengan mekanisme kunci agar dua orang tidak meng-apply secara bersamaan. State tersimpan di cloud, kolaborasi jadi mudah, konflik berkurang. Tapi ada satu masalah besar yang sengaja belum kita singgung: isi state itu sendiri tidak aman.
Coba ingat apa saja yang disimpan di dalam opentofu.tfstate. Bukan cuma resource ID seperti i-0a1b2c3d, tapi juga seluruh atribut hasil apply — dan di sinilah bahayanya. Saat sebuah database menghasilkan password secara otomatis, atau sebuah modul menyimpan nilai rahasia sebagai atribut, nilai itu ikut tertanam di state dalam bentuk plaintext. Siapa pun yang bisa membaca bucket S3 kalian — atau backend state yang bocor — otomatis bisa membaca semua rahasia itu.
Di episode ini kita akan membahas fitur eksklusif pertama OpenTofu yang menjadi pembeda besar dari Terraform: native client-side state encryption. Kalian akan melihat bagaimana state dienkripsi di sisi client sebelum dikirim ke storage, mempelajari struktur block encryption, dan mengenal pilihan key provider yang tersedia.
Banyak engineer menganggap state file sebagai "detail teknis internal" dan menaruhnya di bucket S3 tanpa proteksi tambahan. Padahal di balik resource ID yang terlihat polos, state menyimpan data sensitif:
Warning
Access control di bucket S3 memang penting, tapi tidak cukup. Backend remote state dibaca otomatis oleh mesin CI, tooling lain, dan kadang dibackup ke lokasi yang tidak terpantau. Kalian tidak bisa mengandalkan "siapa yang bisa membuka bucket" saja — datanya harus aman bahkan saat berada di storage yang tidak kalian kontrol penuh.
Terraform sejak lama mengandalkan dua pertahanan: sensitive = true untuk menyembunyikan nilai dari output dan log, serta akses ketat ke backend. Keduanya menyembunyikan informasi dari mata manusia, tapi file di storage tetap tersimpan polos — siapa pun yang mencuri file-nya langsung mendapat segalanya. Di sinilah OpenTofu melangkah lebih jauh.
Native client-side state encryption bekerja dengan prinsip sederhana: data dienkripsi di mesin yang menjalankan tofu plan atau tofu apply, dan hanya ciphertext yang dikirim ke remote backend. Storage hanya melihat gumpalan byte acak — bahkan jika bucket bocor, tidak ada yang bisa dibaca tanpa kunci.
Konsep ini mirip buku harian yang disimpan di brankas bank: brankas (bucket S3) hanya menyimpan buku yang sudah terkunci gembok, sedangkan yang membuka gembok adalah kunci yang kalian simpan terpisah.
Arsitektur konfigurasinya dibagi menjadi tiga lapisan:
| Lapisan | Peran |
|---|---|
key_provider | Sumber kunci enkripsi — dari mana kunci diambil (KMS, passphrase, dan lain-lain) |
method | Algoritma enkripsi yang dipakai (misalnya AES-GCM) plus kunci dari key provider mana |
target (state / plan) | Bagian data yang dilindungi — state file, plan file, atau keduanya |
encryptionMari lihat konfigurasi lengkap untuk mengenkripsi state file memakai AWS KMS:
encryption {
key_provider "aws_kms" "main" {
kms_key_id = "arn:aws:kms:ap-southeast-1:123456789012:key/xxxx"
}
method "aes_gcm" "main" {
keys = key_provider.aws_kms.main
}
state {
method = method.aes_gcm.main
}
}Baca konfigurasi ini dari bawah ke atas: target state menggunakan method.aes_gcm.main, method itu mengambil kunci dari key_provider.aws_kms.main, dan key provider meminta kunci dari AWS KMS. Setiap kali OpenTofu menulis state, ia memanggil AWS KMS untuk mendapat data key, mengenkripsi state dengan AES-GCM, lalu mengirim hasilnya ke backend.
Setelah block ini aktif, coba buka state di S3 lewat konsol — yang kalian lihat bukan JSON indah berisi resource, melainkan blok terenkripsi. Menjalankan tofu plan dan tofu apply tetap seperti biasa; workflow kalian tidak berubah sama sekali.
Note
Block encryption juga bisa diterapkan ke plan file dengan menambahkan blok plan { method = method.aes_gcm.main } di dalamnya. Keuntungannya: file plan hasil tofu plan -out=plan.tfplan — yang sering disimpan di cache CI — ikut terlindungi.
OpenTofu mendesain abstraksi key_provider agar kalian bisa memilih sumber kunci sesuai ekosistem yang dipakai:
| Key Provider | Sumber Kunci | Cocok Untuk |
|---|---|---|
aws_kms | AWS KMS Customer Managed Key | Tim yang sudah penuh di AWS |
gcp_kms | Google Cloud KMS | Tim yang berjalan di GCP |
azure_keyvault | Azure Key Vault | Tim di ekosistem Azure |
pbkdf2 | Passphrase yang diturunkan jadi kunci | Developer solo atau tim kecil |
openpgp | Public key OpenPGP | Kasus tanpa cloud KMS |
external | Program eksternal kustom | Integrasi HSM atau vault internal |
Untuk tim kecil yang belum punya KMS, provider pbkdf2 adalah jalan termudah — cukup satu passphrase yang diubah OpenTofu menjadi kunci AES melalui iterasi PBKDF2:
encryption {
key_provider "pbkdf2" "my_passphrase" {
passphrase = "ganti-dengan-passphrase-kuat"
}
method "aes_gcm" "main" {
keys = key_provider.pbkdf2.my_passphrase
}
state {
method = method.aes_gcm.main
}
}Warning
Passphrase PBKDF2 yang hilang berarti state yang tersimpan tidak bisa dipulihkan — tidak ada mekanisme recovery bawaan karena enkripsi terjadi sebelum data meninggalkan client. Simpan passphrase di password manager tim dan kombinasikan dengan backup state versi lama. Untuk produksi, cloud KMS lebih disarankan karena kuncinya dikelola terpusat dan bisa di-rotate.
Fitur ini murni eksklusif OpenTofu — di Terraform, state selalu disimpan apa adanya di backend. Setelah migrasi, kalian cukup menambahkan block encryption lalu menjalankan tofu plan dan tofu apply; state lama akan dienkripsi otomatis pada penulisan berikutnya, tanpa migrasi manual.
Praktik yang direkomendasikan:
Pada episode 6 ini kita membangun fondasi keamanan state di OpenTofu:
encryption terdiri dari tiga lapisan: key_provider (sumber kunci), method (algoritma seperti AES-GCM), dan target (state / plan).Ini adalah pertahanan berlapis terbaik untuk salah satu aset terpenting dalam IaC. Di episode 7 selanjutnya kita akan membahas fitur eksklusif OpenTofu kedua: Dynamic Provider Iteration — memuat banyak instansi provider secara dinamis memakai for_each untuk mengelola multi-region dan multi-account dengan kode yang ringkas. Sampai jumpa di episode berikutnya!