4. 证书轮换机制:TLS证书生命周期、K8s Secret管理证书、cert-manager与自动轮换流程

在Kubernetes集群中,TLS证书是保障服务间通信与外部域名解析安全的核心组件。证书轮换机制失效,会导致客户端(如CoreDNS、Ingress Controller)使用过期证书发起TLS握手,进而引发外部域名解析失败。本节深入剖析证书生命周期、K8s Secret管理方式以及cert-manager的自动轮换流程。

4.1 TLS证书生命周期

TLS证书从签发到销毁经历四个关键阶段,每个阶段都可能成为故障点:

阶段 描述 常见故障
签发 CA(证书颁发机构)根据CSR生成证书,包含公钥、有效期、SAN(Subject Alternative Name)等字段。 SAN缺失导致域名不匹配;有效期设置过短或过长。
分发 证书以Secret形式注入Pod或Ingress Controller。 Secret未及时更新;Pod未挂载最新Secret。
使用 服务端在TLS握手时提供证书,客户端验证证书链与有效期。 证书过期;中间证书缺失;客户端时钟偏差。
轮换 在证书过期前生成新证书并替换旧证书。 轮换失败导致服务中断;新旧证书交替期混乱。
关键指标:证书剩余有效期(Days Left)是SRE必须监控的指标。建议在证书到期前30天、7天、1天分别设置告警。

4.2 Kubernetes Secret管理证书

Kubernetes使用tls类型的Secret存储TLS证书与私钥。Secret的更新机制直接影响证书轮换的生效速度。

4.2.1 Secret结构

apiVersion: v1
kind: Secret
metadata:
  name: example-tls
  namespace: default
type: kubernetes.io/tls
data:
  tls.crt: <base64-encoded-cert>
  tls.key: <base64-encoded-key>

4.2.2 Secret更新与Pod热加载

Pod通过以下方式引用Secret:

  • 环境变量:Secret更新后,环境变量不会自动刷新,必须重启Pod。
  • Volume挂载:Secret更新后,挂载的文件会自动更新(默认同步周期约60秒),但应用进程需要监听文件变化并重新加载证书。
排错陷阱:许多应用(如Nginx、Envoy)默认不监听证书文件变化。即使Secret已更新,Pod仍使用旧证书,导致TLS握手失败。必须配置证书热加载或手动重启Pod。

4.3 cert-manager与自动轮换流程

cert-manager是Kubernetes上最流行的证书管理工具,它通过自定义资源(CRD)实现证书的自动签发与轮换。

4.3.1 核心组件

组件 作用
Issuer / ClusterIssuer 定义证书颁发来源(如Let's Encrypt、自建CA、Vault)。
Certificate 声明需要管理的证书,指定域名、Secret名称、Issuer引用。
Order / Challenge 处理ACME协议中的订单与挑战(HTTP-01、DNS-01)。
Secret cert-manager将签发的证书写入指定的K8s Secret。

4.3.2 自动轮换流程

cert-manager在证书剩余有效期30天时触发轮换(可通过renewBefore字段调整)。完整流程如下:

  1. 监控:cert-manager控制器定期检查Certificate资源中证书的剩余有效期。
  2. 触发:当剩余有效期小于renewBefore(默认30天)时,启动轮换。
  3. 签发:向Issuer发起新证书签发请求,生成新的密钥对与CSR。
  4. 存储:将新证书与私钥写入目标Secret,更新tls.crt和tls.key。
  5. 通知:cert-manager不负责重启Pod,但可通过Reloader、Keel等工具监听Secret变化并触发Pod滚动更新。
最佳实践:结合stakater/Reloader或kubewatch,在Secret更新后自动滚动更新Deployment/StatefulSet,确保Pod立即加载新证书。

4.4 证书轮换与外部域名解析的关联

当集群内组件(如CoreDNS、Ingress Controller)使用证书与外部服务通信时,证书轮换失败会导致:

  • TLS握手失败:客户端拒绝过期证书,连接中断。
  • DNS查询被拦截:部分外部DNS服务器要求TLS认证,证书过期后查询被拒绝。
  • 证书链不完整:轮换后未包含中间证书,客户端无法构建完整信任链。

下图展示了cert-manager自动轮换证书并更新Secret,最终影响Pod证书加载的完整链路:

cert-manager 自动轮换流程与证书加载链路 cert-manager 监控Certificate资源 Issuer / ClusterIssuer Let's Encrypt / 自建CA 签发新证书 生成密钥对 + CSR K8s Secret tls.crt / tls.key Pod (应用) Volume挂载 / 热加载 外部服务 TLS握手验证 ⚠ 常见故障点 1. Secret更新后Pod未重载证书 2. 轮换触发时间过晚导致证书过期

4.5 证书轮换配置示例

以下是一个完整的Certificate资源定义,展示如何配置自动轮换:

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: example-cert
  namespace: default
spec:
  secretName: example-tls
  duration: 2160h   # 90天
  renewBefore: 720h # 30天前开始轮换
  subject:
    organizations:
      - Example Corp
  commonName: api.example.com
  dnsNames:
    - api.example.com
    - *.api.example.com
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
排错建议:使用kubectl describe certificate example-cert查看证书状态与轮换历史。若轮换失败,检查Issuer配置、网络连通性及ACME挑战日志。

4.6 证书轮换故障排查清单

检查项 命令/方法 预期结果
证书剩余有效期 openssl x509 -in tls.crt -noout -enddate 剩余时间 > renewBefore
Secret内容 kubectl get secret example-tls -o yaml tls.crt与tls.key为最新base64值
Pod挂载状态 kubectl exec pod -- cat /etc/ssl/certs/tls.crt 与Secret内容一致
cert-manager日志 kubectl logs -n cert-manager deploy/cert-manager 无轮换失败错误
应用热加载配置 检查应用配置(如Nginx的ssl_certificate) 支持文件变化重载