全链路mTLS在Kubernetes中必须依赖服务网格,因其需控制平面策略下发、Sidecar证书加载与TLS拦截、证书生命周期管理三者协同;手动硬编码仅支持点对点且易出错。

全链路 mTLS 在 Kubernetes 中不是“开个开关就自动生效”的事,它依赖服务网格控制平面的策略下发、Sidecar 的证书加载与 TLS 握手拦截、以及证书生命周期管理三者协同。没用 Istio/Linkerd 等服务网格,靠应用层硬编码实现不了“全链路”——只能是点对点,且极易出错。
为什么必须用服务网格(而非手动配置)才能叫“全链路”
“全链路”意味着从入口网关 → 服务 A → 服务 B → 数据库代理(或外部 mTLS 服务)全程加密且双向认证。手动在每个服务里写 TLS 配置,会遇到:
- 证书轮换时需逐个重启所有服务,无法做到无缝续签
- 不同语言客户端(Go/Python/Java)的
tls.Config参数含义和默认行为不一致,比如InsecureSkipVerify误设为true就等于废掉校验 - 服务发现地址(如
svc-name.ns.svc.cluster.local)与证书 SAN 不匹配,Envoy 或 Go net/http 都会直接拒绝连接,报错类似x509: certificate is valid for xxx, not yyy - 出口流量(egress)到外部 mTLS 服务时,Sidecar 默认不拦截 HTTPS 流量,需显式配
ServiceEntry+DestinationRule才能注入客户端证书
Istio 中启用 STRICT mTLS 的最小必要配置
仅启用 istio-injection=enabled 标签和安装 Istio 并不够。必须显式声明两个资源:
-
PeerAuthentication:控制谁必须提供证书。全局策略示例:apiVersion: security.istio.io/v1beta1 kind: PeerAuthentication metadata: name: default namespace: istio-system spec: mtls: mode: STRICT—— 这会让所有启用了注入的 Pod 拒绝非 mTLS 流量 -
DestinationRule:告诉 Sidecar “调用这个服务时,必须用 ISTIO_MUTUAL 模式”。示例:apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: httpbin-egress spec: host: httpbin.org trafficPolicy: tls: mode: ISTIO_MUTUAL—— 缺少这个,即使 PeerAuthentication 开了,出向流量仍走明文
验证 mTLS 是否真正在链路每一段生效
不能只测 curl http://svc 成功就认为 OK。要分段确认:
- 进站:在 ingressgateway Pod 里执行
istioctl proxy-config secret -n istio-system istio-ingressgateway-xxx,输出中应有default和ROOTCA两个 secret,且状态为ACTIVE - 服务间:进入任意业务 Pod,执行
curl -v https://target-svc.ns.svc.cluster.local,响应头中必须含200 OK,且curl日志显示* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384和* Server certificate: ... - 出站:若调用外部 mTLS 服务,需检查 egress gateway 的
istioctl pc cluster输出,确认目标服务对应的 cluster TLS 配置为ISTIO_MUTUAL,而非DISABLE或ISTIO_TLS
最容易被忽略的是证书 SAN 和 DNS 名匹配问题——Istio 默认用 SPIFFE ID(spiffe://cluster.local/ns/ns/sa/sa-name)签发证书,但某些旧版客户端或自建 CA 可能只填了 DNS 名。一旦 mismatch,连接会在 TLS 握手阶段静默失败,日志里只有 upstream connect error or disconnect/reset before headers,查起来极费时间。


















