kubernetes 中实现微服务全链路 mtls 双向加密必须依托 istio 等服务网格统一管控证书与策略,手动配置无法解决证书轮换、多语言 tls 行为不一致及 san 匹配等硬伤;需同时配置 peerauthentication(strict 模式)和 destinationrule(istio_mutual),并用 cert-manager + spiffe 身份自动化签发证书。

在 Kubernetes 中实现微服务间全链路 mTLS 双向加密,本质是让服务从入口到出口、从 A 到 B 再到 C 的每一跳通信都强制使用双向 TLS 认证——既验证对方身份,也向对方证明自己。这不能靠改几个配置或加几行代码完成,必须依托服务网格(如 Istio 或 Linkerd)统一管控证书、策略与流量拦截。
为什么必须用服务网格,而不是手动配置
“全链路”意味着路径上每个环节都参与 mTLS:入口网关 → 服务 A → 服务 B → 数据库代理/外部 mTLS 服务。手动在每个应用里写 TLS 配置会立刻遇到三个硬伤:
- 证书轮换需逐个重启所有服务,无法做到零中断续签
- 不同语言客户端(Go/Python/Java)对 tls.Config 的默认行为不一致,比如 InsecureSkipVerify 误设为 true 就等于关闭校验
- 服务发现地址(如 httpbin.default.svc.cluster.local)必须与证书 SAN 完全匹配,否则 Envoy 或 net/http 直接拒绝连接,报错类似 x509: certificate is valid for xxx, not yyy
Istio 中启用 STRICT 全链路 mTLS 的最小必要配置
仅开启自动注入(istio-injection=enabled)和安装 Istio 不够。必须同时定义两个资源:
-
PeerAuthentication:控制哪些流量必须提供有效证书。全局策略示例(作用于 istio-system 命名空间):
apiVersion: security.istio.io/v1beta1 kind: PeerAuthentication metadata: name: default namespace: istio-system spec: mtls: mode: STRICT这会让所有已注入 Sidecar 的 Pod 拒绝非 mTLS 流量。 -
DestinationRule:告诉 Sidecar “调用这个服务时,必须用 ISTIO_MUTUAL 模式”。例如调用外部 https://httpbin.org:
apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: httpbin-egress spec: host: httpbin.org trafficPolicy: tls: mode: ISTIO_MUTUAL缺少它,即使 PeerAuthentication 开了,出向流量仍走明文。
验证每一段是否真正生效
不能只测 curl http://svc 成功就认为 OK。要分段确认:
- 进站:在 istio-ingressgateway Pod 里执行 istioctl proxy-config secret -n istio-system,输出中应同时存在 default(工作负载证书)和 ROOTCA(根证书)
- 服务间:进入任一服务 Pod,执行 curl -v https://target.default.svc.cluster.local,响应头应为 200,且 Envoy 日志中出现 SSL handshake completed 和 verified peer certificate
- 出站:若访问外部 mTLS 服务,需额外配 ServiceEntry + DestinationRule,并检查 Sidecar 是否在 egress 流量中注入客户端证书
证书体系必须自动化且身份可信
不要手动生成分发证书。推荐方案是:
- 用 cert-manager + 私有 CA(如 Vault 或 Istio 内置 CA) 签发证书,避免依赖公网 Let’s Encrypt(不适用于内部服务身份)
- 每个服务绑定唯一 ServiceAccount,证书 SAN 使用 SPIFFE 格式:spiffe://cluster.local/ns/default/sa/my-sa,便于服务网格识别身份
- 私钥仅注入对应 Pod,挂载路径权限设为 0400,禁止被其他容器读取











