Tutorial End-to-End: VPC + Compute Engine + SSH dengan Terragrunt di GCP

Introduction

Tutorial ini adalah kelanjutan dari https://blog.igunawan.com/setup-gcp-untuk-connect-cli-dengan-service-account-impersonation/ yang membahas setup awal kredensial GCP. Anggap kita sudah:

  • ✅ Punya service account learn-devops-engineer@PROJECT_ID.iam.gserviceaccount.com
  • ✅ Akun Google kita sudah punya role Service Account Token Creator + Service Account User di SA tersebut
  • ✅ gcloud auth application-default login --impersonate-service-account=… sukses print token

Jika Belum silahkan baca artikel sebelumnya https://blog.igunawan.com/setup-gcp-untuk-connect-cli-dengan-service-account-impersonation/

Result

VPC dev-hub-vpc (region asia-southeast2)
├─ hub-subnet-public    (10.30.0.0/24)   — VM jump host di sini
└─ hub-subnet-private   (10.30.16.0/24)  — VM app private di sini

Cloud Router + Cloud NAT     — outbound internet untuk private subnet

Firewall:
├─ allow-internal             — intra-VPC semua protokol (10.0.0.0/8)
├─ allow-iap-ssh              — SSH lewat IAP dari 35.235.240.0/20
├─ allow-http                 — HTTP (80) untuk VM tag 'http-server'
├─ allow-https                — HTTPS (443) untuk VM tag 'https-server'
└─ allow-ssh-internet         — SSH langsung dari IP whitelist (DEV ONLY)

Compute Engine:
├─ vm-public-jump    (e2-micro, Ubuntu 22.04, external IP) — SSH entry point
├─ vm-private-app    (e2-micro, Ubuntu 22.04, no external IP)
└─ vm-private-app-2  (e2-micro, Ubuntu 22.04, no external IP)

SSH access:
├─ ssh jump                  — langsung ke jump host
└─ ssh private-app           — chained via jump host ke private VM

Struktur Project

days-6-gcp-terragrunt/
├── modules/gcp/
│   ├── vpc/
│   │   ├── main.tf              ← VPC + subnets + Cloud Router + NAT + 5 firewall rules
│   │   ├── variables.tf         ← input flags (enable_nat, enable_firewall, dll)
│   │   └── outputs.tf           ← network_id, subnet self_links, NAT id
│   └── compute/
│       ├── main.tf              ← google_compute_instance (for_each VMs)
│       ├── variables.tf         ← list of VMs (flexible)
│       └── outputs.tf           ← vm_summary map (internal_ip, external_ip, dll)
└── live/gcp/
    ├── root.hcl                 ← provider + impersonation
    ├── dev/
    │   ├── vpc/terragrunt.hcl   ← input VPC dev
    │   └── compute/terragrunt.hcl ← input VM dev (2 VMs)
    └── prod/
        ├── vpc/terragrunt.hcl   ← input VPC prod (mirror dev)
        └── compute/             ← (opsional, mirror dev)

Step 1 — Provisioning VPC + Subnets + NAT + Firewall

1.1 Cek file live/gcp/dev/vpc/terragrunt.hcl

Pastikan isinya seperti ini:

include "root" {
  path = find_in_parent_folders("root.hcl")
}

terraform {
  source = "${get_terragrunt_dir()}/../../../../modules/gcp/vpc"
}

inputs = {
  name   = "dev-hub-vpc"
  region = "asia-southeast2"

  subnets = [
    {
      name = "hub-subnet-public"
      cidr = "10.30.0.0/24"
    },
    {
      name = "hub-subnet-private"
      cidr = "10.30.16.0/24"
    },
  ]

  # Cloud NAT hanya untuk subnet private
  subnets_private = ["hub-subnet-private"]

  # Enable semua fitur
  enable_nat                 = true
  enable_firewall            = true
  enable_public_web_firewall = true

  # SSH langsung dari internet — DEV ONLY
  enable_ssh_internet         = true
  ssh_internet_source_ranges = ["xx.xx.xx.xx/32"]   # GANTI dengan IP rumah kita
}

