适用于负载平衡器的 Cloud NGFW 基本功能版

1. 简介

此 Codelab 探讨了 Cloud Next Generation Firewall (NGFW) Essentials,以了解如何使用区域级网络防火墙政策来保护内部应用负载平衡器 (ALB) 和代理网络负载平衡器 (NLB)。

Cloud NGFW 是一种完全分布式的防火墙服务,具有高级威胁防护和微细分功能,可保护 Google Cloud 工作负载。在负载平衡器级别启用 Cloud NGFW 会将一致的防火墙政策规则应用于任何进入内部基于代理的负载平衡器的 TCP 流量。它通过针对所有服务更广泛地强制执行政策,简化了组织安全状况的配置。

此 Codelab 涵盖以下 Cloud NGFW 和 Cloud 负载平衡器产品及功能:

  • Cloud NGFW 基本功能版
  • 区域级网络防火墙政策数量
  • 区域级内部应用负载均衡器
  • 后端托管式实例组 (MIG) 和 Private Service Connect (PSC) 网络端点组 (NEG)

注意:如需了解负载平衡器目标的防火墙政策规则的最新支持功能和限制,请参阅 Cloud NFGW 文档。

学习内容

  • 启用以负载平衡器为目标的基本 Cloud NGFW 防火墙政策规则
  • 使用虚拟机实例和 PSC 后端保护内部使用方负载平衡器服务
  • 测试客户端访问并验证防火墙日志

所需条件

2. 概念

防火墙功能层级

Cloud NGFW 有三个功能层级:基本功能版、标准版和企业版。每个递进层级都提供额外的网络流量过滤和检查功能。

Cloud NGFW 基本功能版过滤功能摘要:

层级

能力

网络层

规则参数示例

基本功能版

IP 地址和范围过滤

IP

--src-ip-ranges=1.1.1.0/24,2.2.2.2/32

基本功能版

地址组

IP

--src-address-groups=special-ranges

基本功能版

协议和端口过滤

TCP

--layer4-configs=tcp

基本功能版

安全标记

元数据

--src-secure-tags=tagValues/987654321098

基本功能版

网络类型过滤

IP / 元数据

--src-network-type=INTRA_VPC

负载平衡器转发规则明确定义了目标 TCP 端口。防火墙规则 --layer4-configs= 参数只能指定 tcp。端口值由转发规则本身隐含。

地址组和网络类型有助于提高防火墙政策规则的效率。负载平衡器的防火墙政策规则支持 VPC_NETWORKSINTRA_VPC 网络类型。

注意:负载平衡器的防火墙政策规则仅支持 --direction=INGRESS。这些规则旨在控制对负载平衡器公开的服务的访问权限。

数据平面过滤

Cloud NFGW 基本功能版涵盖基本的第 3 层 (IP 地址) 和第 4 层 (TCP 端口) 有状态防火墙规则。这些防火墙政策规则功能均可在负载平衡器数据平面中高效执行,无需进行完整的数据包检查。

虚拟机实例为目标的 Cloud NGFW Essentials 政策规则在分布式 VPC 网络结构中强制执行,这是核心 Google Cloud 软件定义网络 (Andromeda) 的一部分。数据包过滤和防火墙政策规则在每个虚拟机实例的 Hypervisor 级别强制执行,在数据包到达虚拟机实例网络接口之前执行。

负载平衡器为目标的 Cloud NGFW 基本功能版政策规则通过 Google Cloud 负载平衡器的底层技术(尤其是 Envoy 服务代理基础架构)强制执行。使用相同的 Cloud NFGW 资源模型和规则结构,在基于代理的负载平衡器数据平面中直接强制执行有状态数据包过滤。

负载平衡器目标

负载平衡器为目标的 Cloud NGFW 政策与以虚拟机实例为目标的政策之间存在一些关键区别。

通过指定 --target-type=INTERNAL_MANAGED_LB 以及对负载平衡器转发规则 --target-forwarding-rules=FR_NAME 的特定引用,防火墙政策规则可以应用于目标单个负载平衡器。如需以 VPC 网络区域(其中区域由政策限定范围)中的所有负载平衡器转发规则为目标,应省略具体引用,只需添加 --target-type=INTERNAL_MANAGED_LB 标志即可。

如果规则配置中--target-type参数设置,则该规则默认自动应用于所有虚拟机实例,而应用于负载平衡器。

Codelab 网络

此 Codelab 使用一个包含一个 VPC 网络的项目,以及以下资源:

  • 两个区域级子网
  • 一个区域级网络防火墙政策
  • 三个区域级内部应用负载平衡器
    • www 具有虚拟机实例组后端的 HTTP 服务
    • api 具有虚拟机实例组后端的 HTTP 服务
    • gcs 具有 PSC NEG 后端到 Google API 的 HTTPS 服务
  • 两个虚拟机实例,用于测试各种允许和拒绝政策

figure1

图 1. Codelab 网络

以负载平衡器为目标的防火墙政策规则会关联到负载平衡器转发规则资源。负载平衡器本身由单独定义的资源组成,这些资源共同配置以提供完整的负载均衡服务。转发规则定义直接引用为其定义的特定目标代理资源。

figure2

图 1. Cloud NFGW 适用于负载平衡器资源

Cloud NGFW Essentials 过滤器已编入负载平衡器数据平面,并在定义的目标代理服务层(类似于虚拟机实例接口)实现,使用相同的分布式一致性防火墙机制来强制执行政策。

3. 项目设置

