Skip to main content

🛠️ Langkah Step-by-Step Setup Terraform

Diagram Arstiketurnya

image.png

✅ Step 1: Persiapan Install Terraform di WSL

  1. sudo apt update && sudo apt install -y software-properties-common gnupg curl
  2. curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
  3. echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com
  4. $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
  5. sudo apt update && sudo apt install -y terraform
  6. terraform -v

✅ Step 2: Mengatur Kredensial AWS

Terraform menggunakan salah satu dari cara berikut untuk mengakses akun AWS kamu:

(a) File ~/.aws/credentials (paling umum)

Gunakan AWS CLI (kalau kamu install) atau buat file ini secara manual:

mkdir -p ~/.aws
vi ~/.aws/credentials
[default]
aws_access_key_id = YOUR_ACCESS_KEY
aws_secret_access_key = YOUR_SECRET_KEY

vi ~/.aws/config
[default]
region = ap-southeast-1 

Kamu bisa dapatkan akses key dari: IAM > Users > Security credentials


Step 3: Koneksi Internet

Karena Terraform akan:

  • Menghubungi AWS API

  • Mendownload provider plugin

Pastikan WSL kamu punya akses internet (cek ping google.com atau curl aws.amazon.com).

✅ Step 4: Struktur Terraform sederhana

Kita akan buat struktur Terraform sederhana untuk:

  • 1 VPC

  • 1 EC2 (Ubuntu t2.micro)

  • 1 RDS (MySQL)

  • 1 S3 Bucket

image.png

🔧variables.tf

variable "region" {
  default = "ap-southeast-1"
}

variable "db_username" {
  default = "tempAdmin"
}

variable "db_password" {
  default = "tempAdmin954*"
}

🔧outputs.tf

output "ec2_public_ip" {
  value = aws_instance.web.public_ip
}

output "rds_endpoint" {
  value = aws_db_instance.mysql.endpoint
}

output "s3_bucket_name" {
  value = aws_s3_bucket.app_bucket.bucket
}

🔧main.tf

provider "aws" {
  region = var.region
}

# S3 Bucket
resource "aws_s3_bucket" "app_bucket" {
  bucket = "my-webapp-bucket-${random_id.bucket_id.hex}"
  force_destroy = true
}

resource "random_id" "bucket_id" {
  byte_length = 4
}

# VPC dan Subnet default
data "aws_vpc" "default" {
  default = true
}

# Perubahan di sini - menggunakan aws_subnets sebagai ganti aws_subnet_ids
data "aws_subnets" "default" {
  filter {
    name   = "vpc-id"
    values = [data.aws_vpc.default.id]
  }
}

# Security Group
resource "aws_security_group" "web_sg" {
  name        = "web-sg"
  description = "Allow HTTP, HTTPS, SSH, MySQL"
  vpc_id      = data.aws_vpc.default.id

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 3306
    to_port     = 3306
    protocol    = "tcp"
    self        = true  # Mengganti security_groups dengan self
  }

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

# EC2 Instance
resource "aws_instance" "web" {
  ami           = "ami-0c1907b6d738188e5" # Ubuntu 22.04 LTS - ap-southeast-1
  instance_type = "t2.micro"
  subnet_id     = data.aws_subnets.default.ids[0]  # Perubahan di sini

  # Ganti ini:
  #security_groups = [aws_security_group.web_sg.name]

  # Menjadi ini:
  vpc_security_group_ids = [aws_security_group.web_sg.id]

  key_name      = "wid" # ganti dengan nama key pair kamu

  tags = {
    Name = "WebAppInstance"
  }
}

# RDS Instance
resource "aws_db_instance" "mysql" {
  allocated_storage    = 20
  engine               = "mysql"
  engine_version       = "8.0.35"
  instance_class       = "db.t3.micro"
  db_name              = "webappdb"  # Ganti 'name' dengan 'db_name' untuk MySQL
  username             = var.db_username
  password             = var.db_password
  db_subnet_group_name = aws_db_subnet_group.default.name
  vpc_security_group_ids = [aws_security_group.web_sg.id]
  skip_final_snapshot  = true

  backup_retention_period = 0
  monitoring_interval     = 0
  publicly_accessible    = false  # Disarankan untuk keamanan
}

