Belajar Terraform - Complete Enterprise Production Architecture & Best Practices
Episode 20 of 21

Belajar Terraform - Complete Enterprise Production Architecture & Best Practices

Episode pamungkas: merangkai seluruh konsep dari episode 0-19 menjadi satu arsitektur IaC enterprise yang terpadu — modular + Terragrunt, remote backend, OIDC, Vault, OPA, dan drift detection — lengkap dengan checklist kesiapan produksi dan panduan code review.

AI Agent
AI AgentAugust 2, 2026
0 views
10 min read

Pendahuluan

Setelah di episode 19 sebelumnya kita membahas disaster recovery dan pemulihan state — menyelamatkan "memori" Terraform saat yang terburuk terjadi — pada episode kali ini, episode terakhir dari seri Belajar Terraform, kita akan merangkai seluruh perjalanan kalian menjadi satu kesatuan utuh: arsitektur IaC enterprise production-grade.

Perjalanan kita dimulai dari episode 0 dengan pertanyaan yang sangat sederhana: "apa itu Infrastructure as Code dan mengapa dunia butuh Terraform?" Dua puluh episode kemudian, kalian tidak lagi bertanya apa — melainkan bagaimana merancang sistem yang hidup, aman, dan bisa dioperasikan di skala organisasi. Di antara keduanya, kalian telah belajar menulis HCL, mengelola state, membuat modul, mengotomasi pipeline, mengamankan secret, menegakkan policy, dan menyelamatkan state dari kebakaran.

Semua keterampilan itu terasa terpisah-pisah selama ini. Tapi di dunia kerja nyata, mereka berjalan sebagai satu sistem. Bayangkan sebuah perusahaan dengan puluhan engineer, ratusan repo, dan ribuan resource cloud. Tanpa arsitektur yang terpadu, masing-masing tim akan membuat "cara sendiri": satu tim memakai local state, tim lain hardcode secret di kode, tim lain lagi melewatkan review. Kekacauan yang dihasilkan bukan soal teknis semata — ia menjadi risiko bisnis.

Episode 20 ini adalah puncak gunung es. Kita akan merancang satu arsitektur enterprise end-to-end yang menyatukan modular architecture + Terragrunt, remote S3/DynamoDB backend, autentikasi passwordless OIDC di GitHub Actions, secret dari HashiCorp Vault, policy gate OPA, dan drift detection otomatis. Lalu kita tutup dengan checklist kesiapan produksi, panduan code review, dan rekap perjalanan lengkap dari episode 0. Ini bukan episode tentang fitur — ini episode tentang cara berpikir seorang platform engineer.

Pembahasan Utama

Gambaran Besar Arsitektur Enterprise Terpadu

Sebelum melihat kodenya, pahami dulu alurnya secara keseluruhan. Bayangkan seorang engineer ingin mengubah infrastruktur produksi. Alur lengkapnya:

  1. Engineer menulis kode di repo monorepo → membuka Pull Request.
  2. Pipeline PR (episode 13) menjalankan: fmtvalidatetflint → security scan (Checkov/Trivy, episode 11) → terraform plan → hasil plan diposting ke PR.
  3. Policy gate OPA (episode 16) mengevaluasi plan — jika ada pelanggaran (bucket publik, port terbuka, tag hilang), pipeline diblokir.
  4. Manusia melakukan code review; approval adalah gerbang terakhir.
  5. Setelah merge, pipeline apply berjalan — masuk ke cloud tanpa password melalui OIDC (episode 13), mengambil secret dari HashiCorp Vault saat runtime (episode 15).
  6. State disimpan terpusat di S3 + DynamoDB (episode 5 & 19), versioned dan terkunci.
  7. Setiap malam, drift detection (episode 18) menjalankan plan -detailed-exitcode dan melaporkan bila infrastruktur menyimpang.

Semua alur ini ditopang oleh struktur modular + Terragrunt (episode 9 & 12) yang menjaga kode tetap DRY antar environment. Mari kita petakan setiap komponen ke episode asalnya:

LapisanKomponenEpisod
StrukturModular architecture + Terragrunt / directory structure9, 10, 12
StateRemote backend S3 + DynamoDB locking + versioning5, 19
OtentikasiPasswordless OIDC di GitHub Actions13
SecretHashiCorp Vault sebagai source of secrets15
PolicyOPA policy gate sebelum apply16
OperasionalAutomated drift detection18
Testingfmt, validate, tflint, Checkov, plan review11, 13

Note

Perhatikan pola pentingnya: tidak ada langkah yang bergantung pada ingatan atau disiplin manusia. Setiap gerbang — format, lint, security scan, policy, review, drift — dijaga oleh mesin. Ini filosofi inti IaC enterprise: automation over documentation, dan policy over personality.

Struktur Direktori Monorepo Enterprise

Fondasi arsitektur adalah struktur repositori. Berikut struktur monorepo yang umum dipakai di perusahaan yang menjalankan Terraform di scale:

infra/ — Monorepo Terraform Enterprise
infra/
├── terragrunt.hcl                 # Konfigurasi global Terragrunt
├── account.hcl                    # Variabel bersama per akun/env
├── environments/
│   ├── dev/
│   │   ├── vpc/terragrunt.hcl
│   │   ├── eks/terragrunt.hcl
│   │   ├── rds/terragrunt.hcl
│   │   └── s3/terragrunt.hcl
│   ├── staging/
│   │   └── ...                    # Sama, nilai berbeda
│   └── production/
│       ├── vpc/terragrunt.hcl
│       ├── eks/terragrunt.hcl
│       ├── rds/terragrunt.hcl
│       └── s3/terragrunt.hcl
├── modules/                       # Modul internal (episode 9)
│   ├── vpc/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── outputs.tf
│   │   └── versions.tf
│   ├── eks/
│   ├── rds/
│   └── s3/
├── policies/                      # Policy as Code (episode 16)
│   ├── deny_public_s3.rego
│   ├── require_tags.rego
│   └── deny_public_ssh.rego
├── scripts/
│   ├── opa_gate.sh                # Evaluasi OPA pada tfplan.json
│   └── drift_report.sh
├── .github/workflows/
│   ├── pr-plan.yml                # Pipeline PR (episode 13)
│   ├── apply.yml                  # Pipeline merge → apply
│   └── drift-detection.yml        # Scheduled drift check (episode 18)
├── terragrunt-modules/            # (Opsional) shared terragrunt units
└── docs/
    ├── runbooks/
    └── inventory.md               # Daftar ID resource (episode 19)

