第18章 网格自签名根证书过期

本章内容根据一个线上真实案例的诊断过程总结而来。问题的现象是,用户的某一个Kubernetes集群节点重启之后,无法成功创建Istio虚拟服务和应用Pod。诊断过程较为曲折,有一定参考价值。

这个问题实际上和Citadel证书系统相关,证书问题导致新业务无法部署,给用户带来不便。值得庆幸的是,在阿里云几位工程师的通力合作下,问题得到了快速的解决。

我们在总结问题排查经验的同时,会深入解释Citadel证书体系,期望帮助读者理解Istio证书体系和解决Istio证书相关疑难问题。


18.1 连续重启的Citadel

CitadelIstio的证书分发中心。证书即某个实体的身份证明,可以直接代表实体本身参与信息交流活动。Citadel作为证书分发中心,负责服务网格中每个服务身份证书的创建任务,以保障服务之间安全交流。

在处理问题之始,我们观察到的第一个现象是,Citadel再也无法启动了。这直接导致集群无法创建新的虚拟服务和Pod实例。观察Citadel,发现其连续重启,并输出以下报错信息。

报错信息(原文未提供完整日志,此处保留原始描述)

通过代码分析以及最后一行的报错,可以推出问题背后的逻辑:Citadel不能启动,是因为其无法创建自签名的证书(Failed to create a self-signed Citadel)。

Citadel无法创建自签名证书的原因,是它不能创建密钥和证书(failed to create CA KeyCertBundle)。

以上两点的根本原因,是在验证创建的自签名证书的时候验证失败(cannot verify the cert with the provided root chain and cert pool)。


18.2 一般意义上的证书验证

证书的签发关系,会把证书连接成一棵证书签发关系树,如图18-1所示。顶部是根证书,一般由可信第三方持有,根证书都是自签名的,即其不需要其他机构来对其身份提供证明。其他层级的CA证书,都是由上一层的CA证书签发的。最底层的证书,是给具体应用使用的证书。

验证这棵“树”上的证书,分两种情况。

  • 根证书验证。因为根证书既是签发者,又是被签发者,所以根证书验证只需要提供根证书本身,一般都能验证成功。
  • 其他证书验证。需要提供证书本身,以及其上层的所有CA证书,包括根证书。

图18-1 多级证书签发关系

图片说明

原书此处有图18-1,展示根证书→中间CA→叶证书的签发树结构,根证书自签名,其他证书由上层CA签发。验证时根证书只需自身,其他证书需要完整的信任链。


18.3 自签名证书验证失败

从报错可以看出,Citadel启动失败的根本原因,是其创建的自签名证书无法通过验证。这一点其实很矛盾,因为对于新建的自签名证书来说,CA就是它自己,是不应该验证失败的。


18.4 大神定理

有一条“定理”,就是有些问题我们绞尽脑汁,耗费大量时间也无法解决,但求助于资深的专家,可能只需要几分钟的时间就能解决。在本章问题的处理过程中,这条“真理”再次被验证。

因为实在想不通上面的逻辑,所以我请教了一位资深的专家。他看了一下报错,判断这是CA证书过期问题。使用Istio官方提供的证书验证脚本 root-transition.sh,很快证实了他的判断。


18.5 Citadel证书体系

问题解决了,这里总结一下Citadel证书体系。大多数用户使用Istio的时候,都会选择使用自签名的根证书。如图18-2所示,自签名根证书、证书,以及证书使用者sidecar三者之间有三种关系。

  • 根证书和证书之间的签发关系。这种关系,保证了信任的传递性质。
  • 证书和sidecar之间的持有和被持有关系。从某种意义上说,这是在Pod/sidecar和证书之间画上了等号。
  • 根证书和sidecar之间的信任关系。与前两种关系一起考虑,sidecar信任根证书签发的所有证书。

图18-2 Citadel证书体系

图片说明

原书此处有图18-2,展示根证书→中间证书(由根签发)→sidecar的持有关系,以及根证书→sidecar的直接信任关系。

以上三条即可保证,在互相通信的时候,Pod/sidecar之间可以成功完成TLS双向认证。


18.6 经验

对这个问题的排查过程,告诉我们两条经验。

一条是,很多工程师写的代码,报错很容易词不达意。这个问题的报错,说的是“创建”证书失败,但实际上代码用的是验证集群已有CA证书的逻辑,所以我们排查问题时,需要特别留意这一点。

另一条是,不要放过任何一条相关信息,也就是我经常说的,“Every single bit matters”。这个问题实际上有另外一条线索,就是Pod和虚拟服务创建失败,其报错有更明显的提示信息。

关键经验

  • 报错信息可能误导:注意区分“创建”与“验证”的实际逻辑。
  • 不要遗漏任何辅助线索,比如Pod/虚拟服务创建失败的具体错误。

18.7 总结

Istio比较早期的版本中,自签名CA证书有效期只有一年时间,如果使用老版本Istio超过一年,就会遇到这个问题。当证书过期之后,我们创建新的虚拟服务或者Pod,都会因为CA证书过期而失败。而这时如果要重启Citadel,它会读取过期证书并验证其有效性,就会出现以上Citadel不能启动的问题。

这个CA证书在Kubernetes集群中是以 istio-ca-secret 命名的Secret,我们可以使用 openssl 解码证书来查看有效期。这个问题比较简单的处理方法,就是删除这个Secret,并重启Citadel,这时Citadel会转而采用新建和验证自签名CA证书的逻辑并刷新CA证书。我们也可以参考官方网站页面 extending self-signed certificate lifetime 中的方式进行处理。

操作摘要

  • 确认问题:istio-ca-secret 中的CA证书已过期。
  • 验证命令:kubectl get secret istio-ca-secret -n istio-system -o json | jq -r '.data["ca-cert.pem"]' | base64 -d | openssl x509 -noout -dates
  • 简易解决:删除Secret → 重启Citadel(自动重建新证书)。
  • 长效方案:参考官方文档更新证书生命周期。