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字段调整)。完整流程如下:
- 监控:cert-manager控制器定期检查Certificate资源中证书的剩余有效期。
- 触发:当剩余有效期小于
renewBefore(默认30天)时,启动轮换。 - 签发:向Issuer发起新证书签发请求,生成新的密钥对与CSR。
- 存储:将新证书与私钥写入目标Secret,更新
tls.crt和tls.key。 - 通知: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证书加载的完整链路:
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) | 支持文件变化重载 |