Drift Detection #
Drift adalah kondisi di mana infrastruktur aktual yang berjalan di cloud berbeda dari apa yang didefinisikan dalam konfigurasi Terraform. Ini terjadi lebih sering dari yang kamu kira — seseorang mengedit security group langsung di console untuk debugging, sebuah auto-scaling event mengubah jumlah instance, atau layanan cloud secara otomatis memodifikasi atribut tertentu. Drift yang tidak dideteksi dan dikelola bisa menjadi sumber bug yang sulit dilacak dan security hole yang tidak disadari.
Apa itu Drift #
Drift terjadi ketika ada ketidaksesuaian antara tiga hal: konfigurasi Terraform yang kamu tulis, state yang Terraform simpan, dan kondisi aktual di cloud.
flowchart TD
subgraph "Kondisi Ideal (Sinkron)"
A1["Konfigurasi (.tf)\nport 443 only"] -.->|"sama"| B1["State (.tfstate)\nport 443 only"]
B1 -.->|"sama"| C1["Realita (cloud)\nport 443 only"]
end
subgraph "Kondisi Drift"
A2["Konfigurasi (.tf)\nport 443 only"] -.->|"sama"| B2["State (.tfstate)\nport 443 only"]
B2 -.->|"BERBEDA ❌"| C2["Realita (cloud)\nport 443 + 22 + 8080"]
end
D["Seseorang buka port 22\ndan 8080 di console"] --> C2
style A1 fill:#e8f5e9,stroke:#2e7d32
style B1 fill:#e8f5e9,stroke:#2e7d32
style C1 fill:#e8f5e9,stroke:#2e7d32
style A2 fill:#e3f2fd,stroke:#1565c0
style B2 fill:#e3f2fd,stroke:#1565c0
style C2 fill:#ffebee,stroke:#c62828
style D fill:#fff3e0,stroke:#e65100Ada dua jenis drift yang perlu dibedakan:
flowchart TD
A["Jenis Drift"] --> B["Drift State ↔ Realita\n(Paling umum)"]
A --> C["Drift Konfigurasi ↔ State\n(Jarang, tapi berbahaya)"]
B --> B1["Kondisi cloud berubah\ntanpa sepengetahuan Terraform\nState masih menyimpan data lama"]
C --> C1["State diedit manual\natau corrupt\nKonfigurasi .tf tidak sinkron"]
B1 --> D["Solusi: terraform plan\natau terraform apply -refresh-only"]
C1 --> E["Solusi: terraform import\natau perbaiki state"]
style B fill:#fff3e0,stroke:#e65100
style C fill:#ffebee,stroke:#c62828
style D fill:#e8f5e9,stroke:#2e7d32
style E fill:#e8f5e9,stroke:#2e7d32| Jenis Drift | Penyebab | Frekuensi | Bahaya |
|---|---|---|---|
| State ↔ Realita | Perubahan manual di console, layanan cloud otomatis | Sangat sering | Sedang — Terraform masih punya konfigurasi yang benar |
| Konfigurasi ↔ State | Edit state manual, state corrupt | Jarang | Tinggi — bisa menyebabkan destroy/create yang tidak diharapkan |
Mendeteksi Drift #
Ada beberapa cara untuk mendeteksi drift, dari yang paling sederhana hingga yang paling fleksibel.
flowchart TD
A["Cara Mendeteksi Drift"] --> B["terraform plan\n(refresh + diff)"]
A --> C["terraform plan\n-refresh-only"]
A --> D["terraform refresh\n(update state only)"]
B --> B1["Refresh state dari cloud\nHitung perbedaan\ndengan konfigurasi\nTampilkan rencana perubahan"]
C --> C1["Refresh state dari cloud\nTampilkan perbedaan\nantara state dan realita\nTANPA menghitung config diff"]
D --> D1["Update state dari cloud\nTidak ada output\nBerguna untuk sync state"]
B --> B2["Cocok untuk:\nSebelum apply rutin"]
C --> C2["Cocok untuk:\nDrift detection terjadwal"]
D --> D2["Cocok untuk:\nSync state sebelum\nlangkah lain"]
style B fill:#e3f2fd,stroke:#1565c0
style C fill:#e8f5e9,stroke:#2e7d32
style D fill:#fff3e0,stroke:#e65100# Cara 1: terraform plan (melakukan refresh sebelum plan)
terraform plan
# Jika ada drift, plan akan menampilkan perubahan
# meskipun kamu tidak mengubah konfigurasi apapun
# Output jika ada drift:
# ~ aws_security_group.web will be updated in-place
# ~ ingress = [
# + {
# + from_port = 22
# + protocol = "tcp"
# + to_port = 22
# + cidr_blocks = ["0.0.0.0/0"]
# },
# ]
#
# Note: Objects have changed outside of Terraform
# Cara 2: terraform plan -refresh-only
# Hanya menampilkan perbedaan antara state dan realita
# tanpa menghitung perubahan dari konfigurasi
terraform plan -refresh-only
# Cara 3: terraform refresh (update state saja)
terraform refresh
# Memperbarui state file dengan kondisi aktual di cloud
# tanpa mengubah infrastruktur dan tanpa output detail
| Perintah | Refresh State? | Tampilkan Diff? | Ubah Infrastruktur? |
|---|---|---|---|
terraform plan | ✅ Ya | ✅ Config vs realita | ❌ Tidak |
terraform plan -refresh-only | ✅ Ya | ✅ State vs realita | ❌ Tidak |
terraform refresh | ✅ Ya | ❌ Tidak | ❌ Tidak |
terraform apply | ✅ Ya | ✅ Config vs realita | ✅ Ya |
Penyebab Drift yang Paling Umum #
flowchart TD
A["Penyebab Drift"] --> B["Perubahan Manual\ndi Console"]
A --> C["Layanan Cloud\nOtomatis"]
A --> D["Apply Parsial\nyang Gagal"]
A --> E["Tool Lain\n(Ansible, CLI)"]
A --> F["State Tidak\nSinkron"]
B --> B1["Developer buka port SSH\ndi security group\nuntuk debugging\nLupa dikembalikan"]
C --> C1["Auto Scaling ubah\ndesired capacity\nAWS rotasi sertifikat\nManaged service update minor"]
D --> D1["Apply gagal di tengah\nBeberapa resource berhasil\ndibuat, sisanya tidak\nState tidak konsisten"]
E --> E1["kubectl apply ubah\nresource yang sama\ndi managed Terraform\nAnsible configure server"]
F --> F1["State file lama\natau corrupt\nTidak mencerminkan\nkondisi aktual"]
style B fill:#ffebee,stroke:#c62828
style C fill:#fff3e0,stroke:#e65100
style D fill:#fff3e0,stroke:#e65100
style E fill:#fff3e0,stroke:#e65100
style F fill:#fff3e0,stroke:#e65100| Penyebab | Frekuensi | Contoh | Pencegahan |
|---|---|---|---|
| Perubahan manual di console | Paling sering | Buka port, ubah tag, tambah rule | Kebijakan tim + IAM restriction |
| Layanan cloud otomatis | Sering | Auto scaling, sertifikat rotasi | ignore_changes untuk atribut ini |
| Apply parsial | Kadang | Gagal di tengah jalan | State locking + retry |
| Tool lain | Kadang | Ansible, kubectl, CLI script | Satu tool per resource |
| State corrupt/tidak sinkron | Jarang | File corrupt, merge conflict | Remote state + locking |
Merespons Drift #
Saat drift terdeteksi, ada dua pilihan strategis. Pilihan tergantung pada konteks: apakah perubahan di console itu disengaja atau tidak.
flowchart TD
A["Drift Terdeteksi!"] --> B{"Perubahan di console\nitu disengaja?"}
B -->|"Tidak (kesalahan)"| C["Opsi 1: Terraform Menang\nRevert ke konfigurasi"]
B -->|"Ya (emergency fix)"| D{"Sudah didokumentasikan\ndi .tf?"}
D -->|"Belum"| E["Opsi 2: Realita Menang\nUpdate config .tf"]
D -->|"Sudah"| F["Tidak masalah\nPlan akan kosong"]
C --> C1["terraform apply\nTerraform revert\ninfrastruktur ke\nkonfigurasi .tf"]
E --> E1["terraform apply -refresh-only\nUpdate state\ndari kondisi aktual\nLalu edit .tf"]
E1 --> E2["Commit .tf yang sudah\ndiupdate ke Git"]
style C fill:#e3f2fd,stroke:#1565c0
style E fill:#fff3e0,stroke:#e65100
style F fill:#e8f5e9,stroke:#2e7d32Opsi 1: Terraform Menang (Revert ke Konfigurasi) #
# Kembalikan infrastruktur ke kondisi yang dikonfigurasi
terraform apply
# Terraform akan mengubah infrastruktur agar sesuai dengan .tf
# Berguna jika perubahan manual adalah kesalahan
Opsi 2: Realita Menang (Terima Perubahan) #
# Update state agar mencerminkan kondisi aktual
terraform apply -refresh-only
# State diupdate, konfigurasi .tf tidak berubah
# Langkah berikutnya: update konfigurasi .tf agar sesuai
# dengan kondisi aktual, lalu commit ke version control
# Contoh: Drift terdeteksi — port 22 dibuka di luar Terraform
# Setelah diskusi tim, diputuskan port 22 memang diperlukan
# tapi harus dikelola oleh Terraform
# Update konfigurasi .tf:
resource "aws_security_group" "web" {
name = "web-sg"
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
# Tambahkan aturan yang sebelumnya dibuka manual:
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = [var.office_cidr] # Batasi ke IP kantor, bukan 0.0.0.0/0
}
}
# Commit konfigurasi ini, lalu apply
Mencegah Drift #
flowchart TD
A["Strategi Pencegahan Drift"] --> B["1. Kebijakan Tim"]
A --> C["2. Automated Detection"]
A --> D["3. ignore_changes"]
A --> E["4. Emergency Procedures"]
B --> B1["Semua perubahan infra\nharus melalui Terraform\nIAM policy restriction\nCode review untuk .tf"]
C --> C1["Jadwalkan plan -refresh-only\nsetiap hari kerja\nAlert ke Slack/email\nExit code 2 = drift"]
D --> D1["Untuk atribut yang\nmemang berubah otomatis\n(desired_capacity, tags,\ncertificate rotation)"]
E --> E1["Boleh edit manual\nsaat emergency\nTAPI wajib buat\nTerraform PR dalam 24 jam"]
style B fill:#e3f2fd,stroke:#1565c0
style C fill:#e8f5e9,stroke:#2e7d32
style D fill:#fff3e0,stroke:#e65100
style E fill:#f3e5f5,stroke:#7b1fa2ignore_changes untuk Atribut yang Berubah Otomatis
#
# Contoh: Auto Scaling Group — desired_capacity berubah oleh scaling policy
resource "aws_autoscaling_group" "web" {
name = "web-asg"
min_size = 2
max_size = 10
desired_capacity = 2
lifecycle {
# desired_capacity bisa berubah oleh auto scaling policy
# atau manual scaling — abaikan perubahan ini di Terraform
ignore_changes = [desired_capacity]
}
}
| Atribut yang Sering Drift | Resource | Solusi |
|---|---|---|
desired_capacity | ASG, Managed Node Group | ignore_changes |
tags (ditambah tool lain) | EC2, S3, dll | ignore_changes pada tag tertentu |
ingress / egress | Security Group | Kebijakan tim |
certificate_arn | ALB Listener | ignore_changes jika rotasi otomatis |
Automated Drift Detection di CI/CD #
# Contoh: GitHub Actions untuk drift detection terjadwal
# .github/workflows/drift-detection.yml
name: Terraform Drift Detection
on:
schedule:
- cron: '0 8 * * 1-5' # Setiap hari kerja jam 8 pagi
jobs:
drift-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
- name: Terraform Init
run: terraform init
- name: Check for Drift
id: plan
run: |
terraform plan -refresh-only -detailed-exitcode
# Exit code 0: tidak ada perubahan
# Exit code 1: error
# Exit code 2: ada perubahan (drift terdeteksi)
continue-on-error: true
- name: Alert jika ada drift
if: steps.plan.outputs.exitcode == '2'
run: |
echo "Drift detected! Check Terraform plan output."
# Kirim notifikasi ke Slack, PagerDuty, dll.
flowchart LR
A["Schedule:\nSetiap hari\njam 8 pagi"] --> B["terraform init"]
B --> C["terraform plan\n-refresh-only\n-detailed-exitcode"]
C --> D{"Exit code?"}
D -->|"0: No changes"| E["✅ Tidak ada drift\nLog dan selesai"]
D -->|"2: Changes detected"| F["⚠️ Drift!\nKirim alert"]
D -->|"1: Error"| G["❌ Error\nLog dan alert"]
F --> H["Notifikasi\nke Slack/email"]
G --> I["Notifikasi\nke PagerDuty"]
style E fill:#e8f5e9,stroke:#2e7d32
style F fill:#fff3e0,stroke:#e65100
style G fill:#ffebee,stroke:#c62828| Exit Code | Arti | Aksi |
|---|---|---|
| 0 | Tidak ada perubahan | Log dan selesai |
| 1 | Error (misal: credential salah) | Log error, alert tim |
| 2 | Ada perubahan (drift terdeteksi) | Kirim notifikasi, buat issue |
Ringkasan #
- Drift adalah kondisi normal yang akan selalu terjadi di tim yang aktif — yang penting adalah mendeteksi dan meresponsnya dengan cepat.
terraform plan -refresh-onlyadalah cara paling aman untuk mendeteksi drift tanpa risiko mengubah infrastruktur.- Dua pilihan saat drift terdeteksi: apply untuk kembalikan ke konfigurasi, atau update konfigurasi untuk mencerminkan realita — pilih sesuai konteks.
ignore_changesuntuk atribut yang memang dikelola di luar Terraform — mencegah false-positive drift detection.- Automated drift detection yang dijadwalkan (misal: setiap hari kerja jam 8 pagi) memastikan tim mengetahui drift sebelum menjadi masalah production.
-detailed-exitcodememungkinkan integrasi dengan CI/CD — exit code 2 = drift terdeteksi.- Kebijakan tim yang jelas tentang perubahan manual adalah pertahanan pertama — bukan tool, tapi kebiasaan.