Automated Apply #

Automated apply adalah tujuan akhir dari Terraform CI/CD yang matang — perubahan konfigurasi yang sudah di-review dan di-merge secara otomatis diterapkan ke infrastruktur tanpa perlu seseorang yang menjalankan perintah secara manual. Ini menghilangkan bottleneck “tunggu si A yang punya akses untuk apply”, memastikan konsistensi antara kode dan infrastruktur, dan memungkinkan tim bergerak lebih cepat. Tapi “otomatis” bukan berarti “tanpa kontrol” — justru automated apply yang baik memiliki lebih banyak safeguard dibanding apply manual.

Prasyarat Automated Apply yang Aman #

Automated apply tanpa prasyarat yang tepat lebih berbahaya dari apply manual. Berikut apa yang harus ada sebelum mengaktifkan automated apply.

PRASYARAT AUTOMATED APPLY:

REVIEW PROCESS:
  ✓ Semua perubahan melalui PR / merge request
  ✓ Minimal 1 reviewer yang approve sebelum merge
  ✓ Plan output tampil di PR agar reviewer melihat DAMPAK, bukan hanya kode

STATE MANAGEMENT:
  ✓ Remote state dengan locking (S3 + DynamoDB atau Terraform Cloud)
  ✓ State tidak bisa diakses atau dimodifikasi langsung oleh siapapun selain pipeline

CREDENTIALS:
  ✓ CI/CD mendapatkan credentials via OIDC (bukan stored secrets)
  ✓ Credentials berbeda untuk plan dan apply (plan: read-only, apply: full)

MONITORING:
  ✓ Notifikasi saat apply berhasil atau gagal
  ✓ Log apply tersimpan dan bisa diaudit
  ✓ Alert jika ada perubahan yang tidak terduga (drift detection)

GitOps: Branch sebagai Source of Truth #

GitOps adalah pendekatan di mana kondisi branch Git tertentu selalu mencerminkan kondisi infrastruktur yang seharusnya. Setiap merge ke branch tersebut secara otomatis memicu apply.

GITOPS BRANCHING STRATEGY:

  main branch      → production environment
  staging branch   → staging environment
  develop branch   → development environment

  Alur perubahan:
  feature-branch → PR ke develop → auto-apply dev
  develop → PR ke staging        → auto-apply staging (atau dengan approval)
  staging → PR ke main           → apply production (selalu dengan approval)

  Setiap branch mencerminkan kondisi environment-nya.
  Git history = audit trail infrastruktur.
# GitHub Actions: GitOps-style automated apply
# .github/workflows/terraform-gitops.yml

name: Terraform GitOps

on:
  push:
    branches: [develop, staging, main]
    paths: ['infrastructure/**']

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Determine Environment
        id: env
        run: |
          case "${{ github.ref_name }}" in
            develop)  echo "environment=dev"        >> $GITHUB_OUTPUT
                      echo "auto_approve=true"       >> $GITHUB_OUTPUT ;;
            staging)  echo "environment=staging"    >> $GITHUB_OUTPUT
                      echo "auto_approve=true"       >> $GITHUB_OUTPUT ;;
            main)     echo "environment=production"  >> $GITHUB_OUTPUT
                      echo "auto_approve=false"      >> $GITHUB_OUTPUT ;;
          esac          

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: >
            arn:aws:iam::${{ vars.AWS_ACCOUNT_ID }}:role/TerraformApplyRole-${{ steps.env.outputs.environment }}            
          aws-region: ap-southeast-1

      - uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: "1.7.0"

      - name: Terraform Init
        run: terraform init
        working-directory: infrastructure/environments/${{ steps.env.outputs.environment }}

      - name: Terraform Plan
        run: terraform plan -out=tfplan -no-color
        working-directory: infrastructure/environments/${{ steps.env.outputs.environment }}

      - name: Terraform Apply (Auto-approve for non-production)
        if: steps.env.outputs.auto_approve == 'true'
        run: terraform apply tfplan
        working-directory: infrastructure/environments/${{ steps.env.outputs.environment }}

      - name: Terraform Apply (Production — requires environment approval)
        if: steps.env.outputs.auto_approve == 'false'
        run: terraform apply tfplan
        working-directory: infrastructure/environments/${{ steps.env.outputs.environment }}
        environment: production  # Environment protection rules berlaku di sini

Safeguard: Deteksi Perubahan Berbahaya Sebelum Apply #

Pipeline yang baik memiliki pemeriksaan tambahan sebelum apply berjalan, terutama untuk mendeteksi perubahan yang berpotensi merusak.

#!/bin/bash
# check-plan-safety.sh — jalankan setelah terraform plan, sebelum apply

PLAN_OUTPUT=$(terraform show -json tfplan)

# Hitung resource yang akan dihapus
DESTROY_COUNT=$(echo $PLAN_OUTPUT | jq '[.resource_changes[] | select(.change.actions[] == "delete")] | length')

