1. 概览
本实验将向您介绍 Google Kubernetes Engine (GKE) 上的 ClusterNetworkPolicy。ClusterNetworkPolicy 适用于各种用例,可在整个集群范围内应用,并在管理员层和基准层强制执行。在此示例中,我们将演示如何使用 TPU、vLLM 和验证在 GKE 上通过 LLM 部署 (Gemma) 进行控制。
您将使用以下技术:
- Google Kubernetes Engine (GKE) - 基础容器编排平台,用于托管私密、可扩缩的工作负载。
- ClusterNetworkPolicy (CNP) - 集群级多层级网络政策,可在 Admin、NetworkPolicy 和 Baseline 层级实现 SecOps 护栏。
- vLLM TPU 推理引擎 - 在 Google TPU 上使用与 OpenAI 兼容的 REST 端点,为轻量级 Gemma 4 模型 (google/gemma-4-E2B-it) 提供高吞吐量推理服务。
角色和用户画像
网络政策 API 围绕特定的组织角色进行构建:
- 集群管理员使用 (
ClusterNetworkPolicy):在管理员和基准层级强制执行集群安全防护措施。 - 命名空间管理员使用 (
NetworkPolicy):管理特定命名空间内的租户级边界和隔离。 - 应用开发者使用 (
NetworkPolicy):为特定于应用的微服务定义精细规则。
为了配置此环境,您将部署一个自定义专用 VPC、Cloud NAT 以及一个具有专用 TPU 节点池的专用 GKE 集群。
为了保护集群,您将编写多层 ClusterNetworkPolicy 资源以及标准 NetworkPolicy 对象,以强制执行严格的网络安全措施。然后,您将部署一个 AI 工作负载,该工作负载使用 vLLM 和 Google Cloud TPU 来部署 Gemma 4 模型。
最后,您将建立一个工作基准,应用安全政策,并使用 Cloud Logging 和实时 Hubble eBPF 可观测性流配置 NetworkLogging,以审核这些政策决策并验证丢包情况。所有配置都将结合使用 Terraform、gcloud 和 kubectl.
在本实验中,您将学习如何执行以下任务:
- 使用 Terraform 预配专用网络、GKE 集群和 Cloud TPU v5e 加速器。
- 配置 GKE NetworkLogging 以记录连接遥测数据。
- 使用官方 vllm/vllm-tpu 容器映像在 TPU 上部署 Gemma 4 E2B。
- 在应用限制之前,请先建立一个可正常运行的基准,以证明端到端连接。
- 应用
Baseline-tierClusterNetworkPolicy,以默认拒绝未经授权的跨命名空间流量。 - 应用开发者管理的 NetworkPolicy,将访问权限委托给授权客户端。
- 应用
Admin-tierClusterNetworkPolicy,以强制执行会覆盖开发者设置的全局出站流量保护措施。 - 使用 Hubble eBPF 流和 Cloud Logging 验证实时丢包和通过情况。
在本实验中,您将创建以下模式。
图 1. 
2. Google Cloud 服务设置
自定进度的环境设置
- 登录 Google Cloud 控制台,然后创建一个新项目或重复使用现有项目。如果您还没有 Gmail 或 Google Workspace 账号,则必须创建一个。