访问您的项目

本 Codelab 使用单个 Google Cloud 项目。配置步骤使用 gcloud cli CLI 和 Linux shell 命令。

首先,访问 Google Cloud 云项目命令行:

设置项目 ID

gcloud config set project YOUR_PROJECT_ID_HERE

启用 API 服务

gcloud services enable \
  cloudresourcemanager.googleapis.com \
  compute.googleapis.com \
  dns.googleapis.com \
  networksecurity.googleapis.com \
  certificatemanager.googleapis.com

设置 shell 环境变量

# set your region preference
export REGION_1="us-west1"
# set your zone preference
export ZONE_1="us-west1-c"
# fetch project info and verify vars set
export PROJECT_ID=$(gcloud config list --format="value(core.project)")
export PROJECT_NO=$(gcloud projects describe ${PROJECT_ID} --format="value(projectNumber)")
echo ${REGION_1}
echo ${ZONE_1}
echo ${PROJECT_ID}
echo ${PROJECT_NO}

4. 网络基础知识

在本部分中,您将部署具有以下特征的网络基础架构:

  • 全球 VPC 网络和区域子网
  • 用于保护 VPC 网络的区域级网络防火墙政策
  • Cloud Router 和 Cloud NAT,供服务器提取软件包
  • 负载平衡器入站流量的 IP 地址预留和 DNS 记录

创建网络资源

# create vpc network
gcloud compute networks create vnet-foo --subnet-mode=custom
# create subnet for clients
gcloud compute networks subnets create subnet-foo-1 \
  --network=vnet-foo \
  --region=${REGION_1} \
  --range=10.0.0.0/24 \
  --enable-private-ip-google-access
# create subnet for backend servers
gcloud compute networks subnets create subnet-foo-2 \
  --network=vnet-foo \
  --region=${REGION_1} \
  --range=172.16.0.0/24 \
  --enable-private-ip-google-access
# create proxy subnet
gcloud compute networks subnets create subnet-foo-3 \
  --purpose=REGIONAL_MANAGED_PROXY \
  --role=ACTIVE \
  --network=vnet-foo \
  --region=${REGION_1} \
  --range=172.16.128.0/23

创建防火墙组件

稍后添加特定于负载平衡器的目标时,将使用此处创建的基本区域级网络防火墙政策。政策必须与负载平衡器位于同一区域。

创建地址组

首先,创建一个地址组,以确定支持负载平衡器功能的来源健康检查探测 IP 范围。必须允许这些范围,负载平衡器后端才能被视为健康。稍后,它还将与以负载平衡器为目标的防火墙政策规则搭配使用。

# create address group
gcloud network-security address-groups create uhc-probes \
  --description="health check probes" \
  --type=IPv4 \
  --capacity=42 \
  --location=${REGION_1}
# add ip ranges to address group
gcloud network-security address-groups add-items uhc-probes \
  --items=35.191.0.0/16,130.211.0.0/22 \
  --location=${REGION_1}

创建防火墙政策

# create fw policy
gcloud compute network-firewall-policies create fw-policy-foo-${REGION_1} \
  --description="foo fw ${REGION_1}" \
  --region=${REGION_1}
# create fw policy rule to allow in iap
gcloud compute network-firewall-policies rules create 1001 \
  --description="allow iap for ssh" \
  --firewall-policy=fw-policy-foo-${REGION_1} \
  --firewall-policy-region=${REGION_1} \
  --action=allow \
  --direction=INGRESS \
  --layer4-configs=tcp:22 \
  --src-ip-ranges=35.235.240.0/20
# create fw policy rule to allow in health checks
gcloud compute network-firewall-policies rules create 1002 \
  --description="allow health checks to backends" \
  --firewall-policy=fw-policy-foo-${REGION_1} \
  --firewall-policy-region=${REGION_1} \
  --action=allow \
  --direction=INGRESS \
  --layer4-configs=tcp \
  --src-address-groups=projects/${PROJECT_ID}/locations/${REGION_1}/addressGroups/uhc-probes
# create fw policy rule to allow in lb proxies
gcloud compute network-firewall-policies rules create 1003 \
  --description="allow lb proxy" \
  --firewall-policy=fw-policy-foo-${REGION_1} \
  --firewall-policy-region=${REGION_1} \
  --action=allow \
  --direction=INGRESS \
  --layer4-configs=tcp:80,tcp:443,tcp:8080 \
  --src-ip-ranges=172.16.128.0/23
# associate fw policy to vnet
gcloud compute network-firewall-policies associations create \
  --name=fw-policy-association-foo-${REGION_1} \
  --firewall-policy=fw-policy-foo-${REGION_1} \
  --network=vnet-foo \
  --firewall-policy-region=${REGION_1}

配置网络服务

创建 Cloud Router 和 NAT 网关

# create router for nat
gcloud compute routers create cr-nat-foo \
  --network=vnet-foo \
  --asn=16550 \
  --region=${REGION_1}
# create nat gateway
gcloud compute routers nats create natgw-foo \
  --router=cr-nat-foo \
  --region=${REGION_1} \
  --auto-allocate-nat-external-ips \
  --nat-all-subnet-ip-ranges

预留 IP 地址

# reserve vip for lb www service
gcloud compute addresses create vip-foo-www \
  --region=${REGION_1} \
  --subnet=subnet-foo-1 \
  --addresses=10.0.0.101
# reserve vip for lb api service
gcloud compute addresses create vip-foo-api \
  --region=${REGION_1} \
  --subnet=subnet-foo-1 \
  --addresses=10.0.0.102
