4. VPC 防火墙规则实战
VPC 防火墙规则是 Google Cloud 中控制虚拟机实例进出流量的核心机制。理解它的关键在于:规则不是绑定在子网或实例 IP 上,而是通过方向、优先级、目标、来源/目的地、协议端口这五个维度共同决定一条流量是否被允许。本节围绕入站与出站规则、优先级数值、目标标签与服务账号、层级防火墙策略展开,并给出可复现的配置与排错方法。
一、入站与出站:方向决定匹配逻辑
每条规则必须声明方向。入站(ingress)规则匹配“谁可以访问我”,其匹配字段是来源(source),可以是 IPv4/IPv6 网段、来源标签或来源服务账号;出站(egress)规则匹配“我可以访问谁”,其匹配字段是目的地(destination),同样支持网段、目标标签或目标服务账号。方向一旦选错,规则永远不会命中预期流量,这是排错中最常见的低级错误。
需要特别记住默认行为:VPC 创建时会自动生成两条隐含规则——default-allow-internal 允许同网段内部互通,default-allow-ssh 等允许特定管理端口;同时存在一条优先级最低的隐含 deny-all-ingress 和 deny-all-egress。也就是说,没有显式允许的入站流量默认被拒绝,没有显式允许的出站流量默认也被拒绝。很多“实例能 ping 通自己却访问不了外网”的问题,根源就是缺少出站允许规则。
二、优先级:数值越小越优先
优先级取值范围为 0~65535,数值越小优先级越高。当多条规则同时匹配一条流量时,系统按优先级从高到低逐条评估,命中第一条即停止,不再继续向下匹配。因此“允许”和“拒绝”不是简单叠加,而是先到先得。
一个典型陷阱是:管理员添加了一条优先级 1000 的 deny 规则封禁某来源,却发现流量仍然放行。原因往往是存在一条优先级 65534 的默认允许规则,但 1000 比 65534 更优先,理应生效——真正的问题通常是 deny 规则的目标标签写错,导致根本没匹配到实例。排错时应先确认“规则是否命中”,再讨论“优先级是否生效”。
三、目标标签与服务账号:规则如何定位实例
规则通过“目标”决定作用于哪些实例。目标有两种表达方式:目标标签(target tags)和目标服务账号(target service accounts)。标签是附加在实例上的字符串,配置简单但容易被误删或拼写错误;服务账号是实例身份,绑定更稳定,适合生产环境。
来源/目的地侧同样可以使用标签或服务账号。例如允许 Web 层访问数据库层,可以写成:来源为 web-sa 服务账号,目标为 db-sa 服务账号,端口 3306。这样即使实例 IP 变化,规则依然有效。下面这张图展示了入站与出站规则在实例、标签、服务账号之间的匹配关系与优先级评估顺序。
四、层级防火墙策略:组织与文件夹级统一管控
普通 VPC 防火墙规则作用于单个 VPC。当企业有多个项目、多个 VPC 时,逐个项目维护规则成本高且容易遗漏。层级防火墙策略(Hierarchical Firewall Policy)允许在组织、文件夹、项目层级定义规则,并向下继承。其评估顺序是:先评估组织级策略,再评估文件夹级,最后评估项目级 VPC 规则;同一层级内仍按优先级数值比较。
层级策略的一个重要特性是支持“跳转(goto_next)”动作。如果高层级规则动作为 goto_next,则继续评估下一层级;如果为 allow 或 deny,则直接终止。这使得组织可以强制一条“禁止所有实例开放 22 端口到公网”的底线规则,同时不干扰各项目自己的业务规则。
五、配置示例:允许 Web 访问数据库
假设有两个实例:web-1 带标签 web、服务账号 web-sa@proj.iam.gserviceaccount.com;db-1 带标签 db、服务账号 db-sa@proj.iam.gserviceaccount.com。目标是仅允许 Web 层通过 3306 访问数据库层。
gcloud compute firewall-rules create allow-web-to-db \
--network=prod-vpc \
--direction=INGRESS \
--action=ALLOW \
--rules=tcp:3306 \
--source-service-accounts=web-sa@proj.iam.gserviceaccount.com \
--target-service-accounts=db-sa@proj.iam.gserviceaccount.com \
--priority=1000
gcloud compute firewall-rules create deny-db-from-others \
--network=prod-vpc \
--direction=INGRESS \
--action=DENY \
--rules=tcp:3306 \
--source-ranges=0.0.0.0/0 \
--target-tags=db \
--priority=2000
这里第一条规则优先级 1000,只允许 web-sa 访问 db-sa;第二条优先级 2000,拒绝其他所有来源访问带 db 标签的实例的 3306 端口。由于 1000 先于 2000 评估,Web 层流量命中第一条被允许,其余流量落到第二条被拒绝。注意第二条使用标签而非服务账号,是为了覆盖可能未绑定服务账号的实例。
六、排错方法:从“是否命中”到“为何不生效”
排错应遵循固定顺序,避免盲目改优先级。第一步,使用 gcloud compute firewall-rules list --filter 确认规则存在且方向正确;第二步,检查目标标签或服务账号是否真的附加在实例上,可用 gcloud compute instances describe 查看 tags 与 serviceAccounts 字段;第三步,确认来源/目的地网段是否覆盖实际流量;第四步,检查协议端口写法,例如 tcp:3306 与 3306 含义不同;第五步,再核对优先级顺序。
reporter 字段区分 SRC 与 DEST,比逐条猜测规则高效得多。最后给出一个可直接使用的检查清单,用于每次新增或修改防火墙规则后快速自检:
| 检查项 | 判断依据 | 常见错误 |
|---|---|---|
| 方向 | 入站看来源,出站看目的地 | 把出站规则写成入站 |
| 目标 | 标签或服务账号已附加到实例 | 标签拼写不一致 |
| 来源/目的地 | CIDR 或 SA 覆盖真实流量 | 用了错误的子网段 |
| 协议端口 | tcp:3306 格式正确 | 漏写协议前缀 |
| 优先级 | 数值小者先评估 | deny 优先级高于 allow |
| 层级策略 | 组织/文件夹规则是否 goto_next | 高层级直接 deny 覆盖业务 |
掌握以上五点后,绝大多数“规则写了却不生效”的问题都可以在几分钟内定位。核心心法只有一句:先确认规则是否命中目标,再讨论优先级和动作。