Gateway 对象存在,不等于七层策略已覆盖调用

第 26 篇在节点 ztunnel 上讨论身份、加密和四层流量;现在要让 orders 带 x-canary: yes 的 HTTP 请求去 inventory-v2,并拒绝未经允许的 POST /reserve,必须进一步核对 waypoint 的七层能力。控制面创建 waypoint、目标 Service 选择使用 waypoint、实际请求进入该代理,以及后端按规则应答,是四个不同事实。仅凭一个 Gateway Ready 或一次 200,不能断言数据面真正经 waypoint。

无绑定、已绑定和绕过三条路径:只有实际进入 waypoint 的请求才验证其 L7 路由与授权

Waypoint 是 ambient 模式下按范围共享的 Envoy 七层代理,而不是每个工作负载 Pod 内的 sidecar。面向 Service 的请求可通过附着选择使用它;目标 Service 的匹配、HTTPRoute 的 Service parentRefs 和七层授权的目标引用均需对应同一个实际流量对象。istio.io/use-waypoint 等绑定方式、waypoint Gateway 的监听能力、跨 namespace 限制与支持范围必须在固定 Istio/Gateway API 版本核对,不能把存在 waypoint 自动当成目标流量已转向。相反,直达 Pod IP、sidecar 来源、网格外客户端或网关来源是否经过 waypoint,均按来源模式与目标附着方式分别验证,不能根据一条 Service 路径外推。

授权点与旁路为什么要一起画

在图中,正常路径是 orders → 源 ztunnel → waypoint (L7) → 目标 ztunnel → inventory,与不走 waypoint 的四层路径作对照。七层 HTTP 方法、路径与请求头在 waypoint 判断;接收端 ztunnel 仍可作适用的四层身份判断,但它看到的对等身份在经 waypoint 的段上可能是 waypoint,不是最初的 orders。把原来绑定在 sidecar 工作负载上的策略原封不动转移,容易造成该拒绝的请求绕过七层检查,或该放行的来源被误拒。强制必须通过 waypoint 时,还须在接收端配置适用的四层限制并测试旁路确实被拒绝,而不能只写一条 HTTPRoute。

inventory 的只读 /quote 和合成写接口 /reserve 提供不同副作用判据:正常组读报价应返回期望的 inventory_version;配置七层拒绝后,写接口不应新增账本行。若仅观察客户端拒绝而未查库存账本,可能遗漏“拒绝发生前写入”;若只是把 POST /reserve 改造成应用本身 400,则也不能算 waypoint 授权已经通过。还需让请求带同一个逻辑操作标识和独立的 attempt ID,避免代理重试遮蔽错误实例。

三态与绕过对照

在 examples/service-mesh/ 先运行只读 context 前置检查:

1
SM_CONTEXT=service-mesh-lab SM_NAMESPACE=service-mesh-lab bash scripts/check-02.sh

隔离集群具备已冻结版本、ztunnel 与可用 Gateway API 实现后,依次对比:①未创建 waypoint 的 Service 调用基线;②已创建 waypoint 但尚未为库存目标绑定;③显式绑定后,检查绑定状态、控制面解析与 waypoint 当前 listener/route,发同一 SKU 的带头/不带头请求,比较 v1/v2 后端版本。每组保存资源快照、来源 Pod 身份、请求 ID、代理实际访问日志与应用账本,而非只截图 Gateway Ready。负例是在目标已绑定的前提下对受控 POST /reserve 配置拒绝;再从直达 Pod IP 和一个未适配的来源分别试探,记录是绕过、明确拒绝还是网络失败。策略希望拒绝却成功或账本增加时,断言必须非零并判 L7 验收失败。

尚未建立 Istio/ztunnel/waypoint 集群及实际绑定条件,上述路由、授权和绕过对照均 NOT_RUN;run-01.sh 的副作用账本仅可作为应用行为基线,不能充当 waypoint 拦截结果。

创建、绑定和限制绕行是三个动作

沿用第 26 篇的 ambient 集群与探针,从 examples/service-mesh 执行。Gateway API 采用基础安装脚本固定的 v1.3.0 standard CRD。mainline/27/waypoint.yaml 一次创建 Gateway、HTTPRoute 与 Service 级授权;创建 Gateway 不会自动让库存流量经过它。

1
2
3
SM_CONTEXT=kind-service-mesh-ambient bash mainline/26/run.sh apply
SM_CONTEXT=kind-service-mesh-ambient bash mainline/27/run.sh apply
SM_CONTEXT=kind-service-mesh-ambient bash mainline/27/run.sh bind

