Mengamankan Workload dengan ClusterNetworkPolicy GKE - Contoh Inferensi AI (Gemma, TPU)

1. Ringkasan

Lab ini memperkenalkan Anda pada ClusterNetworkPolicy di Google Kubernetes Engine (GKE). ClusterNetworkPolicy diterapkan untuk berbagai kasus penggunaan dan dapat diterapkan di seluruh Cluster serta diterapkan di tingkat Admin dan dasar pengukuran. Dalam contoh ini, kami akan menunjukkan kontrol dengan deployment LLM (Gemma) di GKE dengan TPU, vLLM, dan validasi.

Anda akan menggunakan teknologi berikut:

  • Google Kubernetes Engine (GKE) — Platform orkestrasi container dasar untuk menghosting workload pribadi yang skalabel.
  • ClusterNetworkPolicy (CNP) — Kebijakan jaringan multi-tingkat cakupan cluster yang memungkinkan batasan SecOps di seluruh tingkat Admin, NetworkPolicy, dan Baseline.
  • vLLM TPU Inference Engine — Inferensi throughput tinggi yang menyajikan model Gemma 4 ringan (google/gemma-4-E2B-it) di Google TPU dengan endpoint REST yang kompatibel dengan OpenAI.

Peran dan Persona

Network Policy API disusun berdasarkan persona organisasi tertentu:

  • Penggunaan Administrator Cluster (ClusterNetworkPolicy): Menerapkan batasan keamanan di seluruh cluster pada tingkat Admin dan dasar pengukuran.
  • Penggunaan Administrator Namespace (NetworkPolicy): Mengelola batas dan isolasi tingkat tenant dalam namespace tertentu.
  • Penggunaan Developer Aplikasi (NetworkPolicy): Menentukan aturan terperinci untuk microservice khusus aplikasi.

Untuk mengonfigurasi lingkungan ini, Anda akan men-deploy VPC pribadi kustom, Cloud NAT, dan cluster GKE pribadi dengan node pool TPU khusus.

Untuk mengamankan cluster, Anda akan membuat resource ClusterNetworkPolicy multi-tingkat bersama objek NetworkPolicy standar untuk menerapkan guardrail jaringan yang ketat. Kemudian, Anda akan men-deploy workload AI yang menggunakan vLLM, TPU Google Cloud untuk menyajikan model Gemma 4.

Terakhir, Anda akan membuat dasar pengukuran yang berfungsi, menerapkan kebijakan keamanan, dan mengonfigurasi NetworkLogging menggunakan Cloud Logging dan streaming kemampuan observasi Hubble eBPF langsung untuk mengaudit keputusan kebijakan tersebut dan memverifikasi paket yang dihapus. Semua konfigurasi akan menggunakan kombinasi Terraform, gcloud, dan kubectl.

Di lab ini, Anda akan mempelajari cara melakukan tugas berikut:

  • Menyediakan jaringan pribadi, cluster GKE, dan akselerator Cloud TPU v5e menggunakan Terraform.
  • Mengonfigurasi NetworkLogging GKE untuk mencatat telemetri koneksi.
  • Men-deploy Gemma 4 E2B di TPU menggunakan image container vllm/vllm-tpu resmi.
  • Buat dasar pengukuran yang berfungsi untuk membuktikan konektivitas menyeluruh sebelum menerapkan batasan.
  • Terapkan ClusterNetworkPolicy Baseline-tier untuk menolak traffic lintas namespace yang tidak sah secara default.
  • Menerapkan NetworkPolicy yang dikelola developer untuk mendelegasikan akses ke klien yang diizinkan.
  • Terapkan ClusterNetworkPolicy Admin-tier untuk menerapkan guardrail egress global yang menggantikan setelan developer.
  • Memverifikasi penurunan dan penerusan paket langsung menggunakan (aliran eBPF Hubble dan Cloud Logging).

Di lab ini, Anda akan membuat pola berikut.

Gambar 1. dbe5e5f7b35afb8e.jpeg

2. Penyiapan layanan Google Cloud

Penyiapan lingkungan mandiri

  1. Login ke Konsol Google Cloud dan buat project baru atau gunakan kembali project yang sudah ada. Jika belum memiliki akun Gmail atau Google Workspace, Anda harus membuatnya.

295004821bab6a87.png37d264871000675d.png96d86d3d5655cdbe.png

  • Project name adalah nama tampilan untuk peserta project ini. String ini adalah string karakter yang tidak digunakan oleh Google API. Anda dapat memperbaruinya kapan saja.
  • Project ID bersifat unik di semua project Google Cloud dan tidak dapat diubah (tidak dapat diubah setelah ditetapkan). Konsol Cloud otomatis membuat string unik; biasanya Anda tidak mementingkan kata-katanya. Di sebagian besar codelab, Anda harus merujuk Project ID-nya (umumnya diidentifikasi sebagai PROJECT_ID). Jika tidak suka dengan ID yang dibuat, Anda dapat membuat ID acak lainnya. Atau, Anda dapat mencobanya sendiri, dan lihat apakah ID tersebut tersedia. ID tidak dapat diubah setelah langkah ini dan tersedia selama durasi project.
  • Sebagai informasi, ada nilai ketiga, Project Number, yang digunakan oleh beberapa API. Pelajari lebih lanjut ketiga nilai ini di dokumentasi.
  1. Selanjutnya, Anda harus mengaktifkan penagihan di Konsol Cloud untuk menggunakan resource/API Cloud. Menjalankan operasi dalam codelab ini tidak akan memakan banyak biaya, bahkan mungkin tidak sama sekali. Guna mematikan resource agar tidak menimbulkan penagihan di luar tutorial ini, Anda dapat menghapus resource yang dibuat atau menghapus project-nya. Pengguna baru Google Cloud memenuhi syarat untuk mengikuti program Uji Coba Gratis senilai $300 USD.

Mulai Cloud Shell

