记一次K8s证书过期导致控制平面组件反复 Unauthorized 的排查与修复

故障现象

  • 通过 kubectl create deployment 创建应用后,Pod 一直未被创建,Deployment 一直处于 NotReady 状态。
  • 查看 kube-system 命名空间下的 kube-controller-manager Pod,发现日志反复报错:
1
E0513 02:21:45.091033 leaderelection.go:332] error retrieving resource lock kube-system/kube-controller-manager: Unauthorized
  • 稍后发现 kube-scheduler 也出现了类似问题,集群整体不可用。

环境信息

  • Kubernetes 版本:1.28(但远端提示较新,不影响)
  • 部署方式:kubeadm
  • 集群节点:单 master 节点
  • 证书过期时间:系统显示 controller-manager 证书已过期(2026-04-21),而当前时间为 2026-05-13

错误的排查方向(易错点)

起初通过 kubectl config view 检查 /etc/kubernetes/controller-manager.conf 内嵌的客户端证书时,证书有效期竟然显示为 2027 年。
这误导我们认为证书没有过期,于是排查了:

  • CA 指纹比对(一致)
  • API Server 的 --client-ca-file 参数(正确指向 /etc/kubernetes/pki/ca.crt
  • RBAC ClusterRole system:kube-controller-manager 的权限(发现缺少 configmaps/endpoints 的写权限,修复后仍报错)
  • 网络连通性(curl api-server 正常)
  • API Server 日志级别(开启 --v=4 后捕获到真实报错)

以上调试几乎走遍了认证、授权、网络三个方向,但问题并未根治。

真正原因

最终通过提升 apiserver 日志级别(--v=4),在 authentication.go:70 中捕获到关键日志:

1
2
3
4
5

Unable to authenticate the request err="[x509: certificate has expired or is not yet valid:
current time 2026-05-13T02:54:39Z is after 2026-04-21T06:52:36Z,
verifying certificate SN=XXXXXXXXXXX ... failed: x509: certificate has expired or is not yet valid]

这说明:controller-manager 实际使用的客户端证书并未更新,仍然是过期的那一份。

为什么证书看起来很新,但实际使用时却已过期?

  • kubeadm certs renew all 确实更新了 /etc/kubernetes/pki/ 下的证书文件和 /etc/kubernetes/*.conf 中内嵌的证书数据。
  • kube-controller-manager 是一个静态 Pod,kubelet 仅当 Pod 重新创建时才会重新读取 manifest 和相关的证书/配置文件。
  • 如果证书续期后没有强制重启 controller-manager 的 Pod(或者重启 kubelet 时,kubelet 仍然使用了旧的镜像或证书缓存),Pod 内存态仍会使用旧证书。
  • 特别是一些集群在 controller-manager 的 manifest 中使用了独立的证书文件(如 --client-certificate=/etc/kubernetes/pki/controller-manager.crt),而不是仅通过 kubeconfig 内嵌证书。这种情况下,即使 kubeconfig 文件已更新,只要 .crt/.key 文件仍是旧的,组件就会一直使用过期证书。

虽然 /etc/kubernetes/controller-manager.conf 中的证书已经更新,但 Pod 启动时可能从某个地方加载了旧的证书路径,导致实际发起请求时携带的是过期证书。

最终解决方案

解决问题的核心:强制让 kube-controller-manager 和 kube-scheduler 的静态 Pod 以全新的状态重建,从而加载已更新的证书。

具体操作步骤

  1. 临时移走静态 Pod 的 manifest 文件
    这样 kubelet 检测到 manifest 丢失,会自动停止并删除对应的 Pod。

    1
    mv /etc/kubernetes/manifests/kube-controller-manager.yaml /root/
  2. 确认 Pod 已彻底消失

    1
    2
    kubectl get pod -n kube-system -l component=kube-controller-manager
    # 应无结果输出
  3. 将 manifest 文件移回原位

    1
    mv /root/kube-controller-manager.yaml /etc/kubernetes/manifests/

    此时 kubelet 发现新 manifest 会立刻创建全新的 Pod,Pod 启动时会读取已更新的 kubeconfig 或证书文件,从而使用新证书。

  4. 对 kube-scheduler 执行相同的操作(因为 scheduler 同样基于静态 Pod,且也出现了相同问题)

    1
    2
    3
    4
    mv /etc/kubernetes/manifests/kube-scheduler.yaml /root/
    # 确认 pod 删除
    kubectl get pod -n kube-system -l component=kube-scheduler
    mv /root/kube-scheduler.yaml /etc/kubernetes/manifests/
  5. 验证修复

    • 查看 controller-manager 日志不再出现 Unauthorized:
      1
      kubectl logs -n kube-system -l component=kube-controller-manager --tail=10
      应显示 successfully acquired lease。
    • 创建一个测试 Deployment 并观察 Pod 状态:
      1
      2
      kubectl create deployment test-ok --image=nginx --replicas=1
      kubectl get pods -w
      Pod 应能顺利 Running。

经验总结

  1. 证书过期后,更新文件 ≠ 立刻生效
    静态 Pod 需要重建才能加载新证书,直接 systemctl restart kubelet 不一定能保证清理所有旧状态(例如旧容器未被彻底销毁)。移走 manifest → 确认删除 → 移回 是一个更可靠的方式。
  2. 善用 API Server 的高级日志
    当组件报 Unauthorized 且基本排查无果时,务必开启 –v=4 或更高日志级别,直接查看 apiserver 的认证/授权拒绝详情,能瞬间缩小问题范围。
  3. 注意控制器组件的证书加载方式
    如果 manifest 中同时使用了 –kubeconfig 和 –client-certificate / –client-key,需要确保所有引用的证书文件都被更新,否则仍会使用旧证书。
  4. 不要忽略 scheduler 等其它静态 Pod
    当 controller-manager 出现证书问题时,通常 scheduler 也面临相同问题,应一并处理,避免集群长时间不可用。

拓展:自动化预防建议

  • 配置 kubeadm certs check-expiration 的定时监控,提前预警证书到期。
  • 编写更新脚本,在 kubeadm certs renew all 后,自动执行静态 Pod 的重建流程(移走 manifest + 移回)。
  • 对于生产集群,建议使用 kubeadm 的证书自动轮换功能,或提前规划证书续期窗口。

免责声明:本文所述操作均在测试环境中验证,生产环境操作前请充分评估影响并做好备份。