基于政策的路由 (PBR) Codelab

1. 简介

基于政策的路由

基于政策的路由可让您根据数据包的目标 IP 地址以外的更多因素选择下一个跃点。您还可以按协议和来源 IP 地址匹配流量。匹配的流量会重定向到内部网络负载平衡器。这可以帮助您在网络流量的路径中插入防火墙等设备。

创建基于政策的路由时,您可以选择让路由处理哪些资源的流量。该路由可适用于以下情况:

  • 整个网络:所有虚拟机 (VM) 实例、VPN 网关和互连
  • 使用网络标记:选择 VPC 中的虚拟机实例
  • 互连区域:所有通过该区域的 VLAN 连接进入 VPC 网络的流量

基于政策的路由的下一个跃点必须是有效的内部网络负载平衡器,并且与基于政策的路由位于同一 VPC 网络中。

默认情况下,内部网络负载平衡器使用对称哈希,因此流量可以到达传出路径和返回路径上的同一设备,而无需配置源 NAT。

基于政策的路由的优先级高于其他路由类型,但特殊返回路径除外。

如果两个基于政策的路由具有相同的优先级,则 Google Cloud 会使用确定性的内部算法来选择单个基于政策的路由,并忽略具有相同优先级的其他路由。基于政策的路由不使用最长前缀匹配,仅选择优先级最高的路由。

您可以为单向流量创建一条规则,也可以创建多条规则来处理双向流量。

如需将基于政策的路由与 Cloud Interconnect 结合使用,路由必须应用于整个区域中的所有 Cloud Interconnect 连接。基于政策的路由不能仅应用于单个 Cloud Interconnect 连接。

从基于政策的路由接收流量的虚拟机实例必须启用 IP 转发

使用 PBR 时的注意事项

必须进行特殊配置,才能通过以下方式使用基于政策的路由。

例如,将 PBR 与 GKE、PSC 或 PGA/PSA 搭配使用。

如需详细了解适用于 GKE 的 PBR,请点击此处;如需了解一般 PBR 限制部分,请点击此处

学习内容

  • 如何配置基于政策的路由

所需条件

  • 具备部署实例和配置网络组件方面的知识
  • VPC 防火墙配置知识

2. 测试环境

此 Codelab 将利用单个 VPC。此环境中将有两个计算资源(clienta 和 clientb),会将数据包发送到另一个服务器资源。使用 PBR 和过滤器,当 clientb 流量直接进入服务器时,我们将强制来自 clienta 的流量通过另一个计算资源强制执行防火墙。下图说明了该路径。

bff32b01ada8e9ad.png

在上图中,从技术上讲,PBR 路径应该存在 ILB(网络内部负载平衡器)。为简单起见,省略了这一步。

3. 准备工作

Codelab 需要单个项目。

从 cloudshell 中:

export project_id=`gcloud config list --format="value(core.project)"`
export region=us-central1
export zone=us-central1-a
export prefix=codelab-pbr

4. 启用 API

请启用 API 以使用产品(如果尚未启用)

从 cloudshell 中:

gcloud services enable compute.googleapis.com
gcloud services enable networkconnectivity.googleapis.com

5. 创建 VPC 网络和子网

VPC 网络

创建 Codelab-pbr-vpc VPC:

从 cloudshell 中:

gcloud compute networks create $prefix-vpc --subnet-mode=custom 

子网

在所选区域中创建相应的子网:

从 cloudshell 中:

gcloud compute networks subnets create $prefix-vpc-subnet \
   --range=10.10.10.0/24 --network=$prefix-vpc --region=${region}

6. 创建防火墙规则

要允许 IAP 连接到您的虚拟机实例,请创建以下防火墙规则:

  • 适用于您希望可以使用 IAP 访问的所有虚拟机实例。
  • 允许来自 IP 范围 35.235.240.0/20 的入站流量。此范围包含 IAP 用于 TCP 转发的所有 IP 地址。

从 cloudshell 中:

gcloud compute firewall-rules create $prefix-allow-iap-proxy \
--direction=INGRESS \
--priority=1000 \
--network=$prefix-vpc \
--action=ALLOW \
--rules=tcp:22 \
--source-ranges=35.235.240.0/20

如需允许服务器使用标准 HTTP 端口 (TCP 80) 和 ICMP 协议,请执行以下操作:

  • 适用于带有“server”网络标记的资源
  • 允许来自所有来源的入站流量

从 cloudshell 中:

gcloud compute firewall-rules create $prefix-allow-http-icmp \
--direction=INGRESS \
--priority=1000 \
--network=$prefix-vpc \
--action=ALLOW \
--rules=tcp:80,icmp \
--source-ranges=0.0.0.0/0 \
--target-tags=server

如需允许 FW 接收数据包,请允许所有协议和端口上的入站流量。

  • 适用于带有网络标记“fw”的资源
  • 允许来自 10.10.10.0/24 来源的入站流量