Meskipun Google Cloud dapat dioperasikan dari jarak jauh menggunakan laptop Anda, dalam codelab ini, Anda akan menggunakan Google Cloud Shell, lingkungan command line yang berjalan di Cloud.

Dari Konsol Google Cloud, klik ikon Cloud Shell di toolbar kanan atas:

Mengaktifkan Cloud Shell

Hanya perlu waktu beberapa saat untuk penyediaan dan terhubung ke lingkungan. Jika sudah selesai, Anda akan melihat tampilan seperti ini:

Screenshot terminal Google Cloud Shell yang menunjukkan bahwa lingkungan telah terhubung

Mesin virtual ini berisi semua alat pengembangan yang Anda perlukan. Layanan ini menawarkan direktori beranda tetap sebesar 5 GB dan beroperasi di Google Cloud, sehingga sangat meningkatkan performa dan autentikasi jaringan. Semua pekerjaan Anda dalam codelab ini dapat dilakukan di browser. Anda tidak perlu menginstal apa pun.

3. Menyiapkan lingkungan dengan Terraform

Untuk menyelesaikan lab ini,

  • Anda memerlukan akses ke kuota TPU v5e di region dan zona yang dipilih, misalnya (us-central1-a, us-west4-a, us-south1-a, us-west1-c, europe-west4-b). Anda harus mengikuti dokumen paket TPU dan mengaktifkan kuota TPU untuk mendapatkan akses.
  • Ini adalah deployment kecil yang memerlukan 4 chip TPU v5e (ct5lp-hightpu-4t), yang akan membentuk slice 2x2 dalam satu zona.

Untuk menggunakan Hugging Face

  • Token Hugging Face: Token Akses diperlukan untuk mendownload bobot model Gemma.
  • Setujui perjanjian penggunaan yang diperlukan.

Kita akan membuat VPC kustom dengan aturan firewall, subnet, lalu cluster autopilot. Buka konsol Cloud dan pilih project yang akan Anda gunakan.

  1. Buka Cloud Shell yang terletak di kanan atas konsol, pastikan Anda melihat project ID yang benar di Cloud Shell, konfirmasi perintah apa pun untuk mengizinkan akses. b51b80043d3bac90.png
  2. Buat direktori bernama gke-cnp-lab,, lalu pindah ke direktori tersebut.
mkdir -p gke-cnp-lab && cd gke-cnp-lab
  1. Sekarang buat beberapa variabel. Catatan: edit REGION, ZONE untuk mencerminkan lokasi sebenarnya tempat Anda memiliki akses ke resource TPU. Default yang digunakan di region lab us-west4 dan zona us-west4-a
export PROJECT_ID=$(gcloud config get-value project)
export REGION="us-west4"
export ZONE="us-west4-a"
export NETWORK="cnp-demo-vpc"
export SUBNET="cnp-main-subnet"
export CLUSTER_NAME="cnp-demo-cluster"
  1. Simpan variabel konfigurasi Anda ke skrip bantuan di direktori gke-cnp-lab. Jika sesi Cloud Shell Anda terputus atau direset, Anda dapat memulihkan variabel aktif dengan cepat dengan menjalankan source ./env.sh
cat << EOF > env.sh
export PROJECT_ID="${PROJECT_ID}"
export REGION="${REGION}"
export ZONE="${ZONE}"
export NETWORK="${NETWORK}"
export SUBNET="${SUBNET}"
export CLUSTER_NAME="${CLUSTER_NAME}"

echo -e "\n=== Validating Environment Configuration ==="
echo "Project ID   : \${PROJECT_ID}"
echo "Region       : \${REGION}"
echo "Zone         : \${ZONE}"
echo "Network Name : \${NETWORK}"
echo "Subnet Name  : \${SUBNET}"
echo "Cluster Name : \${CLUSTER_NAME}"

if [[ -z "\${PROJECT_ID}" || -z "\${REGION}" || -z "\${ZONE}" || -z "\${NETWORK}" || -z "\${SUBNET}" || -z "\${CLUSTER_NAME}" ]]; then
  echo -e "\n[ERROR] One or more environment variables are missing! Check your configuration."
else
  echo -e "\n[SUCCESS] Environment variables successfully populated and validated."
fi
EOF

chmod +x env.sh
source ./env.sh
  1. Sekarang, tambahkan beberapa file konfigurasi. Perintah ini akan membuat file terraform.tfvars , variables.tf, dan main.tf berikut di direktori gke-cnp-lab.
cat << EOF > terraform.tfvars
project_id   = "${PROJECT_ID}"
region       = "${REGION}"
zone         = "${ZONE}"
network_name = "${NETWORK}"
subnet_name  = "${SUBNET}"
cluster_name = "${CLUSTER_NAME}"
EOF

cat << 'EOF' > variables.tf
variable "project_id" {
  type        = string
  description = "Google Cloud Project ID"
}

variable "region" {
  type        = string
  description = "Target GCP region"
}

variable "zone" {
  type        = string
  description = "Target GCP zone"
}

variable "network_name" {
  type        = string
  description = "VPC network name"
}

variable "subnet_name" {
  type        = string
  description = "Subnetwork name"
}

variable "cluster_name" {
  type        = string
  description = "GKE cluster name"
}
EOF

cat << 'EOF' > main.tf
terraform {
  required_version = ">= 1.5.0"
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "~> 7.32.0"
    }
    google-beta = {
      source  = "hashicorp/google-beta"
      version = "~> 7.32.0"
    }
  }
}

provider "google" {
  project = var.project_id
  region  = var.region
}

provider "google-beta" {
  project = var.project_id
  region  = var.region
}

# 1. Custom Private VPC Network
resource "google_compute_network" "vpc" {
  name                    = var.network_name
  auto_create_subnetworks = false
  mtu                     = 8896
}

# 2. Private Subnet with Secondary IP Ranges for Pods & Services
resource "google_compute_subnetwork" "subnet" {
  name                     = var.subnet_name
  ip_cidr_range            = "10.10.0.0/20"
  region                   = var.region
  network                  = google_compute_network.vpc.id
  private_ip_google_access = true

  secondary_ip_range {
    range_name    = "gke-pods"
    ip_cidr_range = "10.20.0.0/16"
  }
  secondary_ip_range {
    range_name    = "gke-services"
    ip_cidr_range = "10.30.0.0/20"
  }
}

# 3. Cloud Router & Cloud NAT for Secure Outbound Egress
resource "google_compute_router" "router" {
  name    = "${var.network_name}-router"
  network = google_compute_network.vpc.id
  region  = var.region
}

resource "google_compute_router_nat" "nat" {
  name                               = "${var.network_name}-nat"
  router                             = google_compute_router.router.name
  region                             = var.region
  nat_ip_allocate_option             = "AUTO_ONLY"
  source_subnetwork_ip_ranges_to_nat = "ALL_SUBNETWORKS_ALL_IP_RANGES"
}

# 4. Internal Firewall Rules
resource "google_compute_firewall" "allow_internal" {
  name      = "${var.network_name}-allow-internal"
  network   = google_compute_network.vpc.id
  direction = "INGRESS"
  priority  = 1000
  allow {
    protocol = "all"
  }
  source_ranges = ["10.10.0.0/20", "10.20.0.0/16", "10.30.0.0/20"]
}

# 5. Private GKE Cluster with Observability and Dataplane V2
resource "google_container_cluster" "primary" {
  name               = var.cluster_name
  location           = var.region
  node_locations     = [var.zone]
  network            = google_compute_network.vpc.id
  subnetwork         = google_compute_subnetwork.subnet.id
  initial_node_count = 1

  datapath_provider = "ADVANCED_DATAPATH"

  # FIX: Observability config must be nested inside monitoring_config
  monitoring_config {
    advanced_datapath_observability_config {
      enable_metrics = true
      enable_relay   = true
    }
  }

  release_channel {
    channel = "RAPID"
  }

  ip_allocation_policy {
    cluster_secondary_range_name  = "gke-pods"
    services_secondary_range_name = "gke-services"
  }

  private_cluster_config {
    enable_private_nodes    = true
    enable_private_endpoint = false
    master_ipv4_cidr_block  = "172.16.0.0/28"
  }

  node_config {
    machine_type = "e2-standard-4"
    oauth_scopes = ["https://www.googleapis.com/auth/cloud-platform"]
  }

  deletion_protection = false
}

# 6. Dedicated Cloud TPU v5e Node Pool (ct5lp-hightpu-4t / 2x2 Topology)
resource "google_container_node_pool" "tpu_pool" {
  provider       = google-beta
  name           = "tpu-v5e-pool"
  location       = var.region
  node_locations = [var.zone]
  cluster        = google_container_cluster.primary.name
  node_count     = 1

  node_config {
    machine_type = "ct5lp-hightpu-4t"
    oauth_scopes = ["https://www.googleapis.com/auth/cloud-platform"]

    labels = {
      "cloud.google.com/gke-tpu-accelerator" = "tpu-v5-lite-podslice"
      "cloud.google.com/gke-tpu-topology"    = "2x2"
    }

    taint {
      key    = "google.com/tpu"
      value  = "present"
      effect = "NO_SCHEDULE"
    }
  }
}
EOF
  1. Pastikan Anda berada di direktori gke-cnp-lab dan jalankan perintah berikut
    terraform init Menginisialisasi direktori kerja. Ini adalah langkah pertama dan akan mendownload penyedia yang diperlukan untuk konfigurasi yang diberikan.
    terraform plan -out menghasilkan rencana eksekusi, yang menunjukkan tindakan yang akan dilakukan Terraform untuk men-deploy infrastruktur Anda. -out memungkinkan Anda menyimpan rencana eksekusi ke biner bernama. Anda dapat melihat apa yang akan terjadi tanpa melakukan perubahan apa pun.
    terraform apply menjalankan update.
terraform init 
terraform plan -out cnpgke 
  1. Terapkan rencana eksekusi. Karena Anda menerapkan rencana eksekusi yang disimpan, rencana tersebut akan segera dijalankan tanpa meminta konfirmasi (Proses ini mungkin memerlukan waktu antara 6 -10 menit)
terraform apply cnpgke
  1. Verifikasi deployment infrastruktur Anda:
gcloud container clusters get-credentials ${CLUSTER_NAME} --region ${REGION} --project=${PROJECT_ID}
echo -e "\n=== Verifying Cluster Nodes ==="
kubectl get nodes -L cloud.google.com/gke-tpu-accelerator,cloud.google.com/gke-tpu-topology

8b187e355548b7c5.png

4. Mengonfigurasi Logging Jaringan

Sebelum men-deploy workload dan kebijakan, konfigurasikan Logging Jaringan GKE untuk mencatat telemetri koneksi dan keputusan kebijakan audit di Cloud Logging.

  1. Di direktori gke-cnp-lab, buat manifes konfigurasi NetworkLogging
cat << 'EOF' > 00-network-logging.yaml
apiVersion: networking.gke.io/v1alpha1
kind: NetworkLogging
metadata:
  name: default
spec:
  cluster:
    allow:
      delegate: false
      log: true
    deny:
      delegate: false
      log: true
EOF
  1. Menerapkan konfigurasi ke cluster
kubectl apply -f 00-network-logging.yaml
kubectl get networklogging default

Catatan: Anda mungkin melihat peringatan yang menyatakan bahwa resource tidak memiliki kubectl.kubernetes.io/last-applied-configuration annotation.. Hal ini sepenuhnya normal dan sudah diperkirakan. GKE membuat objek NetworkLogging default terlebih dahulu saat cluster diaktifkan, dan kubectl apply hanya mengambil alih pengelolaannya untuk menerapkan aturan baru Anda.

5. Men-deploy Workload Gemma 4 dan Probe Klien

Anda akan membuat namespace terisolasi untuk menguji evaluasi kebijakan multi-tingkat:

  • gemma-llm: Menampung workload inferensi Gemma 4 inti (tier: ai-core).
  • client-ns: Menampung aplikasi chat RAG yang diotorisasi (tier: app-frontend).
  • untrusted-tenant: Menampung container pemeriksaan yang tidak sah (tier: untrusted).
  1. Di gke-cnp-lab directory,, buat manifes 01-namespaces-clients.yaml yang berisi namespace dan pod klien pengujian:
cat << 'EOF' > 01-namespaces-clients.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: gemma-llm
  labels:
    tier: ai-core
---
apiVersion: v1
kind: Namespace
metadata:
  name: client-ns
  labels:
    tier: app-frontend
---
apiVersion: v1
kind: Namespace
metadata:
  name: untrusted-tenant
  labels:
    tier: untrusted
---
# Authorized Client Pod
apiVersion: apps/v1
kind: Deployment
metadata:
  name: rag-agent-client
  namespace: client-ns
  labels:
    app: rag-agent
spec:
  replicas: 1
  selector:
    matchLabels:
      app: rag-agent
  template:
    metadata:
      labels:
        app: rag-agent
    spec:
      containers:
        - name: client
          image: curlimages/curl:latest
          command: ["/bin/sh", "-c", "sleep 86400"]
---
# Rogue / Untrusted Probe Pod
apiVersion: apps/v1
kind: Deployment
metadata:
  name: rogue-client
  namespace: untrusted-tenant
  labels:
    app: rogue-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: rogue-app
  template:
    metadata:
      labels:
        app: rogue-app
    spec:
      containers:
        - name: probe
          image: curlimages/curl:latest
          command: ["/bin/sh", "-c", "sleep 86400"]
EOF
  • Terapkan namespace dan deployment klien:
kubectl apply -f 01-namespaces-clients.yaml
kubectl get namespaces gemma-llm client-ns untrusted-tenant --show-labels

Men-deploy Workload vLLM dan Gemma

Buat secret Hugging Face Anda. Ganti YOUR_ACTUAL_HUGGING_FACE_TOKEN dengan token Anda:

export HF_TOKEN="YOUR_ACTUAL_HUGGING_FACE_TOKEN"
echo $HF_TOKEN
kubectl create secret generic hf-secret -n gemma-llm --from-literal=hf_token=${HF_TOKEN}
  1. Buat manifes workload inferensi Gemma 4 yang menargetkan Cloud TPU v5e menggunakan vllm-tpu:
cat << 'EOF' > 02-gemma4-tpu-vllm.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: gemma-serving
  namespace: gemma-llm
  labels:
    app: gemma-service
spec:
  replicas: 1
  selector:
    matchLabels:
      app: gemma-service
  template:
    metadata:
      labels:
        app: gemma-service
        ai.gke.io/model: gemma4
        ai.gke.io/inference-server: vllm-tpu
    spec:
      tolerations:
        - key: "google.com/tpu"
          operator: "Exists"
          effect: "NoSchedule"
      nodeSelector:
        cloud.google.com/gke-tpu-accelerator: tpu-v5-lite-podslice
        cloud.google.com/gke-tpu-topology: 2x2
      containers:
        - name: vllm-inference
          image: vllm/vllm-tpu:latest
          command: ["python3", "-m", "vllm.entrypoints.openai.api_server"]
          args:
            - "--model=google/gemma-4-E2B-it"
            - "--tensor-parallel-size=4"
            - "--host=0.0.0.0"
            - "--port=8000"
            - "--max-model-len=4096"
            - "--max-num-batched-tokens=4096"
          env:
            - name: HF_TOKEN
              valueFrom:
                secretKeyRef:
                  name: hf-secret
                  key: hf_token
            - name: HUGGING_FACE_HUB_TOKEN
              valueFrom:
                secretKeyRef:
                  name: hf-secret
                  key: hf_token
          volumeMounts:
            - mountPath: /dev/shm
              name: dshm
          ports:
            - name: http-inference
              containerPort: 8000
          resources:
            requests:
              google.com/tpu: "4"
              memory: "32Gi"
              cpu: "8"
            limits:
              google.com/tpu: "4"
              memory: "32Gi"
              cpu: "8"
          startupProbe:
            httpGet:
              path: /health
              port: 8000
            failureThreshold: 120
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /health
              port: 8000
            periodSeconds: 5
      volumes:
        - name: dshm
          emptyDir:
            medium: Memory
---
apiVersion: v1
kind: Service
metadata:
  name: gemma-service
  namespace: gemma-llm
spec:
  type: ClusterIP
  selector:
    app: gemma-service
  ports:
    - name: http
      protocol: TCP
      port: 8000
      targetPort: 8000
EOF
  1. Buat deployment.
kubectl apply -f 02-gemma4-tpu-vllm.yaml
  1. Untuk memantau status penyelesaian, jalankan skrip berikut di bawah ini. Pod akan menunggu hingga node disediakan sebelum dapat melanjutkan, proses ini mungkin memerlukan waktu 13 menit atau lebih.
echo "       __|__"
echo "  --@--(_|_)--@--"
echo ""
echo "Waiting for Gemma 4 TPU Pod to initialize and become Ready..."

# 1. Wait for the pod to be scheduled and reach the Running state
kubectl wait -n gemma-llm --for=condition=Ready pod -l app=gemma-service --timeout=600s

echo ""
echo "✅ Pod is Running! Streaming vLLM engine initialization logs..."

# 2. Stream logs until Uvicorn/vLLM is ready to serve
kubectl logs -n gemma-llm -l app=gemma-service -c vllm-inference -f | sed -u '/Application startup complete/q'

echo ""
echo "🚀 Gemma 4 on TPU v5e is ready for inference!"

6. Memahami Evaluasi Kebijakan dan Status Default

Sebelum menerapkan kebijakan jaringan, pahami cara GKE ClusterNetworkPolicy dan NetworkPolicy Kubernetes standar berinteraksi di berbagai tingkat evaluasi.

Traffic di GKE dievaluasi melalui model prioritas multi-tingkat:

Admin Tier ⟶ NetworkPolicy Tier ⟶ Baseline Tier ⟶ Default GKE Behavior