- 项目名称是此项目参与者的显示名称。它是 Google API 尚未使用的字符串。您可以随时对其进行更新。
- 项目 ID 在所有 Google Cloud 项目中是唯一的,并且是不可变的(一经设置便无法更改)。Cloud 控制台会自动生成一个唯一字符串;通常情况下,您无需关注该字符串。在大多数 Codelab 中,您都需要引用项目 ID(通常用
PROJECT_ID标识)。如果您不喜欢生成的 ID,可以再随机生成一个 ID。或者,您也可以尝试自己的项目 ID,看看是否可用。完成此步骤后便无法更改该 ID,并且此 ID 在项目期间会一直保留。 - 此外,还有第三个值,即部分 API 使用的项目编号,供您参考。如需详细了解所有这三个值,请参阅文档。
- 接下来,您需要在 Cloud 控制台中启用结算功能,以便使用 Cloud 资源/API。运行此 Codelab 应该不会产生太多的费用(如果有的话)。若要关闭资源以避免产生超出本教程范围的结算费用,您可以删除自己创建的资源或删除项目。Google Cloud 新用户符合参与 300 美元免费试用计划的条件。
启动 Cloud Shell
虽然可以通过笔记本电脑对 Google Cloud 进行远程操作,但在此 Codelab 中,您将使用 Google Cloud Shell,这是一个在云端运行的命令行环境。
在 Google Cloud 控制台 中,点击右上角工具栏中的 Cloud Shell 图标:

预配和连接到环境应该只需要片刻时间。完成后,您应该会看到如下内容:

这个虚拟机已加载了您需要的所有开发者工具。它提供了一个持久的 5 GB 主目录,并且在 Google Cloud 中运行,大大增强了网络性能和身份验证功能。您在此 Codelab 中的所有工作都可以在浏览器中完成。您无需安装任何程序。
3. 使用 Terraform 设置环境
为完成此实验,
- 您需要有权访问所选区域和可用区中的 TPU v5e 配额,例如 (
us-central1-a, us-west4-a, us-south1-a, us-west1-c, europe-west4-b)。您应按照 TPU 方案文档中的说明启用 TPU 配额,以获取访问权限。 - 这是一个小型部署,需要 4 个 TPU v5e 芯片 (
ct5lp-hightpu-4t),),这些芯片将在单个可用区中形成一个 2x2 切片。
使用 Hugging Face
我们将创建一个具有防火墙规则和子网的自定义 VPC,然后创建一个 Autopilot 集群。打开 Cloud 控制台,然后选择您要使用的项目。
- 打开 Cloud Shell(位于控制台右上角),确保在 Cloud Shell 中看到正确的项目 ID,并确认所有允许访问的提示。

- 创建名为
gke-cnp-lab,的目录,然后切换到该目录。
mkdir -p gke-cnp-lab && cd gke-cnp-lab
- 现在,创建一些变量。注意:请修改 REGION 和 ZONE,以反映您有权访问 TPU 资源的实际位置。实验中使用的默认区域
us-west4和可用区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"
- 将配置变量保存到 gke-cnp-lab 目录中的辅助脚本。如果您的 Cloud Shell 会话断开连接或重置,您可以运行
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
- 现在,添加一些配置文件。这些命令将在 gke-cnp-lab 目录中创建以下文件:terraform.tfvars、variables.tf、main.tf。
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
- 确保您位于 gke-cnp-lab 目录中,然后运行以下命令
terraform init初始化工作目录。这是第一步,它会下载给定配置所需的提供程序。terraform plan -out会生成执行计划,显示 Terraform 将采取哪些操作来部署您的基础架构。-out允许您将执行计划保存到命名的二进制文件中。您可以在不进行任何更改的情况下查看会发生什么。terraform apply会运行更新。
terraform init
terraform plan -out cnpgke
- 应用执行计划。由于您应用的是已保存的执行计划,因此该计划会立即执行,而不会提示您进行确认(这可能需要 6-10 分钟)
terraform apply cnpgke
- 验证基础架构部署:
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

