4. 证书轮换失败常见原因:CA不可用、Secret权限不足、证书签名请求(CSR)被拒绝、节点时间偏差

Cilium Agent 的 mTLS 证书轮换依赖 Kubernetes 控制面与底层 PKI 基础设施的协同工作。任何一环出现故障,都会导致 Agent 无法获取新证书,进而引发连通性中断。以下是生产环境中最常见的四类根因及其诊断方法。

⚠️ 故障影响范围:证书轮换失败通常不会立即杀死 Agent 进程,但会导致现有 TLS 连接在证书过期后中断,影响范围从单个 Pod 到整个集群的节点间通信。修复优先级应为“高”。

4.1 CA 不可用

证书轮换的第一步是 Agent 向 CA(证书颁发机构)发起签名请求。如果 CA 服务不可达或响应超时,轮换流程将直接阻塞。

常见场景

  • 内部 CA Pod 崩溃或重启:例如 cert-manager 或 cfssl 控制器处于 CrashLoopBackOff 状态。
  • CA 服务网络策略阻断:Agent 所在节点无法通过 ClusterIP 或 NodePort 访问 CA 端点。
  • CA 证书链失效:根证书或中间证书过期,导致新签发的证书无法被信任。

诊断命令

# 检查 CA 服务 Pod 状态
kubectl get pods -n cilium-system -l k8s-app=ca-service

# 测试 CA 端点连通性(从 Agent 节点执行)
curl -v --connect-timeout 5 https://ca-service.cilium-system.svc.cluster.local:443/healthz

# 查看 Agent 日志中的 CA 连接错误
kubectl logs -n cilium-system -l k8s-app=cilium-agent --tail=50 | grep -i "ca\|certificate\|tls"
🔍 关键指标:如果 curl 返回 Connection refused 或 Timeout,且 CA Pod 日志无异常,优先检查 NetworkPolicy 和 Service Endpoint 是否正常。
CA 不可用故障链路图 CA 不可用故障链路 Cilium Agent CSR 请求 CA 服务 ❌ 不可用/超时 诊断要点: • 检查 CA Pod 状态:kubectl get pods -n <namespace> -l app=ca • 测试 CA 端点:curl -v https://ca-service:443/healthz

4.2 Secret 权限不足

Cilium Agent 在轮换证书时,需要将新证书写入 Kubernetes Secret 对象。如果 Agent 使用的 ServiceAccount 缺少对 Secret 的 get、update 或 patch 权限,轮换将失败。

权限模型对比

资源 所需操作 常见 RBAC 缺失 典型错误日志
secrets get, update, patch 缺少 update 或 patch Forbidden: user "system:serviceaccount:cilium-system:cilium-agent" cannot update resource "secrets"
secrets (跨命名空间) get, update ClusterRole 未绑定到目标命名空间 secrets "cilium-ca" is forbidden: User cannot get resource "secrets" in API group ""

修复步骤

  1. 确认 Agent 使用的 ServiceAccount:
    kubectl get pods -n cilium-system -l k8s-app=cilium-agent -o jsonpath='{.items[0].spec.serviceAccount}'
  2. 检查当前 RBAC 绑定:
    kubectl describe clusterrolebinding cilium-agent
    kubectl describe rolebinding -n cilium-system cilium-agent
  3. 补充缺失权限(示例):
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: cilium-agent-secret
    rules:
    - apiGroups: [""]
      resources: ["secrets"]
      verbs: ["get", "list", "watch", "update", "patch"]
💡 最佳实践:避免使用 * 通配权限。明确列出 get、update、patch 三个动词,并限制到 cilium-system 命名空间内的 Secret 资源。

4.3 证书签名请求(CSR)被拒绝

当 Agent 提交 CSR 到 Kubernetes 内置的 certificates.k8s.io API 时,集群的 CSR 审批控制器可能因策略原因拒绝请求。