d4cf83398c69b6b8.png

Alur pengujian kami

===================================================
           4-STAGE POLICY EVALUATION FLOW
===================================================

[Stage 1: Default State]
 ├── Pre-Policy State: Default Kubernetes allow-all
 ├── Ingress: client-ns  ──▶ Gemma 4: ALLOWED (200 OK)
 ├── Ingress: untrusted  ──▶ Gemma 4: ALLOWED (200 OK)
 ├── Egress:  All Pods   ──▶ Metadata: ALLOWED (Exposed)
 └── Security Posture: ⚠️ Overly permissive
      │
      ▼
[Stage 2: Baseline Lockdown]
 ├── Policy: ClusterNetworkPolicy (tier: Baseline)
 ├── Rule: Default-deny all cross-namespace ingress
 ├── Ingress: client-ns  ──▶ Gemma 4: DROPPED (Timeout)
 ├── Ingress: untrusted  ──▶ Gemma 4: DROPPED (Timeout)
 └── Security Posture: 🛑 Zero-trust baseline active
      │
      ▼
[Stage 3: Developer Delegation]
 ├── Policy: NetworkPolicy (tier: NetworkPolicy)
 ├── Rule: App team allows ingress from client-ns
 ├── Ingress: client-ns  ──▶ Gemma 4: ALLOWED (200 OK)
 ├── Ingress: untrusted  ──▶ Gemma 4: DROPPED (Timeout)
 └── Security Posture: 🔀 App isolation achieved
      │
      ▼
[Stage 4: Admin Guardrail]
 ├── Policy: ClusterNetworkPolicy (tier: Admin)
 ├── Rule: Cluster-wide metadata drop (169.254.169.254)
 ├── Egress:  All Pods   ──▶ Metadata: DROPPED (Timeout)
 ├── Dev NetPol bypass attempt:   OVERRIDDEN (Blocked)
 └── Security Posture: 🔒 Enforced guardrail
===================================================

Membangun Fondasi Dasar (Pengujian Pra-Kebijakan)

Pastikan model Gemma 4 responsif dan menyalurkan permintaan inferensi. Di Kubernetes standar tanpa kebijakan, semua traffic lintas namespace diizinkan secara implisit.

  1. Uji inferensi dari klien yang diizinkan di client-ns:
kubectl exec -n client-ns deploy/rag-agent-client -- curl --connect-timeout 3 -s -X POST \
  http://gemma-service.gemma-llm.svc.cluster.local:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "google/gemma-4-E2B-it",
    "messages": [{"role": "user", "content": "Explain zero trust in one short sentence."}],
    "max_tokens": 40
  }' | jq -r '.choices[0].message.content'
  1. Uji inferensi dari klien tidak sah yang tidak diizinkan di untrusted-tenant:
kubectl exec -n untrusted-tenant deploy/rogue-client -- curl --connect-timeout 3 -s -X POST \
  http://gemma-service.gemma-llm.svc.cluster.local:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "google/gemma-4-E2B-it",
    "messages": [{"role": "user", "content": "Explain zero trust in one short sentence."}],
    "max_tokens": 40
  }' | jq -r '.choices[0].message.content'
  1. Uji apakah pod di ketiga namespace dapat menjangkau server metadata (169.254.169.254):
echo -e "\n[1/3] Testing Metadata access from Gemma serving pod (gemma-llm)..."
kubectl exec -n gemma-llm deploy/gemma-serving -- curl --connect-timeout 3 -s -w "\nHTTP Code: %{http_code}\n" -H "Metadata-Flavor: Google" \
  http://169.254.169.254/computeMetadata/v1/instance/zone || echo "🛑 RESULT: Connection Timed Out (Blocked)"

echo -e "\n[2/3] Testing Metadata access from authorized client (client-ns)..."
kubectl exec -n client-ns deploy/rag-agent-client -- curl --connect-timeout 3 -s -w "\nHTTP Code: %{http_code}\n" -H "Metadata-Flavor: Google" \
  http://169.254.169.254/computeMetadata/v1/instance/zone || echo "🛑 RESULT: Connection Timed Out (Blocked)"

echo -e "\n[3/3] Testing Metadata access from rogue client (untrusted-tenant)..."
kubectl exec -n untrusted-tenant deploy/rogue-client -- curl --connect-timeout 3 -s -w "\nHTTP Code: %{http_code}\n" -H "Metadata-Flavor: Google" \
  http://169.254.169.254/computeMetadata/v1/instance/zone || echo "🛑 RESULT: Connection Timed Out (Blocked)"

7. Pengujian evaluasi Tingkat Kebijakan Jaringan dan Dasar Pengukuran

Pada langkah ini, dengan bertindak sebagai Cluster Administrator, Anda akan menerapkan Tingkat dasar ClusterNetworkPolicy untuk menetapkan postur default-deny penggantian di seluruh cluster. Setiap komunikasi lintas namespace yang tidak diizinkan secara eksplisit oleh tingkat yang lebih tinggi akan dihapus.

Menetapkan Postur Zero-Trust (Paket Dasar Pengukuran)

  1. Buat manifes kebijakan Paket dasar 03-baseline-deny.yaml:
cat << 'EOF' > 03-baseline-deny.yaml
apiVersion: policy.networking.k8s.io/v1alpha2
kind: ClusterNetworkPolicy
metadata:
  name: baseline-default-deny
spec:
  tier: Baseline
  priority: 1000
  subject:
    namespaces: {}
  ingress:
    # 1. Allow CoreDNS Ingress cluster-wide so DNS resolution never breaks
    - name: allow-dns-ingress
      action: Accept
      from:
        - namespaces: {}
      protocols:
        - udp:
            destinationPort:
              number: 53
        - tcp:
            destinationPort:
              number: 53
    # 2. Default Deny all other cross-namespace ingress
    - name: baseline-deny-cross-ns
      action: Deny
      from:
        - namespaces: {}
EOF
  1. Terapkan kebijakan tingkat Dasar:
