2026/10/21 6:47:08

Kubernetes证书过期怎么办?kubeadm集群证书年限修改与续期完全指南

Kubernetes证书过期怎么办?kubeadm集群证书年限修改与续期完全指南 早上八点半监控群里弹出一条告警kube-apiserver 证书剩余有效期不足 30 天。这个场景对任何自建过 Kubernetes 集群的人来说都不陌生尤其在用 kubeadm 维护的集群里证书过期几乎是每年都要面对一次的事故。很多人第一反应是能不能直接把证书可用年限改成十年一劳永逸答案并没有想象中那么简单因为一个集群里同时存在好几类证书它们各自的签发机制、续期命令、控制参数完全不一样。这篇文章就围绕“Kubernetes 证书可用年限修改”这件事把控制平面证书的默认策略、过期后的急救流程、kubelet 证书的独立规则、从源头改年限的可行路线以及改完之后的验证和长期巡检一条线讲清楚。无论是刚接手集群的新手还是已经踩过几次证书坑的运维都能在这篇里找到可以直接照做的步骤。1. 一年一签是默认策略不是安全法则先别急着改年限第一步是把集群里到底有哪些证书搞清楚。kubeadm 初始化和节点加入时会在控制平面节点上生成一套完整的 PKI 体系大部分证书都集中在/etc/kubernetes/pki目录下。1.1 控制平面证书的类型与信任关系我把常见证书的用途列成了一张表实际排查时对照看会清晰很多路径/文件用途/etc/kubernetes/pki/ca.crt/ca.key集群根 CA签发控制平面组件证书、kubelet 客户端证书/etc/kubernetes/pki/apiserver.crt/apiserver.keykube-apiserver 对外提供服务的证书/etc/kubernetes/pki/apiserver-kubelet-client.crtapiserver 访问 kubelet 时使用的客户端证书/etc/kubernetes/pki/front-proxy-ca.crt/front-proxy-ca.key聚合层代理 CA给扩展 API Server 用/etc/kubernetes/pki/front-proxy-client.crt聚合层客户端证书/etc/kubernetes/pki/etcd/ca.crt/ca.keyetcd 集群的根 CA独立于集群根 CA/etc/kubernetes/pki/etcd/server.crtetcd 对外服务端证书/etc/kubernetes/pki/etcd/peer.crtetcd 节点间通信证书/etc/kubernetes/pki/etcd/healthcheck-client.crt健康检查用客户端证书/etc/kubernetes/admin.conf等 kubeconfig内嵌客户端证书用于 kubectl、controller-manager、scheduler 访问 apiserver这里最容易被忽略的是“信任链”问题。apiserver 的证书必须由/etc/kubernetes/pki/ca.crt对应的私钥签发etcd 的证书必须由etcd/ca.crt签发聚合层证书必须由front-proxy-ca.crt签发。手动改证书时如果破坏了这套对应关系组件启动会直接报 x509 错误根本起不来。1.2 为什么默认只签一年kubeadm 生成证书的时候控制平面组件证书有效期默认是 365 天CA 根证书默认是 10 年。看到十年和一年的落差很多人会以为 CA 是“永久”的其实不是CA 的有效期同样受源码里的常量控制只不过 kubeadm 官方认为根 CA 私钥保存得更严格长期风险可控。组件证书只签一年的理由很直白证书轮换机制已经足够成熟短期证书能有效压缩私钥泄露后的影响窗口。如果某个组件的私钥意外泄露最长也就影响一年到期后证书自动失效攻击者手里的私钥就变成废品。从这个角度看一年一签不是设计缺陷而是官方在“安全”和“运维成本”之间做的取舍。真正该做的不是取消轮换而是把轮换流程自动化、可控化。1.3 先分清哪些证书会“卡住”业务集群证书给业务带来的故障通常分两类一类是 apiserver、controller-manager、scheduler、etcd 这些静态证书过期导致组件间通信失败最典型的现象是 kubectl 执行命令报certificate has expired另一类是 kubelet 证书过期表现是节点状态变成 NotReadyPod 调度不上去但 apiserver 本身看起来又是正常的。这两类问题的处理路径完全不同。静态证书主要靠kubeadm certs renew续期kubelet 证书则依赖 controller-manager 的签名参数和 kubelet 自动轮换机制。如果混在一起处理很容易出现“改了 apiserver 证书过了几天节点又 NotReady”的尴尬局面。后面的章节我会把两条线分开讲。2. 证书告警来了先看状态再动手遇到证书过期最忌讳的是直接跑去删掉旧证书、重新生成。所有操作应该从“查看状态”开始先弄清楚哪些证书快到期、哪些证书还健康再做定向处理。2.1 用一条命令看清全部证书状态kubeadm 提供了现成的检查命令在控制平面节点上执行即可kubeadm certs check-expiration输出大致长这样每行对应一个证书文件或 kubeconfig 里内嵌的证书CERTIFICATE EXPIRES RESIDUAL TIME CERTIFICATE AUTHORITY EXTERNALLY MANAGED admin.conf May 05, 2025 15:20 UTC 28d ca.crt no apiserver May 05, 2025 15:20 UTC 28d ca.crt no apiserver-kubelet-client May 05, 2025 15:20 UTC 28d ca.crt no controller-manager.conf May 05, 2025 15:20 UTC 28d ca.crt no etcd/healthcheck-client May 05, 2025 15:20 UTC 28d etcd/ca.crt no etcd/peer May 05, 2025 15:20 UTC 28d etcd/ca.crt no etcd/server May 05, 2025 15:20 UTC 28d etcd/ca.crt no front-proxy-client May 05, 2025 15:20 UTC 28d front-proxy-ca.crt no scheduler.conf May 05, 2025 15:20 UTC 28d ca.crt no重点看RESIDUAL TIME和EXTERNALLY MANAGED两列。EXTERNALLY MANAGED为 yes 的时候说明该证书由外部证书管理器接管kubeadm 不会也不应该动它这时候不能依赖kubeadm certs renew要去找对应的管理平台处理。2.2kubeadm certs renew all的正确操作姿势确认证书快到期之后标准操作是kubeadm certs renew all它会根据当前 kubeadm 内置的默认有效期重新签发所有证书和 kubeconfig。我建议命令执行前先备份这条经验在多次续期事故里都被验证过cp -r /etc/kubernetes/pki /etc/kubernetes/pki.bak.$(date %F) cp /etc/kubernetes/admin.conf /etc/kubernetes/admin.conf.bak.$(date %F) kubeadm certs renew all需要注意renew all只负责把新证书写到磁盘并不会热加载到正在运行的组件进程里。很多人执行完这条命令后立刻看集群状态发现 apiserver 日志还是报证书过期就以为续期没生效其实只是进程还在用旧证书。此时需要触发组件重新加载。最简单的办法是先重启 kubeletsystemctl restart kubelet如果重启后 apiserver、controller-manager、scheduler 等静态 Pod 仍然没有重新读取证书那就用更强制的手段把对应的 manifest 文件移走再移回让 kubelet 感知到变化并重建容器cd /etc/kubernetes/manifests mv kube-apiserver.yaml /tmp/ sleep 5 mv /tmp/kube-apiserver.yaml /etc/kubernetes/manifests/controller-manager、scheduler、etcd 的 manifest 也用同样的方式处理。这么做是因为静态 Pod 的 spec 没有变化时kubelet 未必会重建容器而证书又是以文件挂载进去的进程不重启就永远读不到新证书。2.3 续期后的三个隐藏动作漏一个都会留隐患第一更新你本地 kubectl 使用的 kubeconfig。renew all会重新签发/etc/kubernetes/admin.conf但如果你本机的 kubectl 是从旧 admin.conf 拷贝出来的旧证书已经过期那 kubeconfig 里的客户端证书也过期了。续期之后要把新 admin.conf 拉回本地重新配置。第二高可用集群要逐节点执行不是只跑一台。多个控制平面节点的证书各自独立存储共享同一个 CA但每台机器上的证书文件是自己那份。只在一台节点上 renew其他节点的证书依然是旧的apiserver 最怕这种“集群内部证书不一致”的状态。第三etcd 证书续期后要保证 etcd 进程重新加载。etcd 是静态 Pod处理方式同上mv 掉 manifest 再放回即可。多 etcd 成员的集群不要同时重启所有成员最好一个节点处理完确认 etcd 集群健康再处理下一个避免短时间内 etcd 成员大面积重启造成选举抖动。3. kubelet 证书的年限是另一套规则很多人在做证书续期时把 kubelet 的证书给漏了因为它在kubeadm certs renew all的输出里根本不会出现。原因很简单kubelet 的证书不是 kubeadm 签发的而是 kubelet 自己发起 CSR 请求由 controller-manager 里的 signer 负责签字。3.1 kubelet 证书的存放位置与轮换机制kubelet 的客户端证书和服务端证书放在/var/lib/kubelet/pki目录下。你会看到kubelet-client-current.pem这类名字它其实是一个符号链接真正指向带有时间戳的文件。kubelet 在自动轮换时会生成新文件并更新软链接而不是原地覆盖。这个机制决定了不要手动去修改kubelet-client-current.pem的内容手动覆盖软链接指向的旧文件很容易把轮换状态搞坏。kubelet 也不是等到证书过期才动手而是会在证书剩余时间低于某个阈值时自动发起新的 CSR 申请。只要 controller-manager 正常批准签名kubelet 证书实际上是“自我维持”的不需要管理员每年手工换一次。3.2 通过 cluster-signing-duration 控制 kubelet 证书年限如果确实希望 kubelet 证书的有效期更长控制参数在 kube-controller-manager 上。默认情况下controller-manager 给 CSR 签发的证书有效期是 8760 小时也就是 365 天。修改方式是在/etc/kubernetes/manifests/kube-controller-manager.yaml的启动参数里加一行spec: containers: - name: kube-controller-manager command: - kube-controller-manager - --cluster-signing-duration87600h87600 小时等于十年。改完后重启 kube-controller-manager之后新签发的 kubelet 客户端证书和服务端证书都会变成十年有效。这里有一个容易踩的坑修改参数只对“之后新签发”的证书生效已经签发的旧证书不会因此自动延长。如果你希望立刻生效可以手动删除/var/lib/kubelet/pki下的旧证书文件并重启 kubelet让 kubelet 重新发起 CSR。不过正常情况下没必要这么做kubelet 会按自己的轮换节奏自然过渡到十年期证书。3.3 轮换链路上真正的风险点把 kubelet 证书改成十年之后最容易忽视的是“轮换请求被拒绝”。kubelet 发起 CSR 后默认由 controller-manager 的kubelet-serving和kube-apiserver-client这两个 signer 自动批准。如果集群里有人配置了额外的审批策略或者 signer 被异常关闭kubelet 的 CSR 就会一直卡在 Pending 状态直到旧证书过期节点直接 NotReady。排查的时候用这条命令看 CSR 列表最直接kubectl get csr看到大量 Pending 状态且为kubernetes.io/kube-apiserver-client-kubelet的请求基本就是自动批准链路出了问题。另外如果你把cluster-signing-duration改得非常大还要确认 kubelet 的自动轮换开关是开着的否则证书到期后依然不会自动续期。kubeadm 部署的集群默认开了 rotation但手动搭建的集群不一定。4. 想改十年先搞清两条路线的取舍讲完了应急处理和 kubelet 参数回到最初的问题到底能不能让证书十年一换。答案是可以但必须选对路线。这里我整理了两条主流做法一条是改 kubeadm 源码一条是用外部 CA 体系两者各有代价。4.1 路线一修改 kubeadm 源码重新编译kubeadm 生成证书时有效期写在源码常量里。以常见版本为例文件位置在kubeadm/app/constants/constants.goconst ( CertificateValidityPeriod time.Hour * 24 * 365 CACertificateValidityPeriod time.Hour * 24 * 365 * 10 )第一行控制普通组件证书第二行控制 CA 根证书。把它们改成十年或二十年const ( CertificateValidityPeriod time.Hour * 24 * 365 * 10 CACertificateValidityPeriod time.Hour * 24 * 365 * 10 )然后在 Kubernetes 源码根目录执行make kubeadm编译出的kubeadm二进制替换到所有控制平面节点的/usr/bin/kubeadm。之后不管是kubeadm init新建集群还是对已有集群执行kubeadm certs renew all生成的证书都会按新常量确定有效期。这条路线看起来直接但代价也直接每次 Kubernetes 小版本升级都要重新编译否则新旧 kubeadm 混用会带来证书有效期不一致的问题。如果你所在环境是离线内网、版本升级节奏很慢、并且完全由自己掌控 kubeadm 分发这条路可行。如果集群升级频繁、用了第三方集群安装工具就别碰源码改动了维护成本会超出收益。4.2 路线二用外部 CA 签发长期证书更接近标准做法第二条路线是把证书签发权从 kubeadm 内部 CA 转移到自己的 PKI 体系。具体做法是用 openssl 或 cfssl 生成独立根 CA然后手动签发十年期的组件证书替换掉/etc/kubernetes/pki下的对应文件。以 apiserver 证书为例关键是 SAN 配置不能出错。kubeadm 签发的证书里天生带着 apiserver 需要的 IP 和 DNS 条目手动签发时漏掉任何一个apiserver 启动后客户端访问就会报证书校验失败。一个最小可用的 OpenSSL 配置文件如下[req] distinguished_name dn req_extensions v3_req prompt no [dn] CN kube-apiserver [v3_req] keyUsage keyEncipherment, digitalSignature extendedKeyUsage serverAuth, clientAuth subjectAltName alt_names [alt_names] DNS.1 kubernetes DNS.2 kubernetes.default DNS.3 kubernetes.default.svc DNS.4 kubernetes.default.svc.cluster.local DNS.5 lb.example.internal IP.1 10.96.0.1 IP.2 192.168.100.10IP.1是集群 Service 网段里的第一个地址也就是 apiserver 的 ClusterIPIP.2是控制平面节点的 IP 或负载均衡 VIP。签发命令参考openssl genrsa -out apiserver.key 2048 openssl req -new -key apiserver.key -out apiserver.csr -config apiserver-openssl.cnf openssl x509 -req -in apiserver.csr \ -CA /etc/kubernetes/pki/ca.crt \ -CAkey /etc/kubernetes/pki/ca.key \ -CAcreateserial \ -out apiserver.crt \ -days 3650 \ -extensions v3_req \ -extfile apiserver-openssl.cnf替换好证书后用前面说过的“mv manifest 触发静态 Pod 重建”方式让组件重新加载。4.3 两条路线怎么选我的建议维度改 kubeadm 源码外部 CA新建集群生效每次都要用自编译二进制需要提前配置 PKI 流程已有集群续期重新执行 renew all 即生效要逐证书替换并重启组件升级成本每次版本升级重新编译升级不影响证书体系最大风险二进制不受官方管理私钥泄露影响面大、回退难适合场景离线内网、长期不升级有规范化 PKI 体系的团队我的建议是除非集群数量很少且团队对 kubeadm 源码很熟否则优先考虑外部 CA 路线同时保留 kubelet 证书的自动轮换机制。组件证书改成十年kubelet 证书继续走 CSR 自动轮换这样既减少了人工操作点又不破坏 Kubernetes 原生的证书管理逻辑。5. 证书改完怎么验证以及后续怎么少踩坑证书操作结束后最怕的是静默出错。apiserver 证书明明换了但某个组件因为种种原因还在用旧证书集群表面看起来正常等下一次重启才暴露问题。所以验证这一步不能省。5.1 验证命令从证书文件到组件行为先看文件层确认证书的到期时间和 SAN 是否正确openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -text | grep -A2 Validity openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -text | grep -A10 Subject Alternative Name再用 kubeadm 全局审视一遍kubeadm certs check-expiration如果还有证书显示剩余时间不对说明续期没有完全生效。接着看组件行为apiserver 日志里出现x509: certificate signed by unknown authority或certificate has expired都说明证书链路有问题journalctl -u kubelet -n 200 | grep -i x509 kubectl get nodes kubectl get --raw /healthz最后做一个最直观的业务验证正常执行一次 Pod 的创建和删除流程确认 apiserver、scheduler、kubelet 之间的认证链路是通的。5.2 把证书检查做成巡检任务而不是年底事故见过太多集群是“证书过期前一天才被运维发现”本质上是因为没有人把检查变成例行任务。写一个简单的检查脚本放到控制平面节点的 crontab 里每天跑一次是投入产出比最高的动作。#!/bin/bash # /usr/local/bin/check-cert-expiration.sh for cert in /etc/kubernetes/pki/*.crt /etc/kubernetes/pki/etcd/*.crt; do enddate$(openssl x509 -enddate -noout -in $cert | cut -d -f2) end_ts$(date -d $enddate %s) now_ts$(date %s) remain_days$(( (end_ts - now_ts) / 86400 )) if [ $remain_days -lt 30 ]; then echo 即将到期: $cert 剩余 ${remain_days} 天 fi donecron 里加上执行权限然后定时任务可以这样写0 9 * * * /usr/local/bin/check-cert-expiration.sh /var/log/cert-check.log 215.3 几年踩坑之后我总结的几个原则先说升级窗口kubeadm upgrade默认会顺带执行证书续期如果集群版本要升级尽量把证书续期绑定到升级窗口里一起做省一次割接时间。但千万不要在证书剩余时间已经不足两周时直接升级先kubeadm certs renew all把地基打稳再动版本。再说多控制平面集群每个控制平面节点的证书文件都是独立的不能认为一台机器 renew 成功等于全员成功。操作时一台一台来每台机器做完都要kubeadm certs check-expiration确认再切到下一台。最后是备份习惯。每次证书操作之前把/etc/kubernetes/pki和所有 kubeconfig 打包备份是我个人强烈推荐的动作。证书操作本身不难难的是万一中途改坏了 apiserver 的一个 CN 或 SAN想要凭记忆恢复原状几乎不可能。有一份半小时前的备份至少能把集群拉回可用状态再继续排查。这些习惯看上去琐碎但在真实事故里每一条都帮我少熬过好几个夜。