Rahasia di IaC bocor lewat tiga pintu: output plan, state plaintext, dan kredensial statis di kode. Episode ini menggabungkan client-side state encryption dengan sensitive variables, lalu menarik rahasia dinamis dari Vault, AWS Secrets Manager, dan GCP Secret Manager saat apply.

Di episode 14 sebelumnya kita meninjau managed platforms — Spacelift, env0, Scalr — dan Digger. Semua platform itu menjalankan OpenTofu, tapi tidak satu pun yang bisa menyelamatkan kalian ketika rahasia sudah bocor lewat hal yang mereka anggap biasa: file state, output plan, atau variabel yang ditulis asal. Keamanan infrastruktur tidak ditentukan oleh platform, melainkan oleh bagaimana rahasia disimpan, dienkripsi, dan dikirim ke engine.
Di episode 15 ini kita mengeraskan dua lapis sekaligus. Pertama, kita mengombinasikan client-side state encryption — yang pertama kali kita bahas di episode 6 — dengan sensitive variables agar rahasia tidak tampil di plan maupun output. Kedua, kita mengganti kredensial statis di kode dengan rahasia dinamis yang ditarik langsung saat tofu apply dari HashiCorp Vault, AWS Secrets Manager, dan GCP Secret Manager.
Menulis password langsung di variables.tf adalah kebiasaan yang harus dihentikan sejak hari pertama. Cara yang benar: jadikan variabel itu sensitive = true, sehingga nilainya tidak pernah ditampilkan di output tofu plan maupun tofu output, dan tidak tampil ketika dirender ke layar:
variable "db_password" {
type = string
sensitive = true
description = "Password database, dipasok dari secret manager saat apply"
}
output "db_connection_string" {
value = "${var.db_username}@${var.db_endpoint}"
sensitive = true
}Nilai sensitive membuat OpenTofu mengganti isinya dengan panah merah di output plan. Hanya satu tanda peringatan yang harus diingat: sensitive = true hanya menutupi tampilan — nilai aslinya tetap tersimpan utuh di state.
Caution
Jangan pernah menaruh nilai rahasia di file .tfvars yang di-commit, karena jejaknya akan abadi di riwayat git. Di CI, pasok variabel sensitive lewat secret environment atau file .tfvars yang dihasilkan pipeline dan dibuang setelah digunakan.
Lapisan tadi hanya mengatur tampilan. Lapisan berikutnya adalah penyimpanan: state berisi nilai asli dari setiap resource, termasuk password dan kunci. Di episode 6 kita sudah melihat solusi OpenTofu untuk ini — client-side state encryption, yang mengenkripsi state di client sebelum dikirim ke backend, sehingga bahkan admin S3 pun tidak bisa membaca isinya:
encryption {
key_provider "aws_kms" "main" {
kms_key_id = "arn:aws:kms:ap-southeast-1:123456789012:key/example-key-id"
}
method "aes_gcm" "main" {
keys = key_provider.aws_kms.main
}
state {
method = method.aes_gcm.main
}
}Kombinasikan keduanya: sensitive = true menjaga rahasia agar tidak tampil di output dan plan, sementara encryption menjaga rahasia yang sama agar tidak terbaca di state. Ini dua sisi dari satu pintu keamanan yang sama.
Kredensial statis di dalam file .tf — token atau key — selalu menjadi risiko: tersalin ke laptop, bocor ke git, atau menginap di cache CI. Solusinya adalah menarik rahasia saat apply, bukan menyimpannya. Provider Vault membaca secret dari HashiCorp Vault langsung pada waktu OpenTofu menjalankan ekspresi:
variable "vault_token" {
type = string
sensitive = true
}
provider "vault" {
address = var.vault_addr
token = var.vault_token
}
data "vault_generic_secret" "db" {
path = "secret/data/db/prod"
}
resource "aws_db_instance" "postgres" {
engine = "postgres"
username = data.vault_generic_secret.db.data["username"]
password = data.vault_generic_secret.db.data["password"]
}Perhatikan polanya: rahasia tidak pernah disimpan sebagai literal di kode. OpenTofu membaca nilai dari Vault saat apply berlangsung, dan nilai tersebut tidak akan pernah muncul di riwayat git.
Ketika seluruh stack sudah berjalan di satu cloud, memakai secret manager bawaan cloud mengurangi komponen yang harus dikelola. Di AWS, data source aws_secretsmanager_secret_version mengambil nilai terbaru sebuah secret, dan nilainya bisa berupa JSON yang di-decode:
data "aws_secretsmanager_secret_version" "db" {
secret_id = "prod/db-credentials"
}
resource "aws_db_instance" "postgres" {
engine = "postgres"
username = jsondecode(data.aws_secretsmanager_secret_version.db.secret_string)["username"]
password = jsondecode(data.aws_secretsmanager_secret_version.db.secret_string)["password"]
}Di GCP, google_secret_manager_secret_version mengambil versi secret yang aktif dan nilainya tersedia lewat atribut secret_data:
data "google_secret_manager_secret_version" "api_key" {
secret = "api-key"
}
resource "google_cloudfunctions2_function" "api" {
environment_variables = {
API_KEY = data.google_secret_manager_secret_version.api_key.secret_data
}
}| Sumber rahasia | Kapan cocok dipakai | Data source OpenTofu |
|---|---|---|
| HashiCorp Vault | Multi-cloud, rotasi aktif, policy ketat | vault_generic_secret |
| AWS Secrets Manager | Stack penuh di AWS | aws_secretsmanager_secret_version |
| GCP Secret Manager | Stack penuh di GCP | google_secret_manager_secret_version |
Tip
Rotasi rahasia di secret manager tidak mengharuskan perubahan kode sama sekali. Saat nilai berubah di Vault atau AWS, jalankan ulang tofu plan lalu tofu apply — data source membaca versi terbaru dan resource yang bergantung padanya diperbarui otomatis.
sensitive = true pada variabel dan output; dua-duanya punya jalur kebocoran masing-masing.plan.tfplan ke artefak publik — plan menyimpan nilai rahasia yang sama seperti state.tofu console dan tofu plan -no-color bisa menampilkan nilai sensitive — waspadai saat menangkap log.Pada episode 15 ini kita telah mengeraskan penanganan rahasia:
sensitive = true pada variabel dan output untuk menghentikan kebocoran di plan dan output.vault_generic_secret saat apply.aws_secretsmanager_secret_version dan google_secret_manager_secret_version untuk cloud-native.Mengamankan rahasia adalah satu hal; memastikan apa yang boleh dan tidak boleh dibuat di cloud adalah hal lain. Di episode 16 selanjutnya kita akan membangun Policy as Code dengan Open Policy Agent: mengekstrak plan JSON dengan tofu show -json dan menulis aturan Rego yang menolak security group port 22 terbuka ke publik atau storage tanpa enkripsi. Sampai jumpa!