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:#e65100

Ada 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 DriftPenyebabFrekuensiBahaya
State ↔ RealitaPerubahan manual di console, layanan cloud otomatisSangat seringSedang — Terraform masih punya konfigurasi yang benar
Konfigurasi ↔ StateEdit state manual, state corruptJarangTinggi — 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
PerintahRefresh 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
PenyebabFrekuensiContohPencegahan
Perubahan manual di consolePaling seringBuka port, ubah tag, tambah ruleKebijakan tim + IAM restriction
Layanan cloud otomatisSeringAuto scaling, sertifikat rotasiignore_changes untuk atribut ini
Apply parsialKadangGagal di tengah jalanState locking + retry
Tool lainKadangAnsible, kubectl, CLI scriptSatu tool per resource
State corrupt/tidak sinkronJarangFile corrupt, merge conflictRemote 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:#2e7d32

Opsi 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:#7b1fa2

ignore_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 DriftResourceSolusi
desired_capacityASG, Managed Node Groupignore_changes
tags (ditambah tool lain)EC2, S3, dllignore_changes pada tag tertentu
ingress / egressSecurity GroupKebijakan tim
certificate_arnALB Listenerignore_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 CodeArtiAksi
0Tidak ada perubahanLog dan selesai
1Error (misal: credential salah)Log error, alert tim
2Ada 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-only adalah 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_changes untuk 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-exitcode memungkinkan integrasi dengan CI/CD — exit code 2 = drift terdeteksi.
  • Kebijakan tim yang jelas tentang perubahan manual adalah pertahanan pertama — bukan tool, tapi kebiasaan.

← Sebelumnya: Idempotency   Berikutnya: Apa itu Resource? →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact