别再手动传证书了!K8s里用cert-manager自动管理TLS证书的保姆级教程
告别手动证书管理:cert-manager在Kubernetes中的全自动TLS实践
凌晨三点,服务突然中断——原因竟是证书过期。这种场景对Kubernetes运维团队来说再熟悉不过。传统手动管理证书的方式不仅耗时耗力,还隐藏着巨大的运维风险。本文将带你用cert-manager构建自动化证书管理体系,让TLS证书的申请、续期和部署实现全生命周期无人值守。
1. 为什么需要自动化证书管理?
手动管理TLS证书就像用算盘处理现代金融交易——理论上可行,但效率与风险完全不成正比。当集群规模超过10个服务时,管理员需要跟踪数十个证书的过期时间,手动执行重复的签发流程。更危险的是,90%的证书相关事故都源于人为疏忽导致的过期未更新。
cert-manager作为Kubernetes原生的证书管理工具,通过与Let's Encrypt等CA的集成,实现了:
- 自动续期:在证书到期前自动申请新证书
- 集中配置:通过CRD统一管理所有证书策略
- 无缝集成:自动将证书注入Ingress和Pod
- 多CA支持:同时对接Let's Encrypt、Venafi等不同CA
# 手动管理证书的典型生命周期 openssl req -new -newkey rsa:2048 -nodes -keyout tls.key -out tls.csr kubectl create secret tls my-cert --cert=tls.crt --key=tls.key # 然后每月检查一次过期时间...2. 搭建cert-manager基础环境
2.1 安装cert-manager
cert-manager的安装需要三个核心组件:
- CustomResourceDefinitions:扩展Kubernetes API
- Controller:证书生命周期管理核心
- Webhook:验证和修改资源配置
使用官方提供的manifest一键安装最新稳定版:
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.11.0/cert-manager.yaml验证安装成功的三个关键点:
- 所有pod处于Running状态
- 出现cert-manager开头的CRD资源
- 能够创建ClusterIssuer资源
注意:生产环境建议使用helm进行安装,便于后续升级和配置管理
2.2 配置Let's Encrypt ClusterIssuer
Let's Encrypt提供两种验证方式:
- HTTP-01:通过域名解析验证
- DNS-01:通过DNS记录验证(支持通配符)
以下是配置DNS验证的ClusterIssuer示例(以Cloudflare为例):
apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-prod spec: acme: server: https://acme-v02.api.letsencrypt.org/directory email: admin@example.com privateKeySecretRef: name: letsencrypt-prod-account-key solvers: - dns01: cloudflare: apiTokenSecretRef: name: cloudflare-api-token key: token关键参数说明:
| 参数 | 说明 | 生产环境建议值 |
|---|---|---|
| server | ACME服务器地址 | 生产用v02而非staging |
| 紧急通知邮箱 | 公司运维专用邮箱 | |
| privateKeySecretRef | 账户密钥存储位置 | 使用kms加密的secret |
3. 证书签发实战场景
3.1 为Ingress自动配置证书
传统方式需要手动创建secret然后配置Ingress,cert-manager只需一个annotation即可自动完成:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: web-app annotations: cert-manager.io/cluster-issuer: "letsencrypt-prod" spec: tls: - hosts: - app.example.com secretName: app-tls-cert rules: - host: app.example.com http: paths: - path: / pathType: Prefix backend: service: name: web-app port: number: 80证书状态验证命令:
kubectl get certificate kubectl describe certificate app-tls-cert3.2 为工作负载直接签发证书
某些场景下服务不通过Ingress暴露,但仍需要TLS加密。cert-manager可以通过Certificate资源直接管理:
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: grpc-server-cert spec: secretName: grpc-tls duration: 2160h # 90天 renewBefore: 720h # 到期前30天续期 commonName: grpc.internal dnsNames: - grpc.internal - grpc.prod.svc.cluster.local issuerRef: name: letsencrypt-prod kind: ClusterIssuer证书将自动注入到指定secret中,Pod可以直接挂载使用:
containers: - name: grpc-server volumeMounts: - name: tls mountPath: /etc/tls volumes: - name: tls secret: secretName: grpc-tls4. 高级配置与故障排查
4.1 多CA策略配置
生产环境通常需要混合使用不同CA,cert-manager支持基于注解的签发策略选择:
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: mixed-ca-cert annotations: cert-manager.io/issuer-selector: "ca-type in (internal, letsencrypt)" spec: secretName: mixed-ca-tls issuerRef: name: ca-pool kind: ClusterIssuer --- apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: ca-pool spec: issuerGroups: - name: internal issuers: - name: vault-issuer kind: Issuer - name: letsencrypt issuers: - name: letsencrypt-prod kind: ClusterIssuer4.2 常见问题排查指南
当证书签发失败时,按以下步骤排查:
检查Issuer状态:
kubectl describe clusterissuer letsencrypt-prod查看CertificateRequest:
kubectl get certificaterequest kubectl describe certificaterequest <name>检查Order资源(ACME专用):
kubectl get order kubectl describe order <name>查看Pod日志:
kubectl logs -n cert-manager -l app.kubernetes.io/instance=cert-manager
典型错误场景处理:
| 错误现象 | 可能原因 | 解决方案 |
|---|---|---|
| CertificateRequest pending | CA服务器不可达 | 检查网络策略和出口规则 |
| Invalid domain | DNS配置错误 | 验证域名解析和DNS策略 |
| Rate limit exceeded | Let's Encrypt限制 | 切换临时使用staging环境 |
5. 生产环境最佳实践
5.1 证书监控与告警
虽然cert-manager会自动续期,但仍需建立监控体系:
apiVersion: monitoring.coreos.com/v1 kind: PrometheusRule metadata: name: cert-manager-alerts spec: groups: - name: cert-manager rules: - alert: CertificateExpiringSoon expr: certmanager_certificate_expiration_timestamp_seconds - time() < 86400 * 30 for: 5m labels: severity: warning annotations: summary: "Certificate will expire soon (instance {{ $labels.instance }})" description: "Certificate {{ $labels.name }} expires in {{ humanizeDuration (($value - time())) }}"5.2 安全加固措施
私钥保护:
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: secured-cert spec: privateKey: rotationPolicy: Always algorithm: RSA size: 4096网络策略限制:
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: cert-manager-egress spec: podSelector: matchLabels: app.kubernetes.io/instance: cert-manager egress: - to: - ipBlock: cidr: 0.0.0.0/0 except: - 192.168.0.0/16 ports: - protocol: TCP port: 443备份策略:
# 备份关键Issuer配置 kubectl get clusterissuer -o yaml > clusterissuers-backup.yaml # 备份所有证书私钥 kubectl get secret -l cert-manager.io/certificate-name -o yaml > certificates-backup.yaml
在万级规模集群中运行cert-manager两年后,我们总结出三点核心经验:第一,一定要为DNS验证配置专用服务账号,避免使用全局API密钥;第二,定期轮换ACME账户私钥,建议每半年一次;第三,开发环境使用staging端点时,要注意其证书不受主流浏览器信任的特性。