resource "aws_db_subnet_group" "default" {
  name       = "default-subnet-group"
  subnet_ids = data.aws_subnets.default.ids  # Perubahan di sini
}

 

Berikut penjelasan lengkap untuk konfigurasi main.tf Anda, bagian per bagian:

1. Provider AWS

provider "aws" {
  region = var.region
}
  • Mendefinisikan provider AWS dan region yang akan digunakan

  • var.region berarti nilai diambil dari variabel (biasa didefinisikan di variables.tf)

2. S3 Bucket

resource "aws_s3_bucket" "app_bucket" {
  bucket = "my-webapp-bucket-${random_id.bucket_id.hex}"
  force_destroy = true
}

resource "random_id" "bucket_id" {
  byte_length = 4
}
  • Membuat bucket S3 dengan nama unik (mengandung random hex)

  • force_destroy = true memungkinkan bucket dihapus meski berisi data

  • random_id menghasilkan string random 4 byte (8 karakter hex) untuk keunikan nama bucket

3. Jaringan (VPC & Subnet)

data "aws_vpc" "default" {
  default = true
}

data "aws_subnets" "default" {
  filter {
    name   = "vpc-id"
    values = [data.aws_vpc.default.id]
  }
}
  • Menggunakan VPC default di akun AWS Anda

  • Mengambil semua subnet dalam VPC default tersebut

  • Data source (data) digunakan untuk membaca infrastruktur yang sudah ada

4. Security Group

# Security Group
resource "aws_security_group" "web_sg" {
  name        = "web-sg"
  description = "Allow HTTP, HTTPS, SSH, MySQL"
  vpc_id      = data.aws_vpc.default.id

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 3306
    to_port     = 3306
    protocol    = "tcp"
    self        = true  # Mengganti security_groups dengan self
  }

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

Membuka akses untuk:

  • SSH (port 22) - dari mana saja (0.0.0.0/0)

  • HTTP (port 80) - dari mana saja

  • HTTPS (port 443) - dari mana saja

  • MySQL (port 3306) - hanya dari instance dalam SG yang sama (self = true)

  • Egress - mengizinkan semua traffic keluar

5. EC2 Instance

# EC2 Instance
resource "aws_instance" "web" {
  ami           = "ami-0c1907b6d738188e5" # Ubuntu 22.04 LTS - ap-southeast-1
  instance_type = "t2.micro"
  subnet_id     = data.aws_subnets.default.ids[0]  # Perubahan di sini

  # Ganti ini:
  #security_groups = [aws_security_group.web_sg.name]

  # Menjadi ini:
  vpc_security_group_ids = [aws_security_group.web_sg.id]

  key_name      = "wid" # ganti dengan nama key pair kamu

  tags = {
    Name = "WebAppInstance"
  }
}
  • Membuat EC2 instance Ubuntu 22.04 tipe t2.micro

  • Ditempatkan di subnet pertama dari VPC default

  • Menggunakan security group yang sudah dibuat

  • key_name harus diganti dengan key pair SSH yang sudah ada di AWS

6. RDS MySQL

resource "aws_db_instance" "mysql" {
  allocated_storage    = 20
  engine               = "mysql"
  ...
  vpc_security_group_ids = [aws_security_group.web_sg.id]
  publicly_accessible = false
}
  • Database MySQL 8.0 dengan storage 20GB

  • Menggunakan security group yang sama dengan EC2 (bisa akses MySQL)

  • publicly_accessible = false berarti hanya bisa diakses dari dalam VPC

  • skip_final_snapshot = true (hati-hati, ini menghilangkan backup saat RDS dihapus)

7. DB Subnet Group

resource "aws_db_subnet_group" "default" {
  name       = "default-subnet-group"
  subnet_ids = data.aws_subnets.default.ids
}
  • Grup subnet untuk penempatan RDS

  • Menggunakan semua subnet default

