Remote #

Remote state memindahkan file terraform.tfstate dari mesin lokalmu ke penyimpanan terpusat yang bisa diakses oleh semua anggota tim dan CI/CD pipeline. Ini bukan sekadar “state di tempat lain” — remote backend biasanya datang dengan fitur tambahan yang krusial: enkripsi at rest, versioning otomatis, dan state locking. Artikel ini membahas cara mengkonfigurasi backend yang paling umum digunakan dan kapan memilih yang mana.

Konsep Backend #

Backend adalah komponen Terraform yang bertanggung jawab menyimpan state dan menjalankan operasi tertentu. Secara default, backend adalah local. Mengkonfigurasi remote backend mengubah di mana state disimpan.

LOCAL BACKEND (default):
  State → terraform.tfstate (di mesinmu)
  Locking → tidak ada
  Versioning → terraform.tfstate.backup (1 versi saja)

REMOTE BACKEND (S3, GCS, Terraform Cloud, dll.):
  State → bucket/container di cloud
  Locking → DynamoDB / GCS locks / built-in
  Versioning → S3 versioning / built-in history
  Enkripsi → at rest + in transit
  Audit → access log tersedia
flowchart TD
    A["terraform apply"] --> B{"Backend?"}

    B -->|"Default\n(local)"| C["terraform.tfstate"]
    B -->|"Remote"| D["S3 / GCS /\nTerraform Cloud"]

    C --> E["⚠️ Tidak ada locking"]
    C --> F["1 file backup saja"]
    C --> G["Tidak ter-encrypt"]

    D --> H["✅ State locking"]
    D --> I["✅ Versioning otomatis"]
    D --> J["✅ Enkripsi at rest"]
    D --> K["✅ Audit log"]

    style A fill:#e3f2fd,stroke:#1565c0
    style C fill:#fff3e0,stroke:#e65100
    style D fill:#e8f5e9,stroke:#2e7d32

Backend S3 (AWS) #

S3 adalah pilihan paling umum untuk tim yang bekerja di AWS. Kombinasi S3 untuk storage dan DynamoDB untuk locking adalah pola standar industri.

# backend.tf
terraform {
  backend "s3" {
    bucket         = "my-terraform-state-prod"
    key            = "production/terraform.tfstate"
    region         = "ap-southeast-1"

    # Enkripsi at rest
    encrypt        = true

    # State locking menggunakan DynamoDB
    dynamodb_table = "terraform-state-lock"

    # Opsional: gunakan IAM role untuk akses
    # role_arn = "arn:aws:iam::123456789:role/TerraformStateRole"
  }
}
# Buat resource S3 bucket dan DynamoDB table untuk state backend
# (biasanya dikerjakan terpisah sebelum konfigurasi utama)

resource "aws_s3_bucket" "terraform_state" {
  bucket = "my-terraform-state-prod"

  # Mencegah penghapusan bucket yang berisi state
  lifecycle {
    prevent_destroy = true
  }
}

resource "aws_s3_bucket_versioning" "terraform_state" {
  bucket = aws_s3_bucket.terraform_state.id
  versioning_configuration {
    status = "Enabled"  # Wajib — memungkinkan recovery state lama
  }
}

resource "aws_s3_bucket_server_side_encryption_configuration" "terraform_state" {
  bucket = aws_s3_bucket.terraform_state.id
  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "AES256"
    }
  }
}

resource "aws_dynamodb_table" "terraform_lock" {
  name         = "terraform-state-lock"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }
}
flowchart TD
    A["Terraform\nKonfigurasi"] --> B["S3 Bucket\n(state storage)"]
    A --> C["DynamoDB Table\n(locking)"]
    B --> D["Versioning\naktif"]
    B --> E["Enkripsi\nAES256"]
    B --> F["prevent_destroy\nlifecycle"]

    style A fill:#e3f2fd,stroke:#1565c0
    style B fill:#e8f5e9,stroke:#2e7d32
    style C fill:#fff3e0,stroke:#e65100

Backend GCS (Google Cloud) #

Untuk tim yang bekerja di Google Cloud, GCS backend sudah mendukung locking secara native tanpa perlu resource tambahan.

terraform {
  backend "gcs" {
    bucket  = "my-terraform-state"
    prefix  = "production"
    # GCS backend sudah built-in locking — tidak perlu resource tambahan
  }
}

Terraform Cloud / HCP Terraform #

Terraform Cloud (sekarang bernama HCP Terraform) adalah opsi managed yang menyertakan state storage, locking, versioning, run history, dan UI untuk review plan — semua dalam satu paket.

terraform {
  cloud {
    organization = "my-org"

    workspaces {
      name = "production"
    }
  }
}
# Login ke Terraform Cloud
terraform login
# Akan membuka browser untuk autentikasi

# Setelah login, init akan setup workspace di Terraform Cloud
terraform init

Struktur Key yang Baik untuk S3 #

Saat menggunakan S3 backend untuk beberapa environment atau proyek, struktur key yang konsisten memudahkan navigasi.

STRUKTUR KEY YANG DIREKOMENDASIKAN:

s3://my-terraform-state/
  ├── production/
  │   ├── networking/terraform.tfstate
  │   ├── compute/terraform.tfstate
  │   └── database/terraform.tfstate
  ├── staging/
  │   ├── networking/terraform.tfstate
  │   └── compute/terraform.tfstate
  └── dev/
      └── terraform.tfstate

Konfigurasi per environment:
  key = "production/networking/terraform.tfstate"
  key = "production/compute/terraform.tfstate"
  key = "staging/networking/terraform.tfstate"

Remote State Output: Membaca State dari Workspace Lain #

Salah satu fitur powerful remote state adalah kemampuan membaca output dari workspace Terraform lain. Ini memungkinkan infrastruktur di-modularisasi ke beberapa workspace yang terpisah tapi bisa saling berbagi data.

# Workspace "networking" membuat VPC dan meng-output VPC ID
# outputs.tf di workspace networking:
output "vpc_id" {
  value = aws_vpc.main.id
}

output "private_subnet_ids" {
  value = aws_subnet.private[*].id
}
# Workspace "compute" membaca output dari workspace "networking"
data "terraform_remote_state" "networking" {
  backend = "s3"

  config = {
    bucket = "my-terraform-state"
    key    = "production/networking/terraform.tfstate"
    region = "ap-southeast-1"
  }
}

# Gunakan output dari workspace networking
resource "aws_instance" "web" {
  ami       = var.ami_id
  subnet_id = data.terraform_remote_state.networking.outputs.private_subnet_ids[0]
}
terraform_remote_state membuat coupling langsung antara dua workspace — perubahan output di workspace networking bisa berdampak ke workspace compute. Pertimbangkan menggunakan variable input dan mengoper nilainya secara eksplisit jika coupling yang erat ini tidak diinginkan.
sequenceDiagram
    participant C as Workspace Compute
    participant B as Backend S3
    participant N as Workspace Networking
    
    Note over N: terraform apply selesai
    N->>B: Tulis state + outputs
    Note over B: State tersimpan<br/>vpc_id = vpc-abc123<br/>subnet_ids = [subnet-x, subnet-y]
    
    Note over C: terraform plan dimulai
    C->>B: data "terraform_remote_state" "networking"
    B-->>C: Return outputs
    C->>C: Gunakan vpc_id, subnet_ids
    Note over C: Plan selesai

    style N fill:#e8f5e9,stroke:#2e7d32
    style B fill:#fff3e0,stroke:#e65100
    style C fill:#e3f2fd,stroke:#1565c0
flowchart LR
    A["Workspace\nNetworking"] -->|outputs:\nvpc_id, subnet_ids| B["terraform_remote_state\ndata source"]
    B -->|baca output| C["Workspace\nCompute"]
    C -->|"subnet_id =\ndata.terraform_remote_state...\n.outputs.private_subnet_ids[0]"| D["aws_instance.web"]

    style A fill:#e8f5e9,stroke:#2e7d32
    style B fill:#fff3e0,stroke:#e65100
    style C fill:#e3f2fd,stroke:#1565c0

Multi-Backend Failover #

Terraform tidak mendukung failover backend secara native — jika backend S3 down, terraform apply akan gagal. Tapi ada pola yang bisa diterapkan untuk meningkatkan resilience.

# PROBLEM: S3 backend unavailable → pipeline stuck
$ terraform plan
# Error: failed to retrieve state from S3: RequestError...
# → Seluruh pipeline CI/CD terhenti

# SOLUSI 1: Cross-region replication pada S3 bucket
# Aktifkan cross-region replication pada S3 state bucket
resource "aws_s3_bucket_replication_configuration" "terraform_state" {
  role   = aws_iam_role.replication.arn
  bucket = aws_s3_bucket.terraform_state.id

  rule {
    id     = "replicate-state"
    status = "Enabled"

    destination {
      bucket        = aws_s3_bucket.terraform_state_replica.arn
      storage_class = "STANDARD"
    }
  }
}

# Bucket replica di region berbeda
resource "aws_s3_bucket" "terraform_state_replica" {
  provider = aws.replica_region
  bucket   = "my-terraform-state-prod-replica"
}

# BACKEND TIDAK BISA OTOMATIS FAILOVER
# Tapi jika S3 primary down, kamu bisa temporary switch backend:
# LANGKAH EMERGENCY: Switch ke backup bucket
# 1. Update backend.tf ke bucket replica
# 2. Jalankan terraform init untuk reconfigure
terraform init -migrate-state -force-copy
# 3. Setelah primary kembali, switch kembali dan re-migrate

# SOLUSI 2: Backend configuration dengan workspace
# Simpan konfigurasi backend di Terraform Cloud/Enterprise
# yang hosted oleh HashiCorp → availability lebih tinggi

State Encryption Deep Dive #

# AWS S3 SSE-S3 (default encryption, basic)
# Setiap object di-encrypt dengan S3-managed key
# Tidak perlu konfigurasi — aktif otomatis di bucket baru

# AWS S3 SSE-KMS (recommended untuk production)
# Enkripsi menggunakan KMS key yang bisa di-manage sendiri
# Memungkinkan audit trail siapa yang mengakses key
# SSE-KMS encryption untuk state bucket
resource "aws_s3_bucket_server_side_encryption_configuration" "terraform_state" {
  bucket = aws_s3_bucket.terraform_state.id

  rule {
    apply_server_side_encryption_by_default {
      kms_key_id        = aws_kms_key.terraform_state.arn
      sse_algorithm     = "aws:kms"
    }
    bucket_key_enabled = true  # Mengurangi KMS API costs
  }
}

resource "aws_kms_key" "terraform_state" {
  description             = "KMS key untuk Terraform state encryption"
  deletion_window_in_days = 30
  enable_key_rotation     = true  # Auto-rotate key setiap tahun
}

resource "aws_kms_alias" "terraform_state" {
  name          = "alias/terraform-state"
  target_key_id = aws_kms_key.terraform_state.key_id
}
PERBANDINGAN ENCRYPTION OPTIONS:

  SSE-S3 (AES256):
    Keamanan: Standar
    Key management: S3-managed (tidak bisa diatur)
    Audit: Tidak bisa track siapa yang decrypt
    Cost: Gratis
    Cocok untuk: Dev, staging, proyek personal

  SSE-KMS:
    Keamanan: Tinggi
    Key management: Customer-managed key (CMK)
    Audit: CloudTrail log semua key usage
    Cost: $1/key/month + API call charges
    Cocok untuk: Production, compliance requirements

  Customer-provided key (SSE-C):
    Keamanan: Sangat tinggi
    Key management: Customer supplies key di setiap request
    Audit: Full control
    Cost: Gratis (tapi management overhead tinggi)
    Cocok untuk: Extreme security requirements (jarang dipakai)

Remote State Data Lifecycle #

Memahami lifecycle remote state membantu merencanakan strategy penanganan state dari pembuatan hingga penghapusan.

flowchart TD
    A["terraform init\n(setup backend)"] --> B["State kosong"]
    B --> C["terraform apply #1\n(buat resource pertama)"]
    C --> D["State v1\n(serial: 1)"]
    D --> E["terraform apply #2\n(tambah resource)"]
    E --> F["State v2\n(serial: 2)"]
    F --> G["S3 Versioning:\nv1 tetap tersimpan"]
    G --> H["terraform destroy\n(hapus semua resource)"]
    H --> I["State vN\n(serial: N, resources: [])"]
    I --> J["State tetap di S3\n(empty tapi ada)"]
    J --> K["Manual cleanup\ndiperlukan"]

    style A fill:#e3f2fd,stroke:#1565c0
    style D fill:#e8f5e9,stroke:#2e7d32
    style G fill:#fff3e0,stroke:#e65100
    style K fill:#ffebee,stroke:#c62828
# State setelah terraform destroy TIDAK otomatis terhapus dari S3
# State berisi {"resources":[]} tapi file tetap ada
# Plus semua versi lama tetap ada di S3 versioning

# Cleanup state yang sudah tidak dipakai:
# 1. Hapus current state version
aws s3 rm s3://my-terraform-state/production/terraform.tfstate

# 2. Hapus semua versi lama (termasuk delete markers)
aws s3api list-object-versions \
  --bucket my-terraform-state \
  --prefix production/terraform.tfstate \
  --query 'Versions[*].[VersionId,Key]' \
  --output text | while read vid key; do
    aws s3api delete-object --bucket my-terraform-state --key "$key" --version-id "$vid"
  done

# 3. Hapus DynamoDB lock entry (jika masih ada)
aws dynamodb delete-item \
  --table-name terraform-state-lock \
  --key '{"LockID":{"S":"my-terraform-state/production/terraform.tfstate"}}'
# MONITORING STATE BUCKET:
# Ukuran state file biasanya kecil (KB-MB), tapi versioning bisa
# mengakumulasi storage jika sering apply

# Cek jumlah versi per state file
aws s3api list-object-versions \
  --bucket my-terraform-state \
  --query 'length(Versions)'

# Set lifecycle policy untuk auto-cleanup versi lama
# (jika tidak ingin simpan semua history)
# Lifecycle rule untuk menghapus versi lama
resource "aws_s3_bucket_lifecycle_configuration" "terraform_state" {
  bucket = aws_s3_bucket.terraform_state.id

  rule {
    id     = "cleanup-old-versions"
    status = "Enabled"

    noncurrent_version_expiration {
      noncurrent_days = 90  # Hapus versi lama setelah 90 hari
    }

    noncurrent_version_transition {
      noncurrent_days = 30
      storage_class   = "GLACIER"  # Pindah ke Glacier setelah 30 hari
    }
  }
}

Ringkasan #

  • Remote backend memindahkan state ke penyimpanan terpusat dengan fitur tambahan: enkripsi, versioning otomatis, dan locking.
  • S3 + DynamoDB adalah kombinasi standar industri untuk AWS — S3 untuk storage, DynamoDB untuk locking.
  • GCS backend sudah built-in locking — tidak butuh resource tambahan seperti DynamoDB.
  • Terraform Cloud adalah opsi managed lengkap — state storage, locking, run history, dan UI dalam satu paket.
  • Struktur key yang konsisten di S3 (<env>/<component>/terraform.tfstate) memudahkan navigasi untuk proyek multi-environment.
  • terraform_remote_state memungkinkan workspace lain membaca output — powerful tapi menciptakan coupling, gunakan dengan pertimbangan.
  • Multi-backend failover tidak didukung native — gunakan S3 cross-region replication dan reconfigure backend saat darurat.
  • SSE-KMS direkomendasikan untuk production — menyediakan audit trail melalui CloudTrail dan key rotation otomatis.
  • State tetap ada di S3 setelah terraform destroy — lakukan manual cleanup untuk menghapus file kosong dan versi lama.
  • S3 lifecycle policy bisa otomatis memindahkan versi lama ke Glacier dan menghapus setelah 90 hari.

← Sebelumnya: Local   Berikutnya: Locking →

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