# reserve vip for lb gcs service
gcloud compute addresses create vip-foo-gcs \
  --region=${REGION_1} \
  --subnet=subnet-foo-1 \
  --addresses=10.0.0.103

创建 DNS 记录

# create dns zone
gcloud dns managed-zones create zone-foo \
  --description="private zone for foo" \
  --dns-name=foo.com \
  --networks=vnet-foo \
  --visibility=private
# create dns record for www service
gcloud dns record-sets create www.foo.com \
  --zone=zone-foo \
  --type=A \
  --ttl=300 \
  --rrdatas="10.0.0.101"
# create dns record for api service
gcloud dns record-sets create api.foo.com \
  --zone=zone-foo \
  --type=A \
  --ttl=300 \
  --rrdatas="10.0.0.102"
# create dns record for gcs service
gcloud dns record-sets create gcs.foo.com \
  --zone=zone-foo \
  --type=A \
  --ttl=300 \
  --rrdatas="10.0.0.103"

网络设置部分到此结束…接下来将介绍如何配置负载平衡器。

5. 负载平衡器服务

在本部分中,您将为以下三项服务部署负载平衡器组件(后端服务、网址映射、目标代理和转发规则):

  1. 端口 80 上的 www 服务 (ilb-foo-www)
  2. 端口 8080 上的 api 服务 (ilb-foo-api)
  3. 端口 443 上具有 TLS 证书的 gcs 服务 (ilb-foo-gcs)

以及支持性后端资源:

  1. 在托管式实例组中运行 HTTP 服务器的虚拟机实例
  2. Private Service Connect (PSC) 网络端点组 (NEG) 到 Google API
  3. Google Cloud Storage (GCS) 存储分区

设置后端资源

创建虚拟机实例组服务器

www 负载平衡器将使用运行 Apache 网络服务器并侦听端口 80 的虚拟机实例组后端服务器。

api 负载平衡器将使用侦听端口 8080 的同一虚拟机实例组。

# create vm startup config with http server
cat > vm-server-startup.sh << 'OEOF'
#! /bin/bash
set -e
apt-get update
apt-get install apache2 -y
vm_hostname="$(curl -H "Metadata-Flavor:Google" \
http://169.254.169.254/computeMetadata/v1/instance/name)"
vm_zone="$(curl -H "Metadata-Flavor:Google" \
http://169.254.169.254/computeMetadata/v1/instance/zone | cut -d/ -f4)"
echo "www served from: $vm_hostname in zone $vm_zone on port 80" | \
tee /var/www/html/index.html
echo "Listen 8080" | tee -a /etc/apache2/ports.conf
mkdir -p /var/www/api
echo "api served from: $vm_hostname in zone $vm_zone on port 8080" | \
tee /var/www/api/index.html
tee /etc/apache2/sites-available/api.conf << EOF
<VirtualHost *:8080>
    DocumentRoot /var/www/api
</VirtualHost>
EOF
a2ensite api.conf
systemctl restart apache2
OEOF
# create managed instance group template
gcloud compute instance-templates create mig-template-foo \
  --machine-type=e2-micro \
  --network=vnet-foo \
  --region=${REGION_1} \
  --subnet=subnet-foo-2 \
  --no-address \
  --shielded-secure-boot \
  --metadata-from-file=startup-script=vm-server-startup.sh
# create regional managed instance group
gcloud compute instance-groups managed create mig-foo \
  --region=${REGION_1} \
  --size=2 \
  --template=mig-template-foo \
  --base-instance-name=service-foo
# create named ports for instance group
gcloud compute instance-groups managed set-named-ports mig-foo \
  --named-ports=www-port:80,api-port:8080 \
  --region=${REGION_1}

创建存储桶

gcs 负载平衡器将使用 PSC NEG 后端通过 Google API 前端连接到 Cloud Storage 存储分区。

# create random bucket name
export BUCKET=$(openssl rand -hex 12)
echo ${BUCKET}

注意:关闭 shell 会话后,环境变量会丢失。记下存储分区名称,以便在以后的会话中完成此步骤。

# create bucket
gcloud storage buckets create gs://${BUCKET} --location=${REGION_1}
# give compute sa object admin role on bucket
gcloud storage buckets add-iam-policy-binding gs://${BUCKET} \
  --member=serviceAccount:${PROJECT_NO}-compute@developer.gserviceaccount.com \
  --role=roles/storage.objectAdmin

创建证书

gcs 负载平衡器将使用部署到目标 HTTPS 代理的自签名证书终止客户端 HTTPS 请求。

# create cert
openssl req -x509 -newkey rsa:2048 \
  -nodes \
  -days 365 \
  -keyout foo-gcs-key.pem \
  -out foo-gcs-cert.pem \
  -subj "/CN=Foo, Inc." \
  -addext "subjectAltName=DNS:gcs.foo.com"
# upload to certificate manager
gcloud certificate-manager certificates create cert-foo-gcs \
  --private-key-file=foo-gcs-key.pem \
  --certificate-file=foo-gcs-cert.pem \
  --location=${REGION_1}

创建负载均衡器组件

使用以下脚本自动部署负载平衡器组件。这有助于提高所涉及的所有配置元素的速度和准确性。

部署负载平衡器创建脚本

# create script file
cat > create_lbs.sh << EOF
#!/bin/bash
set -e

