CA 证书的手动轮换
此页面展示如何手动轮换证书颁发机构(CA)证书。
开始之前
你需要有一个 Kubernetes 集群,并且必须配置 kubectl 命令行工具以与你的集群通信。建议在至少有两个不充当控制平面主机的节点的集群上运行本教程。如果你还没有集群,可以使用 minikube 创建一个,或者可以使用以下 Kubernetes 游乐场之一
手动轮换 CA 证书
注意
请务必备份你的证书目录以及配置文件和任何其他必要的文件。
此方法假设 Kubernetes 控制平面在具有多个 API 服务器的 HA 配置中运行。还假设 API 服务器正常终止,以便客户端可以干净地断开与一个 API 服务器的连接并重新连接到另一个 API 服务器。
具有单个 API 服务器的配置在 API 服务器重新启动时将遇到不可用。
将新的 CA 证书和私钥(例如:
ca.crt
、ca.key
、front-proxy-ca.crt
和front-proxy-ca.key
)分发到 Kubernetes 证书目录中所有控制平面节点。更新 kube-controller-manager的
--root-ca-file
标志,以同时包含旧的和新的 CA,然后重新启动 kube-controller-manager。在此之后创建的任何ServiceAccount 都将获得包含旧的和新的 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
并删除副本。Issue 1350 用于 kubeadm 跟踪 kube-controller-manager 无法接受 CA 包的错误。
等待控制器管理器更新服务帐户 Secret 中的
ca.crt
,以包含旧的和新的 CA 证书。如果在 API 服务器使用新的 CA 之前启动任何 Pod,则新的 Pod 将获得此更新,并将信任旧的和新的 CA。
重新启动所有使用集群内部配置的 Pod(例如:kube-proxy、CoreDNS 等),以便它们可以使用链接到 ServiceAccount 的 Secret 中更新的证书颁发机构数据。
- 确保 CoreDNS、kube-proxy 和其他使用集群内部配置的 Pod 按预期工作。
将旧的和新的 CA 追加到
kube-apiserver
配置中的--client-ca-file
和--kubelet-certificate-authority
标志对应的文件中。将旧的和新的 CA 追加到
kube-scheduler
配置中的--client-ca-file
标志对应的文件中。通过分别替换
client-certificate-data
和client-key-data
的内容来更新用户帐户的证书。有关为单个用户帐户创建证书的信息,请参阅 为用户帐户配置证书。
此外,分别使用 Base64 编码的旧的和新的证书颁发机构数据来更新 kubeconfig 文件中的
certificate-authority-data
部分更新 Cloud Controller Manager 的
--root-ca-file
标志,以同时包含旧的和新的 CA,然后重新启动 cloud-controller-manager。注意
如果你的集群没有 cloud-controller-manager,你可以跳过此步骤。按滚动方式执行以下步骤。
重新启动任何其他聚合的 API 服务器 或 webhook 处理程序,以信任新的 CA 证书。
通过更新 kubelet 配置中的
clientCAFile
和kubelet.conf
中的certificate-authority-data
对应的文件来重新启动 kubelet,以在所有节点上使用旧的和新的 CA。如果你的 kubelet 没有使用客户端证书轮换,请更新所有节点上的
kubelet.conf
中的client-certificate-data
和client-key-data
以及通常在/var/lib/kubelet/pki
中找到的 kubelet 客户端证书文件。使用新的 CA 签名的证书(
apiserver.crt
、apiserver-kubelet-client.crt
和front-proxy-client.crt
)重新启动 API 服务器。 你可以使用现有的私钥或新的私钥。 如果你更改了私钥,那么也在 Kubernetes 证书目录中更新这些私钥。由于你集群中的 Pod 信任旧的和新的 CA,因此会发生短暂的断开连接,之后 Pod 的 Kubernetes 客户端会重新连接到新的 API 服务器。 新的 API 服务器使用由新的 CA 签名的证书。
- 重新启动kube-scheduler以使用并信任新的 CA。
- 确保控制平面组件的日志中没有 TLS 错误。
注意
To generate certificates and private keys for your cluster using the `openssl` command line tool, see [Certificates (`openssl`)](/docs/tasks/administer-cluster/certificates/#openssl). You can also use [`cfssl`](/docs/tasks/administer-cluster/certificates/#cfssl).
注释任何 DaemonSet 和 Deployment 以触发更安全的滚动方式进行 Pod 替换。
for namespace in $(kubectl get namespace -o jsonpath='{.items[*].metadata.name}'); do for name in $(kubectl get deployments -n $namespace -o jsonpath='{.items[*].metadata.name}'); do kubectl patch deployment -n ${namespace} ${name} -p '{"spec":{"template":{"metadata":{"annotations":{"ca-rotation": "1"}}}}}'; done for name in $(kubectl get daemonset -n $namespace -o jsonpath='{.items[*].metadata.name}'); do kubectl patch daemonset -n ${namespace} ${name} -p '{"spec":{"template":{"metadata":{"annotations":{"ca-rotation": "1"}}}}}'; done done
注意
To limit the number of concurrent disruptions that your application experiences, see [configure pod disruption budget](/docs/tasks/run-application/configure-pdb/).
Depending on how you use StatefulSets you may also need to perform similar rolling replacement.
如果你的集群使用引导令牌来加入节点,请使用新的 CA 更新
kube-public
命名空间中的 ConfigMapcluster-info
。base64_encoded_ca="$(base64 -w0 /etc/kubernetes/pki/ca.crt)" kubectl get cm/cluster-info --namespace kube-public -o yaml | \ /bin/sed "s/\(certificate-authority-data:\).*/\1 ${base64_encoded_ca}/" | \ kubectl apply -f -
验证集群功能。
检查来自控制平面组件、kubelet 和 kube-proxy 的日志。 确保这些组件没有报告任何 TLS 错误;有关更多详细信息,请参阅 查看日志。
验证来自任何聚合的 api 服务器和使用集群内部配置的 Pod 的日志。
一旦成功验证了集群功能
更新所有服务帐户令牌,使其仅包含新的 CA 证书。
- 所有使用集群内部 kubeconfig 的 Pod 最终都需要重新启动以获取新的 Secret,这样就没有 Pod 依赖于旧的集群 CA。
通过从 kubeconfig 文件和
--client-ca-file
、--root-ca-file
标志对应的文件中删除旧的 CA 来重新启动控制平面组件。在每个节点上,通过从
clientCAFile
标志对应的文件和 kubelet kubeconfig 文件中删除旧的 CA 来重新启动 kubelet。 你应该以滚动更新的方式执行此操作。如果你的集群允许你进行此更改,你也可以通过替换节点而不是重新配置它们来推出更改。