Kubernetes 证书管理终极指南:深入解析 cert-manager 的架构与实战

文章目录
1. 引言:云原生时代的信任基石
在零信任(Zero Trust)安全模型和 HTTPS 全面普及的今天,TLS 证书的管理已成为基础设施运维中不可忽视的一环。手动申请、部署和轮换证书不仅效率低下,更是导致服务中断(因证书过期)的常见原因。
cert-manager 是 Kubernetes 生态中事实上的标准证书管理控制器。它不仅是一个从 Let’s Encrypt、HashiCorp Vault、Venafi 或私有 PKI 获取证书的工具,更是一套基于 CRD(自定义资源定义)的声明式证书自动化编排系统。
本文将深入剖析 cert-manager 的工作原理,并展示其在复杂生产场景下的应用。
2. 核心架构与工作原理
cert-manager 遵循 Kubernetes 的控制器模式(Controller Pattern)。它引入了一组 CRD 来描述证书的生命周期。理解这些资源对象是掌握 cert-manager 的关键。
2.1 核心 CRD 资源关系图谱
- Issuer / ClusterIssuer: 定义证书颁发机构(CA)。Issuer: 命名空间(Namespace)隔离,只能为同 namespace 下的资源签发。ClusterIssuer: 全局资源,可服务于所有 namespace。
- Certificate: 定义用户期望的证书状态(域名、有效期、密钥算法等)。这是用户主要交互的资源。
- CertificateRequest: 类似于传统的 CSR(证书签名请求)。cert-manager 根据 Certificate 自动生成此资源,向 Issuer 申请签名。
- Order & Challenge (仅 ACME): 当使用 ACME 协议(如 Let’s Encrypt)时,cert-manager 会创建 Order 资源来追踪订单,并创建 Challenge 资源来处理域名所有权验证(HTTP-01 或 DNS-01)。
- Secret: 最终存储 TLS 私钥和证书的 Kubernetes 原生资源,供 Ingress 或 Pod 挂载使用。
2.2 控制回路(Reconciliation Loop)
- 用户创建一个 Certificate 对象。
- cert-manager 控制器检测到新对象,验证其有效性。
- 控制器生成私钥(如果不存在)并创建 CertificateRequest。
- 根据指定的 Issuer 类型:如果是 CA/SelfSigned/Vault:直接签署并返回证书。如果是 ACME:触发 Order 和 Challenge 流程,完成域名验证后获取证书。
- 获取的证书被保存到 Kubernetes Secret 中。
- 控制器持续监控证书有效期,在临近过期(默认 30 天前)时自动触发更新流程。
3. 实战配置:ACME 协议与 Let’s Encrypt
这是最常用的场景,用于为公网服务提供免费、自动续期的可信证书。
3.1 HTTP-01 vs DNS-01:深度对比
在选择验证方式时,必须根据网络架构做出决策:
| 特性 | HTTP-01 | DNS-01 |
|---|---|---|
| 原理 | 在特定路径放置文件,CA 通过 HTTP 访问验证 | 在 DNS 区域添加 TXT 记录,CA 查询 DNS 验证 |
| 依赖 | 需要 80 端口对外开放且指向集群 | 需要 DNS 提供商的 API 访问权限 |
| 通配符证书 | 不支持 (*.example.com) | 支持 |
| 内网环境 | 仅适用于公网可达的服务 | 适用于内网服务(只要公网 DNS 可解析) |
| 适用场景 | 简单 Web 应用,非通配符 | 复杂架构、通配符、防火墙后的服务 |
3.2 实战:配置 ClusterIssuer (HTTP-01)
首先,通过 Helm 安装 cert-manager(略)。然后定义 ClusterIssuer:
code Yaml
downloadcontent_copy
expand_less
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
# 生产环境 URL
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@example.com
privateKeySecretRef:
name: letsencrypt-prod-account-key
solvers:
- http01:
ingress:
class: nginx # 指定处理验证请求的 Ingress Class
3.3 实战:配置 ClusterIssuer (DNS-01 with Cloudflare)
对于 DNS-01,需要配置 DNS 提供商的凭据(以 Cloudflare 为例):
- 创建 Secret 存储 API Token: code Bashdownloadcontent_copyexpand_less
kubectl create secret generic cloudflare-api-token-secret \ --from-literal=api-token=<YOUR_CLOUDFLARE_API_TOKEN> \ -n cert-manager - 定义 ClusterIssuer: code Yamldownloadcontent_copyexpand_less
apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-dns-prod spec: acme: server: https://acme-v02.api.letsencrypt.org/directory email: admin@example.com privateKeySecretRef: name: letsencrypt-dns-prod-key solvers: - dns01: cloudflare: email: admin@example.com apiTokenSecretRef: name: cloudflare-api-token-secret key: api-token
4. 应用集成:如何消费证书
配置好 Issuer 后,有两种主要方式将证书应用到工作负载中。
4.1 模式一:Ingress Shim(推荐,全自动化)
这是最优雅的方式。只需在 Ingress 资源中添加 Annotation,cert-manager 会监视 Ingress 资源,自动创建 Certificate 对象、申请证书并回填到 Secret。
code Yaml
downloadcontent_copy
expand_less
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
annotations:
# 关键注解:指定使用哪个 ClusterIssuer
cert-manager.io/cluster-issuer: "letsencrypt-prod"
# 可选:强制 HTTP 重定向到 HTTPS
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- app.example.com
secretName: app-tls-secret # cert-manager 将自动创建此 Secret
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app
port:
number: 80
4.2 模式二:显式 Certificate 资源(高级场景)
如果你不使用 Ingress(例如使用 Gateway API,或者直接挂载证书到 Pod 进行 mTLS),或者需要更复杂的证书配置(如增加 SAN IP、自定义密钥算法),则需要显式定义 Certificate。
code Yaml
downloadcontent_copy
expand_less
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: internal-db-cert
namespace: database
spec:
secretName: db-tls-auth
duration: 2160h # 90天
renewBefore: 360h # 15天前续期
commonName: db-service.database.svc
isCA: false
privateKey:
algorithm: ECDSA
size: 256
usages:
- server auth
- client auth
dnsNames:
- db-service.database.svc.cluster.local
- localhost
issuerRef:
name: internal-ca-issuer # 指向一个内部 CA Issuer
kind: ClusterIssuer
5. 进阶场景:私有 PKI 与企业级应用
在企业内部,通常需要签发不受信任公网认可但企业内部受信任的证书(Intranet)。
5.1 使用 CA Issuer
最简单的方法是将现有的 CA 根证书和私钥导入 Kubernetes Secret,然后创建一个 CA Issuer。
code Yaml
downloadcontent_copy
expand_less
# 1. 创建 Secret 包含 ca.crt 和 tls.key
# 2. 定义 Issuer
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: corporate-ca
spec:
ca:
secretName: corporate-root-ca-secret
这使得你可以像申请 Let’s Encrypt 证书一样,轻松地为内部微服务签发证书,实现全链路加密(End-to-End Encryption)。
5.2 集成 HashiCorp Vault
对于高安全性要求的环境,私钥不应存储在 Kubernetes Secret 中。cert-manager 可以作为中间人,通过 PKI 引擎向 Vault 申请签名,而 Vault 负责私钥的安全管理。
6. 运维与故障排查深度指南
6.1 故障排查流程
当证书没有成功签发(Secret 未生成或为空)时,请遵循以下排查路径:
- 检查 Certificate 状态: code Bashdownloadcontent_copyexpand_less
kubectl describe certificate <name>查看 Conditions 和 Events。通常会显示 “Waiting for CertificateRequest”。 - 检查 CertificateRequest: code Bashdownloadcontent_copyexpand_less
kubectl describe certificaterequest <name>如果失败,通常是 Issuer 配置错误或拒绝了请求。 - 检查 Order 和 Challenge (仅 ACME):
这是最容易出错的地方。 code Bashdownloadcontent_copyexpand_lesskubectl get order -n <ns> kubectl describe challenge <challenge-name> -n <ns>常见错误 1: DNS 记录未传播。常见错误 2: 防火墙阻止了 Let’s Encrypt 访问 .well-known/acme-challenge 路径。常见错误 3: Self-check 失败(cert-manager 会在通过 ACME 验证前先自测,如果集群内部网络不通,这里会报错)。
6.2 监控与告警
不要等到证书过期导致服务宕机才发现问题。建议利用 Prometheus 监控 cert-manager 暴露的指标:
- certmanager_certificate_expiration_timestamp_seconds: 证书过期时间戳。
- certmanager_certificate_ready_status: 证书是否就绪。
设置告警规则:当 ready_status 为 0 或 有效期小于 15 天且未成功续期时触发 P1 告警。
7. 总结
cert-manager 不仅仅是一个证书申请工具,它是 Kubernetes 安全基础设施的重要组件。通过将证书生命周期管理抽象为 CRD,它实现了“基础设施即代码”在安全领域的落地。
- 对于公网服务,使用 ClusterIssuer + Ingress Annotation + Let’s Encrypt 实现零成本自动化。
- 对于内网服务,使用 CA Issuer 或 Vault 实现微服务间的 mTLS。
- 对于运维,建立完善的监控体系,关注 Challenge 资源的执行状态。
掌握 cert-manager,意味着构建了一个健壮、自动化的信任分发网络,这是云原生架构迈向成熟的必经之路。
更多推荐
所有评论(0)