# --- Create load balancer for www service port 80 ---
echo "--- Creating Load Balancer for WWW Service (ilb-foo-www) on port 80 ---"

echo "ilb-foo-www: creating health check (hc-foo-www)"
gcloud compute health-checks create http hc-foo-www \
  --use-serving-port \
  --region=${REGION_1}

echo "ilb-foo-www: creating backend service (bes-foo-www)"
gcloud compute backend-services create bes-foo-www \
  --load-balancing-scheme=INTERNAL_MANAGED \
  --protocol=HTTP \
  --port-name=www-port \
  --health-checks=hc-foo-www \
  --health-checks-region=${REGION_1} \
  --region=${REGION_1}

echo "ilb-foo-www: adding managed instance group (mig-foo) to backend service (bes-foo-www)"
gcloud compute backend-services add-backend bes-foo-www \
  --balancing-mode=UTILIZATION \
  --instance-group=mig-foo \
  --instance-group-region=${REGION_1} \
  --region=${REGION_1}

echo "ilb-foo-www: creating url map (ilb-foo-www)"
gcloud compute url-maps create ilb-foo-www \
  --default-service=bes-foo-www \
  --region=${REGION_1}

echo "ilb-foo-www: creating target http proxy (proxy-foo-www)"
gcloud compute target-http-proxies create proxy-foo-www \
  --url-map=ilb-foo-www \
  --url-map-region=${REGION_1} \
  --region=${REGION_1}

echo "ilb-foo-www: creating forwarding rule (fr-foo-www)"
gcloud compute forwarding-rules create fr-foo-www \
  --load-balancing-scheme=INTERNAL_MANAGED \
  --network=vnet-foo \
  --subnet=subnet-foo-1 \
  --subnet-region=${REGION_1} \
  --address=vip-foo-www \
  --ports=80 \
  --target-http-proxy=proxy-foo-www \
  --target-http-proxy-region=${REGION_1} \
  --region=${REGION_1}

echo "--- Successfully created Load Balancer for WWW Service (ilb-foo-www) ---"
echo

# --- Create load balancer for api service port 8080 ---
echo "--- Creating Load Balancer for API Service (ilb-foo-api) on port 8080 ---"

echo "ilb-foo-api: creating health check (hc-foo-api)"
gcloud compute health-checks create http hc-foo-api \
  --use-serving-port \
  --region=${REGION_1}

echo "ilb-foo-api: creating backend service (bes-foo-api)"
gcloud compute backend-services create bes-foo-api \
  --load-balancing-scheme=INTERNAL_MANAGED \
  --protocol=HTTP \
  --port-name=api-port \
  --health-checks=hc-foo-api \
  --health-checks-region=${REGION_1} \
  --region=${REGION_1}

echo "ilb-foo-api: adding managed instance group (mig-foo) to backend service (bes-foo-api)"
gcloud compute backend-services add-backend bes-foo-api \
  --balancing-mode=UTILIZATION \
  --instance-group=mig-foo \
  --instance-group-region=${REGION_1} \
  --region=${REGION_1}

echo "ilb-foo-api: creating url map (ilb-foo-api)"
gcloud compute url-maps create ilb-foo-api \
  --default-service=bes-foo-api \
  --region=${REGION_1}

echo "ilb-foo-api: creating target http proxy (proxy-foo-api)"
gcloud compute target-http-proxies create proxy-foo-api \
  --url-map=ilb-foo-api \
  --url-map-region=${REGION_1} \
  --region=${REGION_1}

echo "ilb-foo-api: creating forwarding rule (fr-foo-api)"
gcloud compute forwarding-rules create fr-foo-api \
  --load-balancing-scheme=INTERNAL_MANAGED \
  --network=vnet-foo \
  --subnet=subnet-foo-1 \
  --subnet-region=${REGION_1} \
  --address=vip-foo-api \
  --ports=8080 \
  --target-http-proxy=proxy-foo-api \
  --target-http-proxy-region=${REGION_1} \
  --region=${REGION_1}

echo "--- Successfully created Load Balancer for API Service (ilb-foo-api) ---"
echo

# --- Create load balancer for gcs service port 443 ---
echo "--- Creating Load Balancer for GCS Service (ilb-foo-gcs) on port 443 ---"

echo "ilb-foo-gcs: creating network endpoint group (neg-psc-gcs)"
gcloud compute network-endpoint-groups create neg-psc-gcs \
  --network-endpoint-type=private-service-connect \
  --psc-target-service=storage.${REGION_1}.rep.googleapis.com \
  --region=${REGION_1}

echo "ilb-foo-gcs: creating backend service (bes-foo-gcs)"
gcloud compute backend-services create bes-foo-gcs \
  --load-balancing-scheme=INTERNAL_MANAGED \
  --protocol=HTTPS \
  --region=${REGION_1}

echo "ilb-foo-gcs: adding network endpoint group (neg-psc-gcs) to backend service (bes-foo-gcs)"
gcloud compute backend-services add-backend bes-foo-gcs \
  --network-endpoint-group=neg-psc-gcs \
  --network-endpoint-group-region=${REGION_1} \
  --region=${REGION_1}

echo "ilb-foo-gcs: creating url map (ilb-foo-gcs)"
gcloud compute url-maps create ilb-foo-gcs \
  --default-service=bes-foo-gcs \
  --region=${REGION_1}

echo "ilb-foo-gcs: creating target https proxy (proxy-foo-gcs)"
gcloud compute target-https-proxies create proxy-foo-gcs \
  --url-map=ilb-foo-gcs \
  --url-map-region=${REGION_1} \
  --certificate-manager-certificates=cert-foo-gcs \
  --region=${REGION_1}

