Istio mTLS排障经常发生在把 PERMISSIVE 切到 STRICT 之后:某些服务突然 503、TLS 握手失败,或者只有跨命名空间调用失败。此时不要只看“服务端是否开启 STRICT”,还要同时确认调用方是否在网格内、DestinationRule 是否影响客户端 TLS、SDS 证书是否下发,以及端口协议是否被正确识别。
Istio 使用 PeerAuthentication 控制服务端接收何种 mTLS 模式,并通过 DestinationRule 等客户端规则影响发起端 TLS 行为[1][2][3]。因此,服务端 STRICT 与客户端明文、证书缺失或端口协议错误,都可能造成看起来相似的连接失败。
如果你需要先理解服务网格边界,可以阅读 服务网格专题;如果问题涉及灰度和流量治理,可结合 Kubernetes最佳实践 一起排查路由层影响。

图1:Istio mTLS 排障信号关系图展示调用方、策略、证
现象分型:先判断失败发生在哪一层
mTLS 问题常与 VirtualService、DestinationRule、Gateway、Service 端口和应用错误混在一起。第一步要按日志和返回码分层,而不是直接回滚所有策略。
| 现象 | 可能层次 | 优先证据 |
|---|---|---|
| TLS handshake、certificate 错误 | 证书或客户端 TLS | sidecar 日志、proxy-config secret |
| 503、no healthy upstream | 路由或 endpoint | Envoy access log、cluster 状态 |
| 只在 STRICT 后失败 | 调用方不在网格或客户端未用 mTLS | tls-check、sidecar 注入状态 |
| 单端口失败 | 端口命名或协议识别 | Service port name、DestinationRule |
| 跨命名空间失败 | 策略范围或调用方差异 | PeerAuthentication 作用域 |
istioctl proxy-status
istioctl authn tls-check <client-pod>.<namespace> <service>.<namespace>.svc.cluster.local
kubectl get peerauthentication,destinationrule -A
这些命令用于观察代理同步和 mTLS 关系,PeerAuthentication 与 DestinationRule 字段应按官方参考解释[2][3]。涉及修改认证策略时,应先在命名空间或单服务范围灰度验证。
STRICT 切换前:先盘点所有调用方
PeerAuthentication 决定服务端接收明文、宽容模式还是严格 mTLS,具体字段和模式应以官方参考为准[2]。直接把命名空间或全局切到 STRICT 前,必须确认所有调用方都能发起 mTLS,包括旧服务、Job、运维工具、网关入口和未注入 sidecar 的 Pod。
切换前建议建立调用方清单:
- 同命名空间内已注入 sidecar 的服务。
- 跨命名空间调用方及其注入状态。
- Gateway、Ingress、外部系统和运维脚本。
- CronJob、Job、临时调试 Pod。
- 服务网格外的监控探针或健康检查。
Istio 官方 mTLS 迁移文档建议通过分阶段方式从 PERMISSIVE 迁移到 STRICT[1]。生产环境中,PERMISSIVE 不是长期目标,但它是观察真实调用方的安全过渡阶段。