从 cloudshell 中:

gcloud compute firewall-rules create $prefix-fw-allow-ingress \
--direction=INGRESS \
--priority=1000 \
--network=$prefix-vpc \
--action=ALLOW \
--rules=all \
--source-ranges=10.10.10.0/24 \
--target-tags=fw

允许健康检查探测

  • 应用于带有网络标记“fw”的资源
  • 允许来自健康检查范围的入站流量

从 cloudshell 中:

gcloud compute firewall-rules create $prefix-allow-hc-ingress \
--direction=INGRESS \
--priority=1000 \
--network=$prefix-vpc \
--action=ALLOW \
--rules=tcp:80 \
--source-ranges=130.211.0.0/22,35.191.0.0/16 \
--target-tags=fw

7. 创建 Cloud Router 路由器和Cloud NAT

本部分旨在让专用虚拟机能够从互联网下载相应的软件包。

创建 Cloud Router 路由器

从 cloudshell 中:

gcloud compute routers create ${prefix}-cr \
--region=${region} \
--network=${prefix}-vpc

创建 Cloud NAT 网关

从 cloudshell 中:

gcloud compute routers nats create ${prefix}-nat-gw-${region} \
--router=${prefix}-cr \
--router-region=${region} \
--auto-allocate-nat-external-ips \
--nat-all-subnet-ip-ranges

8. 创建计算实例

创建计算实例 ClientA、ClientB、FW 和 Server:

从 cloudshell 中:

gcloud compute instances create clienta \
   --subnet=$prefix-vpc-subnet \
   --no-address \
   --private-network-ip=10.10.10.10 \
   --zone $zone \
   --tags client \
   --metadata startup-script='#! /bin/bash
apt-get update'

从 cloudshell 中:

gcloud compute instances create clientb \
   --subnet=$prefix-vpc-subnet \
   --no-address \
   --private-network-ip=10.10.10.11 \
   --zone $zone \
   --tags client \
   --metadata startup-script='#! /bin/bash
apt-get update'

从 cloudshell 中:

gcloud compute instances create server \
   --subnet=$prefix-vpc-subnet \
   --no-address \
   --private-network-ip=10.10.10.200 \
   --zone $zone \
   --tags server \
   --metadata startup-script='#! /bin/bash
sudo su
apt-get update
apt-get -y install tcpdump
apt-get -y install nginx
cat > /var/www/html/index.html << EOF
<html><body><p>Server</p></body></html>
EOF'

从 cloudshell 中:

gcloud compute instances create fw \
   --subnet=$prefix-vpc-subnet \
   --can-ip-forward \
   --no-address \
   --private-network-ip=10.10.10.75 \
   --zone $zone \
   --tags fw \
   --metadata startup-script='#! /bin/bash
apt-get update
sudo apt-get -y install tcpdump
sudo apt-get -y install nginx
sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -I FORWARD -d 10.10.10.200 -j REJECT'

9. 在不使用 PBR 的情况下测试连接

通过 SSH 连接到我们最近创建的客户端计算虚拟机,并验证两个客户端与服务器之间的连接。

从 cloudshell1 登录 clienta:

gcloud compute ssh clienta --zone=$zone --tunnel-through-iap

运行以下命令:

ping 10.10.10.200 -c 5
curl 10.10.10.200/index.html

ping 和 curl 请求应该会成功。

输出:

root@clienta:~$ ping 10.10.10.200 -c 5
PING 10.10.10.200 (10.10.10.200) 56(84) bytes of data.
64 bytes from 10.10.10.200: icmp_seq=1 ttl=64 time=1.346 ms
64 bytes from 10.10.10.200: icmp_seq=2 ttl=64 time=0.249 ms
64 bytes from 10.10.10.200: icmp_seq=3 ttl=64 time=0.305 ms
64 bytes from 10.10.10.200: icmp_seq=4 ttl=64 time=0.329 ms
64 bytes from 10.10.10.200: icmp_seq=5 ttl=64 time=0.240 ms
root@clienta:~$ curl 10.10.10.200/index.html
<html><body><p>Server</p></body></html>

点击 + 以打开另一个 Cloudshell 标签页。

3722d8574c3812b1

在 cloudshell2 中设置要使用的变量:

export project_id=`gcloud config list --format="value(core.project)"`
export region=us-central1
export zone=us-central1-a
export prefix=codelab-pbr

从 cloudshell2 SSH 到 clientb:

gcloud compute ssh clientb --zone=$zone --tunnel-through-iap

运行以下命令:

ping 10.10.10.200 -c 5
curl 10.10.10.200/index.html

ping 和 curl 请求应该会成功。

输出:

root@clientb:~$ ping 10.10.10.200 -c 5
PING 10.10.10.200 (10.10.10.200) 56(84) bytes of data.
64 bytes from 10.10.10.200: icmp_seq=1 ttl=64 time=1.346 ms
64 bytes from 10.10.10.200: icmp_seq=2 ttl=64 time=0.249 ms
64 bytes from 10.10.10.200: icmp_seq=3 ttl=64 time=0.305 ms
64 bytes from 10.10.10.200: icmp_seq=4 ttl=64 time=0.329 ms
64 bytes from 10.10.10.200: icmp_seq=5 ttl=64 time=0.240 ms
root@clientb:~$ curl 10.10.10.200/index.html
<html><body><p>Server</p></body></html>

现在,退出虚拟机终端并返回 Cloudshell。

10. 创建实例组

为您的第一个虚拟机创建非代管实例组。

从 cloudshell 中:

gcloud compute instance-groups unmanaged create pbr-uig --zone=$zone

将 fw 实例添加到非代管实例组。

从 cloudshell 中:

gcloud compute instance-groups unmanaged add-instances pbr-uig --instances=fw --zone=$zone

11. 创建健康检查

为后端服务创建健康检查。我们将进行简单的 TCP 端口 80 健康检查。

从 cloudshell 中:

gcloud compute health-checks create tcp $prefix-hc-tcp-80 --region=$region --port 80

12. 创建后端服务

创建要附加到转发规则的后端服务。

从 cloudshell 中:

gcloud compute backend-services create be-pbr --load-balancing-scheme=internal --protocol=tcp --region=$region --health-checks=$prefix-hc-tcp-80 --health-checks-region=$region

现在,将该实例组添加到后端服务。

从 cloudshell 中:

gcloud compute backend-services add-backend be-pbr --region=$region --instance-group=pbr-uig --instance-group-zone=$zone

13. 创建转发规则

从 cloudshell 中:

gcloud compute forwarding-rules create fr-pbr --region=$region --load-balancing-scheme=internal --network=$prefix-vpc --subnet=$prefix-vpc-subnet --ip-protocol=TCP --ports=ALL --backend-service=be-pbr --backend-service-region=$region --address=10.10.10.25 --network-tier=PREMIUM

14. 创建 PBR 规则

此 PBR 规则适用于客户。如果来源 IP 为 10.10.10.10/32(客户端 IP 地址),目标 IP 为 10.10.10.0/24,则此代理会将所有 IPv4 流量路由到转发规则 10.10.10.0/24。

这意味着,clienta 将与 PBR 匹配,而不是 clientb。

从 cloudshell 中:

gcloud network-connectivity policy-based-routes create pbr-client \
   --network=projects/$project_id/global/networks/$prefix-vpc \
   --next-hop-ilb-ip=10.10.10.25 \
   --source-range=10.10.10.10/32 \
   --destination-range=10.10.10.0/24 \
   --protocol-version=IPv4 \
   --priority=1000 \
   --tags=client

此 PBR 规则适用于服务器。如果来源 IP 为 10.10.10.200/32 且目标 IP 为 10.10.10.10/32,则此代理会将所有 IPv4 流量路由到转发规则 10.10.10.200/32。

从 cloudshell 中:

gcloud network-connectivity policy-based-routes create pbr-server \
   --network=projects/$project_id/global/networks/$prefix-vpc \
   --next-hop-ilb-ip=10.10.10.25 \
   --source-range=10.10.10.200/32 \
   --destination-range=10.10.10.10/32 \
   --protocol-version=IPv4 \
   --priority=2000 \
   --tags=server

15. 使用 PBR 测试连接

现在,我们将验证 PBR 功能。“操”实例配置了 iptables,以拒绝发往服务器的请求。如果 PBR 正常运行,则之前在 clienta 上处理的请求现在将失败,而 clientb 仍然成功。

通过 SSH 连接到 clienta 计算虚拟机并运行相同的测试。

在 cloudshell1 中运行以下命令:

gcloud compute ssh clienta --zone=$zone --tunnel-through-iap

运行以下命令:

ping 10.10.10.200 -c 5
curl 10.10.10.200/index.html

输出:

root@clienta:~$ ping 10.10.10.200 -c 5
PING 10.10.10.200 (10.10.10.200) 56(84) bytes of data.
From 10.10.10.75 icmp_seq=1 Destination Port Unreachable
From 10.10.10.75 icmp_seq=2 Destination Port Unreachable
From 10.10.10.75 icmp_seq=3 Destination Port Unreachable
From 10.10.10.75 icmp_seq=4 Destination Port Unreachable
From 10.10.10.75 icmp_seq=5 Destination Port Unreachable
root@clienta:~$ curl 10.10.10.200/index.html
curl: (7) Failed to connect to 10.10.10.200 port 80: Connection refused

由于请求失败,我们可以确认 PBR 正在主动将 clienta 的流量路由到被配置为阻止此流量的 fw 实例。