echo "ilb-foo-gcs: creating forwarding rule (fr-foo-gcs)"
gcloud compute forwarding-rules create fr-foo-gcs \
  --load-balancing-scheme=INTERNAL_MANAGED \
  --network=vnet-foo \
  --subnet=subnet-foo-1 \
  --subnet-region=${REGION_1} \
  --address=vip-foo-gcs \
  --ports=443 \
  --target-https-proxy=proxy-foo-gcs \
  --target-https-proxy-region=${REGION_1} \
  --region=${REGION_1}

echo "--- Successfully created Load Balancer for GCS Service (ilb-foo-gcs) ---"
echo

echo "All load balancers created successfully."
EOF
# make script executable
chmod +x create_lbs.sh
# run script
./create_lbs.sh

注意:此脚本需要几分钟才能完成。

验证负载平衡器创建

检查转发规则和后端服务是否已部署。

# check forwarding rules
gcloud compute forwarding-rules list
# check backend services
gcloud compute backend-services list

负载平衡器设置部分到此结束…接下来将配置客户端虚拟机实例。

6. 客户端访问

创建虚拟机客户端资源

在本部分中,您将部署客户端并验证端到端连接。

创建虚拟机实例

# set variables for client ip addresses
export VM_ALLOW_IP="10.0.0.11"
export VM_DENY_IP="10.0.0.12"
echo ${VM_ALLOW_IP}
echo ${VM_DENY_IP}
# create client 1 vm
gcloud compute instances create vm-allow \
  --machine-type=e2-micro \
  --zone=${ZONE_1} \
  --subnet=subnet-foo-1 \
  --no-address \
  --private-network-ip=${VM_ALLOW_IP} \
  --scopes=cloud-platform \
  --shielded-secure-boot
# create client 2 vm
gcloud compute instances create vm-deny \
  --machine-type=e2-micro \
  --zone=${ZONE_1} \
  --subnet=subnet-foo-1 \
  --no-address \
  --private-network-ip=${VM_DENY_IP} \
  --scopes=cloud-platform \
  --shielded-secure-boot

测试基准服务

来自客户端 vm-allow 的测试

注意:在发出 instances create 命令后不久,虚拟机实例就会上线,并且可以通过 ssh 使用 IAP 进行访问。如果首次尝试时请求失败,您可能需要等待片刻。

# send request to foo www service
gcloud compute ssh vm-allow --zone=${ZONE_1} --command="
  curl -s www.foo.com"
# send request to foo api service
gcloud compute ssh vm-allow --zone=${ZONE_1} --command="
  curl -s api.foo.com:8080"

测试通过负载平衡器将文件上传到 Google Cloud Storage。

# send request to foo gcs service
gcloud compute ssh vm-allow --zone=${ZONE_1} --command="
  echo 'test one on the way' > test-upload-1.txt
  TOKEN=\$(gcloud auth print-access-token)
  curl -s -k -X POST \"https://gcs.foo.com/upload/storage/v1/b/${BUCKET}/o?uploadType=media&name=test-upload-object-1.txt\" \
  -H \"Authorization: Bearer \${TOKEN}\" \
  -H \"Content-Type: text/plain\" \
  --data-binary @test-upload-1.txt"

Cloud Storage API 响应确认网络路径正常运行。

来自客户端 vm-deny 的测试

# send request to foo www service
gcloud compute ssh vm-deny --zone=${ZONE_1} --command="
  curl -s www.foo.com"
# send request to foo api service
gcloud compute ssh vm-deny --zone=${ZONE_1} --command="
  curl -s api.foo.com:8080"
# send request to foo gcs service
gcloud compute ssh vm-deny --zone=${ZONE_1} --command="
  echo 'test two on the way' > test-upload-2.txt
  TOKEN=\$(gcloud auth print-access-token)
  curl -s -k -X POST \"https://gcs.foo.com/upload/storage/v1/b/${BUCKET}/o?uploadType=media&name=test-upload-object-2.txt\" \
  -H \"Authorization: Bearer \${TOKEN}\" \
  -H \"Content-Type: text/plain\" \
  --data-binary @test-upload-2.txt"

注意:这些测试也应该会成功,因为目前还没有防火墙规则以负载平衡器为目标。

至此,所有主要设置部分都已完成…接下来,我们将创建负载平衡器防火墙规则。

7. 负载平衡器防火墙

在本部分中,您将部署以负载平衡器为目标的防火墙政策规则。配置序列将逐步构建安全状况,以允许 vm-allow 访问并阻止 vm-deny 流量流向所有服务。

允许部分流量流向 fr-foo-www

向现有防火墙政策 fw-policy-foo-${REGION_1} 添加新的防火墙政策规则

  • 允许包含 vm-allow 但排除 vm-deny IP 地址的来源 IP 范围
  • 添加额外的来源过滤条件 INTRA_VPC,以便在以负载平衡器为目标的防火墙政策规则中使用网络类型

INTRA_VPCVPC_NETWORKS 的来源网络类型与其他来源参数结合使用时,防火墙政策规则支持以负载平衡器为目标。评估逻辑是两个源形参之间的 AND。在此示例中,流量必须满足 INTRA_VPC --src-ip-ranges=${VM_ALLOW_IP}/32 的条件才能获得允许。

创建规则以允许 vm-allow 定位 fr-foo-www

