换了根证书,只有一半能通
目标
把 istiod 的自签名根替换为我们自己创建的根和中间 CA(插件 CA),并直接从证书中确认:替换的瞬间,只有一方拿到新证书的工作负载之间会中断;以及全部更换完成之后的证书链、身份和有效期。
为什么重要
网格的 mTLS 建立在所有工作负载都信任同一个根的前提之上。把这个根迁移到组织的 PKI,从安全角度看是必须的,但如果不懂顺序就去做,服务之间会有一半断掉。亲眼看一次中断,就能解释“两个根同时被信任的时期”为什么必要。
步骤
- 用
kubectl apply -f /opt/fixtures/istlab/pluginca-app.yaml部署材料,等待就绪。然后在/root/istlab-ca/01-before.txt中写入三行——root_subject=(命名空间 bank 的 ConfigMapistio-ca-root-cert中所含根的 subject)、root_sha256=(该根的 SHA-256 指纹,即openssl x509 -fingerprint -sha256的值部分)、leaf_issuer=(client sidecar 所获得的工作负载证书的 issuer)。 - 在
/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-system中创建 Secretcacerts——把/root/istlab-ca/certs/cluster1/中的四个文件(ca-cert.pem、ca-key.pem、root-cert.pem、cert-chain.pem)以同名的键放入。然后重启 istiod 并等待就绪。工作负载暂时还不要重启。 - 只重启 web。然后在
/root/istlab-ca/04-mixed.txt中写入三行——code=(在 client 中访问http://web/的状态码)、client_root=(client sidecar 的 ROOTCA subject)、web_leaf_issuer=(web sidecar 工作负载证书的 issuer)。 - 也重启 client,使 client → web 重新变为 200。然后把 client sidecar 的工作负载证书链(
default的 certificateChain)以 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=写入。 - 在
/root/istlab-ca/07-lifetimes.txt中写入三行——leaf_hours=(工作负载证书的 notAfter − notBefore,换算为小时,舍去小数)、intermediate_days=(中间 CA 的有效期,以天计)、root_days=(根的有效期,以天计)。 - 在
/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 步)——并在其下写出学到的内容,至少四行。
参考
- 这台 VM 的准备需要 2–4 分钟。已安装 minimal profile(只有 istiod),证书用的 Makefile 位于
/usr/local/istio-1.31.0/tools/certs/Makefile.selfsigned.mk。 - sidecar 获得的证书,可以在
istioctl proxy-config secret deploy/client -n bank -o json中通过default(工作负载证书链)和ROOTCA(所信任的根)查看,值是以 base64 存放的。 - 重启用
kubectl -n bank rollout restart deploy/<이름>(占位符为名称)。第 4 步中只重启 web。 - 常见错误——创建了 cacerts 却不重启 istiod。istiod 只在启动时查看 cacerts。
现在的根是谁创建的
用 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 步)——并在其下写出学到的内容,至少四行。
说明行中请用自己的话写下“要在已经运行的网格上更换根,需要什么样的顺序(同时信任旧根和新根的时期)”。本实验没有这个时期就直接更换,有意看到了中断。