使用 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>