# create fw policy rule
gcloud beta compute network-firewall-policies rules create 2001 \
  --description="allow vm traffic to fr-www" \
  --firewall-policy=fw-policy-foo-${REGION_1} \
  --firewall-policy-region=${REGION_1} \
  --enable-logging \
  --action=allow \
  --direction=INGRESS \
  --layer4-configs=tcp \
  --src-network-type=INTRA_VPC \
  --src-ip-ranges=${VM_ALLOW_IP}/32 \
  --target-type=INTERNAL_MANAGED_LB \
  --target-forwarding-rules=projects/${PROJECT_ID}/regions/${REGION_1}/forwardingRules/fr-foo-www

来自客户端 vm-allow 的测试

# send request to foo www service
gcloud compute ssh vm-allow --zone=${ZONE_1} --command="
  curl -s www.foo.com"

来自客户端 vm-deny 的测试

# send request to foo www service
gcloud compute ssh vm-deny --zone=${ZONE_1} --command="
  curl -s www.foo.com"

注意:之所以成功,是因为负载平衡器的隐式默认防火墙政策规则行为是 --action=allow。需要使用默认(全方位)拒绝规则才能更改此设置。

拒绝向 fr-foo-www 发送的默认流量

添加新的低优先级(优先级编号较高)防火墙政策规则。

  • 拒绝来自任何来源 IP 地址的所有流量
  • 在命中拒绝规则之前,来自 vm-allowfr-foo-www 的流量将被允许

创建规则以拒绝以 fr-foo-www 为目标的流量

# create fw policy rule
gcloud beta compute network-firewall-policies rules create 2999 \
  --description="allow vm traffic to fr-www" \
  --firewall-policy=fw-policy-foo-${REGION_1} \
  --firewall-policy-region=${REGION_1} \
  --enable-logging \
  --action=deny \
  --direction=INGRESS \
  --layer4-configs=tcp \
  --src-ip-ranges=0.0.0.0/0 \
  --target-type=INTERNAL_MANAGED_LB \
  --target-forwarding-rules=projects/${PROJECT_ID}/regions/${REGION_1}/forwardingRules/fr-foo-www

健康检查注意事项

与以虚拟机实例为目标的防火墙政策规则类似,默认的 catchall(隐式)拒绝入站流量规则会阻止来自健康检查探测工具范围的流量,这些流量的目标是负载平衡器后端。因此,我们配置了明确的允许规则,以允许入站健康检查探测范围(请参阅规则 1002)。

重要提示:同样,在为负载平衡器目标创建全盘(明确)拒绝入站流量规则时,必须创建另一条优先级更高(优先级编号更低)的规则,以允许来自健康检查探测范围的入站流量。此规则需要以负载平衡器为目标

# create fw policy rule
gcloud beta compute network-firewall-policies rules create 2002 \
  --description="allow health checks to fr-www" \
  --firewall-policy=fw-policy-foo-${REGION_1} \
  --firewall-policy-region=${REGION_1} \
  --action=allow \
  --direction=INGRESS \
  --layer4-configs=tcp \
  --src-address-groups=projects/${PROJECT_ID}/locations/${REGION_1}/addressGroups/uhc-probes \
  --target-type=INTERNAL_MANAGED_LB \
  --target-forwarding-rules=projects/${PROJECT_ID}/regions/${REGION_1}/forwardingRules/fr-foo-www

来自客户端 vm-deny 的测试

# send request to foo www service
gcloud compute ssh vm-deny --zone=${ZONE_1} --command="
  curl -s www.foo.com"

现在,此命令应该会失败,因为防火墙规则 2999 会拒绝来自 VPC 网络的所有流量。优先级较高的规则(优先级数值较低)2001 仅允许包含 vm-allow 的来源范围。

Ctrl+C 停止 curl 进程。

# send request to foo api service
gcloud compute ssh vm-deny --zone=${ZONE_1} --command="
  curl -s api.foo.com:8080"

vm-deny 仍然可以访问 API 服务!之所以成功,是因为防火墙规则仅专门应用于转发规则 fr-foo-www,而未定位 fr-foo-api

更新规则以面向所有负载平衡器

注意:通过省略 --target-forwarding-rules=FR_NAME,可以将防火墙政策规则应用于 VPC 网络中的所有负载平衡器。

将防火墙政策规则更改为现在应用于 VPC 网络中的所有负载平衡器转发规则目标。

  1. 创建新的入站允许规则 2003,以面向所有转发规则允许虚拟机流量(vm-allow IP 范围)
  2. 创建一条新的入站流量允许规则 2004,以所有转发规则为目标,允许健康检查(uhc-probes 地址组)流量。
  3. 创建新的入站拒绝规则 2998,将所有转发规则作为兜底拒绝规则,以拒绝所有其他流量

修改防火墙规则以面向所有负载平衡器

# create fw policy rule
gcloud beta compute network-firewall-policies rules create 2003 \
  --description="allow vm traffic to all vnet lb fr" \
  --firewall-policy=fw-policy-foo-${REGION_1} \
  --firewall-policy-region=${REGION_1} \
  --enable-logging \
  --action=allow \
  --direction=INGRESS \
  --layer4-configs=tcp  \
  --src-ip-ranges=${VM_ALLOW_IP}/32 \
  --target-type=INTERNAL_MANAGED_LB
