Kubernetes中cert-manager实现ACME自动化证书管理实战

Kubernetes中cert-manager实现ACME自动化证书管理实战

1. 项目概述

在Kubernetes集群中管理TLS证书一直是个让人头疼的问题。传统方式需要手动申请、更新证书,既繁琐又容易出错。cert-manager作为Kubernetes原生的证书管理工具,通过ACME协议实现了证书全生命周期的自动化管理。我在生产环境中使用cert-manager已有三年多,它彻底改变了我们团队处理证书的方式。

cert-manager的核心价值在于将证书申请、续期、轮换等操作转化为声明式的Kubernetes资源。配合Let's Encrypt等ACME服务提供商,可以实现零人工干预的证书管理。本文将深入解析cert-manager的ACME方案实现原理,并分享我在企业级Kubernetes集群中的实战经验。

2. ACME协议与cert-manager架构解析

2.1 ACME协议工作原理

ACME(Automated Certificate Management Environment)是由Let's Encrypt提出的自动化证书管理协议。其核心流程包括:

  1. 账户注册:客户端向ACME服务器注册账户
  2. 域名验证:通过HTTP-01或DNS-01等方式验证域名所有权
  3. 证书签发:验证通过后获取签名证书
  4. 自动续期:在证书到期前自动完成续期

ACME v2版本支持通配符证书,这对Kubernetes Ingress特别有用。我建议优先使用DNS-01验证方式,因为它:

  • 不需要暴露HTTP服务
  • 支持通配符证书
  • 验证过程更可靠

2.2 cert-manager组件架构

cert-manager由以下几个核心组件构成:

组件职责生产环境建议
Issuer/ClusterIssuer定义证书签发者使用ClusterIssuer全局共享
Certificate声明需要的证书为每个域名创建独立资源
Challenge Controller处理ACME挑战监控挑战状态
Order Controller管理证书申请流程关注Order资源状态

在企业环境中,我通常这样部署:

# 使用helm安装cert-manager helm upgrade --install cert-manager jetstack/cert-manager \ --namespace cert-manager \ --create-namespace \ --version v1.11.0 \ --set installCRDs=true

注意:生产环境务必指定稳定版本,避免使用latest标签

3. 企业级ACME方案实现

3.1 DNS-01验证配置实战

DNS-01是目前最可靠的验证方式,特别适合企业环境。以阿里云DNS为例:

  1. 创建ClusterIssuer:
apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-prod spec: acme: server: https://acme-v02.api.letsencrypt.org/directory email: ssl-admin@example.com privateKeySecretRef: name: letsencrypt-prod-account-key solvers: - dns01: aliDNS: accessKeySecretRef: name: alidns-secret key: access-key secretKeySecretRef: name: alidns-secret key: secret-key
  1. 创建DNS API密钥Secret:
kubectl create secret generic alidns-secret \ --namespace cert-manager \ --from-literal=access-key='your-ak' \ --from-literal=secret-key='your-sk'

我在实践中发现几个关键点:

  • 不同云厂商的DNS配置差异较大,需要参考官方文档
  • 密钥需要最小化权限,只授予DNS解析记录修改权限
  • 建议为生产环境和测试环境创建不同的ClusterIssuer

3.2 通配符证书最佳实践

通配符证书可以简化Ingress配置,特别适合多子域名场景:

apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: wildcard-example-com namespace: production spec: secretName: wildcard-example-com-tls issuerRef: name: letsencrypt-prod kind: ClusterIssuer dnsNames: - "*.example.com" - example.com # 包含根域名

经验:虽然通配符证书很方便,但安全团队可能要求关键子域名使用独立证书。需要平衡便利性和安全要求。

4. 生产环境问题排查指南

4.1 常见问题与解决方案

问题现象可能原因解决方案
证书申请卡在pending状态ACME挑战失败检查Challenge资源事件
证书续期失败私钥轮换问题删除旧的CertificateRequest
DNS验证超时API速率限制添加--dns01-recursive-nameservers参数
证书不被信任中间证书缺失确保chain包含完整证书链

4.2 监控与告警配置

完善的监控是生产环境必备项。建议配置:

  1. Prometheus监控指标:
- alert: CertificateExpiringSoon expr: certmanager_certificate_expiration_timestamp_seconds - time() < 86400 * 30 for: 5m labels: severity: warning annotations: summary: "Certificate expiring soon (instance {{ $labels.instance }})" description: "Certificate {{ $labels.name }} will expire in 30 days"
  1. 定期检查证书状态:
# 检查所有命名空间的证书状态 kubectl get certificates --all-namespaces -o wide # 查看具体证书详情 kubectl describe certificate my-cert -n my-ns

5. 高级配置与性能优化

5.1 多ACME账户配置