# Hitung resource yang akan di-replace (destroy + create)
REPLACE_COUNT=$(echo $PLAN_OUTPUT | jq '[.resource_changes[] | select(.change.actions | contains(["delete", "create"]))] | length')

echo "Resources to destroy: $DESTROY_COUNT"
echo "Resources to replace: $REPLACE_COUNT"

# Gagalkan pipeline jika ada destroy di production
if [ "$ENVIRONMENT" = "production" ] && [ "$DESTROY_COUNT" -gt 0 ]; then
  echo "ERROR: Destroy operations detected in production plan!"
  echo "Destroy operations require manual review and explicit override."
  exit 1
fi

# Warning jika ada replace di production
if [ "$ENVIRONMENT" = "production" ] && [ "$REPLACE_COUNT" -gt 0 ]; then
  echo "WARNING: Replace operations detected (resource will be destroyed and recreated)"
  echo "This may cause downtime. Ensure this is intentional."
  # Tidak exit — hanya warning, tetap butuh human approval via environment protection
fi
# Integrasikan check ke pipeline
- name: Check Plan Safety
  run: bash ./scripts/check-plan-safety.sh
  env:
    ENVIRONMENT: ${{ steps.env.outputs.environment }}
  working-directory: infrastructure/environments/${{ steps.env.outputs.environment }}

Rollback Strategy #

Automated apply yang gagal di tengah jalan bisa meninggalkan infrastruktur dalam kondisi partial — sebagian resource sudah dibuat, sebagian belum. Punya strategi rollback yang jelas sangat penting.

STRATEGI ROLLBACK TERRAFORM:

OPSI 1: Re-apply versi sebelumnya (paling aman)
  - Revert commit di Git
  - Pipeline otomatis trigger apply versi lama
  - Terraform akan mengembalikan infrastruktur ke kondisi sebelumnya
  Catatan: Ini hanya bekerja jika resource yang bermasalah bisa diubah kembali
           (tidak semua resource bisa di-rollback dengan aman)

OPSI 2: Terraform apply dari state point tertentu
  - terraform state pull > backup.tfstate  (sebelum apply)
  - Jika apply gagal: terraform apply -target=resource.yang.perlu.diperbaiki
  Catatan: -target hanya untuk perbaikan darurat, bukan workflow rutin

OPSI 3: Restore dari state backup
  - Jika state korup atau tidak konsisten
  - Restore tfstate dari backup sebelumnya
  - Kemudian jalankan plan untuk melihat perbedaan

PENCEGAHAN LEBIH BAIK DARI ROLLBACK:
  ✓ Selalu backup state sebelum apply besar
  ✓ Gunakan create_before_destroy untuk resource kritikal
  ✓ Test perubahan di staging sebelum production
  ✓ Simpan plan output — bisa menjadi referensi saat debugging

Notifikasi Setelah Apply #

Tim perlu tahu ketika infrastruktur berubah — baik berhasil maupun gagal.

# Notifikasi ke Slack setelah apply
- name: Notify Slack on Success
  if: success()
  uses: slackapi/slack-github-action@v1
  with:
    payload: |
      {
        "text": "✅ Terraform apply berhasil",
        "blocks": [
          {
            "type": "section",
            "text": {
              "type": "mrkdwn",
              "text": "*✅ Terraform Apply Berhasil*\nEnvironment: `${{ steps.env.outputs.environment }}`\nCommit: `${{ github.sha }}`\nPR: ${{ github.event.pull_request.html_url }}"
            }
          }
        ]
      }      
  env:
    SLACK_WEBHOOK_URL: ${{ secrets.SLACK_INFRA_WEBHOOK }}

- name: Notify Slack on Failure
  if: failure()
  uses: slackapi/slack-github-action@v1
  with:
    payload: |
      {
        "text": "🚨 Terraform apply GAGAL",
        "blocks": [
          {
            "type": "section",
            "text": {
              "type": "mrkdwn",
              "text": "*🚨 Terraform Apply GAGAL*\nEnvironment: `${{ steps.env.outputs.environment }}`\nLihat log: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
            }
          }
        ]
      }      
  env:
    SLACK_WEBHOOK_URL: ${{ secrets.SLACK_INFRA_WEBHOOK }}

Ringkasan #

  • Prasyarat automated apply: remote state dengan locking, review process melalui PR, credentials via OIDC, dan monitoring notifikasi.
  • GitOps: branch Git mencerminkan kondisi environment — merge ke develop = apply dev, merge ke main = apply production.
  • Dev dan staging bisa auto-apply setelah review; production selalu membutuhkan approval eksplisit melalui environment protection rules.
  • Safeguard deteksi destroy — cegah apply otomatis di production jika ada operasi delete yang tidak terduga dalam plan.
  • Rollback paling aman adalah revert commit di Git dan biarkan pipeline apply versi sebelumnya — ini adalah keunggulan GitOps.
  • Notifikasi selalu ada — tim harus tahu setiap kali infrastruktur berubah, baik berhasil maupun gagal, dengan link ke log yang bisa diaudit.

← Sebelumnya: Plan Approval Strategy   Berikutnya: Policy as Code →

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