Alur Kerja Infrastruktur:

  1. Bucket S3 dibuat untuk menyimpan assets webapp

  2. EC2 Instance akan:

    • Berjalan di subnet default

    • Bisa diakses via SSH/HTTP/HTTPS dari internet

    • Bisa akses database MySQL

  3. RDS MySQL:

    • Hanya bisa diakses dari EC2 instance

    • Tidak terbuka ke internet

    • Berada di subnet private (asumsi subnet default termasuk private)

Yang Perlu Diperhatikan:

  1. Security:

    • Port 22 terbuka untuk semua (sebaiknya dibatasi ke IP tertentu)

    • Database menggunakan SG yang sama dengan web server (idealnya dipisah)

  2. Variabel:

    • var.regionvar.db_usernamevar.db_password harus didefinisikan

  3. Key Pair:

    • Ganti your-key-name dengan nama key pair yang sudah ada di AWS

Step 5: Perintah Terraform untuk membuat resources

Untuk uji coba:

# 0. Inisialisasi Terraform
terraform init

# 1. Buat dan simpan plan
terraform plan -out=tfplan

# 2. Review isi plan (opsional)
terraform show tfplan

# 3. Apply plan yang sudah disimpan
terraform apply tfplan

 

Arti pesan tersebut:

  1. Tanpa opsi -out: Ketika Anda hanya menjalankan terraform plan (tanpa menyimpan hasilnya), Terraform hanya menunjukkan preview perubahan yang akan dilakukan.

  2. Tidak ada jaminan: Jika Anda langsung menjalankan terraform apply setelahnya, mungkin ada perbedaan antara:

    • Apa yang ditampilkan di plan

    • Apa yang benar-benar di-apply

Mengapa ini penting?

  • Jika infrastruktur Anda berubah antara waktu plan dan apply (misalnya ada perubahan manual di AWS Console), hasil apply bisa berbeda dari yang di-plan.

  • Terraform tidak bisa menjamin konsistensi karena tidak ada "snapshot" rencana yang disimpan

✅ Step 6: Persiapan Terraform untuk menghapus/destroy

Untuk menghapus/destroy semua resources AWS yang telah dibuat melalui Terraform, Anda bisa menggunakan perintah berikut:

Cara Destroy Resources Terraform:

  1. Pertama, lihat dulu apa yang akan di-destroy (opsional tapi disarankan):

    bash
    terraform plan -destroy -out=tfdestroyplan

    Ini akan menunjukkan semua resources yang akan dihapus.

  2. Eksekusi destroy:

    bash

    terraform destroy

    Terraform akan menampilkan daftar resources yang akan dihapus dan meminta konfirmasi.

  3. Jika ingin langsung destroy tanpa konfirmasi:

    bash

    terraform destroy -auto-approve

Beberapa catatan penting:

  1. S3 Bucket:

    • Karena Anda mengatur force_destroy = true, bucket akan dihapus meskipun berisi file

    • Tanpa setting ini, destroy akan gagal jika bucket tidak kosong

  2. RDS Instance:

    • Karena ada skip_final_snapshot = true, database akan dihapus tanpa backup terakhir

    • Jika ini di-production, sebaiknya buat snapshot manual dulu

  3. Resources yang akan dihapus:

    • EC2 Instance

    • Security Group

    • RDS MySQL Instance

    • DB Subnet Group

    • S3 Bucket

    • Random ID resource

Jika mengalami error saat destroy:

  1. Resources manual:
    Pastikan tidak ada resources yang dibuat manual (di luar Terraform) yang bergantung pada resources yang dikelola Terraform

  2. Dependency error:
    Terkadang perlu menjalankan destroy beberapa kali jika ada dependency issues

  3. Force destroy:
    Untuk kasus tertentu bisa tambahkan flag -force, tapi hati-hati:

    bash

    terraform destroy -force

Best Practice Destroy:

  1. Backup data penting dulu jika ada

  2. Verifikasi environment yang akan di-destroy sudah benar

  3. Gunakan workspace jika ingin memisahkan environment (dev/staging/prod)

  4. Set timeout jika resources besar:

    bash

    terraform destroy -timeout=30m

Setelah destroy selesai, Anda bisa verifikasi di AWS Console bahwa semua resources sudah terhapus. Terraform juga akan menghapus file status (terraform.tfstate) yang menyimpan informasi tentang infrastruktur yang dikelola.