4. 证书轮换作业(CertificateRotationJob)设计原理:基于 cert-manager 或 kubelet 证书轮换机制
证书轮换作业是保障集群节点身份安全的核心组件。在 Kubernetes 中,节点证书(kubelet 客户端证书)具有有限生命周期,到期前必须完成轮换,否则节点将被 API Server 拒绝准入。本章深入剖析基于 cert-manager 和 kubelet 内置轮换机制 两种主流方案的作业设计原理,并阐述如何通过污点容忍策略控制轮换作业的节点准入行为。
4.1 证书轮换的核心挑战
节点证书轮换面临以下关键问题:
- 证书生命周期管理:默认 kubelet 证书有效期 1 年,需在到期前完成轮换。
- 轮换窗口控制:过早轮换浪费资源,过晚轮换导致节点不可用。
- 节点准入约束:轮换作业应仅在特定节点(如未标记为不可调度)上执行。
- 证书签名请求(CSR)审批:自动或手动审批 CSR 的流程可靠性。
关键指标:证书轮换作业的 SLA 通常要求:轮换成功率 ≥ 99.9%,轮换延迟 ≤ 证书剩余有效期的 10%,且不得因轮换导致节点连续不可用超过 30 秒。
4.2 基于 cert-manager 的证书轮换机制
cert-manager 作为 Kubernetes 原生的证书管理控制器,通过 Certificate 资源对象驱动证书的签发、续期和轮换。其核心流程如下:
- 定义证书资源:创建
CertificateCRD 对象,指定证书名称、密钥名称、签发者(Issuer)、DNS 名称、有效期等参数。 - 证书签发:cert-manager 控制器监听
Certificate资源,调用指定的 Issuer(如自签名、ACME、Vault)签发 X.509 证书。 - 证书存储:签发的证书和私钥以 Kubernetes Secret 形式存储,供 kubelet 或其他组件挂载使用。
- 自动续期:cert-manager 监控证书到期时间,在证书剩余有效期达到配置的
renewBefore阈值时,自动触发重新签发流程。 - 轮换触发:新证书签发后,cert-manager 更新 Secret 中的证书数据,kubelet 通过文件监视或 API 监听感知变化并加载新证书。
关键配置示例:以下是一个 cert-manager Certificate 资源定义,用于 kubelet 节点证书轮换。
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: kubelet-node-cert
namespace: cert-manager
spec:
secretName: kubelet-node-tls
duration: 8760h # 1 年
renewBefore: 720h # 提前 30 天续期
subject:
organizations:
- system:nodes
commonName: system:node:{{ node_name }}
usages:
- client auth
dnsNames:
- "{{ node_name }}"
- "{{ node_name }}.cluster.local"
issuerRef:
name: ca-issuer
kind: ClusterIssuer
4.3 基于 kubelet 内置证书轮换机制
Kubernetes 自 v1.8 起内置了 kubelet 证书轮换功能,无需外部控制器即可自动轮换节点证书。其工作原理如下:
- 启动参数:kubelet 启动时需设置
--rotate-certificates=true和--kubelet-certificate-authority等参数。 - CSR 自动生成:kubelet 在证书到期前自动生成私钥和证书签名请求(CSR),并通过 API Server 提交 CSR 资源。
- CSR 审批:集群管理员或自动审批控制器(如
kube-controller-manager的 CSR 审批循环)批准 CSR。 - 证书分发:审批通过后,kubelet 从 API Server 获取签发的证书,并写入本地文件系统。
- 证书热加载:kubelet 检测到证书文件变化后,重新加载 TLS 配置,无需重启进程。
注意:kubelet 内置轮换机制依赖集群的 CSR 审批策略。若未配置自动审批,管理员需手动批准每个节点的 CSR,在大规模集群中不可行。建议结合
approve-node-csr 控制器或 cert-manager 的 CSR 审批能力。
4.4 两种机制对比分析
| 对比维度 | cert-manager 方案 | kubelet 内置方案 |
|---|---|---|
| 依赖组件 | cert-manager 控制器、Issuer(CA/ACME/Vault) | kube-controller-manager(CSR 审批) |
| 证书存储 | Kubernetes Secret | 节点本地文件系统 |
| 轮换触发 | 基于 renewBefore 时间阈值 |
基于证书到期时间(默认 80% 有效期) |
| CSR 审批 | 支持自动审批(通过 cert-manager 的 approver) | 需外部自动审批或手动审批 |
| 证书格式 | 标准 X.509,支持自定义扩展 | 标准 X.509,受 kubelet 约束 |
| 节点准入控制 | 可通过污点容忍策略控制轮换作业调度 | 节点级轮换,不受调度器控制 |
| 适用场景 | 需要统一证书管理、多签发者、复杂策略的集群 | 简单集群、无需外部 CA 的场景 |
4.5 证书轮换作业的节点准入设计
无论采用哪种机制,证书轮换作业都需要在特定节点上执行。通过污点(Taint)和容忍(Toleration)策略,可以精确控制轮换作业的节点准入行为:
- 节点标记:为需要轮换证书的节点添加特定污点,如
node-role.kubernetes.io/cert-rotation=true:NoSchedule。 - 作业容忍:证书轮换作业(Job 或 CronJob)的 Pod 模板中配置对应的容忍策略,允许其调度到标记节点。
- 轮换窗口:通过
activeDeadlineSeconds和backoffLimit控制轮换作业的执行时间和重试次数。 - 节点状态检查:轮换作业启动前检查节点状态(如
Ready状态、磁盘压力等),避免在异常节点上执行轮换。
作业调度示例:以下是一个证书轮换 Job 的 Pod 模板,配置了节点污点容忍和轮换逻辑。
apiVersion: batch/v1
kind: Job
metadata:
name: cert-rotation-job
namespace: kube-system
spec:
template:
spec:
tolerations:
- key: "node-role.kubernetes.io/cert-rotation"
operator: "Exists"
effect: "NoSchedule"
nodeSelector:
node-role.kubernetes.io/worker: ""
containers:
- name: cert-rotator
image: registry.example.com/cert-rotator:v1.0
command:
- /bin/sh
- -c
- |
# 检查节点证书到期时间
expiry=$(openssl x509 -in /var/lib/kubelet/pki/kubelet-client-current.pem -noout -enddate | cut -d= -f2)
expiry_epoch=$(date -d "$expiry" +%s)
now_epoch=$(date +%s)
remaining=$(( (expiry_epoch - now_epoch) / 86400 ))
if [ $remaining -lt 30 ]; then
echo "证书将在 $remaining 天后到期,触发轮换"
# 触发 cert-manager 续期或 kubelet CSR
kubectl certificate approve $(kubectl get csr | grep node-$(hostname) | awk '{print $1}')
else
echo "证书有效期充足(剩余 $remaining 天),跳过轮换"
fi
volumeMounts:
- name: kubelet-pki
mountPath: /var/lib/kubelet/pki
restartPolicy: Never
volumes:
- name: kubelet-pki
hostPath:
path: /var/lib/kubelet/pki
type: Directory
4.6 证书轮换作业的完整流程
下图展示了基于 cert-manager 的证书轮换作业从触发到完成的完整流程,以及污点容忍策略如何控制作业的节点准入。
4.7 轮换作业的容错与重试策略
证书轮换作业必须设计健壮的容错机制,以应对网络故障、证书签发延迟、节点不可用等异常情况:
| 异常场景 | 处理策略 | 配置参数 |
|---|---|---|
| 证书签发超时 | 设置作业超时时间,超时后自动重试 | activeDeadlineSeconds: 600 |
| CSR 审批失败 | 记录失败原因,等待人工干预或自动重试 | backoffLimit: 3 |
| 节点不可达 | 跳过当前节点,标记为轮换失败,后续重试 | 自定义重试队列 |
| 证书格式错误 | 回滚到旧证书,记录错误日志 | 备份旧证书文件 |
| 并发轮换冲突 | 使用分布式锁或节点级互斥 | 基于 ConfigMap 的锁机制 |
重要提示:证书轮换作业应避免在集群升级、节点维护等操作期间执行。建议通过污点策略将轮换作业与维护窗口隔离,例如在节点添加
node.kubernetes.io/maintenance=true:NoSchedule 污点时,轮换作业的容忍策略不应匹配该污点。
4.8 污点容忍策略与轮换作业的集成设计
将污点容忍策略与证书轮换作业深度集成,可以实现精细化的节点准入控制:
- 轮换窗口污点:在计划轮换的节点上动态添加
cert-rotation.kubernetes.io/window=true:NoSchedule污点,仅允许轮换作业调度。 - 节点角色污点:为不同角色节点(如 control-plane、worker、edge)设置不同污点,轮换作业按角色分批执行。
- 轮换状态污点:轮换完成后自动移除污点,恢复节点正常调度。
- 紧急轮换污点:当证书即将过期(如剩余不足 7 天)时,添加
cert-rotation.kubernetes.io/emergency=true:NoExecute污点,强制立即执行轮换。
最佳实践:建议将证书轮换作业设计为 CronJob,定期扫描集群中所有节点的证书状态,并通过污点容忍策略控制作业的调度范围。以下是一个 CronJob 示例,每 6 小时执行一次证书轮换检查。
apiVersion: batch/v1
kind: CronJob
metadata:
name: cert-rotation-check
namespace: kube-system
spec:
schedule: "0 */6 * * *"
jobTemplate:
spec:
template:
spec:
serviceAccountName: cert-rotation-sa
tolerations:
- key: "cert-rotation.kubernetes.io/window"
operator: "Exists"
effect: "NoSchedule"
containers:
- name: checker
image: registry.example.com/cert-checker:v1.0
command:
- /bin/sh
- -c
- |
# 获取所有节点证书到期时间
for node in $(kubectl get nodes -o name | cut -d/ -f2); do
expiry=$(kubectl get node $node -o jsonpath='{.status.nodeInfo.kubeletVersion}')
# 实际逻辑:检查节点证书文件
echo "检查节点 $node 证书状态"
done
restartPolicy: OnFailure
通过上述设计,证书轮换作业能够安全、可靠地在集群中执行,同时通过污点容忍策略确保作业仅调度到符合条件的节点,避免对集群正常负载造成影响。