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
About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact