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 防火墙规则匹配与优先级评估 外部来源 0.0.0.0/0 或 CIDR 入站规则 ingress 来源:标签 / 服务账号 / CIDR 协议端口:tcp:80,443 优先级评估 数值小 → 优先 命中即停止 目标实例 target tag: web target SA: web-sa 源实例 source tag: web source SA: web-sa 优先级评估 数值小 → 优先 命中即停止 出站规则 egress 目的地:标签 / SA / CIDR 协议端口:tcp:3306 目的地 db-sa / 10.0.2.0/24 优先级评估示例(数值越小越先匹配) deny 3306 prio 1000 allow 3306 prio 2000 allow 80/443 prio 3000 隐含 deny-all prio 65535 评估顺序:1000 → 2000 → 3000 → 65535。若 1000 命中,后续规则不再评估。 注意:目标标签/服务账号写错时规则不命中,会继续向下匹配,容易误判为“优先级失效”。

四、层级防火墙策略:组织与文件夹级统一管控

普通 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 含义不同;第五步,再核对优先级顺序。

使用 VPC 流日志(VPC Flow Logs)可以直接看到某条连接是被允许还是被拒绝,以及命中的规则方向。开启后按 reporter 字段区分 SRC 与 DEST,比逐条猜测规则高效得多。
不要用“先加一条 allow all 再逐步收紧”的方式排错。这会在生产环境短暂放开全部流量,且容易忘记回收。正确做法是保留默认拒绝,只针对具体来源、目标和端口逐条放行。

最后给出一个可直接使用的检查清单,用于每次新增或修改防火墙规则后快速自检:

检查项判断依据常见错误
方向入站看来源,出站看目的地把出站规则写成入站
目标标签或服务账号已附加到实例标签拼写不一致
来源/目的地CIDR 或 SA 覆盖真实流量用了错误的子网段
协议端口tcp:3306 格式正确漏写协议前缀
优先级数值小者先评估deny 优先级高于 allow
层级策略组织/文件夹规则是否 goto_next高层级直接 deny 覆盖业务

掌握以上五点后,绝大多数“规则写了却不生效”的问题都可以在几分钟内定位。核心心法只有一句:先确认规则是否命中目标,再讨论优先级和动作。