11.1 Kubernetes 流量边界:Gateway API 与 NetworkPolicy
生产集群的流量边界要回答两类问题:外部请求怎样进入服务,以及工作负载之间允许怎样通信。前者属于 L4/L7 入口治理,后者通常由 NetworkPolicy 在 L3/L4 建立最小通信面。
从 Ingress 迁移到 Gateway API
Ingress API 仍是稳定 API,但规范已冻结,Kubernetes 官方建议新设计优先采用 Gateway API。更关键的是,社区已在 2026 年 3 月 24 日退役 ingress-nginx,此后不再提供发布、错误修复或安全更新。现有 Ingress 对象不会因此自动失效,但继续使用已退役 controller 与继续使用 Ingress API 是两回事。
Gateway API 把职责拆给不同角色:
| 对象 | 常见所有者 | 责任 |
|---|---|---|
GatewayClass | 基础设施提供者 | 选择 controller 实现 |
Gateway | 平台团队 | listener、地址、证书与接入边界 |
HTTPRoute | 应用团队 | hostname、path、filter 与 backend |
这样应用团队可以管理路由,又不必获得修改共享负载均衡器的全部权限。
下面假设 Gateway API CRD 和对应实现已安装,managed-l7 GatewayClass、edge namespace 与其中的 TLS Secret wildcard-example-com 已存在。atlas-prod 中还需有 atlas-api Service,暴露 Service 端口 8080 并指向就绪后端。跨 namespace 挂接要求路由所在 namespace 符合 listener 的选择器:
apiVersion: v1
kind: Namespace
metadata:
name: atlas-prod
labels:
gateway-access: publicapiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: public-web
namespace: edge
spec:
gatewayClassName: managed-l7
listeners:
- name: https
protocol: HTTPS
port: 443
hostname: "*.example.com"
tls:
mode: Terminate
certificateRefs:
- kind: Secret
name: wildcard-example-com
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
gateway-access: publicapiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: atlas-api
namespace: atlas-prod
spec:
parentRefs:
- name: public-web
namespace: edge
hostnames: ["api.example.com"]
rules:
- matches:
- path:
type: PathPrefix
value: /v1
backendRefs:
- name: atlas-api
port: 8080这里由 allowedRoutes 允许跨 namespace 的 Route 挂接;若 Route 又引用其他 namespace 的 backend,目标 namespace 还需相应的 ReferenceGrant。示例 backend 与 Route 同属 atlas-prod,不需要这项授权。
创建对象成功不代表流量已可用。核对 Gateway 的 Accepted、Programmed,以及对应 Route parent 的 Accepted、ResolvedRefs 条件,并确认 observedGeneration 对应当前配置。然后实际验证 DNS、TLS、Service endpoints 和请求路径;条件为真也不能替代请求测试。所需 filter 和扩展还要匹配实现支持范围。
入口策略从威胁模型推导
生产入口至少要明确:
- TLS 在哪里终止,证书由谁签发和轮换;
- 客户端真实 IP 与转发头由谁信任和重写;
- 认证、限流、请求体上限和超时在哪一层执行;
- canary 权重变化由谁审批,失败如何归零;
- controller、云负载均衡器和 Route 状态如何监控。
不要把某个 controller 的私有 annotation 当成可移植的 Kubernetes 能力。使用扩展前要记录实现依赖与迁移路径。
NetworkPolicy 默认不是防火墙
隔离按方向分别生效:只有策略选中 Pod 且包含相应 policyTypes,该方向才进入隔离状态。多条策略的允许规则取并集,没有按顺序匹配的显式 deny;因此一条宽泛的 allow 可以重新打开默认拒绝收窄的范围。只有网络插件真正实现 NetworkPolicy,策略才会被执行;API 接受 YAML 并不证明数据面已经拦截。
常见基线先拒绝,再逐条放行:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
namespace: atlas-prod
spec:
podSelector: {}
policyTypes: [Ingress, Egress]随后允许 Gateway 数据面到 API。这里假设实际代理 Pod 位于 edge,标签为 app.kubernetes.io/name: gateway-proxy,API Pod 的目标端口也是 8080。应按实现替换;管理配置的 controller Pod 不一定承载用户流量:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-gateway-to-api
namespace: atlas-prod
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: atlas-api
policyTypes: [Ingress]
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: edge
podSelector:
matchLabels:
app.kubernetes.io/name: gateway-proxy
ports:
- protocol: TCP
port: 8080同一个 from 元素中的 namespaceSelector 与 podSelector 是 AND:指定 namespace 中匹配的 Pod。写成两个列表项则是 OR,权限会扩大。源 Pod 的 egress 与目标 Pod 的 ingress 还必须同时允许这条连接;已允许连接的响应流量会隐式放行,不必为每个响应另开一条相反方向的规则。
默认拒绝 Egress 后先恢复基础依赖
全拒绝 egress 通常会同时切断 DNS、身份服务、遥测出口和云元数据访问。放行 DNS 时要按实际 CNI 和 DNS 部署验证 namespace、Pod label、协议与端口,不能照抄网上的 kube-dns 标签。使用 NodeLocal DNSCache 或 hostNetwork 代理时,看到的源/目标可能是节点地址,Pod 选择器未必覆盖该路径;应核实实现中的节点流量例外。
对外部服务若只用 ipBlock,还要考虑 NAT、负载均衡器和供应商 IP 变化。NetworkPolicy 不是域名防火墙,也不理解 HTTP path 或服务身份;需要 L7 策略时,应使用具备相应能力且经过验证的数据面。
策略测试必须从连接两端执行
发布前至少验证:
允许源 → 目标端口:成功
允许源 → 非目标端口:失败
非允许源 → 目标端口:失败
应用 → DNS/身份/遥测:成功
应用 → 未声明外网:失败现有长连接在策略变化后的行为可能依赖实现,不能只测一次新建连接。集群升级或更换 CNI 后也要重跑策略测试。
边界之外仍需工作负载安全
网络隔离不能替代服务认证和容器安全。生产工作负载还应按风险使用:非 root、只读根文件系统、删除不必要 capability、seccomp、受限的 ServiceAccount、Pod Security Admission,以及短期工作负载身份。网络边界失守时,身份与应用授权仍是下一道防线。
下一课处理流量到达后最难迁移的部分:有状态工作负载的身份、存储和恢复。
参考资料
Kubernetes, Ingress
Kubernetes, Ingress NGINX Retirement
Gateway API, Introduction
Gateway API, HTTPRoute
Kubernetes, Network Policies
Gateway API, Cross-namespace routing
Gateway API, ReferenceGrant