通过 SSH 连接到 clientb,并运行相同的连接测试。

在 cloudshell2 中运行以下命令:

gcloud compute ssh clientb --zone=$zone --tunnel-through-iap

运行以下命令:

ping 10.10.10.200 -c 5
curl 10.10.10.200/index.html

输出:

root@clientb:~$ ping 10.10.10.200 -c 5
PING 10.10.10.200 (10.10.10.200) 56(84) bytes of data.
64 bytes from 10.10.10.200: icmp_seq=1 ttl=63 time=0.361 ms
64 bytes from 10.10.10.200: icmp_seq=2 ttl=63 time=0.475 ms
64 bytes from 10.10.10.200: icmp_seq=3 ttl=63 time=0.379 ms
root@clientb:~$ curl 10.10.10.200
<html><body><p>Server</p></body></html>

如您所见,从 clientb 到服务器的请求是成功的。这是因为请求与来源 IP 的 PBR 规则不匹配。

16. [可选] 在防火墙上通过捕获进行验证

在此可选部分中,您可以通过在防火墙虚拟机上截取数据包来验证 PBR。

在 cloudshell1 和 cloudshell2 中,您应该仍然会与 clienta 和 clientb 建立 SSH 连接。

点击 + 以打开另一个 Cloudshell 标签页。

5eb3a9956f7e41a2

在 cloudshell3 中设置变量:

export project_id=`gcloud config list --format="value(core.project)"`
export region=us-central1
export zone=us-central1-a
export prefix=codelab-pbr

通过 SSH 连接到 fw:

gcloud compute ssh fw --zone=$zone --tunnel-through-iap

在 fw (cloudshell3) 上运行以下命令:

sudo tcpdump -i any icmp -nn

从 clienta (cloudshell1) 运行 ping 测试:

ping 10.10.10.200 -c 5

从 clientb (cloudshell2) 运行 ping 测试:

ping 10.10.10.200 -c 5

fw (cloudshell 3) 上的输出:

root@fw:~$ sudo tcpdump -i any icmp -nn
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
17:07:42.215297 ens4  In  IP 10.10.10.10 > 10.10.10.200: ICMP echo request, id 25362, seq 1, length 64
17:07:42.215338 ens4  Out IP 10.10.10.75 > 10.10.10.10: ICMP 10.10.10.200 protocol 1 port 51064 unreachable, length 92
17:07:43.216122 ens4  In  IP 10.10.10.10 > 10.10.10.200: ICMP echo request, id 25362, seq 2, length 64
17:07:43.216158 ens4  Out IP 10.10.10.75 > 10.10.10.10: ICMP 10.10.10.200 protocol 1 port 30835 unreachable, length 92
17:07:44.219064 ens4  In  IP 10.10.10.10 > 10.10.10.200: ICMP echo request, id 25362, seq 3, length 64
17:07:44.219101 ens4  Out IP 10.10.10.75 > 10.10.10.10: ICMP 10.10.10.200 protocol 1 port 2407 unreachable, length 92

您不会在 tcpdump 中看到来自 clientb (10.10.10.11) 的任何数据包,因为 PBR 不适用。

退出返回 cloudshell 以清理资源。

17. 清理步骤

在 Cloud Shell 中,移除 PBR 规则、转发规则、后端服务、健康检查、实例组、计算实例、NAT、Cloud Router 和防火墙规则。

gcloud -q network-connectivity policy-based-routes delete pbr-client

gcloud -q network-connectivity policy-based-routes delete pbr-server

gcloud -q compute forwarding-rules delete fr-pbr --region=$region

gcloud -q compute backend-services delete be-pbr --region=$region

gcloud -q compute health-checks delete $prefix-hc-tcp-80 --region=$region

gcloud -q compute instance-groups unmanaged delete pbr-uig --zone=$zone

gcloud -q compute instances delete clienta --zone=$zone
gcloud -q compute instances delete clientb --zone=$zone
gcloud -q compute instances delete server --zone=$zone
gcloud -q compute instances delete fw --zone=$zone


gcloud -q compute routers nats delete ${prefix}-nat-gw-${region} \
--router=$prefix-cr --router-region=$region

gcloud -q compute routers delete $prefix-cr --region=$region

gcloud -q compute firewall-rules delete $prefix-allow-iap-proxy
gcloud -q compute firewall-rules delete $prefix-allow-http-icmp
gcloud -q compute firewall-rules delete $prefix-fw-allow-ingress
gcloud -q compute firewall-rules delete $prefix-allow-hc-ingress

移除子网和 VPC:

gcloud -q compute networks subnets delete $prefix-vpc-subnet \
    --region $region

gcloud -q compute networks delete $prefix-vpc

18. 恭喜!

恭喜您完成此 Codelab。

所学内容

  • 基于政策的路由