# create fw policy rule
gcloud beta compute network-firewall-policies rules create 2004 \
  --description="allow health checks to all vnet lb fr" \
  --firewall-policy=fw-policy-foo-${REGION_1} \
  --firewall-policy-region=${REGION_1} \
  --enable-logging \
  --action=allow \
  --direction=INGRESS \
  --layer4-configs=tcp \
  --src-address-groups=projects/${PROJECT_ID}/locations/${REGION_1}/addressGroups/uhc-probes \
  --target-type=INTERNAL_MANAGED_LB
# create fw policy rule
gcloud beta compute network-firewall-policies rules create 2998 \
  --description="deny all vnet traffic to all vnet lb fr" \
  --firewall-policy=fw-policy-foo-${REGION_1} \
  --firewall-policy-region=${REGION_1} \
  --enable-logging \
  --action=deny \
  --direction=INGRESS \
  --layer4-configs=tcp \
  --src-ip-ranges=0.0.0.0/0 \
  --target-type=INTERNAL_MANAGED_LB

由于之前以明确负载平衡器转发规则为目标的防火墙政策规则现在与以 VPC 网络中的所有转发规则为目标的规则重复,因此可以将其移除。

# delete redundant fw policy rules
gcloud beta compute network-firewall-policies rules delete 2001 \
  --firewall-policy=fw-policy-foo-${REGION_1} \
  --firewall-policy-region=${REGION_1}

gcloud beta compute network-firewall-policies rules delete 2002 \
  --firewall-policy=fw-policy-foo-${REGION_1} \
  --firewall-policy-region=${REGION_1}

gcloud beta compute network-firewall-policies rules delete 2999 \
  --firewall-policy=fw-policy-foo-${REGION_1} \
  --firewall-policy-region=${REGION_1}

来自客户端 vm-deny 的测试

# send request to foo api service
gcloud compute ssh vm-deny --zone=${ZONE_1} --command="
  curl -s api.foo.com:8080"

现在,此命令应该会失败,因为所有具有 --target-type=INTERNAL_MANAGED_LB 的防火墙政策规则也以 fr-foo-api 为目标。

Ctrl+C 停止 curl 进程。

测试通过负载平衡器从 Google Cloud Storage 下载文件。

# send request to foo gcs service
gcloud compute ssh vm-deny --zone=${ZONE_1} --command="
  TOKEN=\$(gcloud auth print-access-token)
  curl -s -k \"https://gcs.foo.com/storage/v1/b/${BUCKET}/o/test-upload-object.txt?alt=media\" \
  -H \"Authorization: Bearer \${TOKEN}\" \
  -o test-download.txt"

Ctrl+C 停止 curl 进程。

来自客户端 vm-allow 的测试

# send request to foo www service
gcloud compute ssh vm-allow --zone=${ZONE_1} --command="
  curl -s www.foo.com"
# send request to foo api service
gcloud compute ssh vm-allow --zone=${ZONE_1} --command="
  curl -s api.foo.com:8080"
# send request to foo gcs service
gcloud compute ssh vm-allow --zone=${ZONE_1} --command="
  TOKEN=\$(gcloud auth print-access-token)
  curl -s -k \"https://gcs.foo.com/storage/v1/b/${BUCKET}/o/test-upload-object-1.txt?alt=media\" \
  -H \"Authorization: Bearer \${TOKEN}\" \
  -o test-download-1.txt"

验证下载内容

# send request from vm
gcloud compute ssh vm-allow --zone=${ZONE_1} --command="
  cat test-download-1.txt"

所有负载平衡器服务均可供 vm-allow 使用,但已成功阻止 vm-deny 使用。

测试部分到此结束…接下来简要介绍一下日志记录。

8. 防火墙规则日志记录

防火墙日志格式包含以负载平衡器为目标的规则 (--target-type=INTERNAL_MANAGED_LB) 的字段和记录。

日志将包含一个标记为 load_balancer_details 的额外字段,其中包含有关防火墙政策规则所针对的负载平衡器的更多信息。这类似于在防火墙政策规则中以虚拟机实例为目标时的 InstanceDetails 字段格式。

  • load_balancer_details.forwarding_rule_name 显示防火墙政策规则的目标转发规则
  • load_balancer_details.type 指示以哪种基于代理的负载平衡器为目标
  • load_balancer_details.url_map_name 记录类型为应用负载平衡器时使用的网址映射资源

查看日志

查询防火墙日志,查看防火墙政策规则的结果。

gcloud logging read \
  "logName=projects/${PROJECT_ID}/logs/compute.googleapis.com%2Ffirewall \
  AND (jsonPayload.connection.src_ip=\"${VM_ALLOW_IP}\" OR jsonPayload.connection.src_ip=\"${VM_DENY_IP}\")" \
  --project=${PROJECT_ID} \
  --freshness=30m \
  --limit=50 \
  --format="table(
    timestamp:label=TIMESTAMP,
    jsonPayload.connection.src_ip:label=SRC_IP,
    jsonPayload.connection.src_port:label=SRC_PORT,
    jsonPayload.connection.dest_ip:label=DEST_IP,
    jsonPayload.connection.dest_port:label=DEST_PORT,
    jsonPayload.disposition:label=ACTION,
    jsonPayload.rule_details.priority:label=PRIORITY,
    jsonPayload.load_balancer_details.forwarding_rule_name:label=FWD_RULE
  )"

日志输出显示了政策强制执行的有效规则:

  • 规则 2011 允许所有指向所有负载平衡器的 vm-allow 流量
  • 规则 2998 会拒绝所有发往负载平衡器的流量