拒绝原因分类

  • 签名者名称不匹配:CSR 中 spec.signerName 与集群配置的 signer 不一致(例如使用 kubernetes.io/kubelet-serving 而非 cilium.io/agent)。
  • 请求的密钥用途违规:CSR 中包含了 digital signature 但缺少 client auth 或 server auth。
  • Subject 字段格式错误:Common Name (CN) 或 Organization (O) 不符合集群准入策略。
  • 自动审批控制器未配置:集群缺少自动批准 Cilium CSR 的 ClusterRoleBinding 或 CertificateSigningRequest 审批规则。

诊断与修复

# 查看所有 CSR 及其状态
kubectl get csr --all-namespaces

# 查看被拒绝的 CSR 详情
kubectl describe csr cilium-agent-xxxxx

# 手动批准(临时修复)
kubectl certificate approve cilium-agent-xxxxx

# 配置自动审批(推荐)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: cilium-csr-approver
rules:
- apiGroups: ["certificates.k8s.io"]
  resources: ["certificatesigningrequests"]
  verbs: ["get", "list", "watch", "update"]
- apiGroups: ["certificates.k8s.io"]
  resources: ["certificatesigningrequests/approval"]
  verbs: ["update"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: cilium-csr-approver
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cilium-csr-approver
subjects:
- kind: ServiceAccount
  name: cilium-operator
  namespace: cilium-system
🔍 关键检查点:CSR 被拒绝时,kubectl describe csr 的 Status.Conditions 字段会显示 Reason: "Kubernetes API SignerName check" 或 Reason: "Requested key usages not allowed"。根据具体原因调整 CSR 模板。

4.4 节点时间偏差

证书轮换依赖时间戳验证:新证书的 notBefore 和 notAfter 字段基于 CA 的系统时间生成。如果 Agent 所在节点与 CA 之间的时间偏差超过证书有效期窗口(通常为 5 分钟),会导致以下问题:

  • 证书立即过期:节点时间快于 CA 时间,新证书的 notBefore 在未来,Agent 认为证书尚未生效。
  • 验证失败:节点时间慢于 CA 时间,证书的 notAfter 已过,Agent 拒绝加载。
  • CSR 签名时间戳无效:CA 拒绝签名请求,因为请求中的时间戳与 CA 时间偏差过大。

时间偏差检测与修复

检测方法 命令/工具 正常阈值 修复措施
节点与 CA Pod 时间对比 date vs kubectl exec ca-pod -- date < 30 秒 配置 NTP 服务(chrony/ntpd)
证书时间戳验证 openssl x509 -in cert.pem -noout -dates notBefore < now < notAfter 同步节点时间后重新轮换
Agent 日志时间戳异常 kubectl logs ... | grep -i "certificate.*expired\|time.*skew" 无此类日志 检查节点时区配置
节点时间偏差影响证书轮换 节点时间偏差导致证书轮换失败 T0 T1 (CA 签发) T2 (节点接收) CA 时间: T1 节点时间: T1+5m 偏差 > 5min 影响: • 节点时间快于 CA → 证书 notBefore 在未来 → Agent 拒绝加载 • 节点时间慢于 CA → 证书 notAfter 已过 → 验证失败

4.5 综合排查流程

当证书轮换失败时,建议按以下顺序排查:

  1. 检查 Agent 日志:kubectl logs -n cilium-system -l k8s-app=cilium-agent | grep -i "cert\|tls\|csr\|secret"
  2. 验证 CA 可用性:从 Agent 节点 curl CA 健康端点。
  3. 检查 Secret 权限:使用 kubectl auth can-i 模拟 Agent 的 ServiceAccount 操作。
  4. 查看 CSR 状态:kubectl get csr | grep cilium,确认是否有 Pending 或 Denied 状态。
  5. 对比节点与 CA 时间:执行 date 和 kubectl exec ca-pod -- date,确保偏差 < 30 秒。
⚠️ 生产环境建议:在集群中部署 NTP 监控告警(如 Prometheus + node_time_seconds 指标),并配置自动 CSR 审批控制器,从源头减少时间偏差和权限问题导致的轮换失败。