4、自动化轮换工具:Cert-Manager与ACME协议实战
说到证书自动化,Cert-Manager 和 ACME 协议是绕不开的两个名字。我最早接触 Cert-Manager 是在一次 K8s 集群的证书大换血中——当时手动轮换了 200 多个证书,差点没把我累趴下。后来我就在想,能不能让机器自己搞定这些事?
嗯,答案就是 Cert-Manager + ACME。说白了,这套组合拳能让你的证书从申请、下发到轮换,全程无人值守。你想想看,这多省心。
4.1 ACME 协议:自动化的基石
ACME(Automatic Certificate Management Environment)是 IETF 的标准协议(RFC 8555)。它的核心思想很简单:让 CA 和客户端通过自动化的挑战应答来验证域名所有权,然后签发证书。
我个人习惯把 ACME 的工作流程拆成三步:
- 注册:客户端向 CA 注册账号,获取账户密钥对
- 授权:客户端证明自己对域名的控制权(通过 HTTP、DNS 或 TLS 挑战)
- 签发:CA 验证通过后,签发证书并返回给客户端
我在项目中遇到过一个问题:很多人以为 ACME 只能用于 Let's Encrypt。其实不是,现在主流的 CA 基本都支持 ACME 了,比如 ZeroSSL、Google Trust Services、甚至企业自建的 PKI 也能跑 ACME。
ACME 挑战类型对比
| 挑战类型 | 验证方式 | 适用场景 | 优缺点 |
|---|---|---|---|
| HTTP-01 | 在 Web 服务器上放置特定文件 | 公网可达的 Web 服务 | 简单,但需要 80 端口开放 |
| DNS-01 | 在 DNS 记录中添加 TXT 记录 | 通配符证书、内网服务 | 无需公网 IP,但需要 DNS API 权限 |
| TLS-ALPN-01 | 在 TLS 握手时验证 | 仅 TLS 端口的服务 | 无需 80 端口,但支持有限 |
4.2 Cert-Manager:K8s 里的证书管家
Cert-Manager 是 Kubernetes 生态里最流行的证书管理工具。它把证书的生命周期抽象成了 CRD(Custom Resource Definition),你只需要声明想要的证书,剩下的交给它。
它的核心组件包括:
- Issuer / ClusterIssuer:定义证书颁发者(比如 Let's Encrypt、自建 CA)
- Certificate:声明证书的域名、有效期、密钥算法等
- Order / Challenge:ACME 订单和挑战的内部资源
- Secret:证书和私钥最终存储在 K8s Secret 中
我记得第一次部署 Cert-Manager 时,踩了一个坑:Issuer 和 ClusterIssuer 的区别没搞清楚。Issuer 是命名空间级别的,ClusterIssuer 是集群级别的。如果你想让所有命名空间共用同一个 ACME 账号,就得用 ClusterIssuer。
我的建议:生产环境优先用 ClusterIssuer,配合 RBAC 控制访问权限。这样证书策略统一,管理也方便。
4.3 实战:用 Cert-Manager + ACME 自动轮换证书
下面我带你走一遍完整的配置流程。假设我们要为 example.com 和 *.example.com 申请通配符证书,使用 DNS-01 挑战。
4.3.1 安装 Cert-Manager
# 使用 Helm 安装
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--set installCRDs=true
安装完成后,检查 Pod 是否正常运行:
kubectl get pods -n cert-manager
# 应该看到 cert-manager、cert-manager-cainjector、cert-manager-webhook 三个 Pod
4.3.2 配置 DNS 提供商
DNS-01 挑战需要 Cert-Manager 能操作你的 DNS 记录。以阿里云为例,需要创建一个 Secret 存储 API 密钥:
apiVersion: v1
kind: Secret
metadata:
name: alidns-secret
namespace: cert-manager
type: Opaque
stringData:
access-key: "你的AccessKey"
secret-key: "你的AccessKeySecret"
4.3.3 创建 ClusterIssuer
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-account-key
solvers:
- dns01:
alidns:
accessKeySecretRef:
name: alidns-secret
key: access-key
secretKeySecretRef:
name: alidns-secret
key: secret-key
注意:ACME 服务器地址分生产环境和 staging 环境。staging 环境没有速率限制,适合测试。我曾经在生产环境调试时,因为频繁请求触发了 Let's Encrypt 的速率限制,导致证书签发失败。建议先用 staging 验证配置。
4.3.4 声明证书
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: example-tls
namespace: default
spec:
secretName: example-tls-secret
duration: 2160h # 90天
renewBefore: 720h # 提前30天续期
commonName: example.com
dnsNames:
- example.com
- "*.example.com"
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
这里有个关键参数:renewBefore。Cert-Manager 会在证书到期前这个时间点自动触发续期。我一般设置成证书有效期的三分之一,这样有足够的时间处理异常。
4.3.5 验证证书
kubectl get certificate
kubectl describe certificate example-tls
kubectl get secret example-tls-secret -o yaml
如果一切正常,你会看到证书状态变成 Ready,Secret 里包含了 tls.crt 和 tls.key。
4.4 自动化轮换的完整流程
下面这张图展示了 Cert-Manager 与 ACME 协议协同工作的完整流程:
4.5 避坑指南
实战中我踩过不少坑,挑几个典型的说说:
- 速率限制:Let's Encrypt 生产环境每周每个域名只能签发 50 个证书。测试时一定要用 staging 环境。
- DNS 传播延迟:DNS-01 挑战需要等待 DNS 记录生效。如果 DNS 提供商响应慢,可以设置
dns01CheckInterval参数增加等待时间。 - 证书吊销联动:Cert-Manager 本身不处理证书吊销。如果需要吊销证书,得手动调用 CA 的 API 或使用 cert-manager-approver 等工具。
- 密钥安全:私钥存储在 K8s Secret 中,默认是 base64 编码。建议启用 Secret 加密(如 KMS 或 SOPS)保护私钥。
我的经验:我曾经因为 DNS 提供商 API 密钥过期,导致证书续期失败,服务中断了 2 小时。后来我加了一个监控:每天检查证书剩余有效期,小于 15 天就告警。这样即使自动续期失败,也有时间手动处理。
4.6 总结
Cert-Manager + ACME 这套方案,说白了就是把证书管理的脏活累活都交给机器。你只需要声明想要的证书,剩下的申请、验证、签发、续期、存储,全部自动化完成。
我个人觉得,这套方案最大的价值不是省事,而是消除了人为失误。想想看,手动轮换证书时,漏掉一个域名、写错一个 SAN、忘记更新 Secret——这些坑我都踩过。自动化之后,这些风险基本归零。
嗯,如果你还在手动管理证书,真的可以试试 Cert-Manager。从 staging 环境开始,跑通一个域名,再逐步推广到全集群。你会发现,证书管理原来可以这么轻松。