手动轮换 CA 证书

    你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。 建议在至少有两个节点的集群上运行本教程,且这些节点不作为控制平面主机。 如果你还没有集群,你可以通过 Minikube 构建一个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:

    您的 Kubernetes 服务器版本必须不低于版本 v1.13. 要获知版本信息,请输入 .

    • 要了解 Kubernetes 中用户认证的更多信息,参阅 ;
    • 要了解与 CA 证书最佳实践有关的更多信息,参阅单根 CA

    手动轮换 CA 证书

    注意:

    确保备份你的证书目录、配置文件以及其他必要文件。

    这里的方法假定 Kubernetes 的控制面通过运行多个 API 服务器以高可用配置模式运行。 另一假定是 API 服务器可体面地终止,因而客户端可以彻底地与一个 API 服务器断开 连接并连接到另一个 API 服务器。

    如果集群中只有一个 API 服务器,则在 API 服务器重启期间会经历服务中断期。

    1. 将新的 CA 证书和私钥(例如:ca.crtca.keyfront-proxy-ca.crtfront-proxy-client.key)分发到所有控制面节点,放在其 Kubernetes 证书目录下。

    2. 更新 kube-controller-manager--root-ca-file 标志,使之同时包含老的和新的 CA,之后重启组件。

      自此刻起,所创建的所有服务账号都会获得同时包含老的 CA 和新的 CA 的 Secret。

      说明: kube-controller-manager 标志 --client-ca-file--cluster-signing-cert-file 所引用的文件 不能是 CA 证书包。如果这些标志和 --root-ca-file 指向同一个 ca.crt 包文件(包含老的和新的 CA 证书), 你将会收到出错信息。 要解决这个问题,可以将新的 CA 证书复制到单独的文件中,并将 --client-ca-file--cluster-signing-cert-file 标志指向该副本。一旦 ca.crt 不再是证书包文件,就可以恢复有问题的标志指向 ca.crt 并删除该副本。

    3. 如果在 API 服务器使用新的 CA 之前启动了新的 Pod,这些 Pod 也会获得此更新并且同时信任老的和新的 CA 证书。

    4. 重启所有使用集群内配置的 Pods(例如:kube-proxycoredns 等),以便这些 Pod 能够使用 来自 ServiceAccount Secret 中的、已更新的证书机构数据。

      • 确保 corednskube-proxy 和其他使用集群内配置的 Pod 都正按预期方式工作。
    5. 将老的和新的 CA 都追加到 配置的 --client-ca-file--kubelet-certificate-authority 标志所指的文件。

    6. 将老的和新的 CA 都追加到 kube-scheduler 配置的 --client-ca-file 标志所指的文件。

    7. 遵循下列步骤执行滚动更新

      1. 重新启动所有其他 或者 Webhook 处理程序,使之信任新的 CA 证书。

      2. 在所有节点上更新 kubelet 配置中的 clientCAFile 所指文件以及 kubelet.conf 中的 certificate-authority-data 并重启 kubelet 以同时使用老的和新的 CA 证书。

      3. 使用用新的 CA 签名的证书 (apiserver.crtapiserver-kubelet-client.crtfront-proxy-client.crt) 来重启 API 服务器。 你可以使用现有的私钥,也可以使用新的私钥。 如果你改变了私钥,则要将更新的私钥也放到 Kubernetes 证书目录下。

      由于 Pod 既信任老的 CA 也信任新的 CA,Pod 中的客户端会经历短暂的连接断开状态, 之后再连接到使用新的 CA 所签名的证书的新的 API 服务器。

      1. * 重启调度器以使用新的 CA 证书。
      • 确保控制面组件的日志中没有 TLS 相关的错误信息。
      1. 为 Daemonset 和 Deployment 添加注解,从而触发较安全的滚动更新,替换 Pod。

      示例:

      1. for namespace in $(kubectl get namespace -o jsonpath='{.items[*].metadata.name}'); do
      2. kubectl patch deployment -n ${namespace} ${name} -p '{"spec":{"template":{"metadata":{"annotations":{"ca-rotation": "1"}}}}}';
      3. done
      4. for name in $(kubectl get daemonset -n $namespace -o jsonpath='{.items[*].metadata.name}'); do
      5. kubectl patch daemonset -n ${namespace} ${name} -p '{"spec":{"template":{"metadata":{"annotations":{"ca-rotation": "1"}}}}}';
      6. done
    8. 如果你的集群使用启动引导令牌来添加节点,则需要更新 kube-public 名字空间下的 ConfigMap cluster-info,使之包含新的 CA 证书。

      1. base64_encoded_ca="$(base64 -w0 /etc/kubernetes/pki/ca.crt)"
      2. kubectl get cm/cluster-info --namespace kube-public -o yaml | \
      3. /bin/sed "s/\(certificate-authority-data:\).*/\1 ${base64_encoded_ca}/" | \
      4. kubectl apply -f -
    9. 验证集群的功能正常

      1. 验证控制面组件的日志,以及 kubeletkube-proxy 的日志,确保其中没有 抛出 TLS 错误,参阅 查看日志.

      2. 验证被聚合的 API 服务器的日志,以及所有使用集群内配置的 Pod 的日志。

    10. 完成集群功能的检查之后:

      1. 更新所有的服务账号令牌,使之仅包含新的 CA 证书。

        • 使用集群内 kubeconfig 的 Pod 最终也需要被重启,以获得新的服务账号 Secret 数据,进而不再信任老的 CA 证书。