kubectl apply -f 03-baseline-deny.yaml
  1. Menguji konektivitas klien dari client-ns.
kubectl exec -n client-ns deploy/rag-agent-client -- curl --connect-timeout 3 -s -X POST \
  http://gemma-service.gemma-llm.svc.cluster.local:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "google/gemma-4-E2B-it",
    "messages": [{"role": "user", "content": "Explain zero trust in one short sentence."}],
    "max_tokens": 40
  }' | jq -r '.choices[0].message.content'
  1. Uji inferensi dari klien berbahaya yang tidak sah di untrusted-tenant:
kubectl exec -n untrusted-tenant deploy/rogue-client -- curl --connect-timeout 3 -s -X POST \
  http://gemma-service.gemma-llm.svc.cluster.local:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "google/gemma-4-E2B-it",
    "messages": [{"role": "user", "content": "Explain zero trust in one short sentence."}],
    "max_tokens": 40
  }' | jq -r '.choices[0].message.content'

Mendelegasikan Akses ke Developer (Tingkat NetworkPolicy)

Tim aplikasi gemma-llm kini akan menerapkan NetworkPolicy standar dengan cakupan namespace untuk memberikan traffic yang diizinkan dari client-ns.

  1. Buat manifes NetworkPolicy 04-app-networkpolicy.yaml developer:
cat << 'EOF' > 04-app-networkpolicy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-rag-client
  namespace: gemma-llm
spec:
  podSelector:
    matchLabels:
      app: gemma-service
  policyTypes:
    - Ingress
  ingress:
    # Explicitly permit ingress only from pods matching app: rag-agent in client-ns
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: client-ns
          podSelector:
            matchLabels:
              app: rag-agent
      ports:
        - protocol: TCP
          port: 8000
EOF
  1. Terapkan kebijakan:
kubectl apply -f 04-app-networkpolicy.yaml
  1. Menguji konektivitas klien dari client-ns
kubectl exec -n client-ns deploy/rag-agent-client -- curl --connect-timeout 3 -s -X POST \
  http://gemma-service.gemma-llm.svc.cluster.local:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "google/gemma-4-E2B-it",
    "messages": [{"role": "user", "content": "Explain zero trust in one short sentence."}],
    "max_tokens": 40
  }' | jq -r '.choices[0].message.content'
  1. Uji konektivitas dari klien tidak sah di untrusted-tenant:
kubectl exec -n untrusted-tenant deploy/rogue-client -- curl --connect-timeout 3 -s -X POST \
  http://gemma-service.gemma-llm.svc.cluster.local:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "google/gemma-4-E2B-it",
    "messages": [{"role": "user", "content": "Explain zero trust in one short sentence."}],
    "max_tokens": 40
  }' | jq -r '.choices[0].message.content'

8. Evaluasi menerapkan Guardrail Global (Paket Admin)

Sebagai Administrator Cluster, Anda sekarang akan menerapkan ClusterNetworkPolicy Tingkat Admin di bagian paling atas urutan evaluasi GKE. Tingkat ini dievaluasi terlebih dahulu, aturan yang cocok akan langsung diprioritaskan daripada semua tingkat lainnya. Jika tidak ada kecocokan, paket akan diteruskan untuk dievaluasi oleh tingkat yang lebih rendah (NetworkPolicy dan Baseline).

Pada langkah ini, Anda akan menerapkan kebijakan yang:

  • Pembatas Egress Seluruh Cluster: Memblokir semua pod di setiap namespace agar tidak menjangkau Server Metadata Google Cloud (169.254.169.254/32).
  • Dukungan DNS: Mengizinkan semua traffic DNS di port 53 sehingga pod dapat me-resolve nama host (memperhitungkan cache DNS lokal GKE).
  • Delegasi Ingress dan Egress: Meneruskan semua keputusan traffic lainnya ke bawah menggunakan tindakan Pass sehingga kebijakan jaringan developer standar dan aturan default-deny dasar dapat membuat keputusan akhir.
  1. Membuat manifes kebijakan tingkat Admin 05-admin-guardrails.yaml yang menargetkan semua namespace
cat << 'EOF' > 05-admin-guardrails.yaml
apiVersion: policy.networking.k8s.io/v1alpha2
kind: ClusterNetworkPolicy
metadata:
  name: admin-global-guardrails
spec:
  tier: Admin
  priority: 10
  subject:
    namespaces: {}
  ingress:
    - name: delegate-all-ingress
      action: Pass
      from:
        - namespaces: {}
  egress:
    - name: allow-all-dns
      action: Accept
      to:
        - networks:
            - 0.0.0.0/0
      protocols:
        - udp:
            destinationPort:
              number: 53
        - tcp:
            destinationPort:
              number: 53
    - name: block-metadata-server-global
      action: Deny
      to:
        - networks:
            - 169.254.169.254/32
    - name: delegate-other-egress
      action: Pass
      to:
        - namespaces: {}
EOF
  1. Terapkan kebijakan tingkat Admin:
kubectl apply -f 05-admin-guardrails.yaml
  1. Uji pemindahan metadata yang tidak sah di ketiga namespace:
echo -e "\n[1/3] Testing Metadata access from Gemma serving pod (gemma-llm)..."
kubectl exec -n gemma-llm deploy/gemma-serving -- curl --connect-timeout 3 -s -w "\nHTTP Code: %{http_code}\n" -H "Metadata-Flavor: Google" \
  http://169.254.169.254/computeMetadata/v1/instance/zone || echo "🛑 RESULT: Connection Timed Out (Blocked)"

echo -e "\n[2/3] Testing Metadata access from authorized client (client-ns)..."
kubectl exec -n client-ns deploy/rag-agent-client -- curl --connect-timeout 3 -s -w "\nHTTP Code: %{http_code}\n" -H "Metadata-Flavor: Google" \
  http://169.254.169.254/computeMetadata/v1/instance/zone || echo "🛑 RESULT: Connection Timed Out (Blocked)"

