cert-manager ACME 证书签发与排障指南
Certificate 长时间停在 Ready=False,目标 TLS Secret 也迟迟没有出现。这时只盯着 cert-manager controller 的日志,很容易被连续重试的消息带着走。更直接的办法,是查看 cert-manager 已经写进 Kubernetes API 的资源和事件。一次 ACME 签发会留下清晰的处理链。
Certificate 负责描述想要的证书,CertificateRequest 保存本次签发请求,Order 对应 ACME 订单,Challenge 负责证明域名控制权。找到停止变化的那一层,排障范围就会迅速缩小。这篇适合已经安装 cert-manager,并且配置好 ACME
Issuer 或 ClusterIssuer 的集群。完成后可以看懂整条签发链,也能判断故障落在证书请求、ACME 订单、HTTP 路由还是 DNS 传播。先确认签发从哪里开始
cert-manager 常见的触发入口有两个。
第一个入口是直接创建
Certificate。资源里写明域名、签发者和目标 Secret。cert-manager 会生成私钥与 CertificateRequest,拿到证书后再把证书和私钥写进 spec.secretName 指定的 Secret。cert-manager ACME 证书签发与排障指南 (yaml)
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: example-com
namespace: default
spec:
secretName: example-com-tls
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- example.com第二个入口是给
Ingress 添加 cert-manager.io/issuer 或 cert-manager.io/cluster-issuer 注解。ingress-shim 发现注解后,会根据 spec.tls[].secretName 自动维护同名 Certificate。后续流程仍然回到同一条资源链。如果 Ingress 已经加了注解,集群里却没有对应的
Certificate,问题还没进入 ACME 阶段。应先检查注解名称、tls.secretName、命名空间和 ingress-shim 日志。四类资源把签发过程摊开
证书签发可以按下面的顺序理解。
cert-manager ACME 证书签发与排障指南 (text)
Certificate
→ CertificateRequest
→ Order
→ Challenge
Certificate
→ 最终 TLS SecretCertificate 是长期存在的声明。证书首次签发、配置变化或进入续期窗口时,cert-manager 会创建新的 CertificateRequest。使用 ACME 签发者的 CertificateRequest 又会触发一个 Order,随后由 Order 为需要授权的 DNS 名称创建 Challenge。这几个对象都有自己的
status、conditions 和 Events。它们将一段异步过程变成了可以逐层观察的 Kubernetes 资源。排障时无需猜控制器执行到了哪里,只要从上往下查看状态。Order 和 Challenge 都由 cert-manager 自动管理,规格创建后不可修改。需要重试时,应修正关联配置,再让控制器创建新对象。签发成功后,已完成的 Challenge 可能很快被清理,因此健康集群里看不到它并不反常。一次签发会经历什么
准备 ACME 账号
ACME
Issuer 或 ClusterIssuer 代表一个 ACME 账号。spec.acme.privateKeySecretRef.name 指向账号私钥 Secret。这个 Secret 用来识别 ACME 客户端,和业务最终使用的 TLS Secret 是两件东西。先检查签发者是否可用。
cert-manager ACME 证书签发与排障指南 (bash)
kubectl get issuer,clusterissuer
kubectl describe clusterissuer letsencrypt-prodReady=True 才表示账号注册和基础配置已经完成。签发者未就绪时,继续检查 Order 和 Challenge 通常不会得到有效线索。创建私钥和签发请求
目标 Secret 不存在、证书需要续期或
Certificate 的相关配置发生变化时,certificate controller 会启动签发。Events 中常见的第一条线索是目标 Secret 不存在。签发过程中,cert-manager 会准备私钥并创建
CertificateRequest。某些签发与密钥轮换场景会先使用临时 Secret 保存新私钥,Events 会出现 Stored new private key in temporary Secret resource 一类消息。临时 Secret 名字通常带有证书名和随机后缀,不要把它当成最终交付物。CertificateRequest 内保存 CSR,并通过 issuerRef 指向签发者。检查这一层时,重点看请求是否获批、签发者是否找到,以及 Ready 条件给出的原因。cert-manager ACME 证书签发与排障指南 (bash)
kubectl -n <ns> get certificaterequest
kubectl -n <ns> describe certificaterequest <request-name>创建不可修改的 ACME Order
ACME issuer controller 会为
CertificateRequest 创建 Order。一个 Order 对应一次证书请求,里面包含 ACME 服务端返回的授权信息。cert-manager ACME 证书签发与排障指南 (bash)
kubectl -n <ns> get order
kubectl -n <ns> describe order <order-name>Order 创建后不能原地修改。域名、solver 或签发者配置有误时,先修正上游配置。若旧 Order 一直停在失败状态,可以删除它,让 cert-manager 重新发起流程。不要手工创建或编辑 Order。为域名创建 Challenge
Order controller 会为需要授权的 DNS 名称创建 Challenge。如果某个授权在 ACME 服务端已经有效,对应的 Challenge 可能不会再次创建。Challenge controller 会先呈现验证材料,再做 self-check。self-check 通过后,cert-manager 才会请求 ACME 服务端正式校验。检查失败时,控制器会继续重试,
status.reason 和 Events 会保留等待或失败原因。cert-manager ACME 证书签发与排障指南 (bash)
kubectl -n <ns> get challenge
kubectl -n <ns> describe challenge <challenge-name>Presented=True 说明验证材料已经提交到预定位置。Processing=True 且状态长期为 pending,通常意味着 self-check 或 ACME 校验还没有通过。HTTP01 和 DNS01 会在哪里分开
两种 solver 共享前面的资源链,区别集中在 Challenge 怎样证明域名控制权。
项目 | HTTP01 | DNS01 |
|---|---|---|
验证位置 | /.well-known/acme-challenge/ | _acme-challenge TXT 记录 |
临时资源 | 通常有 solver Pod、Service 和 Ingress | 通常没有额外的 Pod、Service 和 Ingress |
self-check 关注点 | 集群内能否通过域名访问 challenge URL | 查询到的 TXT 值是否正确 |
常见故障 | Ingress class、路由、负载均衡、防火墙 | DNS 凭据、zone 选择、传播、递归解析器 |
通配符证书 | 不支持 | 支持 |
HTTP01 要打通一条真实 HTTP 路径
HTTP01 会把 challenge token 暴露在请求域名的固定路径下。cert-manager 通常创建
acmesolver Pod、Service 和 Ingress,把公网请求送到一个很小的 HTTP 服务。cert-manager ACME 证书签发与排障指南 (bash)
kubectl -n <ns> get pod,service,ingress | grep acme
kubectl -n <ns> describe ingress <solver-ingress>先从公网访问 challenge URL,再从集群内的 Pod 访问同一个地址。公网失败时,检查 DNS 解析、负载均衡、防火墙和 Ingress 路由。公网成功而集群内失败时,重点看集群网络、hairpin 路径和 DNS 视图。
ingressClassName 也要核对。未指定 class 的临时 Ingress 可能被多个 Ingress controller 同时处理。使用 edit-in-place 模式时,cert-manager 会修改已有 Ingress,此时要检查原 Ingress,不能继续寻找独立的 solver Ingress。DNS01 要等 TXT 记录被正确查询
DNS01 使用 Issuer 里配置的 DNS provider 凭据创建
_acme-challenge TXT 记录。它适合通配符证书,也适合无法从公网暴露 HTTP 路径的环境。cert-manager ACME 证书签发与排障指南 (bash)
dig TXT _acme-challenge.example.com
kubectl -n <ns> describe challenge <challenge-name>Presented=True 只表示 cert-manager 已经调用 provider 呈现记录,不保证查询端已经能看到正确结果。DNS 传播、权威服务器、递归解析器缓存、错误的 zone 选择和 CNAME 委派都会影响 self-check。遇到
Waiting for dns-01 challenge propagation 时,先核对权威 DNS 返回值,再看 cert-manager 使用的解析路径。修改 controller 的递归 nameserver 参数会改变 self-check 行为,只有确认集群 DNS 视图确实有问题时才需要动它。沿资源链逐层排障
先把相关对象列出来。下面的命令适合签发正在进行或卡住时使用。
cert-manager ACME 证书签发与排障指南 (bash)
kubectl -n <ns> get certificate,certificaterequest,order,challenge,secret然后按照固定顺序检查。
- 查看
Certificate的 Ready 条件和 Events,确认它是否已经启动签发,并记下CertificateRequest名称。 - 查看
CertificateRequest是否获批、是否找到签发者,并记下Order名称。 - 查看
Order的 state、reason 和授权状态,并记下未完成的Challenge。 - 查看
Challenge的presented、processing、state、reason 和 Events,再进入对应 solver 的网络或 DNS 检查。
每一层都优先使用
kubectl describe。Events 经常已经给出缺失 Secret、找不到 Issuer、HTTP self-check 返回码、DNS provider 报错或等待传播等具体原因。如果集群里完全没有
Order,问题多半还在 CertificateRequest 或签发者。如果有 Order 却没有可处理的 Challenge,检查授权状态和 Order 的 Events。如果 Challenge 已经 Presented=True,就把注意力转向外部验证路径。怎样确认签发已经完成
Order 变为 valid 后,cert-manager 会完成 finalize,取得证书链,并把证书与私钥写入 Certificate.spec.secretName 指向的 Secret。目标 Secret 通常包含 tls.crt 和 tls.key,类型为 kubernetes.io/tls。cert-manager ACME 证书签发与排障指南 (bash)
kubectl -n <ns> get certificate <certificate-name>
kubectl -n <ns> get secret <secret-name> -o jsonpath='{.type}{"\n"}'
kubectl -n <ns> get secret <secret-name> -o jsonpath='{.data.tls\.crt}' | wc -c
kubectl -n <ns> get secret <secret-name> -o jsonpath='{.data.tls\.key}' | wc -c最终应看到
Certificate 的 Ready=True,目标 Secret 的类型与字段正确。HTTP01 的 solver 资源和 DNS01 的 TXT 记录会在验证结束后清理。Order、CertificateRequest 或历史 Events 是否仍然存在,会受版本和垃圾回收时机影响,不能把它们的消失当成失败。