图2:服务端 PeerAuthentication 与客户端
STRICT 失败不一定要全局回退
如果只有某个调用方失败,优先检查该调用方是否注入 sidecar、DestinationRule 是否禁用了 TLS、Service 端口是否命名正确。全局回退会恢复流量,但也会掩盖真正的例外边界。
证书链路:SDS 正常才谈策略语义
Istio sidecar 依赖证书和身份实现服务间 mTLS。SDS 证书未下发、根证书不一致、istiod 推送异常或 ServiceAccount 变化,都可能让策略看起来正确但握手失败。
建议检查:
- `istioctl proxy-status` 是否有未同步代理。
- `proxy-config secret` 是否能看到有效证书。
- sidecar 日志是否有 SDS、certificate、secret 错误。
- istiod 日志是否有签发或推送异常。
- Pod 是否近期重建、变更 ServiceAccount 或注入标签。
下面这些 proxy-config 和 istiod 日志检查应结合 Istio mTLS 与流量规则文档解释[1][3]:
istioctl proxy-config secret <pod-name> -n <namespace>
istioctl proxy-config cluster <pod-name> -n <namespace> | grep <service-name>
kubectl logs deploy/istiod -n istio-system --tail=200
证书正常不代表流量一定正常
上述 proxy-config 和 istiod 日志命令用于核对证书与配置下发状态,需结合 Istio mTLS 迁移和流量规则文档理解[1][3]。proxy-config secret 只能说明 sidecar 拿到了证书。流量仍可能因为 DestinationRule、VirtualService、Endpoint、Service 端口协议或应用健康检查失败而不可达。
最小复现:分离策略、证书和路由
当策略和证书看起来都正常时,应构造最小请求路径,避免业务代码、网关、外部依赖和复杂路由干扰。
推荐按下面顺序复现:
- 同命名空间已注入 client 到 server。
- 跨命名空间已注入 client 到 server。
- 未注入 sidecar 的临时 Pod 到 server。
- Gateway 入口到 server。
- 访问 Service 与直连 Pod IP 对比。
每一步都要记录返回码、Envoy access log、应用日志和 tls-check 结果。只有这样,才能判断问题是 mTLS 身份、Envoy 路由,还是应用自身错误。

图3:Istio mTLS 排障时用于隔离策略、证书和路由问题
回退策略:从例外到收敛,而不是长期 PERMISSIVE
排障过程中可以临时回退到 PERMISSIVE 或为特定服务设置例外,但必须有到期时间和复审条件。长期保留宽松策略会让团队误以为 mTLS 已经全面生效。
临时例外至少记录:
- 例外服务、命名空间和调用方。
- 为什么不能立即 STRICT。
- 需要修复的是 sidecar 注入、端口、证书还是外部入口。
- 例外过期时间和复审负责人。
- 回到 STRICT 后的验证命令和成功标准。
小结
Istio mTLS排障应按“现象分型—调用方盘点—策略匹配—证书链路—最小复现”的顺序推进。PeerAuthentication、DestinationRule、sidecar 注入和 SDS 证书要一起看,不能只凭一个 STRICT 配置判断根因。
生产环境建议先用 PERMISSIVE 观察真实调用方,再逐步切换到 STRICT,并把未注入调用方、外部入口和临时例外列入清单。mTLS 的目标是可验证的服务身份,而不是一条全局开关。
参考资料
- [1] Istio Mutual TLS Migration
- [2] Istio PeerAuthentication Reference
- [3] Istio DestinationRule Reference
常见问题
1. Istio mTLS排障时为什么要同时看 DestinationRule?
因为服务端策略只决定接收模式,客户端是否使用 mTLS 还可能受 DestinationRule 影响;DestinationRule 的 TLS 设置需按官方网络配置参考核对[3]。如果服务端要求 STRICT,但客户端规则禁用了 TLS,就可能出现连接失败。
2. STRICT 模式是否应该全局一次性开启?
不建议。全局一次性开启前很难确认所有调用方都在网格内。更稳妥的方式是先用 PERMISSIVE 观察真实调用,再按命名空间、服务或调用路径逐步收敛。
3. proxy-status 全部 SYNCED 还会有 mTLS 问题吗?
会。SYNCED 说明代理配置同步正常,不代表策略语义正确、证书链匹配、端口协议正确或应用健康。还需要结合 tls-check、proxy-config secret 和流量日志判断。
4. 未注入 sidecar 的调用方如何访问 STRICT 服务?
通常不能直接以明文方式访问 STRICT 服务,需要通过受控入口、网关或为特定路径设计例外。临时例外应有过期时间,避免长期绕过 mTLS。
5. 服务网格 mTLS 和 Kubernetes NetworkPolicy 是替代关系吗?
不是。mTLS 解决服务身份认证和加密,NetworkPolicy 控制网络层访问边界。两者可以互补,排障时要分别确认是网格代理拒绝、网络策略拒绝,还是应用返回错误。