Gateway 的关键字段如下。istio.io/waypoint-for: service 表示面向 Service 寻址的请求;直达 Pod IP 不属于同一绑定。库存 Service 上的 istio.io/use-waypoint=inventory-waypoint 决定选择哪个 waypoint。绑定在目的端,因此多个调用方访问同一库存服务时,共用其 L7 处理位置。bind 在设置标签前先应用 transition.yaml,将第 26 篇的 L4 ALLOW 改成允许 orders 与 waypoint 两个身份:库存接收端看到 waypoint 转发身份,若仍只允许 orders,L7 正例会在接收端被拒绝。过渡策略生效后才开始请求验证,此阶段不宣称已经禁止直连。

1
2
3
4
5
6
metadata:
labels: {istio.io/waypoint-for: service}
spec:
gatewayClassName: istio-waypoint
listeners:
- {name: mesh, port: 15008, protocol: HBONE}

HTTPRoute 的 parentRefs 指向 group: ""、kind: Service、name: inventory、端口 8080。x-canary: yes 转给 inventory-v2,其余请求给 inventory-v1。授权则通过 targetRefs 指向同一个 Service,仅允许 orders 主体的 GET /quote。不能把 sidecar 的 workload selector L7 策略原样搬到 ztunnel,那里没有 HTTP 方法与路径执行能力。

1
2
3
4
kubectl --context kind-service-mesh-ambient -n service-mesh-lab exec mesh-probe -c curl -- curl -sv -H 'x-request-id: waypoint-v1' 'http://inventory:8080/quote?sku=paper'
kubectl --context kind-service-mesh-ambient -n service-mesh-lab exec mesh-probe -c curl -- curl -sv -H 'x-canary: yes' -H 'x-request-id: waypoint-v2' 'http://inventory:8080/quote?sku=paper'
kubectl --context kind-service-mesh-ambient -n service-mesh-lab exec mesh-probe -c curl -- curl -sv -X POST -H 'x-request-id: waypoint-deny' 'http://inventory:8080/quote?sku=paper'
SM_CONTEXT=kind-service-mesh-ambient bash mainline/27/run.sh capture

预期前两个响应体版本分别为 v1、v2;POST 应在应用前被策略拒绝。检查 HTTPRoute Accepted、ResolvedRefs、Gateway Programmed,再检查 waypoint 的活动配置及访问记录;200 本身不能证明分流。特别注意错误来源:应用也可能返回 405,必须用 waypoint 的策略拒绝详情和库存没有该 ID 共同确认。

接着运行 enforce:它先安装仅允许 waypoint ServiceAccount 的 L4 策略,再删除允许 orders 直连的过渡 ALLOW,避免先删后建形成没有 ALLOW 的间隙。如果两个 ALLOW 长期同时存在,它们按并集放行,旧策略就可能保留绕行通路;必须确认接收端已更新后再运行绕行负例。

1
SM_CONTEXT=kind-service-mesh-ambient bash mainline/27/run.sh enforce

此时 Service 正例应成功,Pod IP 或未绑定的 inventory-v1 Service 直连应失败。故意移除 inventory 的 use-waypoint 标签后,正例应失败而不是静默绕过 L7;重新执行 bind,核验正例,再执行 enforce 恢复直连限制。若只 bind 而不 enforce,过渡策略仍允许直连,不能宣布安全边界恢复。若系统还有其他宽泛 ALLOW,先排查策略并集,不能仅以本章 YAML 推导封闭性。

1
SM_CONTEXT=kind-service-mesh-ambient bash mainline/27/run.sh cleanup

清理恢复第 26 篇 L4 策略,删除本章 Gateway、路由及 L7 策略。当前真实集群路径为 NOT_RUN。原则是分别验证配置归属、目的服务绑定与后端只接受 waypoint,三者共同构成 L7 控制边界。固定版本 waypoint 文档源码 保留本例标签与作用范围依据。

练习与参考解答

  1. Gateway Ready,库存读请求也返回了 v2,可宣称 waypoint 的 header 规则生效吗?参考解答:不能。v2 可能由别的路由或直接连接命中。保存目标绑定条件、waypoint 当前路由、代理同一请求 ID 的访问记录及后端日志,再用移除绑定或改 header 的反例对照;“已创建”不等于“已经过”。
  2. 只针对 inventory Service 绑定 waypoint,客户端改为访问库存 Pod IP,原七层拒绝规则一定还能保护 POST /reserve 吗?参考解答:不一定。直达工作负载的附着方式须单独配置与验证。以同样操作 ID 记录路径和账本,若旁路成功就将安全断言置为非零;需要强制经过 waypoint 时,再加接收端四层保护并复测合法/绕过两条路径,不能单凭 L7 Route 保障。

官方参考与系列导航

系列导航:26 Ambient 四层数据面 → 27 Waypoint 七层能力(本文)→ 28 迁移与回退。