对于大型集群,建议配置多个ACME账户以避免速率限制:

apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-prod-2 spec: acme: server: https://acme-v02.api.letsencrypt.org/directory email: ssl-admin-2@example.com privateKeySecretRef: name: letsencrypt-prod-account-key-2 solvers: - selector: dnsZones: - "example.com" dns01: cloudflare: apiTokenSecretRef: name: cloudflare-api-token-secret key: api-token

5.2 证书缓存与性能调优

在大规模集群中,cert-manager可能成为性能瓶颈。优化建议:

  1. 调整控制器并发度:
# values.yaml controller: replicas: 3 resources: requests: cpu: 100m memory: 128Mi limits: cpu: 500m memory: 512Mi
  1. 启用证书缓存:
helm upgrade cert-manager jetstack/cert-manager \ --set extraArgs={--enable-certificate-owner-ref=false}
  1. 使用外部证书存储:
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: my-cert spec: secretTemplate: annotations: vault.security.banzaicloud.io/vault-addr: "https://vault:8200"

6. 安全加固与合规实践

6.1 密钥管理最佳实践

  1. 使用KMS加密Secret:
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: my-cert spec: secretTemplate: annotations: kms.vaultproject.io/encrypt: "true"
  1. 定期轮换ACME账户密钥:
# 删除旧密钥Secret kubectl delete secret letsencrypt-prod-account-key -n cert-manager # cert-manager会自动创建新密钥

6.2 合规性检查

  1. 证书必须符合企业安全策略:
apiVersion: policy/v1 kind: ClusterPolicy metadata: name: cert-policy spec: rules: - apiGroups: ["cert-manager.io"] resources: ["certificates"] validate: message: "Certificates must have at least 2048-bit RSA key" pattern: spec: privateKey: algorithm: RSA size: 2048
  1. 禁用不安全的加密算法:
apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-prod spec: acme: server: https://acme-v02.api.letsencrypt.org/directory preferredChain: "ISRG Root X1"

在金融行业项目中,我们还需要额外配置:

  • 证书必须记录到审计日志
  • 私钥必须使用HSM保护
  • 证书有效期不超过90天

7. 与其他工具的集成

7.1 与Istio的集成

在Service Mesh环境中,cert-manager可以为Istio提供证书:

  1. 配置Istio使用cert-manager:
apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: istio-gateway spec: selector: istio: ingressgateway servers: - port: number: 443 name: https protocol: HTTPS tls: mode: SIMPLE credentialName: istio-ingressgateway-certs hosts: - "*.example.com"
  1. 创建对应的Certificate:
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: istio-ingress namespace: istio-system spec: secretName: istio-ingressgateway-certs issuerRef: name: letsencrypt-prod kind: ClusterIssuer dnsNames: - "*.example.com"

7.2 与ExternalDNS的协同

结合ExternalDNS可以实现完整的DNS自动化:

apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: example-com spec: secretName: example-com-tls issuerRef: name: letsencrypt-prod kind: ClusterIssuer dnsNames: - "app.example.com" - "api.example.com" --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: app-ingress annotations: cert-manager.io/cluster-issuer: "letsencrypt-prod" external-dns.alpha.kubernetes.io/hostname: "app.example.com" spec: tls: - hosts: - app.example.com secretName: example-com-tls rules: - host: app.example.com http: paths: - path: / pathType: Prefix backend: service: name: app-service port: number: 80

这种组合可以实现:

  1. 自动创建DNS记录
  2. 自动申请证书
  3. 自动配置Ingress TLS 整个过程完全自动化,无需人工干预

8. 灾备与迁移方案

8.1 备份与恢复策略

  1. 备份关键资源:
# 备份所有Certificate定义 kubectl get certificates --all-namespaces -o yaml > certificates-backup.yaml # 备份所有Issuer/ClusterIssuer kubectl get issuers,clusterissuers --all-namespaces -o yaml > issuers-backup.yaml
  1. 恢复步骤:
# 首先恢复Issuer定义 kubectl apply -f issuers-backup.yaml # 然后恢复Certificate kubectl apply -f certificates-backup.yaml

重要提示:私钥Secret默认不会被备份,需要单独处理。建议使用外部密钥管理系统。

8.2 跨集群迁移方案

在多集群环境中,我推荐以下迁移策略:

  1. 在主集群中创建Certificate资源
  2. 将生成的Secret同步到其他集群:
# 使用kubectl同步Secret kubectl get secret example-com-tls -n app -o yaml \ | kubectl apply --context=cluster-2 -n app -f -
  1. 在其他集群中创建相同的Certificate资源(不指定issuerRef):
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: example-com namespace: app spec: secretName: example-com-tls dnsNames: - "example.com"