echo -e "\n[3/3] Testing Metadata access from rogue client (untrusted-tenant)..."
kubectl exec -n untrusted-tenant deploy/rogue-client -- curl --connect-timeout 3 -s -w "\nHTTP Code: %{http_code}\n" -H "Metadata-Flavor: Google" \
  http://169.254.169.254/computeMetadata/v1/instance/zone || echo "🛑 RESULT: Connection Timed Out (Blocked)"
  1. Menguji konektivitas klien dari client-ns
kubectl exec -n client-ns deploy/rag-agent-client -- curl --connect-timeout 3 -s -X POST \
  http://gemma-service.gemma-llm.svc.cluster.local:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "google/gemma-4-E2B-it",
    "messages": [{"role": "user", "content": "Explain zero trust in one short sentence."}],
    "max_tokens": 40
  }' | jq -r '.choices[0].message.content'
  1. Simulasikan upaya bypass developer dengan menerapkan NetworkPolicy egress izinkan semua di dalam gemma-llm:
cat << 'EOF' > 06-bypass-attempt.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: dev-allow-all-egress
  namespace: gemma-llm
spec:
  podSelector: {}
  policyTypes:
    - Egress
  egress:
    - {}
EOF

kubectl apply -f 06-bypass-attempt.yaml
  1. Uji apakah bypass developer dapat membatalkan pemblokiran akses metadata:
kubectl exec -n gemma-llm deploy/gemma-serving -- curl --connect-timeout 3 -s -w "\nHTTP Code: %{http_code}\n" -H "Metadata-Flavor: Google" \
  http://169.254.169.254/computeMetadata/v1/instance/zone || echo "🛑 RESULT: Connection Timed Out (Admin Guardrail Overrode Developer Policy)"

9. Verifikasi Interaktif dengan Hubble dan Cloud Logging

Untuk mengamati penegakan kebijakan real-time dan keputusan paket audit di seluruh cluster, Anda akan menggunakan sesi Cloud Shell Panel Ganda yang menggabungkan pelacakan paket eBPF tingkat kernel dengan eksekusi uji otomatis.

  1. Klik ikon "+" di menu Cloud Shell untuk membuka tab terminal kedua.
  2. Di tab baru ini, jalankan perintah berikut untuk membuat alias dan mulai mengamati traffic langsung untuk namespace gemma-llm:
# Create an alias to execute Hubble natively inside the relay pod
alias hubble="kubectl exec -it -n gke-managed-dpv2-observability deploy/hubble-relay -c hubble-cli -- hubble"

# Observe real-time traffic to and from the Gemma namespace
hubble observe --follow --namespace gemma-llm
  1. Beralih kembali ke tab Cloud Shell pertama dan pastikan Anda berada di direktori gke-cnp-lab
cd ~/gke-cnp-lab
  1. Jalankan blok berikut untuk membuat dan menjalankan skrip verifikasi otomatis. Skrip ini menjalankan pengujian traffic yang diperlukan dan mengkueri Cloud Logging menggunakan skema metadata tingkat root yang tepat dari GKE untuk menampilkan aturan Dataplane V2 yang tepat yang mengevaluasi permintaan:
cat << 'EOF' > verify-suite.sh
#!/usr/bin/env bash
set -e

echo "========================================================"
echo " 🧪 RUNNING MULTI-TIER POLICY VERIFICATION SUITE"
echo "========================================================"

# Test 1: Ingress Authorized Client -> Gemma (Allowed by NetworkPolicy)
echo -e "\n[1/5] Testing Authorized Client -> Gemma Serving..."
if kubectl exec -n client-ns deploy/rag-agent-client -- \
  curl -s --connect-timeout 3 \
  http://gemma-service.gemma-llm.svc.cluster.local:8000/v1/chat/completions > /dev/null; then
  echo "  ✅ RESULT: FORWARDED (Allowed by Developer Network Policy)"
else
  echo "  🛑 RESULT: FAILED"
fi

# Test 2: Ingress Rogue Client -> Gemma (Blocked by Baseline Tier)
echo -e "\n[2/5] Testing Unauthorized Rogue Tenant -> Gemma Serving..."
if kubectl exec -n untrusted-tenant deploy/rogue-client -- \
  curl -s --connect-timeout 3 \
  http://gemma-service.gemma-llm.svc.cluster.local:8000/v1/chat/completions > /dev/null; then
  echo "  ⚠️ RESULT: UNEXPECTED ALLOW"
else
  echo "  🛑 RESULT: DROPPED (Blocked by Baseline Tier)"
fi

# Test 3: Egress Gemma -> GCP Metadata Server (Blocked by Admin Tier)
echo -e "\n[3/5] Testing Metadata access from Gemma serving pod (gemma-llm)..."
kubectl exec -n gemma-llm deploy/gemma-serving -- \
  curl --connect-timeout 3 -s -w "\nHTTP Code: %{http_code}\n" -H "Metadata-Flavor: Google" \
  http://169.254.169.254/computeMetadata/v1/instance/zone || echo "  🛑 RESULT: Connection Timed Out (Blocked)"

# Test 4: Egress Authorized Client -> GCP Metadata Server (Blocked by Admin Tier)
echo -e "\n[4/5] Testing Metadata access from authorized client (client-ns)..."
kubectl exec -n client-ns deploy/rag-agent-client -- \
  curl --connect-timeout 3 -s -w "\nHTTP Code: %{http_code}\n" -H "Metadata-Flavor: Google" \
  http://169.254.169.254/computeMetadata/v1/instance/zone || echo "  🛑 RESULT: Connection Timed Out (Blocked)"

# Test 5: Egress Rogue Client -> GCP Metadata Server (Blocked by Admin Tier)
echo -e "\n[5/5] Testing Metadata access from rogue client (untrusted-tenant)..."
kubectl exec -n untrusted-tenant deploy/rogue-client -- \
  curl --connect-timeout 3 -s -w "\nHTTP Code: %{http_code}\n" -H "Metadata-Flavor: Google" \
  http://169.254.169.254/computeMetadata/v1/instance/zone || echo "  🛑 RESULT: Connection Timed Out (Blocked)"

