使用 Istio 自动为 Docker 容器签发 mTLS 证书

解读

在国内云原生落地场景中,“零信任”“等保 2.0” 对东西向流量加密有刚性要求。面试官问“Istio 如何自动给 Docker 容器签发 mTLS 证书”,表面看是考 Istio 的证书机制,实质在验证候选人是否能把 Docker 镜像 → 容器运行时 → Sidecar 注入 → CA 体系 → 证书轮换 这一整条链路串起来,并能在国产化环境(麒麟、欧拉、鲲鹏 ARM)里解决镜像源、CPU 架构、国密算法等适配问题。回答时务必把“自动”二字说透:谁负责签发、谁负责挂载、谁负责热更新,故障时如何兜底。

知识点

  1. Docker 容器与 Istio Sidecar 的耦合方式:Sidecar 通过 K8s Admission Webhook 注入,与业务容器共享 Network Namespace,但拥有独立的 PID、Mount Namespace,因此证书文件实际落在 Sidecar 容器内,业务容器无感知。
  2. Istio 证书签发链路:istiod 内置 CA Server(默认基于 Citadel 逻辑),通过 Kubernetes CSR API 或自建 Istio CA gRPC 接口,为每个 Pod 签发 SPIFFE ID 格式的证书,SAN 字段为 spiffe://<trust-domain>/ns/<namespace>/sa/<service-account>
  3. 证书存储与生命周期:证书以 Kubernetes Secret(istio-ca-secret)或 istiod 内存缓存 形式存在,Sidecar 通过 SDS(Secret Discovery Service) 动态挂载,15 分钟轮换一次,无需重启容器。
  4. Docker 镜像层最佳实践:基础镜像必须包含 iptables 与 iproute2 工具集,否则 Sidecar 无法劫持流量;ENTRYPOINT 需使用 dumb-init 或 tini 作为 1 号进程,避免僵尸进程导致证书热更新失败。
  5. 国密合规改造:在国产化环境中,需把 istiod 的 RSA 2048 根 CA 替换为 SM2 根证书,并重新编译 Envoy+BoringSSL 开启 SM2 算法,镜像需使用 麒麟 V10 官方 GCC 9.3 工具链 重编,否则无法通过商密测评。
  6. 故障排查三板斧
    • istioctl pc secret <pod> 查看 SDS 是否下发成功;
    • openssl s_client -connect svc:port 验证握手是否返回 Verify return code: 0
    • docker exec -it -u 1337 <sidecar> cat /etc/certs/cert-chain.pem 确认证书链是否带 SPIFFE ID

答案

要在 Docker 容器里实现 Istio 自动 mTLS,核心是让容器跑在 Kubernetes 之上并启用 Sidecar 注入,Istio 本身并不直接给“裸 Docker”发证书。具体步骤如下:

  1. 构建兼容镜像
    Dockerfile 中引入官方基础镜像 istio/proxyv2:1.19.3,确保包含 pilot-agentenvoy;业务进程使用非 root 用户(UID ≥ 1000),并在镜像里预埋 istio-iptables 规则入口,防止启动时因 CAP_NET_ADMIN 缺失导致流量劫持失败。

  2. 启用 Sidecar 注入
    给命名空间打上 istio-injection=enabled 标签,K8s Mutating Webhook 会自动在 Pod 里追加 istio-proxy 容器;该容器启动后通过 UDS(Unix Domain Socket) 访问同 Pod 内的 agent,agent 再向 istiod 发起 CSR 请求。

  3. CA 与证书签发
    若客户要求 国密双证,可部署 ChinaSM Istio CA 插件,把根证书换成 SM2,istiod 启动参数加 --ca-cert-file=/etc/sm2/ca.crt --ca-key-file=/etc/sm2/ca.key --cert-signer-type=sm2。签发后的证书通过 SDS 推送到 Sidecar,文件路径为 /etc/istio/proxy/cert-chain.pemkey 只存在于内存,不落盘,满足等保“密钥不落地”要求。

  4. 证书轮换与热更新
    Istio 1.19 默认 15 分钟轮换一次,Sidecar 收到新证书后通过 SDS 增量接口 热加载,业务连接不断开;若 istiod 宕机,Sidecar 会 缓存最后一套证书至 24 小时,期间新 Pod 无法启动,但存量 Pod 业务不受影响,实现 Graceful Degradation

  5. Docker 层面的验证
    在容器内执行
    curl -v --cacert /etc/istio/proxy/cert-chain.pem https://productpage:9080
    若返回 SSL handshake has read 3045 bytes and written 421 bytes,且服务端证书 SAN 包含对应 SPIFFE ID,则证明 mTLS 已生效。

拓展思考

  1. 裸 Docker 场景能否脱离 K8s 使用 Istio 证书?
    可以,但需自研 “Sidecar 容器管理器”:用 Docker Compose 启动两个容器,业务容器与 Envoy 容器共享 network 命名空间,再通过 host 模式 把 istiod 的 15010 端口映射到本地,Envoy 以 STATIC 配置手动指定 CA 地址;缺点是失去了 K8s 的自动注入与生命周期管理,证书轮换需自己轮询 SDS,生产极少采用。

  2. 多集群联邦下的跨集群 mTLS
    “东数西算” 场景,上海与乌兰察布集群需互通,此时要在两个 istiod 之间建立 Istio CA 根证书链互信,把 中间 CA 证书 通过 ConfigMap 跨集群分发,并开启 SPIFFE Trust Domain Federation,否则跨集群调用会因 Trust Bundle 不匹配 导致 503 UC 错误。

  3. 性能调优
    国密 SM2 算法在 ARM 鲲鹏 920 上性能仅为 RSA 的 30%,可通过 异步私钥操作 把 SM2 签名卸载到 鲲鹏加速引擎(KAE),重新编译 Envoy 开启 ssl.async_private_key_method,QPS 可提升 2.7 倍,满足双十一大促峰值。

  4. 应急止血方案
    若 istiod 因 CVE 漏洞需紧急下线,可提前通过 istioctl x workload entry configure 导出 WorkloadEntry YAML长期证书(TTL=7 天),业务方以 Docker -v 挂载 方式把证书打进容器,临时关闭 mTLS 严格模式(PeerAuthentication 改为 PERMISSIVE),实现 “离线运行”,待漏洞修复后再重新接入控制面。