4. 配置网络日志记录
在部署工作负载和政策之前,请先配置 GKE 网络日志记录,以便在 Cloud Logging 中记录连接遥测数据和审核政策决策。
- 在
gke-cnp-lab目录中,创建 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
- 将配置应用于集群
kubectl apply -f 00-network-logging.yaml
kubectl get networklogging default
注意:您可能会看到一条警告,指出资源缺少 kubectl.kubernetes.io/last-applied-configuration annotation.。这完全正常,符合预期!GKE 会在集群启动时预先创建一个默认的 NetworkLogging 对象,而 kubectl apply 只是接管其管理,以应用您的新规则。
5. 部署 Gemma 4 工作负载和客户端探测
您将创建隔离的命名空间,以测试多层级政策评估:
gemma-llm:托管核心 Gemma 4 推理工作负载 (tier: ai-core)。client-ns:存放已获授权的 RAG 聊天客户端 (tier: app-frontend)。untrusted-tenant:容纳未经授权的探测容器 (tier: untrusted)。
- 在
gke-cnp-lab directory,中,创建包含命名空间和测试客户端 Pod 的01-namespaces-clients.yaml清单:
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
- 应用命名空间和客户端部署:
kubectl apply -f 01-namespaces-clients.yaml
kubectl get namespaces gemma-llm client-ns untrusted-tenant --show-labels
部署工作负载 vLLM 和 Gemma
创建 Hugging Face 密钥。将 YOUR_ACTUAL_HUGGING_FACE_TOKEN 替换为您的令牌:
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}
- 使用 vllm-tpu 创建针对 Cloud TPU v5e 的 Gemma 4 推理工作负载清单:
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
- 创建部署。
kubectl apply -f 02-gemma4-tpu-vllm.yaml
- 如需监控完成状态,请运行以下脚本。Pod 会等到节点预配完成后再继续,这可能需要 13 分钟以上。
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. 了解政策评估和默认状态
在应用网络政策之前,请先了解 GKE ClusterNetworkPolicy 和标准 Kubernetes NetworkPolicy 如何在不同的评估层级中交互。
GKE 中的流量通过多层级优先级模型进行评估:
Admin Tier ⟶ NetworkPolicy Tier ⟶ Baseline Tier ⟶ Default GKE Behavior

我们的测试流程
===================================================
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
===================================================
建立基准(政策测试前)
验证 Gemma 4 模型是否正常运行并正在处理推理请求。在没有政策的标准 Kubernetes 中,所有跨命名空间流量都会被隐式允许。
- 在
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'
- 在
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'
- 测试所有三个命名空间中的 Pod 是否都可以访问元数据服务器 (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. 评估测试基准和网络政策层级
在此步骤中,您将以集群管理员的身份应用基准层级ClusterNetworkPolicy,以建立集群范围内的后备默认拒绝状态。任何未获得更高层级明确允许的跨命名空间通信都将被丢弃。
建立零信任安全状况(基准层级)
- 创建
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
- 应用基准层级政策:
kubectl apply -f 03-baseline-deny.yaml
- 测试来自
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'
- 测试来自 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'
向开发者授予访问权限(NetworkPolicy 层级)
gemma-llm 应用团队现在将应用一个标准的命名空间级 NetworkPolicy,以允许来自 client-ns 的授权流量。
- 创建开发者
04-app-networkpolicy.yamlNetworkPolicy 清单:
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
- 应用政策:
kubectl apply -f 04-app-networkpolicy.yaml
- 测试来自
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'
- 测试来自
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. 评估强制执行全局护栏(管理员层级)
作为集群管理员,您现在将在 GKE 评估顺序的最顶层强制执行管理员层级ClusterNetworkPolicy。系统会首先评估此层级,任何匹配的规则都会立即优先于所有其他层级。如果没有匹配项,数据包会被传递到较低层级(NetworkPolicy 和 Baseline)进行评估。
在此步骤中,您将应用一项政策,该政策会:
- 集群级出站流量护栏:阻止每个命名空间中的所有 Pod 访问 Google Cloud 元数据服务器 (
169.254.169.254/32)。 - DNS 支持:允许端口 53 上的所有 DNS 流量,以便 Pod 可以解析主机名(考虑到 GKE 的本地 DNS 缓存)。
- 入站和出站流量委托:使用“通过”操作将所有其他流量决策向下传递,以便标准开发者网络政策和基准默认拒绝规则可以做出最终决策。
- 创建针对所有命名空间的
05-admin-guardrails.yaml管理员层级政策清单
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
- 应用管理员层级政策:
kubectl apply -f 05-admin-guardrails.yaml
- 测试所有三个命名空间中的元数据渗漏:
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)"
- 测试来自
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'
- 在 gemma-llm 中应用允许所有出站流量的 NetworkPolicy,模拟开发者尝试绕过限制:
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
- 测试开发者绕过功能是否可以解除元数据访问限制:
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. 使用 Hubble 和 Cloud Logging 进行交互式验证
为了观察整个集群中的实时政策执行和数据包审核决策,您将使用双窗格 Cloud Shell 会话,将内核级 eBPF 数据包跟踪与自动化测试执行相结合。
- 点击 Cloud Shell 菜单中的“+”图标,打开第二个终端标签页。
- 在此新标签页中,运行以下命令以创建别名并开始观察
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
- 切换回第一个 Cloud Shell 标签页,并确保您位于
gke-cnp-lab目录中
cd ~/gke-cnp-lab
- 运行以下代码块,创建并执行自动验证脚本。此脚本会运行所需的流量测试,并使用 GKE 的确切根级元数据架构查询 Cloud Logging,以显示评估请求的确切 Dataplane V2 规则:
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
- 当脚本在第一个标签页中执行时,请在第二个标签页中观察 Hubble 输出。
在 Hubble(标签页 2)中:您会看到已获授权的 HTTP 请求被转发(显示为绿色)。对于被屏蔽的流量,您会看到红色 (DROPPED) 事件。流氓租户:连接由管理员层传递,并在基准层被屏蔽。元数据查询:其获取云凭据的请求会在管理员层立即被阻止。

在 Cloud Logging 中(标签页 1):脚本最后会拉取发送到 Google Cloud Logging 的确切审核记录。这会明确证明哪个层级(管理员或基准)和哪项政策负责阻止未经授权的流量,并采用本地化、时区感知的时间戳格式。

10. 清理
- 关闭第二个标签页
- 切换回第一个 Cloud Shell 标签页。
- 按顺序删除已部署的 Kubernetes 清单、命名空间和 Secret:
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
- 使用以下命令清理基础架构,输入
yes进行确认
terraform destroy --auto-approve
- 验证活动项目中的所有资源是否都已完全终止:
gcloud container clusters list --region=us-west4
gcloud compute networks list
- 删除
gke-cnp-lab目录和内容:
cd
rm -r gke-cnp-lab
11. 恭喜
您已成功完成“使用 GKE ClusterNetworkPolicy 保护 AI 推理工作负载”Codelab!
通过完成本实操实验,您设计并验证了一个强大的多层纵深防御网络架构,用于在 Google Kubernetes Engine 上运行敏感的私有 LLM 工作负载。
您已完成的操作:
- 基础设施即代码:使用 Terraform 动态预配了高度安全的专用 Standard GKE 集群、专用区域级子网和专用 Cloud TPU v5e 硬件。
- 遥测和可观测性:配置了 Dataplane V2 网络日志记录以及内核级 eBPF Hubble 跟踪,以实现深度运行时数据包可见性。
- 分层安全状况:例如,在三个不同的评估层级之间明确划分运营职责:
- 管理员层级:在整个集群范围内强制执行、不可绕过的出站流量防护机制,可阻止横向元数据凭证访问 (169.254.169.254)。
- NetworkPolicy 层级:将命名空间范围的入站流量边界委托给应用开发者,以安全地授权生产客户端连接。
- 基准层级:构建了集群范围的后备安全网,默认拒绝未经授权的租户流量。
- 实时审核:运行完整的验证测试套件,在 Linux 内核级别监控实时丢包情况,并直接在 Google Cloud Logging 中查询结构化政策操作审核
后续步骤/了解详情
您可以详细了解 GKE 网络