TIMESTAMP                       SRC_IP     SRC_PORT  DEST_IP     DEST_PORT  ACTION   PRIORITY  FWD_RULE
YYYY-MM-DDTHH:MM:SS.850967068Z  10.0.0.11  48480     10.0.0.103  443        ALLOWED  2003      fr-foo-gcs
YYYY-MM-DDTHH:MM:SS.418613380Z  10.0.0.11  37340     10.0.0.101  80         ALLOWED  2003      fr-foo-www
YYYY-MM-DDTHH:MM:SS.213234118Z  10.0.0.12  55950     10.0.0.103  443        DENIED   2998      fr-foo-gcs
YYYY-MM-DDTHH:MM:SS.981484412Z  10.0.0.11  41738     10.0.0.101  80         ALLOWED  2003      fr-foo-www
YYYY-MM-DDTHH:MM:SS.189358071Z  10.0.0.12  55950     10.0.0.103  443        DENIED   2998      fr-foo-gcs
YYYY-MM-DDTHH:MM:SS.061463883Z  10.0.0.12  55950     10.0.0.103  443        DENIED   2998      fr-foo-gcs
YYYY-MM-DDTHH:MM:SS.965498098Z  10.0.0.12  53284     10.0.0.102  8080       DENIED   2998      fr-foo-api

您还可以在 Google Cloud 控制台中使用 Logs Explorer 查看日志。前往 console.cloud.google.com/logs/query,然后使用标准 VPC 防火墙日志 compute.googleapis.com/firewall

logName=projects/${PROJECT_ID}/logs/compute.googleapis.com%2Ffirewall

日志记录部分到此结束…接下来是清理!

9. 清理

# delete client compute resources
gcloud -q compute instances delete vm-deny --zone=${ZONE_1}

gcloud -q compute instances delete vm-allow --zone=${ZONE_1}

# next
# delete load balancer resources for gcs
gcloud -q compute forwarding-rules delete fr-foo-gcs --region=${REGION_1}

gcloud -q compute target-https-proxies delete proxy-foo-gcs --region=${REGION_1}

gcloud -q compute url-maps delete ilb-foo-gcs --region=${REGION_1}

gcloud -q compute backend-services delete bes-foo-gcs --region=${REGION_1}

gcloud -q compute addresses delete vip-foo-gcs --region=${REGION_1}

# next
# delete load balancer resources for api
gcloud -q compute forwarding-rules delete fr-foo-api --region=${REGION_1}

gcloud -q compute target-http-proxies delete proxy-foo-api --region=${REGION_1}

gcloud -q compute url-maps delete ilb-foo-api --region=${REGION_1}

gcloud -q compute backend-services delete bes-foo-api --region=${REGION_1}

gcloud -q compute health-checks delete hc-foo-api --region=${REGION_1}

gcloud -q compute addresses delete vip-foo-api --region=${REGION_1}

# next
# delete load balancer resources for www
gcloud -q compute forwarding-rules delete fr-foo-www --region=${REGION_1}

gcloud -q compute target-http-proxies delete proxy-foo-www --region=${REGION_1}

gcloud -q compute url-maps delete ilb-foo-www --region=${REGION_1}

gcloud -q compute backend-services delete bes-foo-www --region=${REGION_1}

gcloud -q compute health-checks delete hc-foo-www --region=${REGION_1}

gcloud -q compute addresses delete vip-foo-www --region=${REGION_1}

# next
# delete service backend resources
gcloud -q storage rm --recursive gs://${BUCKET}

gcloud -q certificate-manager certificates delete cert-foo-gcs --location=${REGION_1}

gcloud -q compute network-endpoint-groups delete neg-psc-gcs --region=${REGION_1}

gcloud -q compute instance-groups managed delete mig-foo --region=${REGION_1}

gcloud -q compute instance-templates delete mig-template-foo --global

# next
# delete dns, nat, fw resources
gcloud -q dns record-sets delete gcs.foo.com --type=A --zone=zone-foo

gcloud -q dns record-sets delete api.foo.com --type=A --zone=zone-foo

gcloud -q dns record-sets delete www.foo.com --type=A --zone=zone-foo

gcloud -q dns managed-zones delete zone-foo

gcloud -q compute routers delete cr-nat-foo --region=${REGION_1}

gcloud -q compute network-firewall-policies associations delete \
  --firewall-policy=fw-policy-foo-${REGION_1} \
  --name=fw-policy-association-foo-${REGION_1} \
  --firewall-policy-region=${REGION_1}

gcloud -q compute network-firewall-policies delete fw-policy-foo-${REGION_1} --region=${REGION_1}

gcloud -q network-security address-groups delete uhc-probes --location=${REGION_1}

# next
# delete network resources
gcloud -q compute networks subnets delete subnet-foo-3 --region=${REGION_1}

gcloud -q compute networks subnets delete subnet-foo-2 --region=${REGION_1}

gcloud -q compute networks subnets delete subnet-foo-1 --region=${REGION_1}

gcloud -q compute networks delete vnet-foo

# next
# delete shell variables and local files
unset PROJECT_ID REGION_1 ZONE_1 VM_ALLOW_IP VM_DENY_IP BUCKET

rm vm-server-startup.sh create_lbs.sh foo-gcs-key.pem foo-gcs-cert.pem

# end

10. 总结

恭喜!您已成功为负载平衡器配置 Cloud NGFW Essentials

欢迎随时使用此反馈表单提供任何意见、提出问题或做出更正

谢谢!