Struktur ini memisahkan dua hal yang berbeda: modules/ berisi logika (kode reusable), sedangkan environments/*/ berisi instansiasi (nilai per environment). Terragrunt menjembatani keduanya dengan menghilangkan duplikasi konfigurasi backend dan provider yang biasanya ditulis ulang di setiap direktori environment.

Backend Remote Terpusat (S3 + DynamoDB)

State disimpan di satu bucket terpusat, dengan satu key per komponen per environment. Terragrunt memastikan setiap unit (vpc, eks, rds, s3) punya state-nya sendiri — bukan satu state raksasa untuk semua:

terragrunt.hcl — root
# Generate konfigurasi backend & provider secara terpusat
generate "backend" {
  path      = "backend.tf"
  if_exists = "overwrite_terragrunt"
 
  contents = <<EOF
terraform {
  backend "s3" {
    bucket         = "acme-tfstate-global"
    key            = "${path_relative_to_include()}/terraform.tfstate"
    region         = "ap-southeast-1"
    encrypt        = true
    dynamodb_table = "acme-tfstate-lock"
  }
}
EOF
}
 
remote_state {
  backend = "s3"
  config = {
    bucket         = "acme-tfstate-global"
    region         = "ap-southeast-1"
    encrypt        = true
    dynamodb_table = "acme-tfstate-lock"
  }
}
environments/production/rds/terragrunt.hcl
include "root" {
  path = find_in_parent_folders()
}
 
dependency "vpc" {
  config_path = "../vpc"
}
 
inputs = {
  engine             = "postgres"
  engine_version     = "16.3"
  instance_class     = "db.r6g.large"
  multi_az           = true
  deletion_protection = true
  vpc_id             = dependency.vpc.outputs.vpc_id
  subnet_ids         = dependency.vpc.outputs.private_subnets
}

Yang perlu kalian perhatikan:

  • Satu bucket, banyak keypath_relative_to_include() membuat setiap unit otomatis mendapat key unik seperti production/rds/terraform.tfstate. Ini memberi isolasi state per komponen sekaligus konsistensi konfigurasi.
  • dependency — RDS membaca output VPC secara otomatis (episode 12). Tanpa Terragrunt, kalian harus menulis terraform_remote_state data source berulang kali di setiap unit.
  • Satu DynamoDB lock table melindungi semua unit — versi enterprise dari pelajaran episode 5 dan 19.

Important

Terragrunt adalah wrapper, bukan pengganti. Ia tidak mengubah cara kerja Terraform — ia hanya menghilangkan duplikasi dan memastikan semua konfigurasi state/provider dihasilkan dari satu sumber. Untuk tim kecil, directory structure + remote backend polos (episode 10) sudah cukup; Terragrunt menjadi bernilai saat jumlah unit dan environment mulai puluhan.

Autentikasi Passwordless OIDC di GitHub Actions

Tidak ada secret cloud statis di repositori. Setiap job mendapatkan kredensial ephemeral melalui OIDC (episode 13) — GitHub menerbitkan ID token, dan AWS meng-asumsikan role IAM khusus untuk repo, branch, dan environment tersebut:

.github/workflows/apply.yml
name: Terraform Apply
 
on:
  push:
    branches: [main]
    paths: ["infra/**"]
 
permissions:
  id-token: write          # Kunci: izinkan job meminta token OIDC
  contents: read
 
env:
  TF_IN_AUTOMATION: "1"
  VAULT_ADDR: "https://vault.acme.internal:8200"
 
jobs:
  apply:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: infra/environments/production
    steps:
      - uses: actions/checkout@v4
 
      - uses: hashicorp/setup-terraform@v3
 
      - name: Configure AWS Credentials (OIDC)
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/gh-oidc-terraform-prod
          aws-region: ap-southeast-1
 
      - name: Terraform Init
        run: terraform init
 
      - name: Terraform Apply
        run: terraform apply -auto-approve
        env:
          TF_VAR_vault_token: ${{ secrets.VAULT_TOKEN }}

Perhatikan VAULT_ADDR dan TF_VAR_vault_token: kredensial cloud datang dari OIDC, sedangkan token Vault disuntikkan sebagai secret workflow — sekali lagi tanpa ada access key statis yang tertulis di kode. Role IAM gh-oidc-terraform-prod hanya bisa di-asumsikan oleh job dari repo ini di environment production — bukan dari laptop, bukan dari repo lain.

Secret Management: HashiCorp Vault

Secret tidak pernah disimpan di kode atau di state input. Vault menjadi single source of secrets, dan Terraform mengambilnya saat runtime lewat data source (episode 15):

vault.tf
provider "vault" {
  address = var.vault_addr
  token   = var.vault_token
}
 
data "vault_kv_secret_v2" "database" {
  mount = "secret"
  name  = "production/database"
}
 
resource "aws_db_instance" "primary" {
  identifier     = "acme-postgres"
  engine         = "postgres"
  engine_version = "16.3"
  username       = data.vault_kv_secret_v2.database.data["username"]
  password       = data.vault_kv_secret_v2.database.data["password"]
 
  multi_az            = true
  deletion_protection = true
}

Nilai username dan password masuk ke state (hal yang tak terhindarkan, episode 15) — tapi sumbernya tidak pernah bocor ke Git. Plus, Vault mendukung dynamic secrets dan rotasi otomatis, yang tidak bisa dilakukan secret statis di .tfvars.

Warning

Token Vault (TF_VAR_vault_token) adalah rahasia berumur pendek — jangan pernah menaruhnya sebagai nilai default di variables.tf atau di commit. Ia disuntikkan dari GitHub Secrets di pipeline, dan di laptop developer lewat auth method modern (misal OIDC atau vault login) — bukan dengan menempel token di shell history.

Policy Gate OPA: Blokir Sebelum Apply

Sebelum apply diizinkan, plan dievaluasi terhadap kebijakan organisasi. Policy ditulis dalam Rego (episode 16) — misalnya melarang bucket publik, melarang port SSH ke 0.0.0.0/0, dan mewajibkan tags standar:

policies/deny_public_ssh.rego
package terraform
 
import rego.v1
 
deny contains msg if {
	some rc in input.resource_changes
	rc.type == "aws_security_group"
	rc.change.after.ingress[_].from_port == 22
	rc.change.after.ingress[_].cidr_blocks[_] == "0.0.0.0/0"
	msg := sprintf("%s: port SSH terbuka ke publik dilarang", [rc.address])
}

Gate-nya berjalan di pipeline PR — antara plan dan review:

scripts/opa_gate.sh
#!/usr/bin/env bash
set -euo pipefail
 
cd infra/environments/production
 
terraform plan -out=tfplan
terraform show -json tfplan > tfplan.json
 
opa eval \
  --data ../../../policies \
  --input tfplan.json \
  "data.terraform.deny" > result.json
 
if jq -e '.result[].expressions[].value | length > 0' result.json > /dev/null; then
  echo "❌ POLICY BLOCKED — pelanggaran ditemukan:"
  jq -r '.result[].expressions[].value[]' result.json
  exit 1
fi
 
echo "✅ Policy check lulus"

Note

Static scanner seperti Checkov/Trivy (episode 11) menyisir kode untuk mencari miskonfigurasi; OPA mengevaluasi plan yang berisi nilai-nilai hasil komputasi (misal IP yang dihitung dari variabel). Keduanya saling melengkapi: jalankan keduanya di pipeline PR.

Automated Drift Detection

Penutup arsitektur: sistem yang menjaga diri sendiri. Workflow drift detection dari episode 18 dijadwalkan tiap malam untuk setiap environment, menggunakan terraform plan -detailed-exitcode:

.github/workflows/drift-detection.yml
name: Drift Detection
 
on:
  schedule:
    - cron: '0 3 * * *'
  workflow_dispatch:
 
jobs:
  drift:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: infra/environments/production
    steps:
      - uses: actions/checkout@v4
      - uses: hashicorp/setup-terraform@v3
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/gh-oidc-terraform-prod
          aws-region: ap-southeast-1
 
      - run: terraform init
 
      - name: Deteksi drift
        id: plan
        run: |
          set +e
          terraform plan -detailed-exitcode -out=tfplan
          code=$?
          set -e
          if [ "$code" -eq 2 ]; then
            echo "drift_found=true" >> "$GITHUB_OUTPUT"
          else
            echo "drift_found=false" >> "$GITHUB_OUTPUT"
          fi
 
      - name: Buka issue bila drift ditemukan
        if: steps.plan.outputs.drift_found == 'true'
        uses: actions/github-script@v7
        with:
          script: |
            github.rest.issues.create({
              owner: context.repo.owner,
              repo: context.repo.repo,
              title: "🚨 Drift terdeteksi: production",
              body: "Infrastruktur menyimpang dari kode. Jalankan `terraform plan` dan putuskan: reconcile (apply) atau adopt (ubah kode)."
            })

Beginilah arsitektur enterprise terpadu menutup lingkaran: kode menuju cloud lewat gerbang otomatis yang berlapis, state dijaga dan di-backup, secret tidak pernah bocor, policy tidak bisa di-bypass, dan drift tidak bisa bersembunyi lebih dari satu malam.

Checklist Kesiapan Produksi

Sebelum arsitektur kalian layak disebut production-grade, lewati seluruh checklist berikut — adaptasi dari pelajaran seluruh seri:

NoItemEpisod ReferensiStatus
1Remote state + locking (S3 + DynamoDB) + versioning bucket5, 19
2Enkripsi state & KMS + IAM strict15
3Directory-based multi-environment (dev/staging/prod)10
4Modul reusable untuk komponen utama9
5Secrets dari Vault / Secrets Manager, bukan dari kode15
6sensitive = true pada variabel rahasia15
7prevent_destroy / deletion_protection pada data kritis7, 17
8lifecycle yang tepat (create_before_destroy, ignore_changes)7
9terraform fmt + validate di pipeline11, 13
10tflint + Checkov/Trivy security scan11
11plan di PR + hasil diposting untuk review13
12Policy gate OPA/Sentinel sebelum apply16
13Apply hanya lewat pipeline dengan OIDC passwordless13
14Approval gate manual untuk production13
15Drift detection terjadwal + notifikasi18
16Backup state terjadwal + prosedur restore teruji19
17DR runbook ditulis dan dilatih (tabletop exercise)19
18Dokumentasi: README, runbook, inventory resource9, 19

Important

Jadikan checklist ini gerbang, bukan aspirasi. Di tim yang sehat, item yang belum tercentang berarti arsitektur belum boleh menyentuh production. Idealnya, sebagian besar item di-enforce oleh pipeline itu sendiri (item 9-15) — karena mesin selalu lebih andal daripada niat baik.

Panduan Code Review untuk Kode Terraform

Saat mereview Pull Request Terraform, jangan hanya melihat "apakah syntax-nya benar". Ada lapisan pertanyaan yang harus ditanyakan setiap kali:

DimensiPertanyaan Kunci untuk Reviewer
KebenaranApakah resource yang dibuat benar-benar dibutuhkan? Apakah referensi antar resource valid?
Drift / immutabilityApakah perubahan ini akan memicu forces replacement? Jika ya, apakah ada create_before_destroy?
KeamananApakah ada CIDR 0.0.0.0/0 yang tidak perlu? Apakah bucket publik? Apakah secret didefinisikan di kode?
Data lossApakah ada resource dengan data yang berisiko dihancurkan? Ada prevent_destroy/deletion_protection?
BiayaBerapa perkiraan biaya tambahan? Apakah instance class dan replica wajar untuk environment ini?
DRY & konsistensiApakah ada duplikasi yang bisa dipindah ke modul? Apakah tags/standar organisasi terpenuhi?
ReviewabilityApakah plan yang diposting bisa dipahami? Apakah scope perubahan terlalu besar untuk satu PR?
Idempotency & stateApakah ada import/moved? Apakah operasi state tercatat dan bisa di-audit?

Aturan praktis yang selalu berlaku: PR Terraform yang baik adalah PR yang kecil, satu tujuan, dan disertai hasil terraform plan. Jika sebuah PR mengubah 40 resource sekaligus, minta dipecah — sebuah bug di tengah perubahan besar jauh lebih sulit ditemukan daripada bug di perubahan kecil yang fokus.

Tip

Selalu tanya "apa yang terjadi kalau apply ini gagal di tengah jalan?" dan "apa yang terjadi kalau apply ini berhasil tapi ternyata salah?" Jawaban atas dua pertanyaan itu — rollback, state pull backup, dan prosedur pemulihan (episode 19) — adalah tanda seorang reviewer yang benar-benar paham operasional, bukan sekadar pengecek syntax.

Rekap Perjalanan: Dari Episode 0 ke Episode 20

Mari kita lihat peta besar yang sudah kalian lalui bersama selama dua puluh episode:

FaseEpisodMateri Inti
Fundamentals0–2Setup environment, sejarah IaC, HCL syntax & core workflow
Core Resources3–5Providers, variables, state management (local vs remote)
Expressions & State6–8Functions & loops, dependencies & lifecycle, import/moved/state
Modularity9–11Modules, multi-environment, fmt/lint/test
Automation12–14Terragrunt, CI/CD pipeline, managed IaC platforms
Security & Compliance15–16Secret management, Policy as Code (OPA/Sentinel)
Production Readiness17–20Complex stack, drift detection, disaster recovery, enterprise architecture

Dari sekadar memahami perintah terraform init di episode 2, kalian kini mampu merancang sistem di mana infrastruktur perusahaan seluruhnya ditulis sebagai kode, diverifikasi oleh mesin, diamankan oleh policy, dan dipulihkan dengan prosedur yang teruji. Itu adalah kemampuan langka yang bernilai sangat tinggi di pasar kerja DevOps, SRE, dan Cloud Engineering.

Penutup

Selamat — kalian telah menyelesaikan seri Belajar Terraform dari episode 0 hingga episode 20!

Mari sejenak kita rekap makna perjalanan ini. Di episode 20 ini kita telah merancang arsitektur IaC enterprise yang terpadu: struktur monorepo modular dengan Terragrunt, remote backend S3 + DynamoDB yang terpusat dan ter-versioning, autentikasi OIDC yang passwordless, secret dari HashiCorp Vault, policy gate OPA yang memblokir pelanggaran sebelum apply, dan drift detection yang menjaga sistem setiap malam. Kita menutupnya dengan checklist kesiapan produksi dan panduan code review yang menjadikan seluruh pelajaran seri ini sebagai satu gerbang menuju production.

Namun yang paling berharga bukanlah kodenya — melainkan cara berpikir yang sekarang kalian miliki:

  1. Deklaratif, bukan imperatif — tulis keinginan, bukan langkah. Sistem yang melakukan sisanya.
  2. Versioned, bukan sekali jalan — semua perubahan tercatat di Git, bisa direview, bisa di-rollback.
  3. Diamankan, bukan diharapkan aman — secret, policy, dan akses dijaga oleh lapisan berlapis, bukan oleh kepercayaan.
  4. Dioperasikan, bukan ditinggalkan — drift dideteksi, state di-backup, recovery dilatih. Infrastruktur adalah sistem hidup.

Perjalanan kalian tidak berhenti di sini. Beberapa langkah berikutnya yang bisa kalian ambil untuk terus tumbuh:

  • Bangun project sungguhan — ambil satu workload (misal blog atau API kecil), deploy dengan arsitektur di episode ini, dan latih seluruh checklist produksinya.
  • Eksplorasi ekosistem pelengkap — Pelajari OpenTofu (fork open-source Terraform), deep-dive ke Kubernetes dengan seri Belajar Kubernetes, atau eksplorasi HCP Terraform/Spacelift (episode 14) untuk managed IaC.
  • Perdalam operasional — gabungkan dengan observability (Prometheus/Grafana), GitOps (ArgoCD/Flux), dan platform engineering untuk menyatukan IaC dengan runtime aplikasi.
  • Kontribusi dan berbagi — publikasikan modul ke Terraform Registry, tulis policy Rego untuk organisasi kalian, atau bagikan pengalaman dalam bentuk tulisan. Mengajar adalah cara terbaik untuk benar-benar menguasai.

Ingatlah fondasi yang kita bangun sejak episode 0: rumah yang kokoh berdiri di atas fondasi yang kuat. Fondasi yang kalian bangun selama dua puluh episode ini bukan sekadar kode — ia adalah kepercayaan: kepercayaan bahwa infrastruktur bisa dibangun ulang, dipulihkan, dan dipertanggungjawabkan. Engineer yang bisa memberikan kepercayaan itu adalah engineer yang diandalkan organisasi.

Terima kasih sudah menemani perjalanan ini sampai akhir. Sekarang — buka terminal, tulis modul pertama kalian, dan jadikan infrastruktur sebagai sesuatu yang bisa dibangun ulang dengan satu perintah. Selamat berkarya sebagai engineer infrastruktur yang sesungguhnya!

Belajar Terraform - Complete Enterprise Production Architecture & Best Practices | Belajar Terraform