Cara cek IP yang kita gunakan entah itu thetering internet rumah:

curl -s https://api.ipify.org && echo

1.2 Inisialisasi & plan

cd live/gcp/dev/vpc
terragrunt init        # download module + provider
terragrunt plan        # review: akan create 9 resource (VPC + 2 subnet + router + NAT + 5 firewall)

Expected plan output:

Plan: 9 to add, 0 to change, 0 to destroy.

Resources:
  + google_compute_network.this                    "dev-hub-vpc"
  + google_compute_subnetwork.this["hub-subnet-public"]
  + google_compute_subnetwork.this["hub-subnet-private"]
  + google_compute_router.this[0]                  "dev-hub-vpc-router"
  + google_compute_router_nat.this[0]              "dev-hub-vpc-nat"
  + google_compute_firewall.allow_internal[0]      "dev-hub-vpc-allow-internal"
  + google_compute_firewall.allow_iap_ssh[0]       "dev-hub-vpc-allow-iap-ssh"
  + google_compute_firewall.allow_http[0]          "dev-hub-vpc-allow-http"
  + google_compute_firewall.allow_https[0]         "dev-hub-vpc-allow-https"
  + google_compute_firewall.allow_ssh_internet[0]  "dev-hub-vpc-allow-ssh-internet"

1.3 Apply

terragrunt apply
# Ketik "yes" saat prompt

Tunggu ±30 detik sampai apply selesai.

1.4 Verifikasi

# VPC & subnet
gcloud compute networks list --project=$PROJECT_ID
gcloud compute networks subnets list --project=$PROJECT_ID --regions=asia-southeast2

# NAT
gcloud compute routers list --project=$PROJECT_ID
gcloud compute routers nats list --project=$PROJECT_ID --router=dev-hub-vpc-router --region=asia-southeast2

# Firewall (semua rule dev-hub-vpc-*)
gcloud compute firewall-rules list --project=$PROJECT_ID --filter="network:dev-hub-vpc"

Step 2 — Provisioning Compute Engine VMs

2.1 Cek file live/gcp/dev/compute/terragrunt.hcl

include "root" {
  path = find_in_parent_folders("root.hcl")
}

terraform {
  source = "${get_terragrunt_dir()}/../../../../modules/gcp/compute"
}

dependency "vpc" {
  config_path = "../vpc"

  mock_outputs = {
    subnets = {
      "hub-subnet-public"  = { name = "mock", cidr = "10.0.0.0/24",   region = "asia-southeast2", self_link = "projects/mock/regions/asia-southeast2/subnetworks/public" }
      "hub-subnet-private" = { name = "mock", cidr = "10.0.16.0/24",  region = "asia-southeast2", self_link = "projects/mock/regions/asia-southeast2/subnetworks/private" }
    }
  }
  mock_outputs_allowed_terraform_commands = ["init", "validate", "plan", "destroy"]
}

inputs = {
  default_zone = "asia-southeast2-a"
  vpc_subnets  = dependency.vpc.outputs.subnets

  vms = [
    # ----- Jump host (public subnet, external IP, tag ssh-iap + ssh-internet) -----
    {
      name        = "vm-public-jump"
      subnet_name = "hub-subnet-public"
      machine_type = "e2-micro"
      zone         = "asia-southeast2-a"
      image        = "ubuntu-2204-lts"
      external_ip  = true
      tags         = ["ssh-iap", "ssh-internet"]
    },
    # ----- Private VM #1 -----
    {
      name        = "vm-private-app"
      subnet_name = "hub-subnet-private"
      machine_type = "e2-micro"
      zone         = "asia-southeast2-a"
      image        = "ubuntu-2204-lts"
      external_ip  = false
      tags         = ["ssh-iap"]
    },
    # ----- Private VM #2 -----
    {
      name        = "vm-private-app-2"
      subnet_name = "hub-subnet-private"
      machine_type = "e2-micro"
      zone         = "asia-southeast2-a"
      image        = "ubuntu-2204-lts"
      external_ip  = false
      tags         = ["ssh-iap"]
    },
  ]
}

2.2 Inisialisasi & plan

