一次 HTTP 调用可以经过不止一段连接

orders 请求 inventory 看上去只有一个 URL,实际却可能经过 orders 应用 → 本地出站代理 → 网络 → inventory 入站代理 → 库存应用。Istio 的工作负载 mTLS 验证的是代理之间的连接与身份;应用到同 Pod 代理、代理到本地应用的段仍要分别确认。把“服务之间启用了 mTLS”简写成“每个字节在每一段都加密”会遗漏这两段。第 09 篇的应用自己提供 TLS 的演示也不是此处代理 mTLS 的验收。

服务端 PeerAuthentication 决定入站能接受什么连接:PERMISSIVE 同时接受明文和 mTLS,STRICT 要求 mTLS。客户端代理是否真的发起 mTLS,则要看出站配置、目标是否识别为网格工作负载,以及是否存在显式 DestinationRule;不能只看服务端策略推断客户端行为。自动 mTLS 是在合适的发现和配置条件下帮助客户端选择 mTLS,不代表任意网外目标都自动升级。

应用与本地代理的连接段须单独确认,跨 Pod 两个代理之间才是本篇讨论的 mTLS 边界

先固定连接段,再讨论拒绝

在隔离命名空间中,只给 inventory 设置有明确工作负载 selector 的 PeerAuthentication,先使用 PERMISSIVE,分别由入网格的 orders 和不注入代理的测试客户端访问同一库存服务。对两组请求分别保存来源 Pod 是否实际注入、出站和入站代理的活跃 TLS 配置、握手/连接证据、带 ID 的请求结果;可用 Istio 的连接安全策略标签作辅助,不以单个指标替代连接证据。随后只将服务端入站模式改为 STRICT,重复相同请求集。按 Istio 的 mTLS 迁移语义,正常配置的网格内客户端应继续成功,明文客户端不应再直达库存应用;实际现象以代理捕获的拒绝位置为准。

再做一个单独的客户端负例:保留 STRICT,仅在测试用的出站规则中禁用该目标的 TLS。它与“未入网格客户端”不是同一种来源,错误可以在出站或目标握手处暴露。每次只改变一个变量,先撤回上一个测试策略,再测试下一项;不能让先前的授权策略、第 18 篇的出口策略或 Service 端点故障污染结果。

连接 PERMISSIVE 待测 STRICT 待测 判据
orders 代理 → inventory 代理 NOT_RUN NOT_RUN 双方实际使用的证书/连接及应用结果一致
未注入客户端 → inventory 入站代理 NOT_RUN NOT_RUN 明文被接纳或被拒绝,定位在入站握手而非应用业务逻辑
orders 应用 → 本地代理 → 库存应用 NOT_RUN NOT_RUN 单独标注本地两段的协议,不能用跨 Pod 连接代替

STRICT 的负例可能表现为连接断开、TLS 握手失败或客户端收到代理生成的错误,不预设 HTTP 403。如果请求成功,应首先核对 selector 命中、端口级例外、Pod 是否真正注入以及是否绕过代理;成功本身不能证明策略实现失效。

逐项修改入站与出站策略

以下命令在 examples/service-mesh 目录执行,使用 04 章 Kubernetes 1.33.4 / Istio 1.27.0 sidecar 基线,应用容器名 app。先清理前章授权、故障与出口策略;下列预期值尚不是集群实测结果。

1
2
3
4
5
export SM_CONTEXT=kind-service-mesh-sidecar
k() { kubectl --context="$SM_CONTEXT" -n service-mesh-lab "$@"; }
k apply -f mainline/13/probe.yaml
k rollout status deploy/sm-probe --timeout=120s
OUT="evidence/mainline-20/$(date -u +%Y%m%dT%H%M%SZ)"; mkdir -p "$OUT"

mainline/20/plain.yaml 创建没有 sidecar 的 sm-plain;两个客户端都调用同一个 inventory Service。permissive.yaml 与 strict.yaml 使用同名 PeerAuthentication,selector 为 app: inventory,避免同时保留互相覆盖的策略。先确认探针 Pod 的容器清单,注解存在不等于注入成功。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
k apply -f mainline/20/plain.yaml
k rollout status deploy/sm-plain --timeout=120s
k get pods -l app=sm-plain -o jsonpath='{range .items[*]}{.spec.containers[*].name}{"\n"}{end}' > "$OUT/plain-containers.txt"
k apply -f mainline/20/permissive.yaml
k exec deploy/sm-plain -c curl -- curl -H 'x-request-id: ch20-permissive-plain' -fsS --max-time 3 'http://inventory:8080/quote?sku=paper' > "$OUT/permissive-plain.json"
k apply -f mainline/20/strict.yaml
k exec deploy/sm-probe -c curl -- curl -H 'x-request-id: ch20-strict-mesh' -fsS --max-time 3 'http://inventory:8080/quote?sku=paper' > "$OUT/strict-mesh.json"
k exec deploy/sm-plain -c curl -- curl -H 'x-request-id: ch20-strict-plain' -fsS --max-time 3 'http://inventory:8080/quote?sku=paper' > "$OUT/strict-plain.stdout" 2> "$OUT/strict-plain.stderr"; test "$?" -ne 0
k apply -f mainline/20/disable-client.yaml
k exec deploy/sm-probe -c curl -- curl -H 'x-request-id: ch20-client-disabled' -fsS --max-time 3 'http://inventory:8080/quote?sku=paper' > "$OUT/client-disabled.stdout" 2> "$OUT/client-disabled.stderr"; test "$?" -ne 0
k delete -f mainline/20/disable-client.yaml
k exec deploy/sm-probe -c curl -- curl -H 'x-request-id: ch20-recovered' -fsS --max-time 3 'http://inventory:8080/quote?sku=paper' > "$OUT/recovered.json"
istioctl --context="$SM_CONTEXT" proxy-config clusters deploy/sm-probe -n service-mesh-lab -o json > "$OUT/client-clusters.json"
k delete -f mainline/20/strict.yaml
k delete -f mainline/20/plain.yaml

成功判据是 PERMISSIVE 下明文成功、STRICT 下网格来源成功而明文失败;禁用 sm-probe 出站 TLS 后也应失败,删除该客户端规则后恢复。disable-client.yaml 有 workloadSelector,限定到探针,不修改 orders 等其他工作负载。保留客户端 transport socket 以及库存 inbound listener 的 TLS 配置,不能把错误码 403 当成 mTLS 的固定结果。

如果 plain-containers.txt 含 istio-proxy,负例不成立;如果执行失败只是 DNS 或超时,尚未证明入站 TLS 拒绝。应对照同一时间的目标代理日志,并检查 18 章网络策略已撤回。

固定源码入口:Istio 1.27.0 pilot/pkg/security/authn/policy_applier.go。该链接用于核对配置生成或执行机制;完整资源和命令保存在 examples/service-mesh/mainline/20/。静态检查通过不等于集群实验通过。

练习与参考解答

  1. 服务端设置 STRICT,为什么仍要检查客户端出站配置?参考解答:服务端策略约束入站接收,不能指定客户端必然使用 mTLS;两端缺一不可。
  2. 对库存 Pod 内 localhost 的应用端口做明文请求成功,是否推翻代理间 mTLS?参考解答:没有。它测的是本地应用段,不能直接推断跨 Pod 的代理间连接。

官方资料与系列导航

系列导航:19 工作负载身份和证书怎样建立 → 20 mTLS 开启后哪些连接受到保护(本文)→ 21 认证成功为何仍会被拒绝。