Anti-Pattern: Production Failure Scenario #
Setiap insiden infrastruktur yang disebabkan Terraform bisa ditelusuri ke satu dari beberapa anti-pattern yang berulang: state yang tidak dikelola dengan baik, lifecycle yang tidak dikonfigurasi untuk resource kritis, apply yang dilakukan terburu-buru tanpa review plan, atau konfigurasi yang belum ditest di staging. Artikel ini membahas skenario kegagalan yang paling sering terjadi — bukan untuk menakut-nakuti, tapi agar kamu bisa membangun safety net yang tepat sebelum skenario ini terjadi di lingkunganmu.
Skenario 1 — terraform destroy yang Tidak Sengaja #
KRONOLOGI INSIDEN:
09:00 Engineer bermaksud destroy environment dev untuk hemat biaya
09:01 terraform workspace list → lupa cek, masih di workspace production
09:02 terraform destroy → menekan "yes" tanpa baca output
09:03 Semua resource production mulai terhapus
09:05 Alert monitoring berbunyi — production down
09:07 Tim baru sadar yang terjadi
Dampak: 2 jam downtime, data yang tidak ter-backup hilang
PENCEGAHAN:
1. Workspace safety di shell prompt
# .zshrc / .bashrc
terraform_prompt() {
if [ -f .terraform/environment ]; then
workspace=$(cat .terraform/environment 2>/dev/null || echo "default")
if [ "$workspace" = "production" ]; then
echo " ⚠️ PRODUCTION"
fi
fi
}
PS1='$(terraform_prompt) $ '
2. prevent_destroy untuk resource kritis
lifecycle {
prevent_destroy = true
}
# Terraform error sebelum destroy dimulai
3. Konfirmasi tambahan untuk production
# Script wrapper
if [[ "$1" == "destroy" ]] && grep -q "production" .terraform/environment; then
read -p "PRODUCTION DESTROY! Ketik nama environment untuk konfirmasi: " confirm
[ "$confirm" != "production" ] && exit 1
fi
terraform "$@"
4. IAM policy yang tidak membolehkan destroy di production
# IAM policy deny DeleteDBInstance, TerminateInstances, dll.
# untuk role yang digunakan developer — hanya CI/CD pipeline yang bisa
Skenario 2 — State Corruption #
KRONOLOGI INSIDEN:
14:00 Engineer A menjalankan terraform apply di laptop
14:00 Engineer B menjalankan terraform apply di CI/CD pipeline (bersamaan)
14:01 State locking tidak dikonfigurasi (local backend atau S3 tanpa DynamoDB)
14:02 Kedua apply selesai, state terakhir yang tersimpan mengalahkan yang lain
14:03 State tidak lagi mencerminkan infrastruktur yang sebenarnya
14:04 terraform plan menunjukkan perubahan yang aneh
14:05 Tim tidak tahu apa yang benar — state atau realita di cloud?
PENCEGAHAN:
1. Remote backend dengan locking WAJIB
terraform {
backend "s3" {
bucket = "terraform-state"
key = "production/terraform.tfstate"
region = "ap-southeast-1"
dynamodb_table = "terraform-state-lock" ← INI WAJIB
encrypt = true
}
}
2. Tidak ada apply dari laptop untuk production
- Semua apply production hanya dari CI/CD pipeline
- IAM role di laptop: read-only ke production
3. State backup otomatis
# S3 bucket dengan versioning
resource "aws_s3_bucket_versioning" "state" {
bucket = aws_s3_bucket.terraform_state.id
versioning_configuration {
status = "Enabled"
}
}
# Jika state corrupt: restore versi sebelumnya dari S3
Skenario 3 — Downtime karena replace yang Tidak Terduga #
KRONOLOGI INSIDEN:
10:00 Engineer mengubah tag pada aws_db_instance di konfigurasi Terraform
10:01 terraform plan — output panjang, engineer scroll cepat
10:02 Di tengah output (yang tidak dibaca): -/+ aws_db_instance.main (forces replacement)
Ternyata versi RDS minor di parameter group berubah dan forces recreate
10:03 terraform apply -auto-approve (di CI/CD)
10:04 RDS di-destroy, baru dibuat ulang → 15 menit downtime
10:05 Data tidak hilang (ada backup), tapi ada 15 menit outage
PENCEGAHAN:
1. Baca SELURUH output plan sebelum apply
Jangan skip bagian tengah — -/+ bisa tersembunyi di mana saja
2. Cek jumlah destroy/replace di summary
Plan output selalu diakhiri dengan summary seperti:
"Plan: 1 to add, 2 to change, 1 to destroy."
Setiap angka di "to destroy" perlu diperhatikan
3. Automated check untuk destroy di pipeline
terraform plan -out=tfplan
DESTROY=$(terraform show -json tfplan | jq '[.resource_changes[]
| select(.change.actions[] == "delete")] | length')
if [ "$DESTROY" -gt 0 ]; then
echo "ERROR: $DESTROY resource akan dihapus!"
exit 1 # Blokir pipeline
fi
4. create_before_destroy untuk database
resource "aws_db_instance" "main" {
lifecycle {
create_before_destroy = true
}
}
# Masih ada downtime untuk switch koneksi, tapi lebih pendek
Skenario 4 — Secret Terekspos via Plan Output #
KRONOLOGI INSIDEN:
Konfigurasi CI/CD memposting terraform plan output ke PR sebagai comment
Plan output berisi nilai dari variable yang lupa ditandai sensitive = true
PR adalah public (open source project)
API key terekspos ke internet selama beberapa jam sebelum ada yang sadar
PENCEGAHAN:
1. Tandai SEMUA variable dan output sensitif
variable "api_key" {
type = string
sensitive = true ← WAJIB untuk nilai sensitif
}
2. Filter plan output sebelum diposting ke PR
terraform show -no-color tfplan \
| grep -v "sensitive" \ # Filter baris yang mengandung "sensitive"
> plan_filtered.txt
3. Jangan post plan ke PR publik jika ada resource sensitif
Gunakan link ke pipeline log yang membutuhkan autentikasi
alih-alih post langsung ke comment
4. Scan plan output sebelum diposting
# Cek apakah ada pola yang terlihat seperti credential
grep -E "AKIA|password|secret|api_key" plan_output.txt && exit 1
Skenario 5 — Dependency Terbalik yang Menyebabkan Failure #
KRONOLOGI INSIDEN:
Tim A mengelola konfigurasi networking
Tim B mengelola konfigurasi aplikasi — menggunakan terraform_remote_state
ke state networking untuk mendapatkan subnet IDs
Tim A memutuskan untuk me-rename output "public_subnet_ids"
menjadi "subnet_ids_public" (refactoring naming)
Tim A apply → berhasil (output baru sudah ada)
Tim B plan → ERROR: output "public_subnet_ids" tidak ada di remote state
Tim B harus update konfigurasi mereka sebelum bisa plan/apply
PENCEGAHAN:
1. Output contract yang eksplisit dan stabil
# Jangan rename output yang sudah digunakan konfigurasi lain
# Jika perlu rename: tambahkan alias dulu
# outputs.tf networking:
output "public_subnet_ids" {
value = aws_subnet.public[*].id
description = "DEPRECATED: Gunakan subnet_ids_public"
}
output "subnet_ids_public" {
value = aws_subnet.public[*].id
}
2. Koordinasi antar tim sebelum breaking change pada output
Beri notifikasi ke semua tim yang menggunakan remote state
Beri window migrasi sebelum output lama dihapus
3. Pertimbangkan variable input daripada remote state
Coupling yang lebih longgar — tim B mendapat nilai via variable
bukan langsung dari state Tim A
Perubahan naming di Tim A tidak langsung membreaking Tim B
Checklist Safety Net Production #
SEBELUM SETIAP APPLY KE PRODUCTION:
REVIEW PLAN:
□ Baca seluruh output plan, jangan skip
□ Tidak ada operasi -/+ (replace) yang tidak disengaja
□ Jumlah "to destroy" sesuai harapan (idealnya 0)
□ Resource yang berubah sesuai dengan perubahan konfigurasi yang dilakukan
STATE & LOCKING:
□ Remote backend dengan locking aktif
□ Tidak ada plan lain yang sedang berjalan (cek DynamoDB lock table)
□ State sudah di-backup (S3 versioning aktif)
CREDENTIALS & ACCESS:
□ Menggunakan workspace/profile yang benar (bukan dev profile di production)
□ IAM role sesuai (apply role, bukan plan-only role)
POST-APPLY:
□ Verifikasi resource berjalan setelah apply
□ Jalankan smoke test atau health check
□ Notifikasi tim bahwa apply berhasil
JIKA ADA MASALAH:
□ Jangan panic apply ulang — identifikasi masalah dulu
□ Cek state: terraform state list dan terraform state show
□ Jika perlu rollback: revert commit dan apply versi sebelumnya
□ Dokumentasikan insiden untuk post-mortem
Ringkasan #
- terraform destroy yang tidak sengaja dicegah dengan
prevent_destroy, tampilkan workspace di shell prompt, dan kebijakan “tidak ada destroy production dari laptop”.- State corruption terjadi saat dua apply berjalan bersamaan tanpa locking — remote backend dengan DynamoDB locking adalah persyaratan mutlak, bukan opsional.
- Replace yang tidak terduga disebabkan oleh perubahan yang “memaksa” recreate resource — automated check pada jumlah destroy di plan output bisa memblokir pipeline sebelum apply.
- Secret di plan output terjadi karena lupa
sensitive = true— filter output sebelum diposting ke PR publik dan scan untuk pola yang terlihat seperti credential.- Dependency terbalik antar konfigurasi bisa dimitigasi dengan output contract yang stabil, deprecation period sebelum rename, dan koordinasi antar tim.
- Checklist sebelum apply production adalah investasi kecil yang mencegah insiden besar — baca seluruh plan, verifikasi workspace, dan selalu ada post-apply verification.
← Sebelumnya: Anti-Pattern: Over-Complex Module