L
Infrastructure as Code (IaC) β€’ Literally Web ID

Implementasi Infrastructure as Code (IaC) dengan Terraform dan AWS Cloud

⏱️ 22 menit baca β€’ πŸ“… 13 Oct 2026 β€’ πŸ‘οΈ 1 views
Implementasi Infrastructure as Code (IaC) dengan Terraform dan AWS Cloud

1. Konteks Industri & Analisis Akar Masalah

Dalam lanskap pengembangan web modern dan arsitektur infrastruktur enterprise, manajemen infrastruktur manual melalui Console AWS (ClickOps) atau skrip bash ad-hoc telah menjadi bottleneck utama dalam skalabilitas, keamanan, dan keandalan sistem. Ketika sebuah perusahaan web berkembang dari startup kecil menjadi enterprise dengan jutaan pengguna harian, kompleksitas ekosistem webβ€”yang mencakup Load Balancer (ALB), Web Server (Nginx/Apache), aplikasi backend (Go/Node.js/PHP-FPM), sistem database terdistribusi (MySQL/Aurora), caching layer (Redis), manajemen DNS global (Route53/Cloudflare), hingga lapisan keamanan (WAF, SSL/TLS Let's Encrypt)β€”tidak lagi dapat dikelola secara manual tanpa mengundang bencana human error.

Akar masalah dari konfigurasi manual adalah tidak adanya 'Single Source of Truth' (SSOT) yang dapat dilacak, diuji, dan direplikasi. Kondisi sebelum penerapan Infrastructure as Code (IaC) sering kali ditandai oleh fenomena Configuration Drift, di mana lingkungan Staging dan Production berbeda secara signifikan karena perubahan manual yang tidak tercatat, menyebabkan kegagalan deployment yang sulit didiagnosis. Selain itu, pemulihan bencana (Disaster Recovery) memakan waktu berjam-jam bahkan berhari-hari karena tim harus membangun ulang infrastruktur dari nol secara manual.

Dengan mengadopsi Terraform dan AWS Cloud, kita mengubah seluruh infrastruktur menjadi kode deklaratif. Kondisi sesudah penerapan ditandai oleh otomatisasi penuh, kemampuan preview perubahan melalui perintah terraform plan, reproduktifitas lingkungan yang instan, serta auditibilitas keamanan melalui kontrol versi (Git). Buku panduan ini akan mengupas tuntas cara merancang, mengimplementasikan, dan mengoptimalkan arsitektur web multi-tier menggunakan Terraform di AWS, mulai dari manajemen state, pembuatan modul reusable, hingga best practices keamanan tingkat enterprise.

2. Konteks Inti & Deep Dive Arsitektur

Terraform bekerja dengan prinsip declarative syntax menggunakan HashiCorp Configuration Language (HCL). Berbeda dengan skrip prosedural yang mendikte bagaimana sesuatu harus dilakukan langkah demi langkah, Terraform mendefinisikan apa hasil akhir yang diinginkan. Mesin Terraform kemudian menghitung dependency graph dan mengeksekusi rencana eksekusi (execution plan) untuk mencapai kondisi tersebut.

[!IMPORTANT] Memahami arsitektur state management adalah kunci utama dalam mencegah korupsi data infrastruktur saat bekerja dalam tim kolaboratif.

Di balik layar, Terraform menggunakan State File (terraform.tfstate) sebagai peta yang menghubungkan sumber daya di dunia nyata dengan konfigurasi HCL Anda. State ini menyimpan metadata, mapping resource ID, dan atribut sensitif. Untuk lingkungan produksi, state file tidak boleh disimpan secara lokal, melainkan harus disimpan di backend terpusat yang aman seperti AWS S3 dengan enkripsi KMS, disertai penguncian status (State Locking) menggunakan AWS DynamoDB untuk mencegah race condition.

Berikut adalah representasi visual dari alur eksekusi dan arsitektur multi-tier yang akan kita bangun:

+-------------------------------------------------------------------------+
|                           AWS Cloud Environment                         |
|                                                                         |
|   +-----------------------------------------------------------------+   |
|   |                           VPC (10.0.0.0/16)                     |   |
|   |                                                                 |   |
|   |   +--------------------------+     +------------------------+   |   |
|   |   |  Public Subnet A         |     |  Public Subnet B       |   |   |
|   |   |  (ALB / Internet Facing) |     |  (ALB / NAT Gateway)   |   |   |
|   |   +------------+-------------+     +-----------+------------+   |   |
|   |                |                               |                |   |
|   |                v                               v                |   |
|   |   +--------------------------+     +------------------------+   |   |
|   |   |  Private Subnet A        |     |  Private Subnet B      |   |   |
|   |   |  (App: Nginx + Node/Go)  |     |  (App: Nginx + Node/Go)  |   |   |
|   |   +------------+-------------+     +-----------+------------+   |   |
|   |                |                               |                |   |
|   |                v                               v                |   |
|   |   +--------------------------+     +------------------------+   |   |
|   |   |  Database Subnet A       |     |  Database Subnet B     |   |   |
|   |   |  (MySQL RDS / Multi-AZ)  |     |  (Redis ElastiCache)   |   |   |
|   |   +--------------------------+     +------------------------+   |   |
|   +-----------------------------------------------------------------+   |
+-------------------------------------------------------------------------+

Alur data dan eksekusi berjalan sebagai berikut:

  1. Developer menulis kode HCL dan menjalankan terraform init, terraform plan, dan terraform apply.
  2. Terraform berkomunikasi dengan AWS API untuk mem-provision VPC, Subnet, Security Groups, EC2 Instances, RDS, dan ElastiCache.
  3. Terraform memperbarui terraform.tfstate yang disimpan secara aman di S3 dan dikunci via DynamoDB.
  4. Traffic web masuk melalui Application Load Balancer (ALB) di public subnet, diteruskan ke web/app server di private subnet, yang kemudian berinteraksi dengan database MySQL dan cache Redis.

3. Perbandingan Komparatif / Analisis Pendekatan

Dalam membangun infrastruktur cloud, terdapat beberapa pendekatan utama selain Terraform. Tabel berikut menyajikan analisis komparatif mendalam dari berbagai aspek teknis.

Parameter Komparasi Terraform (HashiCorp) AWS CloudFormation AWS CDK (Cloud Development Kit) Ansible (Infrastructure Provisioning)
Paradigma Deklaratif (HCL) Deklaratif (JSON/YAML) Imperatif/Deklaratif (TypeScript/Python) Imperatif (YAML Playbooks)
Cloud Provider Multi-Cloud (AWS, GCP, Azure, dll) Eksklusif AWS Eksklusif AWS (mengkompilasi ke CFn) Multi-Cloud (Konfigurasi & Manajemen OS)
State Management Remote State (S3, Consul, Terraform Cloud) Managed di AWS CloudFormation Service Managed di AWS CloudFormation Service Tanpa State Center (mengandalkan Inventory)
Learning Curve Sedang (HCL mudah dipahami) Tinggi (YAML sangat panjang & verbose) Tinggi (Membutuhkan pemahaman OOP & CloudFormation) Rendah hingga Sedang
Kecepatan Eksekusi Cepat (Parallel graph execution) Lambat (Bergantung pada queue CloudFormation) Lambat (Melalui engine CloudFormation) Sedang (Berbasis SSH/WinRM secara sekuensial)
Trade-off Sumber Daya Memerlukan manajemen state file secara mandiri Batasan ketat pada ukuran template stack Kompleksitas debugging karena abstraksi ganda Kurang optimal untuk provisioning resource cloud tingkat rendah

[!TIP] Untuk arsitektur berbasis AWS murni dengan kebutuhan multi-tier web hosting yang kompleks, kombinasi Terraform untuk provisioning infrastruktur dasar dan Ansible untuk konfigurasi OS/aplikasi bagian dalam adalah standar industri yang paling handal.

4. Prasyarat Sistem & Persiapan Lingkungan

Sebelum menyelam ke dalam kode implementasi, pastikan lingkungan kerja lokal atau CI/CD runner Anda memenuhi spesifikasi berikut:

  • Terraform CLI: Versi 1.5.0 atau yang lebih baru.
  • AWS CLI: Versi 2.x terkonfigurasi dengan kredensial yang memiliki hak akses penuh (AdministratorAccess untuk setup awal, atau policy spesifik least-privilege untuk production).
  • Git: Untuk version control.
  • Make (Opsional): Untuk memudahkan otomatisasi perintah deployment.

Langkah verifikasi awal di terminal:

terraform --version
aws --version
git --version

Pastikan Anda telah membuat IAM User atau IAM Role dengan policy yang mencakup pembuatan VPC, EC2, RDS, IAM, S3, dan DynamoDB. Konfigurasikan kredensial AWS Anda melalui perintah:

aws configure

5. Panduan Implementasi Langkah demi Langkah

Kita akan membangun struktur direktori proyek enterprise yang bersih dan modular. Struktur direktori adalah sebagai berikut:

terraform-aws-enterprise-web/
β”œβ”€β”€ backend.tf
β”œβ”€β”€ main.tf
β”œβ”€β”€ variables.tf
β”œβ”€β”€ outputs.tf
└── modules/
    β”œβ”€β”€ vpc/
    β”‚   β”œβ”€β”€ main.tf
    β”‚   β”œβ”€β”€ variables.tf
    β”‚   └── outputs.tf
    β”œβ”€β”€ compute/
    β”‚   β”œβ”€β”€ main.tf
    β”‚   β”œβ”€β”€ variables.tf
    β”‚   └── outputs.tf
    └── database/
        β”œβ”€β”€ main.tf
        β”œβ”€β”€ variables.tf
        └── outputs.tf

5.1. Konfigurasi Backend (backend.tf)

File ini mengatur penyimpanan remote state secara aman di S3 dan DynamoDB untuk locking.

terraform {
  required_version = ">= 1.5.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }

  backend "s3" {
    bucket         = "company-terraform-state-prod-xyz"
    key            = "web-infrastructure/terraform.tfstate"
    region         = "ap-southeast-1"
    dynamodb_table = "company-terraform-locks"
    encrypt        = true
  }
}

provider "aws" {
  region = var.aws_region

  default_tags {
    tags = {
      Environment = var.environment
      ManagedBy   = "Terraform"
      Project     = "Enterprise-Web"
    }
  }
}

5.2. Definisi Variabel Global (variables.tf)

variable "aws_region" {
  type        = string
  description = "AWS Region utama untuk deployment"
  default     = "ap-southeast-1"
}

variable "environment" {
  type        = string
  description = "Nama lingkungan (production, staging)"
  default     = "production"
}

variable "vpc_cidr" {
  type        = string
  description = "CIDR block untuk VPC"
  default     = "10.0.0.0/16"
}

5.3. Modul VPC (modules/vpc/main.tf)

Modul ini membuat Virtual Private Cloud dengan public dan private subnet di dua Availability Zones untuk high availability.

resource "aws_vpc" "main" {
  cidr_block           = var.vpc_cidr
  enable_dns_hostnames = true
  enable_dns_support   = true

  tags = {
    Name = "${var.environment}-vpc"
  }
}

data "aws_availability_zones" "available" {
  state = "available"
}

resource "aws_subnet" "public" {
  count                   = 2
  vpc_id                  = aws_vpc.main.id
  cidr_block              = cidrsubnet(var.vpc_cidr, 8, count.index)
  availability_zone       = data.aws_availability_zones.available.names[count.index]
  map_public_ip_on_launch = true

  tags = {
    Name = "${var.environment}-public-subnet-${count.index + 1}"
  }
}

resource "aws_subnet" "private" {
  count             = 2
  vpc_id            = aws_vpc.main.id
  cidr_block        = cidrsubnet(var.vpc_cidr, 8, count.index + 10)
  availability_zone = data.aws_availability_zones.available.names[count.index]

  tags = {
    Name = "${var.environment}-private-subnet-${count.index + 1}"
  }
}

resource "aws_internet_gateway" "gw" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "${var.environment}-igw"
  }
}

resource "aws_route_table" "public" {
  vpc_id = aws_vpc.main.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.gw.id
  }

  tags = {
    Name = "${var.environment}-public-rt"
  }
}

resource "aws_route_table_association" "public" {
  count          = 2
  subnet_id      = aws_subnet.public[count.index].id
  route_table_id = aws_route_table.public.id
}

5.4. Modul Compute & Web Server (modules/compute/main.tf)

Modul ini memprovisioning Application Load Balancer dan Auto Scaling Group untuk instance web server Nginx/Node.js di private subnet.

resource "aws_security_group" "alb" {
  name        = "${var.environment}-alb-sg"
  description = "Security group untuk ALB web publik"
  vpc_id      = var.vpc_id

  ingress {
    description = "Allow HTTP dari internet"
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    description = "Allow HTTPS dari internet"
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_lb" "web" {
  name               = "${var.environment}-web-alb"
  internal           = false
  load_balancer_type = "application"
  security_groups    = [aws_security_group.alb.id]
  subnets            = var.public_subnet_ids

  enable_deletion_protection = false
}

resource "aws_lb_target_group" "web" {
  name     = "${var.environment}-web-tg"
  port     = 80
  protocol = "HTTP"
  vpc_id   = var.vpc_id

  health_check {
    path                = "/health"
    healthy_threshold   = 2
    unhealthy_threshold = 10
    timeout             = 5
    interval            = 30
    matcher             = "200"
  }
}

resource "aws_lb_listener" "http" {
  load_balancer_arn = aws_lb.web.arn
  port              = "80"
  protocol          = "HTTP"

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.web.arn
  }
}

5.5. Modul Database (modules/database/main.tf)

Modul ini menyiapkan database MySQL RDS multi-AZ di database subnet.

resource "aws_db_subnet_group" "main" {
  name       = "${var.environment}-db-subnet-group"
  subnet_ids = var.private_subnet_ids

  tags = {
    Name = "${var.environment}-db-subnet-group"
  }
}

resource "aws_security_group" "db" {
  name        = "${var.environment}-db-sg"
  description = "Security group untuk RDS MySQL"
  vpc_id      = var.vpc_id

  ingress {
    description     = "Allow MySQL dari private subnet"
    from_port       = 3306
    to_port         = 3306
    protocol        = "tcp"
    security_groups = var.app_security_group_ids
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_db_instance" "mysql" {
  identifier             = "${var.environment}-mysql-db"
  engine                 = "mysql"
  engine_version         = "8.0"
  instance_class         = "db.t3.medium"
  allocated_storage      = 20
  max_allocated_storage  = 100
  db_name                = "enterprise_db"
  username               = "admin_user"
  password               = var.db_password
  db_subnet_group_name   = aws_db_subnet_group.main.name
  vpc_security_group_ids = [aws_security_group.db.id]
  multi_az               = true
  skip_final_snapshot    = true

  tags = {
    Name = "${var.environment}-mysql"
  }
}

5.6. Root Orchestration (main.tf)

File utama yang merangkai seluruh modul.

module "vpc" {
  source      = "./modules/vpc"
  aws_region  = var.aws_region
  environment = var.environment
  vpc_cidr    = var.vpc_cidr
}

module "compute" {
  source            = "./modules/compute"
  environment       = var.environment
  vpc_id            = module.vpc.vpc_id
  public_subnet_ids = module.vpc.public_subnet_ids
}

module "database" {
  source                 = "./modules/database"
  environment            = var.environment
  vpc_id                 = module.vpc.vpc_id
  private_subnet_ids     = module.vpc.private_subnet_ids
  app_security_group_ids = [module.compute.app_security_group_id]
  db_password            = "SuperSecretPassword123!"
}

6. Bedah Kode & Penjelasan Detail Baris Kunci

  • enable_dns_hostnames = true pada AWS VPC: Sangat krusial dalam arsitektur web modern agar instance EC2 mendapatkan DNS publik yang valid secara otomatis, yang nantinya digunakan oleh layanan integrasi seperti AWS Certificate Manager untuk validasi SSL/TLS.
  • multi_az = true pada AWS RDS: Memastikan replika sinkron dari database MySQL Anda berada di Availability Zone yang berbeda. Jika AZ utama mengalami kegagalan total, AWS secara otomatis melakukan failover ke AZ sekunder dengan downtime minimal (biasanya di bawah 60 detik).
  • skip_final_snapshot = true: Pada contoh kode di atas diatur ke true untuk efisiensi testing. Namun, > [!WARNING]

    PENTING UNTUK PRODUKSI: Pada lingkungan produksi, parameter ini wajib diubah menjadi false (skip_final_snapshot = false) dan disertai dengan penamaan final_snapshot_identifier guna mencegah kehilangan data permanen saat perintah terraform destroy tidak sengaja atau sengaja dijalankan.

7. Skenario Produksi & Studi Kasus Dunia Nyata

Dalam menghadapi lonjakan trafik tinggi (misalnya flash sale e-commerce atau lonjakan trafik media mendadak hingga 100.000 concurrent users), arsitektur Terraform yang kita bangun merespons melalui mekanisme berikut:

  1. Auto Scaling Group (ASG): Menambahkan konfigurasi Target Tracking Scaling Policy berbasis metrik CPU utilization (misalnya, jika rata-rata CPU mencapai 70% selama 3 menit, ASG otomatis menambah jumlah instance EC2 Nginx/Node.js di private subnet).
  2. Load Balancer Distribution: AWS ALB mendistribusikan beban secara merata menggunakan algoritma Least Outstanding Requests ke seluruh instance yang aktif.
  3. Caching Layer (Redis ElastiCache): Permintaan query berulang ke database MySQL dipotong pada tingkat aplikasi menggunakan Redis, menjaga agar penggunaan CPU RDS tetap di bawah batas aman.

8. Common Pitfalls, Anti-Patterns & Solusi

  • Anti-Pattern 1: Menyimpan Secret Password dalam Plaintext di HCL.
    • Solusi: Jangan pernah menulis password database atau API key secara langsung di file main.tf atau variables.tf. Gunakan AWS Secrets Manager atau SSM Parameter Store, lalu ambil nilainya menggunakan data source Terraform (aws_secretsmanager_secret_version).
  • Anti-Pattern 2: Monolitik Terraform State (Satu state file untuk seluruh infrastruktur global).
    • Solusi: Pecah state file berdasarkan domain atau lapisan (Layering State: Networking State, Database State, Application State) menggunakan remote state data source (data.terraform_remote_state).
  • Pitfall 3: Mengabaikan perintah terraform refresh vs terraform plan. Selalu jalankan terraform plan -out=tfplan dan tinjau perubahan secara teliti sebelum mengeksekusi terraform apply tfplan di produksi.

9. Benchmark, Metrik Kinerja & Tuning Performa

Setelah infrastruktur ter-provision, lakukan pengujian beban menggunakan tool benchmark modern seperti k6 atau wrk untuk menguji ketahanan Application Load Balancer dan Auto Scaling Group.

Contoh skrip pengujian k6 (load-test.js):

import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  stages: [
    { duration: '2m', target: 100 }, // Ramp-up hingga 100 users
    { duration: '5m', target: 500 }, // Lonjakan hingga 500 users
    { duration: '2m', target: 0 },   // Ramp-down
  ],
};

export default function () {
  const res = http.get('http://your-alb-dns-name.amazonaws.com/health');
  check(res, {
    'status is 200': (r) => r.status === 200,
    'response time < 200ms': (r) => r.timings.duration < 200,
  });
  sleep(1);
}

Interpretasi Hasil & Tuning: Jika persentase error meningkat atau durasi respons melampaui 500ms, lakukan tuning pada parameter Nginx worker connections, optimalkan indeks tabel MySQL RDS, dan pastikan ukuran instance EC2 (Instance Type) mencukupi alokasi memori RAM untuk memproses antrean worker PHP-FPM atau Node.js.

10. Checklist Penerapan Produksi & Kesimpulan

Gunakan checklist berikut sebelum melakukan Sign-Off rilis infrastruktur ke production:

  • State backend terenkripsi di S3 dengan KMS dan DynamoDB locking aktif.
  • Tidak ada hardcoded secret; seluruh kredensial terintegrasi dengan AWS Secrets Manager.
  • Security Groups menerapkan prinsip Least Privilege (port terbuka hanya yang esensial).
  • Database RDS dikonfigurasi Multi-AZ dengan backup otomatis harian.
  • Konfigurasi Auto Scaling Group teruji dengan skenario lonjakan trafik.
  • CloudWatch Alarms dikonfigurasi untuk memantau error rate 5xx pada ALB dan pemanfaatan CPU tinggi.

Dengan menerapkan Infrastructure as Code menggunakan Terraform dan AWS Cloud secara disiplin dan terstruktur, tim Anda tidak hanya mencapai otomatisasi deployment yang cepat, tetapi juga membangun fondasi arsitektur web yang tangguh, aman, dan siap menghadapi skala enterprise masa depan.

🏷️ Tags: #Devops #Terraform #Aws #Cloud Architecture #Iac