Drift Detection Automation #
Infrastruktur yang dikelola Terraform bisa berubah tanpa melalui Terraform — seseorang mungkin memodifikasi security group langsung di console untuk debug, atau cloud provider otomatis mengubah beberapa atribut resource. Drift adalah kondisi ketika realita infrastruktur tidak lagi sesuai dengan state Terraform. Jika dibiarkan, drift menumpuk dan lama-lama membuat Terraform menjadi tidak bisa dipercaya sebagai sumber kebenaran. Deteksi drift yang dijalankan secara terjadwal memberikan visibilitas atas kondisi ini sebelum menjadi masalah besar.
Apa itu Drift dan Mengapa Berbahaya #
CONTOH DRIFT NYATA:
Terraform state says:
aws_security_group.web:
ingress: [port 443, 0.0.0.0/0]
Realita di AWS:
aws_security_group.web:
ingress: [port 443, 0.0.0.0/0]
[port 22, 0.0.0.0/0] ← Ditambahkan manual untuk debug
[port 8080, 10.0.0.0/8] ← Ditambahkan untuk testing
Akibat:
- Security hole yang tidak disadari (port 22 terbuka ke publik)
- Terraform plan yang dijalankan TANPA drift check akan menghapus rule ini
→ Kejutan saat apply karena "perubahan yang tidak terduga"
- Atau sebaliknya: apply tidak dilakukan karena plan terlihat bersih
tapi realita infrastruktur berbeda
JENIS DRIFT:
1. Konfigurasi berubah di luar Terraform (manual di console)
2. Cloud provider mengubah atribut (maintenance, auto-upgrade)
3. Integrasi pihak ketiga yang memodifikasi resource
4. Tag yang diubah oleh billing tool atau security scanner
Scheduled Plan untuk Deteksi Drift #
Cara paling straightforward untuk mendeteksi drift adalah menjalankan terraform plan secara terjadwal. Jika plan menunjukkan ada perubahan padahal tidak ada yang mengubah konfigurasi, itu adalah drift.
# .github/workflows/drift-detection.yml
name: Drift Detection
on:
schedule:
- cron: '0 8 * * 1-5' # Setiap hari kerja jam 8 pagi
workflow_dispatch: # Bisa dipicu manual jika perlu
jobs:
detect-drift:
name: Detect Drift — ${{ matrix.environment }}
runs-on: ubuntu-latest
strategy:
matrix:
environment: [production, staging]
fail-fast: false # Lanjutkan meski satu environment gagal
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
with:
terraform_version: "1.7.0"
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ vars.AWS_ACCOUNT_ID }}:role/TerraformReadRole
aws-region: ap-southeast-1
- name: Terraform Init
run: terraform init
working-directory: infrastructure/environments/${{ matrix.environment }}
- name: Terraform Plan (Drift Check)
id: plan
run: |
# -detailed-exitcode: exit 0 = tidak ada perubahan, exit 2 = ada perubahan
terraform plan \
-detailed-exitcode \
-no-color \
-refresh=true \
2>&1 | tee plan_output.txt
echo "exit_code=$?" >> $GITHUB_OUTPUT
working-directory: infrastructure/environments/${{ matrix.environment }}
continue-on-error: true
- name: Analyze Drift
id: drift
run: |
EXIT_CODE="${{ steps.plan.outputs.exit_code }}"
case $EXIT_CODE in
0) echo "status=no_drift" >> $GITHUB_OUTPUT
echo "✅ No drift detected in ${{ matrix.environment }}" ;;
1) echo "status=plan_error" >> $GITHUB_OUTPUT
echo "❌ Terraform plan failed — check logs" ;;
2) echo "status=drift_detected" >> $GITHUB_OUTPUT
echo "⚠️ Drift detected in ${{ matrix.environment }}!" ;;
esac
- name: Extract Drift Summary
if: steps.drift.outputs.status == 'drift_detected'
run: |
# Ambil hanya bagian yang relevan dari plan output
grep -E "^ [+~-]|will be|must be replaced|Plan:" plan_output.txt \
| head -50 > drift_summary.txt
cat drift_summary.txt
working-directory: infrastructure/environments/${{ matrix.environment }}
- name: Notify Slack — Drift Detected
if: steps.drift.outputs.status == 'drift_detected'
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "⚠️ Infrastructure drift detected",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*⚠️ Drift Detected: `${{ matrix.environment }}`*\n\nInfrastruktur tidak sesuai dengan state Terraform.\nLihat detail: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
}
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_INFRA_WEBHOOK }}
Terraform Refresh: Memperbarui State #
Saat drift terdeteksi, ada dua respons yang mungkin: kembalikan infrastruktur ke konfigurasi Terraform (apply), atau perbarui state agar mencerminkan kondisi aktual (refresh).
# OPSI 1: Kembalikan infrastruktur ke konfigurasi Terraform
# Ini adalah respons default dan yang paling direkomendasikan
terraform apply
# OPSI 2: Perbarui state agar mencerminkan kondisi aktual
# Gunakan ini jika perubahan manual memang disengaja dan ingin dipertahankan
# PERHATIAN: ini tidak mengubah konfigurasi .tf — hanya state
terraform apply -refresh-only
# terraform refresh (deprecated — gunakan apply -refresh-only)
# terraform refresh
# Setelah refresh-only apply, kamu perlu update konfigurasi .tf
# agar sesuai dengan kondisi aktual, lalu commit ke repository
# Contoh: Setelah drift ditemukan pada security group
# Kondisi aktual: ada rule tambahan yang memang diinginkan
# Pilihan A: Hapus rule manual (kembalikan ke Terraform)
# → terraform apply (tanpa perubahan konfigurasi .tf)
# Pilihan B: Tambahkan rule ke konfigurasi (terima perubahan manual)
resource "aws_security_group_rule" "debug_access" {
type = "ingress"
from_port = 8080
to_port = 8080
protocol = "tcp"
cidr_blocks = ["10.0.0.0/8"]
security_group_id = aws_security_group.web.id
description = "Internal debug access — added after drift review 2024-01-15"
}
# Commit ini ke repository → drift resolved
Mengelola Noise: Drift yang Bisa Diabaikan #
Tidak semua drift adalah masalah. Beberapa atribut memang berubah secara normal dan tidak perlu dikhawatirkan.
# Tambahkan ignore_changes untuk atribut yang memang berubah di luar Terraform
resource "aws_instance" "web" {
ami = var.ami_id
instance_type = var.instance_type
lifecycle {
ignore_changes = [
# AMI berubah saat ada patch otomatis
ami,
# Tags yang ditambahkan oleh billing tool atau security scanner
tags["LastScannedBy"],
tags["CostCenter"],
# User data mungkin diubah oleh automation eksternal
user_data_base64,
]
}
}
# Filter drift report — hanya tampilkan yang bukan dari ignore_changes
# (Terraform sudah otomatis tidak melaporkan atribut dalam ignore_changes)
# Untuk custom filtering: parse JSON plan output
terraform show -json tfplan | jq '
.resource_changes[]
| select(.change.actions != ["no-op"])
| {
resource: .address,
actions: .change.actions,
changes: (.change.before // {} | keys)
}
'
Ringkasan #
- Drift terjadi ketika infrastruktur diubah di luar Terraform — console, CLI ad-hoc, atau automation eksternal. Jika tidak dideteksi, drift menumpuk dan membuat Terraform tidak bisa dipercaya.
- Scheduled plan (
-detailed-exitcode) adalah cara paling straightforward untuk deteksi drift — jalankan setiap hari, alert jika ada perubahan.- Exit code 2 dari
terraform plan -detailed-exitcodeberarti ada perubahan (drift), exit code 0 berarti bersih.- Dua respons saat drift ditemukan:
terraform apply(kembalikan ke konfigurasi) atauterraform apply -refresh-onlylalu update konfigurasi (terima perubahan manual).ignore_changesdi lifecycle block mencegah drift palsu — gunakan untuk atribut yang memang berubah di luar Terraform (tag dari billing tool, AMI patch otomatis).- Alert ke Slack atau channel komunikasi tim saat drift ditemukan — tim perlu tahu dan merespons sebelum drift menjadi masalah yang lebih besar.