使用 kubeadm 进行证书管理
本文以 kubeadm 管理的 Kubernetes 集群为例,说明控制平面证书、kubelet 客户端证书的检查、正常更新、证书过期后的恢复,以及更新后的验证方法。
重要:控制平面证书和 kubelet 证书是两套不同的机制。
kubeadm certs renew all主要负责 kubeadm 管理的控制平面/客户端证书。- kubelet 客户端证书位于
/var/lib/kubelet/pki/,正常情况下应该依靠 kubelet certificate rotation 自动 轮转。- kubelet 证书过期时,不能只执行
kubeadm certs renew all,需要单独恢复 kubelet 的认证。
k8s集群证书过期
官方文档:
https://kubernetes.io/zh-cn/docs/tasks/administer-cluster/kubeadm/kubeadm-certs/
如果 Kubernetes 集群证书过期,常见表现是访问 API Server 失败,例如:
k get no
Unable to connect to the server: tls: failed to verify certificate: x509: certificate has expired or is not yet valid: current time 2025-06-23T07:20:14Z is after 2025-01-02T02:18:40Z
证书问题不一定只表现为 kubectl 无法访问,也可能表现为:
kube-controller-manager、kube-scheduler等控制平面组件持续出现Unauthorized- kubelet 无法正常向 API Server 认证
- Node 状态异常、NotReady
- kubelet 日志中出现
system:anonymous - Calico 等依赖 kubelet/API Server 的组件出现认证相关错误
- CSR 长时间处于
Pending - static Pod 因证书问题无法正常启动或反复重启
因此遇到证书过期问题时,不要只更新一个证书然后立即认为故障已经恢复,应该按照本文最后的检查项逐项确认。
查看证书过期时间
查看控制平面组件证书过期时间
可以使用 kubeadm 查看 kubeadm 管理的证书:
kubeadm certs check-expiration
kubeadm certs check-expiration 会检查 /etc/kubernetes/pki 下的证书,以及 admin.conf、controller-manager.conf、scheduler.conf 中嵌入的客户端证书。
示例:
CERTIFICATE EXPIRES RESIDUAL TIME CERTIFICATE AUTHORITY EXTERNALLY MANAGED
admin.conf Jan 02, 2025 <invalid> ca no
apiserver Jan 02, 2025 <invalid> ca no
apiserver-etcd-client Jan 02, 2025 <invalid> etcd-ca no
apiserver-kubelet-client Jan 02, 2025 <invalid> ca no
controller-manager.conf Jan 02, 2025 <invalid> ca no
etcd-healthcheck-client Jan 02, 2025 <invalid> etcd-ca no
etcd-peer Jan 02, 2025 <invalid> etcd-ca no
etcd-server Jan 02, 2025 <invalid> etcd-ca no
front-proxy-client Jan 02, 2025 <invalid> front-proxy-ca no
scheduler.conf Jan 02, 2025 <invalid> ca no
CERTIFICATE AUTHORITY EXPIRES RESIDUAL TIME
ca Dec 31, 2033 8y
etcd-ca Dec 31, 2033 8y
front-proxy-ca Dec 31, 2033 8y
如果看到 <invalid>,说明对应证书已经过期。
kubelet.conf 不会出现在 kubeadm certs check-expiration 的控制平面证书列表中。
kubelet 默认启用了客户端证书自动轮转,相关证书通常位于:
/var/lib/kubelet/pki/
官方文档:
https://kubernetes.io/zh-cn/docs/tasks/tls/certificate-rotation/
kubeadm 排障文档:
因此,不要因为 kubeadm certs check-expiration 显示控制平面证书正常,就认为 kubelet 证书也一定正常。
查看kubelet证书过期时间
查看 kubelet 当前使用的客户端证书:
openssl x509 \
-in /var/lib/kubelet/pki/kubelet-client-current.pem \
-noout \
-subject \
-issuer \
-dates \
-serial
例如:
subject=O = system:nodes, CN = system:node:k8s-node01
issuer=CN = kubernetes
notBefore=Aug 15 02:18:40 2025 GMT
notAfter=Aug 15 02:18:40 2026 GMT
serial=3926CE667E904BFE3239CDB014E108C4
重点关注:
notAfter
如果已经超过当前时间,则 kubelet 客户端证书已经过期。
也可以查看目录:
ls -lah /var/lib/kubelet/pki/
正常情况下可以看到类似:
kubelet-client-2026-09-27-xxxxxx.pem
kubelet-client-current.pem -> kubelet-client-2026-09-27-xxxxxx.pem
kubelet.crt
kubelet.key
kubelet-client-current.pem 是 kubelet 当前使用的客户端证书,通常是一个软链接。
不要只看文件名判断证书是否有效,最终应使用 openssl x509 -dates 检查证书实际有效期。
正常情况下 kubelet 证书应该如何工作
kubeadm 集群通常通过 kubelet certificate rotation 自动轮转客户端证书。
可以检查 kubelet 配置:
grep -nE 'rotateCertificates|serverTLSBootstrap' /var/lib/kubelet/config.yaml
通常应该至少看到:
rotateCertificates: true
如果配置为:
rotateCertificates: true
表示 kubelet 客户端证书应该进行自动轮转。
正常流程大致为:
kubelet
│
│ 证书接近过期
▼
生成新的 CSR
│
▼
CSR 被批准
│
▼
生成新的 kubelet-client-*.pem
│
▼
更新 kubelet-client-current.pem
│
▼
继续使用新证书
因此,正常情况下不应该每年手工给 Node 更新 kubelet 证书。
如果 kubelet 证书已经过期,应该重点排查:
kubectl get csr
以及 kubelet 日志:
journalctl -u kubelet --since "1 hour ago" --no-pager
手动更新证书
执行证书更新之前,建议先备份 /etc/kubernetes,尤其是:
/etc/kubernetes/pki/
/etc/kubernetes/admin.conf
/etc/kubernetes/controller-manager.conf
/etc/kubernetes/scheduler.conf
/etc/kubernetes/kubelet.conf
例如:
BACKUP_DIR="/root/kubernetes-certs-backup-$(date +%Y%m%d-%H%M%S)" && \
mkdir -p "$BACKUP_DIR" && \
cp -a /etc/kubernetes/pki "$BACKUP_DIR/" && \
cp -a /etc/kubernetes/*.conf "$BACKUP_DIR/" 2>/dev/null && \
echo "备份完成: $BACKUP_DIR"
不要在没有确认 CA 文件和 CA 私钥存在的情况下直接执行破坏性操作。
更新kubelet证书
一、先确认 kubelet 证书是否真的过期
在 Node 上执行:
openssl x509 \
-in /var/lib/kubelet/pki/kubelet-client-current.pem \
-noout \
-subject \
-issuer \
-dates \
-serial
确认 notAfter 已经过期。
同时查看:
journalctl -u kubelet --since "1 hour ago" --no-pager
以及:
kubectl get csr
二、确认控制平面节点存在 CA 私钥
生成新的 kubelet kubeconfig 需要 Kubernetes CA 私钥,因此应该在正常工作的 Control Plane 节点执行。
确认:
ls -lah /etc/kubernetes/pki/ca.crt
ls -lah /etc/kubernetes/pki/ca.key
必须确认:
/etc/kubernetes/pki/ca.crt
/etc/kubernetes/pki/ca.key
都存在。
不要把:
/etc/kubernetes/pki/ca.key
复制到 Node。
CA 私钥属于整个 Kubernetes 集群的核心私钥,应该只保存在受控的 Control Plane 节点。
三、备份 Node 上原有 kubelet 配置和证书
在发生故障的 Node 上执行:
BACKUP_DIR="/root/kubelet-backup-$(date +%Y%m%d-%H%M%S)" && \
mkdir -p "$BACKUP_DIR" && \
cp -a /etc/kubernetes/kubelet.conf "$BACKUP_DIR/" 2>/dev/null && \
cp -a /var/lib/kubelet/pki/kubelet-client* "$BACKUP_DIR/" 2>/dev/null && \
echo "备份完成: $BACKUP_DIR" && \
ls -lah "$BACKUP_DIR"
四、删除失效的 kubelet 客户端证书
只删除 kubelet 客户端证书:
rm -f /var/lib/kubelet/pki/kubelet-client*
同时删除旧的 kubelet kubeconfig:
rm -f /etc/kubernetes/kubelet.conf
不要删除:
/var/lib/kubelet/pki/kubelet.crt
/var/lib/kubelet/pki/kubelet.key
这两个文件和 kubelet 客户端证书轮转不是一回事。
也不要执行:
rm -rf /var/lib/kubelet/pki
除非已经明确知道自己正在处理什么,并且有完整备份。
五、在 Control Plane 生成新的 kubelet.conf
假设故障 Node 为:
k8s-node01
在 Control Plane 执行:
NODE=k8s-node01
然后:
kubeadm kubeconfig user \
--org system:nodes \
--client-name system:node:$NODE \
> /root/${NODE}-kubelet.conf
检查:
ls -lah /root/${NODE}-kubelet.conf
确认证书:
openssl x509 \
-in <(kubectl config view --raw --kubeconfig /root/${NODE}-kubelet.conf -o jsonpath='{.users[0].user.client-certificate-data}' | base64 -d) \
-noout \
-subject \
-issuer \
-dates \
-serial
应该看到类似:
subject=O = system:nodes, CN = system:node:k8s-node01
issuer=CN = kubernetes
notBefore=Sep 27 00:00:00 2026 GMT
notAfter=Sep 27 00:00:00 2027 GMT
$NODE 必须是发生故障的 Node 名称。
例如:
NODE=k8s-node01
不能误写成 Control Plane:
NODE=k8s-master01
否则生成的客户端身份会错误。
六、将新的 kubelet.conf 复制到 Node
在 Control Plane 执行:
scp /root/${NODE}-kubelet.conf root@${NODE}:/etc/kubernetes/kubelet.conf
然后在 Node 上:
chmod 600 /etc/kubernetes/kubelet.conf
检查:
ls -lah /etc/kubernetes/kubelet.conf
七、重启 kubelet
在 Node 上执行:
systemctl restart kubelet
检查:
systemctl status kubelet --no-pager
查看最近日志:
journalctl -u kubelet --since "10 minutes ago" --no-pager
八、确认新的 kubelet 客户端证书已经生成
等待 kubelet 完成认证后:
ls -lah /var/lib/kubelet/pki/
重点查看:
ls -lah /var/lib/kubelet/pki/kubelet-client-current.pem
然后:
openssl x509 \
-in /var/lib/kubelet/pki/kubelet-client-current.pem \
-noout \
-subject \
-issuer \
-dates \
-serial
确认:
subject=O = system:nodes, CN = system:node:k8s-node01
并确认:
notAfter
已经变成未来时间。
不要简单认为:
systemctl restart kubelet
执行成功就代表证书已经恢复。
必须检查 /var/lib/kubelet/pki/kubelet-client-current.pem 是否存在,并确认其 notAfter 已经更新。
九、确认 kubelet.conf 使用的是正确的认证方式
检查:
grep -nE 'client-certificate|client-key|client-certificate-data|client-key-data' /etc/kubernetes/kubelet.conf
如果使用动态轮转证书,应该确认 kubelet 最终使用的是:
/var/lib/kubelet/pki/kubelet-client-current.pem
而不是永久嵌入旧证书的:
client-certificate-data
client-key-data
必要时可以编辑:
vi /etc/kubernetes/kubelet.conf
将对应用户配置调整为:
users:
- name: system:kubelet
user:
client-certificate: /var/lib/kubelet/pki/kubelet-client-current.pem
client-key: /var/lib/kubelet/pki/kubelet-client-current.pem
保存后:
systemctl restart kubelet
然后再次检查:
journalctl -u kubelet --since "10 minutes ago" --no-pager
这一步非常重要。
恢复 kubelet 时不能只关注“生成了一个新的 kubelet.conf”,还需要确认 kubelet 后续能够使用 /var/lib/kubelet/pki/kubelet-client-current.pem 进行正常的证书轮转。
kubelet证书自动轮转失败排查
如果:
rotateCertificates: true
但是证书仍然过期,重点检查下面几项。
查看 kubelet 配置
grep -nE 'rotateCertificates|serverTLSBootstrap' /var/lib/kubelet/config.yaml
查看 CSR
kubectl get csr
如果出现:
NAME AGE SIGNERNAME REQUESTOR CONDITION
csr-xxxxx 10m kubernetes.io/kube-apiserver-client-kubelet system:node:k8s-node01 Pending
说明 kubelet 已经发起 CSR,但没有完成批准。
检查具体 CSR
不要直接批准所有 Pending CSR。
先:
kubectl describe csr <CSR_NAME>
重点确认:
Requesting User
SignerName
Subject
Conditions
确认 CSR 确实来自目标 Node,并且:
CN=system:node:<node-name>
O=system:nodes
确认无误后:
kubectl certificate approve <CSR_NAME>
然后:
kubectl get csr
再次检查:
kubectl describe csr <CSR_NAME>
不建议直接批量批准所有 Pending CSR
不要在生产环境直接执行:
kubectl get csr | grep Pending | awk '{print $1}' | xargs kubectl certificate approve
因为 Pending CSR 不一定全部来自你正在恢复的 kubelet。
正确做法是:
kubectl get csr
找到目标 CSR:
kubectl describe csr <CSR_NAME>
确认身份后:
kubectl certificate approve <CSR_NAME>
更新控制平面组件证书
如果:
kubeadm certs check-expiration
发现控制平面证书已经过期,可以执行:
kubeadm certs renew all
示例输出:
certificate embedded in kubeconfig file admin.conf renewed
certificate embedded in kubeconfig file controller-manager.conf renewed
certificate embedded in kubeconfig file scheduler.conf renewed
执行完成后重新检查:
kubeadm certs check-expiration
确认相关证书的:
EXPIRES
RESIDUAL TIME
已经恢复。
kubeadm certs renew all 不会替代 kubelet 客户端证书自动轮转。
因此即使:
kubeadm certs check-expiration
全部正常,也应该单独检查:
openssl x509 \
-in /var/lib/kubelet/pki/kubelet-client-current.pem \
-noout \
-subject \
-issuer \
-dates
更新 admin.conf
证书更新后,如果当前用户使用的是旧的 admin.conf,可以更新:
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
然后:
kubectl get nodes
确认可以正常访问集群。
重启控制平面组件
kubeadm 部署的控制平面组件通常是 static Pod。
manifest 通常位于:
/etc/kubernetes/manifests/
例如:
ls -lah /etc/kubernetes/manifests/
通常可以看到:
etcd.yaml
kube-apiserver.yaml
kube-controller-manager.yaml
kube-scheduler.yaml
不要一次性移动或删除 /etc/kubernetes/manifests/ 下的全部文件。
例如不建议直接执行:
mv /etc/kubernetes/manifests/* /tmp/k8s-manifests/
因为这样可能同时停止:
- etcd
- kube-apiserver
- kube-controller-manager
- kube-scheduler
如果是单 Control Plane 集群,可能直接导致整个控制平面不可用。
应该一个组件一个组件处理。
重启 kube-controller-manager
例如:
mkdir -p /tmp/k8s-manifests
mv /etc/kubernetes/manifests/kube-controller-manager.yaml \
/tmp/k8s-manifests/
sleep 20
mv /tmp/k8s-manifests/kube-controller-manager.yaml \
/etc/kubernetes/manifests/
然后检查:
crictl ps -a | grep kube-controller-manager
以及:
kubectl get pods -n kube-system -o wide | grep kube-controller-manager
重启 kube-scheduler
mkdir -p /tmp/k8s-manifests
mv /etc/kubernetes/manifests/kube-scheduler.yaml \
/tmp/k8s-manifests/
sleep 20
mv /tmp/k8s-manifests/kube-scheduler.yaml \
/etc/kubernetes/manifests/
检查:
crictl ps -a | grep kube-scheduler
重启 kube-apiserver
mkdir -p /tmp/k8s-manifests
mv /etc/kubernetes/manifests/kube-apiserver.yaml \
/tmp/k8s-manifests/
sleep 20
mv /tmp/k8s-manifests/kube-apiserver.yaml \
/etc/kubernetes/manifests/
然后:
kubectl get --raw='/readyz?verbose'
重启 etcd
如果更新了 etcd 相关证书:
mkdir -p /tmp/k8s-manifests
mv /etc/kubernetes/manifests/etcd.yaml \
/tmp/k8s-manifests/
sleep 20
mv /tmp/k8s-manifests/etcd.yaml \
/etc/kubernetes/manifests/
检查:
crictl ps -a | grep etcd
如果是多 Control Plane 集群,重启控制平面组件时应该结合高可用拓扑进行操作,避免同时影响多个 Control Plane。
如果是单 Control Plane 集群,更应该严格遵守“一个组件一个组件重启”的原则。
static Pod 没有因为删除 Mirror Pod 而真正重启
在实际排障中可能遇到:
kubectl delete pod kube-controller-manager-xxx -n kube-system
执行成功,但是控制平面组件实际运行的 container 并没有按照预期重新创建。
这是因为:
kubectl delete pod
↓
删除 API Server 中的 Mirror Pod 对象
↓
并不等价于直接停止节点上的 static Pod container
static Pod 的真正运行状态由 kubelet 和容器运行时负责。
因此需要结合:
crictl ps -a
检查真实 container。
例如:
crictl ps -a | grep kube-controller-manager
如果确认旧 container 仍然存在,可以结合具体运行时状态进行处理。
在实际故障恢复中,如果确认需要停止旧的 static Pod container,可以使用:
crictl stop <CONTAINER_ID>
然后观察 kubelet 是否重新创建:
crictl ps -a | grep kube-controller-manager
处理 static Pod 时,建议优先使用“修改/移出 manifest → kubelet 检测到 manifest 变化 → 重新创建 Pod”的方式。
crictl stop 更适合作为故障排查和已经明确需要强制停止旧 container 时的辅助手段。
控制平面证书更新后出现 Unauthorized
例如:
Unauthorized
或者 kube-controller-manager 日志中出现:
x509: certificate has expired or is not yet valid
首先确认对应证书:
kubeadm certs check-expiration
然后确认实际配置文件:
ls -lah /etc/kubernetes/controller-manager.conf
ls -lah /etc/kubernetes/scheduler.conf
ls -lah /etc/kubernetes/admin.conf
如果已经执行:
kubeadm certs renew all
需要确保对应 static Pod 已经真正重新加载新的 kubeconfig。
可以检查:
crictl ps -a | grep kube-controller-manager
并查看:
kubectl logs -n kube-system <controller-manager-pod> --tail=100
如果 Mirror Pod 日志获取不到,可以使用容器运行时:
crictl ps -a | grep kube-controller-manager
然后:
crictl logs <CONTAINER_ID>
证书过期后的完整恢复流程
如果遇到类似:
控制平面证书过期
+
kubelet 客户端证书过期
+
Node NotReady
+
CSR Pending
建议按照下面顺序处理。
第一步:确认集群状态
kubectl get nodes -o wide
kubectl get pods -A
kubectl get csr
第二步:检查控制平面证书
kubeadm certs check-expiration
第三步:检查 kubelet 证书
在每个异常 Node:
openssl x509 \
-in /var/lib/kubelet/pki/kubelet-client-current.pem \
-noout \
-subject \
-issuer \
-dates \
-serial
第四步:先恢复异常 Node 的 kubelet 认证
在正常 Control Plane:
NODE=k8s-node01
kubeadm kubeconfig user \
--org system:nodes \
--client-name system:node:$NODE \
> /root/${NODE}-kubelet.conf
复制:
scp /root/${NODE}-kubelet.conf root@${NODE}:/etc/kubernetes/kubelet.conf
Node 上:
chmod 600 /etc/kubernetes/kubelet.conf
systemctl restart kubelet
然后检查:
systemctl status kubelet --no-pager
journalctl -u kubelet --since "10 minutes ago" --no-pager
第五步:确认 kubelet 新证 书
ls -lah /var/lib/kubelet/pki/
openssl x509 \
-in /var/lib/kubelet/pki/kubelet-client-current.pem \
-noout \
-subject \
-issuer \
-dates \
-serial
第六步:处理 CSR
kubectl get csr
对于确认属于目标 Node 的 Pending CSR:
kubectl describe csr <CSR_NAME>
确认无误后:
kubectl certificate approve <CSR_NAME>
第七步:恢复控制平面证书
kubeadm certs renew all
然后:
kubeadm certs check-expiration
第八步:逐个重启 static Pod
不要一次性移动全部 manifest。
按照实际需要:
etcd
kube-apiserver
kube-controller-manager
kube-scheduler
一个一个处理,并在每一步确认组件恢复正常。
第九步:最终验证
kubectl get nodes -o wide
kubectl get pods -A
kubectl get pods -n kube-system
kubectl get csr
kubeadm certs check-expiration
Node 上:
openssl x509 \
-in /var/lib/kubelet/pki/kubelet-client-current.pem \
-noout \
-subject \
-issuer \
-dates
证书更新完成后的检查
1. 检查 kubeadm 管理的证书
kubeadm certs check-expiration
确认不存在:
<invalid>
2. 检查 kubelet 证书
openssl x509 \
-in /var/lib/kubelet/pki/kubelet-client-current.pem \
-noout \
-subject \
-issuer \
-dates \
-serial
确认:
subject=O = system:nodes, CN = system:node:<NODE_NAME>
并确认 notAfter 在未来。
3. 检查 kubelet 配置
grep -nE 'rotateCertificates|serverTLSBootstrap' /var/lib/kubelet/config.yaml
确认:
rotateCertificates: true
4. 检查 kubelet.conf
grep -nE 'client-certificate|client-key|client-certificate-data|client-key-data' /etc/kubernetes/kubelet.conf
确认 kubelet 可以使用当前轮转证书:
/var/lib/kubelet/pki/kubelet-client-current.pem
5. 检查 Node
kubectl get nodes -o wide
应该全部:
Ready