cd live/gcp/dev/compute
terragrunt init
terragrunt plan

Expected plan output:

Plan: 3 to add, 0 to change, 0 to destroy.

Resources:
  + google_compute_instance.this["vm-public-jump"]
      zone: asia-southeast2-a, machine_type: e2-micro, tags: [ssh-iap, ssh-internet]
  + google_compute_instance.this["vm-private-app"]
      zone: asia-southeast2-a, machine_type: e2-micro, tags: [ssh-iap]
  + google_compute_instance.this["vm-private-app-2"]
      zone: asia-southeast2-a, machine_type: e2-micro, tags: [ssh-iap]

2.3 Apply

terragrunt apply
# Ketik "yes" saat prompt

Tunggu ±1–2 menit (booting 3 VM Ubuntu pertama kali).

2.4 Verifikasi

gcloud compute instances list --project=$PROJECT_ID \
  --format='table(name,EXTERNAL_IP,INTERNAL_IP,status)'

# Expected:
# NAME                EXTERNAL_IP     INTERNAL_IP    STATUS
# vm-public-jump      34.128.99.159   10.30.0.2      RUNNING
# vm-private-app                      10.30.16.2     RUNNING
# vm-private-app-2                    10.30.16.3     RUNNING

Catat IP-ini, akan dipakai di Step 4:

  • vm-public-jump external IP = 34.128.99.1
  • vm-private-app internal IP = 10.30.16.2
  • vm-private-app-2 internal IP = 10.30.16.3

Step 3 — SSH Keypair + Register ke GCP

3.1 Generate SSH keypair (kalau belum punya)

# Kalau belum ada, generate (pakai nama apapun, ini contoh pakai id_rsa):
ssh-keygen -t ed25519 -f id_rsa -C "gunawan-gcp-dev"
# Enter passphrase (atau kosongkan)

3.2 Copy isi public key

cat /id_rsa

3.3 Register ke GCP Project Metadata

Buka GCP –> Copmute engine –> metadata –> ssh Keys

  1. Klik EDIT (kanan atas)
  2. Klik + ADD ITEM
  3. Paste dengan format:gunawan:ssh-
  4. Klik Save → confirm popup.

Tunggu ~30 detik untuk propagasi metadata ke VM.

3.4 Verifikasi key sudah masuk VM

# SSH ke jump host (akan auto-handle auth pakai GCP-managed key pertama kali)
gcloud compute ssh vm-public-jump --tunnel-through-iap --zone=asia-southeast2-a --project=$PROJECT_ID

# Begitu masuk shell VM, cek authorized_keys:
cat /authorized_keys
# Harus muncul entry gunawan...

# Exit
exit

Step 4 — Testing Remote SSH to Jump Host

SSH dari local laptop kita karena IP public kita sudah di whitelist untuk khusus PORT 22 :


ssh -i id_rsa user@34.128.99.1

Ketika sudah di Jump Host anggap saja kita ada 2 instance atau VM private dibelakang seperti pada gambar diatas, setup jump host seperti berikut pada file

config

Host private-app
    Hostname 10.30.16.2
    User gunawan
    IdentityFile ~/.ssh/gunawan.pem
    IdentitiesOnly yes
    StrictHostKeyChecking no
    UserKnownHostsFile /dev/null

Host private-app-2
    Hostname 10.30.16.3
    User gunawan
    IdentityFile ~/.ssh/gunawan.pem
    IdentitiesOnly yes
    StrictHostKeyChecking no
    UserKnownHostsFile /dev/null

Jika ingin akses Private-app-1 : ssh private-app-1

Jika ingin akses Private-app-2 : ssh-private-app-2

Cara Destroy ya jika sudah selesai praktiknya

Cara Destroy (urutan penting!)

# Compute dulu (VMs reference VPC), baru VPC
cd live/gcp/dev/compute
terragrunt destroy

cd ../vpc
terragrunt destroy

# Bersihin cache:
rm -rf ../compute/.terragrunt-cache/
rm -rf ../vpc/.terragrunt-cache/

Leave a Reply

Your email address will not be published. Required fields are marked *