echo -e "\n========================================================"
echo " 📋 FETCHING AUDIT TRAIL FROM CLOUD LOGGING"
echo "========================================================"
echo "Waiting 12 seconds for telemetry ingestion..."
sleep 12

echo -e "\n🔍 1. Validating Baseline Tier (Rogue Client Block):"
gcloud logging read '
  resource.type="k8s_node"
  logName=~"logs/policy-action"
  jsonPayload.disposition="deny"
  jsonPayload.src.namespace="untrusted-tenant"
  jsonPayload.dest.namespace="gemma-llm"
' --limit=1 --format="table(
    timestamp.date('%H:%M:%S', tz=LOCAL):label=TIME,
    jsonPayload.src.namespace:label=SRC_NS,
    jsonPayload.dest.namespace:label=DEST_NS,
    jsonPayload.policies[0].name:label=BLOCKED_BY_POLICY
)"

echo -e "\n🔍 2. Validating Admin Tier (Metadata Block across all namespaces):"
gcloud logging read '
  resource.type="k8s_node"
  logName=~"logs/policy-action"
  jsonPayload.disposition="deny"
  jsonPayload.connection.dest_ip="169.254.169.254"
' --limit=3 --format="table(
    timestamp.date('%H:%M:%S', tz=LOCAL):label=TIME,
    jsonPayload.src.namespace:label=SRC_NS,
    jsonPayload.connection.dest_ip:label=DEST_IP,
    jsonPayload.policies[0].name:label=BLOCKED_BY_POLICY
)"
EOF

chmod +x verify-suite.sh
./verify-suite.sh
  1. Saat skrip dijalankan di tab pertama, amati output Hubble di tab kedua.

Di Hubble (Tab 2): Anda akan melihat permintaan HTTP yang diizinkan DITERUSKAN dalam warna hijau. Untuk traffic yang diblokir, Anda akan melihat peristiwa merah (DROPPED). Penyewa Nakal: Koneksi diteruskan oleh Lapisan Admin dan diblokir di Lapisan Dasar Pengukuran. Kueri Metadata: Permintaannya untuk menjangkau kredensial cloud langsung diblokir di Tingkat Admin.

7d68cc0e9b90f820.png

Di Cloud Logging (Tab 1): Skrip selesai dengan menarik data audit yang tepat yang dikirim ke Google Cloud Logging. Tindakan ini secara eksplisit membuktikan Tingkat (Admin atau Dasar Pengukuran) dan Kebijakan mana yang bertanggung jawab untuk menghentikan traffic yang tidak sah, yang diformat dengan stempel waktu yang dilokalkan dan sesuai dengan zona waktu.

b9e48fd473451ca2.png

10. Pembersihan

  1. Tutup tab kedua
  2. Beralih kembali ke tab Cloud Shell pertama Anda.
  3. Hapus manifes, namespace, dan secret Kubernetes yang di-deploy secara berurutan:
cd ~/gke-cnp-lab

# Delete policy and verification scripts
rm -f verify-suite.sh
kubectl delete -f 05-admin-guardrails.yaml --ignore-not-found
kubectl delete -f 04-app-networkpolicy.yaml --ignore-not-found
kubectl delete -f 03-baseline-deny.yaml --ignore-not-found
kubectl delete -f 00-network-logging.yaml --ignore-not-found

# Delete workload deployments, secrets, and namespaces
kubectl delete -f 02-gemma4-tpu-vllm.yaml --ignore-not-found
kubectl delete secret hf-secret -n gemma-llm --ignore-not-found
kubectl delete -f 01-namespaces-clients.yaml --ignore-not-found
  1. Bersihkan infrastruktur dengan perintah berikut, ketik yes untuk mengonfirmasi
terraform destroy --auto-approve
  1. Pastikan semua resource dihentikan dengan baik di project aktif Anda:
gcloud container clusters list --region=us-west4
gcloud compute networks list
  1. Hapus direktori dan konten gke-cnp-lab:
cd
rm -r gke-cnp-lab

11. Selamat

Anda telah berhasil menyelesaikan Codelab Mengamankan Workload Inferensi AI dengan ClusterNetworkPolicy GKE.

Dengan menyelesaikan lab praktik ini, Anda telah mendesain dan memvalidasi arsitektur jaringan defense-in-depth multi-tingkat yang andal untuk menyajikan workload LLM pribadi yang sensitif di Google Kubernetes Engine.

Yang Telah Anda Capai:

  • Infrastructure as Code: Menyediakan Cluster GKE Standard pribadi yang sangat aman, subnet regional pribadi, dan hardware Cloud TPU v5e khusus secara dinamis menggunakan Terraform.
  • Telemetri dan Kemampuan Observasi: Mengonfigurasi Logging Jaringan Dataplane V2 bersama dengan pelacakan Hubble eBPF tingkat kernel untuk mencapai visibilitas paket runtime yang mendalam.
  • Postur Keamanan Hierarkis: Contoh pemisahan tugas operasional yang jelas di tiga tingkat evaluasi yang berbeda:
  • Tingkat Admin: Batasan egress yang diterapkan di seluruh cluster dan tidak dapat dilewati, yang memblokir akses kredensial metadata lateral (169.254.169.254).
  • Tingkat NetworkPolicy: Batas ingress cakupan namespace yang didelegasikan kepada developer aplikasi untuk mengizinkan koneksi klien produksi dengan aman.
  • Tingkat Dasar Pengukuran: Membangun jaring pengaman penggantian di seluruh cluster yang secara default menolak traffic tenant yang tidak sah.
  • Audit Real-Time: Jalankan suite pengujian verifikasi lengkap, pantau penurunan paket real-time di level kernel Linux, dan buat kueri audit tindakan kebijakan terstruktur langsung di Google Cloud Logging

Langkah berikutnya/Pelajari lebih lanjut

Anda dapat membaca selengkapnya tentang jaringan GKE