TT Lab
开始
学习 学习路径 课程

Istio 实测实验室

换了根证书,只有一半能通

在 TT Lab 中继续学习

目标

把 istiod 的自签名根替换为我们自己创建的根和中间 CA(插件 CA),并直接从证书中确认:替换的瞬间,只有一方拿到新证书的工作负载之间会中断;以及全部更换完成之后的证书链、身份和有效期。

为什么重要

网格的 mTLS 建立在所有工作负载都信任同一个根的前提之上。把这个根迁移到组织的 PKI,从安全角度看是必须的,但如果不懂顺序就去做,服务之间会有一半断掉。亲眼看一次中断,就能解释“两个根同时被信任的时期”为什么必要。

步骤

  1. 用 kubectl apply -f /opt/fixtures/istlab/pluginca-app.yaml 部署材料,等待就绪。然后在 /root/istlab-ca/01-before.txt 中写入三行——root_subject=(命名空间 bank 的 ConfigMap istio-ca-root-cert 中所含根的 subject)、root_sha256=(该根的 SHA-256 指纹,即 openssl x509 -fingerprint -sha256 的值部分)、leaf_issuer=(client sidecar 所获得的工作负载证书的 issuer)。
  2. 在 /root/istlab-ca/certs 中,用发行包中的 /usr/local/istio-1.31.0/tools/certs/Makefile.selfsigned.mk,创建根(make -f … root-ca)和集群 cluster1 用的中间 CA(make -f … cluster1-cacerts)。应生成 /root/istlab-ca/certs/root-cert.pem,以及 /root/istlab-ca/certs/cluster1/ 下的 ca-cert.pem、ca-key.pem、root-cert.pem、cert-chain.pem。
  3. 在 istio-system 中创建 Secret cacerts——把 /root/istlab-ca/certs/cluster1/ 中的四个文件(ca-cert.pem、ca-key.pem、root-cert.pem、cert-chain.pem)以同名的键放入。然后重启 istiod 并等待就绪。工作负载暂时还不要重启。
  4. 只重启 web。然后在 /root/istlab-ca/04-mixed.txt 中写入三行——code=(在 client 中访问 http://web/ 的状态码)、client_root=(client sidecar 的 ROOTCA subject)、web_leaf_issuer=(web sidecar 工作负载证书的 issuer)。
  5. 也重启 client,使 client → web 重新变为 200。然后把 client sidecar 的工作负载证书链(default 的 certificateChain)以 PEM 格式保存到 /root/istlab-ca/05-chain.pem。
  6. 从 /root/istlab-ca/05-chain.pem 的第一张证书(工作负载证书)中,把 SAN 的 URI 以 spiffe= 写入 /root/istlab-ca/06-identity.txt,并把该 URI 的信任域(spiffe:// 之后的第一部分)以 trust_domain= 写入。
  7. 在 /root/istlab-ca/07-lifetimes.txt 中写入三行——leaf_hours=(工作负载证书的 notAfter − notBefore,换算为小时,舍去小数)、intermediate_days=(中间 CA 的有效期,以天计)、root_days=(根的有效期,以天计)。
  8. 在 /root/istlab-ca/08-report.md 中写入五行——old_root_subject=(第 1 步)、new_root_subject=(/root/istlab-ca/certs/root-cert.pem 的 subject)、mixed_code=(第 4 步)、after_restart_code=(现在 client → web 的状态码)、leaf_hours=(第 7 步)——并在其下写出学到的内容,至少四行。

参考

现在的根是谁创建的

用 kubectl apply -f /opt/fixtures/istlab/pluginca-app.yaml 部署材料,等待就绪。然后在 /root/istlab-ca/01-before.txt 中写入三行——root_subject=(命名空间 bank 的 ConfigMap istio-ca-root-cert 中所含根的 subject)、root_sha256=(该根的 SHA-256 指纹,即 openssl x509 -fingerprint -sha256 的值部分)、leaf_issuer=(client sidecar 所获得的工作负载证书的 issuer)。

istiod 在没有 cacerts 时会自己生成根,存放在 istio-system/istio-ca-secret 中,并把该根以 istio-ca-root-cert ConfigMap 的形式分发到所有命名空间。工作负载证书是 sidecar 向 istiod 请求获得的,可以在 istioctl proxy-config secret deploy/client -n bank -o json 的 default(工作负载证书链)和 ROOTCA(所信任的根)中看到。值是以 base64 存放的。

创建根和集群用的中间 CA

在 /root/istlab-ca/certs 中,用发行包中的 /usr/local/istio-1.31.0/tools/certs/Makefile.selfsigned.mk,创建根(make -f … root-ca)和集群 cluster1 用的中间 CA(make -f … cluster1-cacerts)。应生成 /root/istlab-ca/certs/root-cert.pem,以及 /root/istlab-ca/certs/cluster1/ 下的 ca-cert.pem、ca-key.pem、root-cert.pem、cert-chain.pem。

Istio 文档推荐的结构是“根放在离线环境,为每个集群给 istiod 一个由该根签发的中间 CA”。这样即使一个集群的密钥泄露,也不必更换根,多个集群信任同一个根,也就能互相信任对方的工作负载。这个 Makefile 是演示用的,文档指出生产中应使用 Vault 之类的 CA。创建之后,请用 openssl verify -CAfile root-cert.pem cluster1/ca-cert.pem 确认证书链。

接入 cacerts,重新启动 istiod

在 istio-system 中创建 Secret cacerts——把 /root/istlab-ca/certs/cluster1/ 中的四个文件(ca-cert.pem、ca-key.pem、root-cert.pem、cert-chain.pem)以同名的键放入。然后重启 istiod 并等待就绪。工作负载暂时还不要重启。

istiod 会在启动时查看是否有 cacerts,有的话就不再用自己生成的根,而是用该中间 CA 签发。已经在运行的 istiod 即使 Secret 出现了也不会察觉,所以要重启。新启动的 istiod 的日志中会留下从 cacerts 读取根的那一行,各命名空间的 istio-ca-root-cert 会换成新根——而已经在运行的 sidecar 所信任的根会怎样,在第 4 步中查看。

只有一方拿到新证书时

只重启 web。然后在 /root/istlab-ca/04-mixed.txt 中写入三行——code=(在 client 中访问 http://web/ 的状态码)、client_root=(client sidecar 的 ROOTCA subject)、web_leaf_issuer=(web sidecar 工作负载证书的 issuer)。

新的 istiod 会给新启动的 web 一张由新中间 CA 签发的证书。但没有重启的 client 的 sidecar 仍然只信任旧根。mTLS 要求双方互相验证对方的证书,所以只要有一方不认识对方的根,连接就建立不起来。在生产中更换根时要设置同时信任旧根和新根的时期,原因就在于此。

让所有工作负载都拿到新证书

也重启 client,使 client → web 重新变为 200。然后把 client sidecar 的工作负载证书链(default 的 certificateChain)以 PEM 格式保存到 /root/istlab-ca/05-chain.pem。

重启后的 client 会信任新根,并获得由新中间 CA 签发的证书。保存下来的证书链按工作负载证书 → 中间 CA → 根的顺序排列,所以可以用 openssl verify -CAfile /root/istlab-ca/certs/root-cert.pem -untrusted /root/istlab-ca/05-chain.pem /root/istlab-ca/05-chain.pem 确认它是否连到我们的根。

证书所表达的身份

从 /root/istlab-ca/05-chain.pem 的第一张证书(工作负载证书)中,把 SAN 的 URI 以 spiffe= 写入 /root/istlab-ca/06-identity.txt,并把该 URI 的信任域(spiffe:// 之后的第一部分)以 trust_domain= 写入。

Istio 的工作负载证书 subject 为空,身份只放在 SAN 的一个 URI 中,格式为 spiffe://<신뢰 도메인>/ns/<네임스페이스>/sa/<서비스어카운트>(占位符依次为信任域、命名空间、服务账号)。授权策略的 principals 就是这个值(去掉 scheme 的部分)。即使更换 CA,只要信任域相同,就不必修改策略。用 openssl x509 -noout -ext subjectAltName 查看。

谁能存活多久

在 /root/istlab-ca/07-lifetimes.txt 中写入三行——leaf_hours=(工作负载证书的 notAfter − notBefore,换算为小时,舍去小数)、intermediate_days=(中间 CA 的有效期,以天计)、root_days=(根的有效期,以天计)。

工作负载证书由 istiod 签发很短的有效期(默认 24 小时),sidecar 会在到期前自动更换。所以即使泄露,受害时间也很短,更换 CA 之后没有重启的工作负载也很快会拿到新证书——不过在那之前,第 4 步那样的中断可能会持续。中间 CA 和根由人来管理,所以寿命很长。日期用 openssl x509 -noout -startdate -enddate 读取,再用 date -d 换算成秒后相减即可。

写下更换根的顺序

在 /root/istlab-ca/08-report.md 中写入五行——old_root_subject=(第 1 步)、new_root_subject=(/root/istlab-ca/certs/root-cert.pem 的 subject)、mixed_code=(第 4 步)、after_restart_code=(现在 client → web 的状态码)、leaf_hours=(第 7 步)——并在其下写出学到的内容,至少四行。

说明行中请用自己的话写下“要在已经运行的网格上更换根,需要什么样的顺序(同时信任旧根和新根的时期)”。本实验没有这个时期就直接更换,有意看到了中断。