这样设计的好处是:

  • 主集群负责证书申请和续期
  • 其他集群只使用证书副本
  • 避免多个集群同时申请相同证书导致ACME速率限制

9. 版本升级与兼容性

9.1 cert-manager版本升级

cert-manager的版本升级需要特别注意CRD兼容性。我的升级流程:

  1. 检查当前版本:
kubectl get deployment cert-manager -n cert-manager -o jsonpath='{.spec.template.spec.containers[0].image}'
  1. 备份现有CRD:
kubectl get crd | grep cert-manager | awk '{print $1}' | xargs -I {} kubectl get crd {} -o yaml > crd-backup.yaml
  1. 执行升级:
helm upgrade cert-manager jetstack/cert-manager \ --namespace cert-manager \ --version v1.11.0 \ --set installCRDs=true

升级后常见问题:旧版CRD可能不兼容新版控制器。遇到问题时可以回退版本或手动迁移CRD。

9.2 Kubernetes版本兼容性

cert-manager与Kubernetes版本的兼容矩阵:

cert-manager版本支持的Kubernetes版本
v1.11.x1.22-1.27
v1.10.x1.21-1.26
v1.9.x1.20-1.25

在升级Kubernetes集群前,务必检查cert-manager的兼容性。我曾经遇到过Kubernetes 1.25升级后webhook无法工作的问题,最终发现是cert-manager版本过旧导致的。

10. 成本控制与优化

10.1 Let's Encrypt速率限制管理

Let's Encrypt有以下重要限制:

  • 每个注册域名每周最多签发50张证书
  • 每个账户每小时最多创建5个新订单
  • 重复验证失败会触发临时封禁

我的优化策略:

  1. 尽可能使用通配符证书减少证书数量
  2. 为不同环境配置不同的ACME账户
  3. 使用证书缓存减少重复申请

10.2 私有ACME服务方案

对于大型企业,可以考虑部署私有ACME服务:

  1. 使用小型step-ca搭建私有CA:
docker run -it --rm -v $(pwd):/home/step \ -e "DOCKER_STEPCA_INIT_NAME=My CA" \ -e "DOCKER_STEPCA_INIT_DNS=ca.example.com" \ smallstep/step-ca step-ca init
  1. 配置cert-manager使用私有ACME:
apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: private-ca spec: acme: server: https://ca.example.com/acme/acme/directory email: ca-admin@example.com privateKeySecretRef: name: private-ca-account-key solvers: - http01: ingress: class: nginx

私有ACME服务的优势:

  • 不受公共CA速率限制
  • 可以自定义证书有效期
  • 适合内部服务使用

11. 企业级部署参考架构

基于多个金融行业项目的经验,我总结的企业级架构:

  1. 网络拓扑

    • 在DMZ区部署专用的cert-manager实例
    • 内部服务使用私有CA签发证书
    • 对外服务使用公共CA
  2. 高可用设计

    • cert-manager部署3个副本
    • 使用Pod反亲和性分布在不同节点
    • 配置HPA自动扩缩容
  3. 安全设计

    • 使用NetworkPolicy限制访问
    • 为不同团队划分命名空间
    • 通过RBAC严格控制访问权限
  4. 监控体系

    • Prometheus监控证书到期时间
    • 日志集中收集分析
    • 关键操作审计日志

示例部署架构图:

+-----------------------+ | Internet | +----------+------------+ | +----------v------------+ | Load Balancer | | (TLS Termination) | +----------+------------+ | +----------v------------+ | Ingress Controller | | (Nginx/ALB) | +----------+------------+ | +----------v------------+ | cert-manager | | (3 Replicas) | +----------+------------+ | +----------v------------+ | Kubernetes API | +----------+------------+ | +----------v------------+ | Vault/HSM | | (Private Key Storage)| +----------------------+

12. 新兴趋势与未来展望

虽然cert-manager目前是Kubernetes证书管理的事实标准,但技术生态仍在演进:

  1. SPIFFE/SPIRE集成: 服务身份认证的新范式,可能改变证书使用方式。cert-manager已开始支持SPIFFE格式的证书。

  2. 证书透明度日志(CT)增强: 越来越多的浏览器要求证书必须记录在CT日志中。cert-manager可以配置自动提交CT日志。

  3. 量子安全加密算法: 随着量子计算发展,传统RSA算法可能被淘汰。cert-manager已经开始支持后量子加密算法。

  4. 多CA自动切换: 智能CA选择功能,可以根据策略自动选择最优CA提供商。

  5. eBPF加速: 使用eBPF优化证书验证和加解密性能,特别是对Service Mesh场景。

在实际项目中,我建议保持对cert-manager新特性的关注,但生产环境应采用经过验证的稳定版本。每次升级前在测试环境充分验证,避免引入不稳定性。