文章目录
-
- cert-manager安装及介绍
- ACME概念理论
- ACME验证HTTP01详解
-
- HTTP01验证过程
- [Ingress solver 路由模式](#Ingress solver 路由模式)
-
- Ingress方式介绍
- ingressClassName
- class
- name
- [Ingress solver 暴露类型](#Ingress solver 暴露类型)
- podTemplate模板
- ingressTemplate
- [Gateway API HTTPRoute 路由模式](#Gateway API HTTPRoute 路由模式)
-
- [Gateway API方式介绍](#Gateway API方式介绍)
- ACME验证DNS01详解
cert-manager安装及介绍
cert-manager概述
参考:Kubernetes cert-manager安装及自签名指南
cert-manager安装
参考:Kubernetes cert-manager安装及自签名指南
ACME概念理论
ACME介绍
ACME 颁发者类型代表在自动证书管理环境(ACME)证书颁发机构服务器注册的独立账户。创建新的 ACME Issuer 时,cert-manager 将生成用于在 ACME 服务器验证用户身份的私钥。
公共 ACME 服务器签发的证书通常默认受客户端计算机信任。这意味着,例如访问使用为该 URL 签发的 ACME 证书的网站时,大多数客户端网页浏览器会默认信任该证书。同时ACME 证书通常免费提供。
ACME 的本质是让 cert-manager 代表客户,去向一个 ACME 证书颁发机构(CA)自动注册账户、完成域名所有权验证、申请并续期证书。
而其中最典型的 ACME CA 就是 Let's Encrypt 。
也就是 cert-manager + ACME + Let's Encrypt = Kubernetes 中免费自动化 HTTPS 证书的主流方案。
使用该方案(如 Let's Encrypt)签发的证书:
- 通常被客户端系统默认信任
- 浏览器默认认可
- 不需要额外自己分发根证书
- 证书通常是免费的
- cert-manager 能自动续期
- 方案对比
和之前的自签名、自构建CA两种方案对比,ACME具备如下优势:
| 类型 | 浏览器默认信任 | 适合公网 HTTPS | 自动化程度 | 成本 |
|---|---|---|---|---|
| SelfSigned | 否 | 否 | 中 | 免费 |
| CA(自建) | 否,需手动分发信任 | 一般不适合公网 | 中 | 免费/自建成本 |
| ACME | 是(公共 CA) | 是 | 高 | 通常免费 |
验证方式
为了让 ACME 证书颁发机构服务器验证客户端是否拥有申请证书的域名(即确保该域名归属于申请者),客户端必须完成相应的验证。
这能确保客户端无法为其不拥有的域名申请证书,从而防止欺诈性仿冒他人网站。参考 RFC8555 标准所述,cert-manager 提供两种挑战验证方式:HTTP01 和 DNS01 挑战。
提示:用来提出申请的,比如在Kubernetes中使用cert-manager提出申请,该节点为ACME客户端,然后Let's Encrypt 响应该申请,Let's Encrypt 为ACME服务端。
HTTP01验证
HTTP01 验证通过在 HTTP URL 端点(如 http://example.com/.well-known/acme-challenge/<token> )上提供计算出的密钥来完成,该端点必须可通过互联网路由访问,此 URL 将使用证书申请对应的域名。
当 ACME 服务器能够通过互联网从此 URL 获取密钥时,即可验证申请者是该域名的所有者。
创建 HTTP01 挑战时,cert-manager 将自动配置集群入口路由,将该 URL 的流量导向用于提供此密钥的小型网络服务器。

DNS01验证
DNS01 挑战通过提供一个存在于 DNS TXT 记录中的计算密钥来完成。当该 TXT 记录在互联网上传播后,ACME 服务器可通过 DNS 查询成功获取此密钥,从而验证客户端是否拥有所申请证书的域名所有权。在具备正确权限的情况下,cert-manager 将自动为申请者的 DNS 提供商提供此 TXT 记录。

两种验证对比:
| 项目 | HTTP-01 | DNS-01 |
|---|---|---|
| 验证入口 | HTTP URL | DNS TXT |
| 是否需要公网 Web 入口 | 是 | 否 |
| 是否依赖 DNS API | 否 | 是 |
| 是否支持通配符 | 否 | 是 |
| 配置难度 | 较低 | 较高 |
| 常见场景 | 普通网站 HTTPS | 通配符 / 无公网入口 |
创建基础 ACME 签发者
所有 ACME Issuers 都遵循相似的配置结构,包含客户端 email 、 server URL、 privateKeySecretRef 以及一个或多个 solvers 。
一个 ACME Issuer / ClusterIssuer 表示:
- 申请者在某个 ACME CA 上的一个账户
- cert-manager 会自动生成该账户的私钥
- 这个账户私钥会保存在 Kubernetes Secret 中
- 后续所有通过这个 Issuer 申请的证书,都是以这个 ACME 账户身份去操作的
- 所以 ACME Issuer 不是"某张证书",而是申请者和 ACME 服务器之间的注册身份 + 请求策略配置
以下是基础 ACME 签发者的配置示例:
shell
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
email: user@example.com # 替换为自己的邮箱,用于 Let's Encrypt 账户注册,证书过期前会收到提醒邮件
profile: tlsserver # 如果 ACME 服务器支持配置文件(profiles),可以在这里指定配置文件名称,参考ACME 证书配置文件
server: https://acme-staging-v02.api.letsencrypt.org/directory # ACME 服务器的目录端点 URL,此为Let's Encrypt 的 staging(测试/预发布)环境,staging 环境签发的证书不受公网信任,仅用于测试验证流程是否正确,生产环境应替换为:https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
# 用于存储 ACME 账户私钥的 Secret 资源。
# 这是在 ACME 提供商处的身份标识,Secret 名称可以任意选择。
# 它会被自动填充数据,因此通常不需要对该 Secret 做任何额外操作。
# 如果丢失了这个身份标识/Secret,可以重新生成一个新的,并且仍然可以为之前账户管理的所有域名生成新证书,但将无法吊销(revoke)使用之前那个账户所生成的证书。
name: example-issuer-account-key
# 添加单个 challenge solver,指定使用 nginx 的 HTTP01 验证方式
solvers:
- http01:
ingress:
ingressClassName: nginx
释义总结:
- email:ACME 账户邮箱,注册 ACME 账户时使用,用于接收证书到期提醒等通知。
- server:ACME 服务器地址,这个字段指定要连接哪个 ACME CA 目录端点。
- privateKeySecretRef:ACME 账户私钥保存位置,即 ACME 账户私钥 保存的 Secret。它不是业务网站证书私钥,而是在 ACME CA 那边的账户身份私钥,cert-manager 用它和 ACME 服务器交互,标识当前的 ACME 账户身份,后续新订单、续签、管理等都依赖它。
- solvers:域名所有权验证方式,cert-manager 用哪种方式完成 challenge 验证。
- profile:证书配置档案(新特性,可选),相对新一些的高级能力。如果 ACME 服务器支持 certificate profiles(证书配置档案),就可以在 Issuer 里通过 profile 指定。
提示:challenge solver 以 dns01 和 http01 配置段的形式存在。
| 字段 | 作用 | 说明 |
|---|---|---|
| ACME 账户注册邮箱 | Let's Encrypt 会在证书即将过期时发送提醒邮件到此邮箱 | |
| profile | ACME 证书配置文件 | 新特性,指定证书用途(如 tlsserver),并非所有 ACME 服务器都支持 |
| server | ACME 服务器地址 | staging = 测试环境,签发的证书浏览器不信任;正式环境要换 URL |
| privateKeySecretRef | 账户私钥存储位 | cert-manager 自动生成并管理,你不需要手动创建这个 Secret |
| solvers | 域名所有权验证方式 | 可以使用 HTTP01 或 DNS01 验证 |
ACME 证书配置文件
提示:此功能在 cert-manager >= v1.18.0 中可用。
ACME 服务器可向 ACME 客户端提供不同的证书配置文件选择。
在 Issuer 或 ClusterIssuer 中使用可选的 profile 字段为 ACME 订单选择配置文件。
Let's Encrypt 已提供多种配置文件,其他 ACME 服务器可能尚未支持配置文件,或提供不同的配置文件,具体需要查阅 ACME 服务器的文档以了解可用配置。可通过下载目录对象确认 ACME 服务器是否支持配置文件。例如:
shell
[root@master01 ~]# curl -fsSL https://acme-staging-v02.api.letsencrypt.org/directory
{
"Jo0ujPKWBmE": "https://community.letsencrypt.org/t/adding-random-entries-to-the-directory/33417",
"keyChange": "https://acme-staging-v02.api.letsencrypt.org/acme/key-change",
"meta": {
"caaIdentities": [
"letsencrypt.org"
],
"profiles": {
"classic": "https://letsencrypt.org/docs/profiles#classic",
"shortlived": "https://letsencrypt.org/docs/profiles#shortlived",
"tlsclient": "https://letsencrypt.org/docs/profiles#tlsclient",
"tlsserver": "https://letsencrypt.org/docs/profiles#tlsserver"
},
"termsOfService": "https://letsencrypt.org/documents/LE-SA-v1.6-August-18-2025.pdf",
"website": "https://letsencrypt.org/docs/staging-environment/"
},
"newAccount": "https://acme-staging-v02.api.letsencrypt.org/acme/new-acct",
"newNonce": "https://acme-staging-v02.api.letsencrypt.org/acme/new-nonce",
"newOrder": "https://acme-staging-v02.api.letsencrypt.org/acme/new-order",
"renewalInfo": "https://acme-staging-v02.api.letsencrypt.org/acme/renewal-info",
"revokeCert": "https://acme-staging-v02.api.letsencrypt.org/acme/revoke-cert"
若支持配置文件,将在 JSON 对象的字段中看到"profiles"标识。
若不指定配置文件,ACME 服务器将使用其默认配置。对于 Let's Encrypt 而言,默认配置为 classic 配置文件。
注意:
- 若指定配置文件但连接的 ACME 服务器尚未支持 ACME 配置文件扩展功能,cert-manager 将在 CertificateRequest 资源上报错。
- 若指定的配置文件未被 ACME 服务器识别,cert-manager 将在 CertificateRequest 资源上报错。
添加多个验证器类型
实际中通常可能希望为不同的 ingress 域名配置不同类型的 challenge solver ,例如使用 DNS01 签发通配符证书,以及使用 HTTP01 验证其他证书时。
solvers 配置段包含一个可选的 selector 字段,可用于指定使用哪些 Certificates ,并进一步确定应利用这些 Certificates 上的哪些 DNS 名称来匹配验证。
有三种选择器类型可用于构成 Certificate 必须满足的要求,以便被选为solver,matchLabels 、 dnsNames 和 dnsZones 。单个solver 上可以包含任意数量的这些选择器。
Match Labels
matchLabel 选择器要求所有 Certificates 必须匹配该配置段字符串映射列表中定义的所有标签。
如下示例 Issuer 将仅匹配同时具有 "use-cloudflare-solver": "true" 和 "email": "user@example.com" 标签的 Certificates 。
shell
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
...
solvers:
- dns01:
cloudflare:
email: user@example.com
apiKeySecretRef:
name: cloudflare-apikey-secret
key: apikey
selector:
matchLabels:
"use-cloudflare-solver": "true"
"email": "user@example.com"
总结:Certificate 必须同时具有对应的 label,才会匹配这个 solver 。
DNS Name
dnsNames 选择器是一个应映射到solvers的精确 DNS 名称列表。这意味着包含这些 DNS 名称中任意一个的 Certificates 将被选中。若找到匹配项,dnsNames 选择器将优先于 dnsZones 选择器。若多个求解器具有相同的 dnsNames 值,则选择 matchLabels 中匹配标签最多的求解器。若匹配数相同,则选择列表中靠前定义的求解器。
如下示例 Issuer 将使用 DNS 名称 example.com 和 *.example.com 解决 Certificates 针对这些域的挑战。
注意:dnsNames 采用精确匹配且不解析通配符,这意味着后续的 Issuer 不会解析诸如 foo.example.com 的 DNS 名称。请使用 dnsZones 选择器类型来匹配区域内的所有子域。
shell
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
...
solvers:
- dns01:
cloudflare:
email: user@example.com
apiKeySecretRef:
name: cloudflare-apikey-secret
key: apikey
selector:
dnsNames:
- 'example.com'
- '*.example.com'
总结:只有 Certificate 中出现这些完全匹配的 DNS 名称时,才会匹配这个 solver 。
DNS Zones
dnsZones 节段定义了该 solver 可处理的 DNS 区域列表。若某个 DNS 名称与任何指定 dnsZones 完全匹配或是其子域,除非配置了更具体的 dnsNames 匹配项,否则将使用此解析器。这意味着对于 www.sys.example.com 域,选择 sys.example.com 将优先于指定 example.com 的解析器。
当多个解析器具有相同 dnsZones 值时,将选择 matchLabels 中匹配标签最多的解析器;若匹配数相同,则选择列表中位置靠前的解析器。
如下示例 Issuer 将将为域 example.com 及其所有子域 *.example.com 匹配验证。
shell
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
...
solvers:
- dns01:
cloudflare:
email: user@example.com
apiKeySecretRef:
name: cloudflare-apikey-secret
key: apikey
selector:
dnsZones:
- 'example.com'
总结:通配符匹配,属于这个 DNS zone 或其子域,都会匹配这个 solver 。
优先顺序
每个 solver 可定义任意数量的三种选择器类型。在以下示例中,CloudFlare 的 DNS01 solver 将用于求解包含 DNS 名称 a.example.com 和 b.example.com 的 Certificates 域名的验证。而 Google CloudDNS 的 DNS01 求解器将用于求解其 DNS 名称与区域 test.example.com 匹配的所有子域(例如 foo.test.example.com )的 Certificates 验证。
对于所有其他质询,仅当 Certificate 同时包含标签 "use-http01-solver": "true" 时,才会使用 HTTP01 求解器。
shell
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
...
solvers:
- http01:
ingress:
ingressClassName: nginx
selector:
matchLabels:
"use-http01-solver": "true"
- dns01:
cloudflare:
email: user@example.com
apiKeySecretRef:
name: cloudflare-apikey-secret
key: apikey
selector:
dnsNames:
- 'a.example.com'
- 'b.example.com'
- dns01:
cloudDNS:
project: my-project-id
hostedZoneName: 'test-example.com'
serviceAccountSecretRef:
key: sa
name: gcp-sa-secret
selector:
dnsZones:
- 'test.example.com'
每个单独的选择器块可以包含多个选择器类型,例如:
shell
solvers:
- dns01:
cloudflare:
email: user@example.com
apiKeySecretRef:
name: cloudflare-apikey-secret
key: apikey
selector:
matchLabels:
'email': 'user@example.com'
'solver': 'cloudflare'
dnsZones:
- 'test.example.com'
- 'example.dev'
如上所示,Cloudflare 的 DNS01 解析器仅当 Certificate 具有来自 matchLabels 的标签且 DNS 名称与 dnsZones 中的区域匹配时,才会用于解决 DNS 名称的验证。
相当于证书既要满足 matchLabels,又要域名落在 dnsZones 中,才会匹配这个 solver。
即多个 selector 类型叠加时,更接近 AND 条件。
提示:排序依据大致是:
- 精确域名匹配优先(dnsNames)
- 再看区域匹配(dnsZones)
- 同等级匹配下,标签更多者优先
- 仍相同时,按声明顺序优先
ACME验证HTTP01详解
HTTP01验证过程
HTTP-01 的本质是ACME CA(例如 Let's Encrypt)需要申请者证明:确实控制某个域名,例如 example.com ,而证明方式是:ACME CA 会去访问某个特定的页面:http://example.com/.well-known/acme-challenge/<token> ,如果能从公网拿到正确内容,就验证通过。
而在 HTTP-01 模式下,cert-manager 一般会针对验证/质询(challenge)过程自动创建或使用以下资源:
- challenge 对应的临时 Pod(acmesolver)
- challenge 对应的 Service
- challenge 对应的 Ingress 或 HTTPRoute
- 把 challenge 路径指向 acmesolver Pod
所以需要了解 cert-manager 如何把 /.well-known/acme-challenge/... 这条请求,安全地暴露到公网,并路由到 solver Pod 。
提示 :cert-manager 不是自己创建一套入口系统,它依赖集群里已有的 Ingress 控制器 或 Gateway API 资源 来完成 HTTP-01 challenge 暴露。
对于入口的创建主要有两种方式:基于 Ingress 的 HTTP01 solver 和基于 Gateway API 的 HTTP01 solver 。
| 模式 | 依赖 | 当前成熟度 | 常见程度 |
|---|---|---|---|
| Ingress solver | Ingress Controller | 高 | 最常见 |
| Gateway API solver | Gateway API + Gateway Controller | 较新 | 新架构/逐步普及 |
Ingress solver 路由模式
Ingress方式介绍
Ingress Solver 三种核心路由模式:ingressClassName / class / name 。
一个最基础的基于 ingressClassName 的 HTTP01 ACME solver 结构:
shell
solvers:
- http01:
ingress:
ingressClassName: nginx
释义:遇到 ACME HTTP-01 challenge 时,请通过 Ingress 方式处理,并且让 nginx 这个 Ingress Controller 来接管。
Ingress solver 需要详细了解如下几个选项:
- ingressClassName
- class
- name
- serviceType
- podTemplate
- ingressTemplate
不同的选项主要是为了说明临时 challenge Ingress 该怎么创建、由谁接管、怎么定制。
ingressClassName
ingressClassName 是当前推荐的方式,其配置如下:
shell
http01:
ingress:
ingressClassName: nginx
如上配置 cert-manager 会:
- 新建一个临时 Ingress
- 这个 Ingress 指定
ingressClassName: nginx - 由 nginx ingress controller 接管
- 将 challenge 路由到 acmesolver Pod
该方式适用于:
- NGINX Ingress Controller
- Traefik(取决于版本与实现)
- HAProxy Ingress
- 大多数现代 ingress 控制器
class
class 方式是为了兼容旧式 Ingress class 注解,其配置如下:
shell
http01:
ingress:
class: gce
如上配置 cert-manager 会:
- 创建一个临时 Ingress
- 这个 Ingress 使用
annotation:kubernetes.io/ingress.class: gce
该方式适用于:Kubernetes 较早时期指定 Ingress Controller 的做法。
name
name 是直接修改现有 Ingress,其配置如下:
shell
http01:
ingress:
name: my-existing-ingress
如上配置 cert-manager 不会新建临时 Ingress,而是:
- 直接修改你指定的那个现有 my-existing-ingress Ingress
- 往里面插入 challenge 路径规则
- 完成 HTTP-01 验证
该方式适用于:适合像 ingress-gce 这种"每个 Ingress 对应一个独立 IP"的控制器,如果新建一个额外 Ingress,可能会导致:新分配一个新 IP,而域名没解析到这个新 IP,从而导致challenge 无法验证,这种情况下,直接复用已有 Ingress 是合理的。
注意:name 方式必须慎用,如果 ingress controller 是"所有 Ingress 共用一个对外 IP"的模式(比如很多 NGINX Ingress 场景),直接改现有 Ingress 可能带来:
- 与现有注解冲突
- 与 controller 特定行为冲突
- 影响业务路由规则
- challenge 路由污染业务 Ingress
name 模式本质是:不新建 challenge Ingress,而是借用已有 Ingress 做 challenge 暴露。
注意:如果三者都不配置,即没有 class,没有 ingressClassName,没有 name,那么 cert-manager 会默认创建新的 Ingress,但不会指定 Ingress class,这会导致集群中所有的 Ingress Controller 都可能接管这个 challenge Ingress。从而带来流量行为不可控(不知道到底哪个 ingress controller 响应 challenge),可能出现验证异常(多控制器竞争处理),因此建议HTTP01 Ingress solver 应明确指定处理者,不要依赖默认行为。
Ingress solver 暴露类型
HTTP01 solver 不只有 Pod 和 Ingress,它还会创建一个 Service,因此就涉及到了暴露类型。其配置如下:
shell
http01:
ingress:
serviceType: ClusterIP
可选值:
- NodePort (此为默认值)
- ClusterIP
NodePort:某些 Ingress Controller 或流量路径依赖这种方式来访问后端 challenge 服务。
ClusterIP:平台不想让 solver Service 暴露为 NodePort,明确知道所用 Ingress Controller 支持 ClusterIP 作为后端访问。
podTemplate模板
acmesolver Pod 是 cert-manager 自动创建的临时 Pod,通过 podTemplate 可以进行更多的配置,配置非常实用,尤其是在多租户、资源受限、策略严格的集群里可以实现额外要求,主要有:
- 必须打上某些 label
- 必须加某些 annotation
- 必须调度到指定节点
- 必须带 tolerations
- 必须指定 resource requests/limits
- 必须使用特定 serviceAccount
- 必须满足 Pod 安全策略
如上针对 pod 的细致配置,都可以通过:podTemplate.metadata 和 podTemplate.spec 实现。
metadata 下可定制:
- labels
- annotations
spec 下可定制:
- nodeSelector
- tolerations
- affinity
- priorityClassName
- serviceAccountName
- securityContext
- imagePullSecrets
- resources
配置模板示例:
shell
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: ...
spec:
acme:
server: ...
privateKeySecretRef:
name: ...
solvers:
- http01:
ingress:
podTemplate:
metadata:
labels:
foo: "bar"
env: "prod"
spec:
nodeSelector:
bar: baz
resources:
requests:
cpu: 20m
memory: 32Mi
limits:
cpu: 150m
memory: 64Mi
注意:除上述字段外,其他 spec 字段不能改,也就是说它不是完整 PodSpec 支持,而是受控扩展点
提示 :cert-manager controller 本身可以通过全局参数 --acme-http01-solver-resource-* 设置 solver Pod 资源限制,但如果在 podTemplate.spec.resources 里也写了资源配置,那么这个 Issuer 级别配置会覆盖全局默认值。
提示 :如果只配置 limits 而不配置 requests,则必须保障配置的limits >= 全局 requests ,否则 Kubernetes 会因为:limits < requests 而拒绝创建 Pod,最终导致 challenge 失败。
ingressTemplate
该字段主要是自定义临时 challenge Ingress,即 podTemplate 是定制 solver Pod,则 ingressTemplate 就是定制 challenge 用的 Ingress。
官方允许在 ingressTemplate.metadata 下添加:
- labels
- annotations
不能改其他 Ingress 字段,所以它的用途不是重定义完整 Ingress,而是做"标记增强"。
该字段主要用在比较复杂的场景,如在多 Ingress Controller 集群里,单纯指定 class 可能还不够,可能还需要一些控制器专属注解,例如:
- nginx 白名单注解
- nginx mergeable ingress 注解
- traefik entrypoint 注解
所以需要ingressTemplate,这些注解可以实现:
- 让 challenge Ingress 被正确控制器接管
- 符合该控制器的特殊行为要求
- 满足平台安全/网络策略
配置模板示例:
shell
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: ...
spec:
acme:
server: ...
privateKeySecretRef:
name: ...
solvers:
- http01:
ingress:
ingressTemplate:
metadata:
labels:
foo: "bar"
annotations:
"nginx.ingress.kubernetes.io/whitelist-source-range": "0.0.0.0/0,::/0"
"nginx.org/mergeable-ingress-type": "minion"
"traefik.ingress.kubernetes.io/frontend-entry-points": "http"
总结:ingressTemplate 是给 cert-manager 自动生成的 challenge Ingress 打上平台所需的元数据。
Gateway API HTTPRoute 路由模式
Gateway API方式介绍
Gateway API依旧属于较新的特性,在 cert-manager 1.15 版本已可用,但仍应视为较新方案,相比 Ingress 更现代,但成熟度与生态经验略少于 Ingress 模式。
Gateway API Solver 的设计思路:和 Ingress 模式类似,Gateway API 模式也不是 cert-manager 自己处理 L7 流量,而是借助已有网关体系:
- Gateway
- HTTPRoute
cert-manager 的行为大致是:
- 发现 ACME HTTP-01 challenge
- 创建临时 HTTPRoute
- 把 /.well-known/acme-challenge/... 路由到 solver Service/Pod
- 让已有 Gateway 对外暴露
- challenge 完成后删除 HTTPRoute
要使用 Gateway API solver,需要满足两个条件:提示:Gateway API CRDs 最好在 cert-manager 启动前就存在。
- 当前集群已安装Gateway API CRDs,具体安装参考:Gateway API 。
- 必须启用 cert-manager 对 Gateway API 的支持,使用kubectl安装的时候开启方式如下:
shell
config:
apiVersion: controller.config.cert-manager.io/v1alpha1
kind: ControllerConfiguration
enableGatewayAPI: true
使用helm部署的时候配置如下:
shell
helm upgrade --install cert-manager ... \
--set config.apiVersion="controller.config.cert-manager.io/v1alpha1" \
--set config.kind="ControllerConfiguration" \
--set config.enableGatewayAPI=true
提示 :有关Gateway API的使用方式不做深入探讨,具体可参考: Configuring the HTTP-01 Gateway API solver 。
ACME验证DNS01详解
DNS01验证介绍
DNS01 是 ACME 域名所有权验证的一种方式。
它的本质不是让 ACME CA 访问网站,而是让 ACME CA 去查 DNS 记录,确认对这个域名有控制权。
通常表现方式为:
shell
_acme-challenge.example.com TXT "某个 challenge 值"
只要 ACME CA 能查询到这个 TXT 记录,并且值正确,就会认可拥有该域名的控制权,然后签发证书。
DNS01 提供商配置必须在 Issuer 资源中指定,本指南主要采用 Let's Encrypt 提供商进行示例和讲解。配置示例模板如下:
配置模板释义:
- 不是在 Certificate 上直接写 DNS Provider
- 而是在 ACME Issuer 的 solvers 里定义 DNS01 solver,Certificate 只是"引用 Issuer",真正的 DNS 自动化能力来自 Issuer 的 solver 配置。
Secret 几乎是必不可少的,因为 cert-manager 要调用 DNS 提供商 API 去自动创建 TXT 记录,所以通常需要:
- API Token
- Access Key / Secret Key
- Service Account
- 认证 JSON
这些一般都放到 Kubernetes Secret 中,再由 Issuer 引用。
shell
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: example-issuer
spec:
acme:
email: user@example.com
server: https://acme-staging-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: example-issuer-account-key
solvers:
- dns01:
cloudDNS:
project: my-project
serviceAccountSecretRef:
name: prod-clouddns-svc-acct-secret
key: service-account.json
每个 Issuer 可以指定多个不同的 DNS01 challenge provider,甚至同一个 provider 也可以配置多个实例。
例如同时配置 Cloudflare 和 Route53,或者配置两个不同账号的 CloudDNS,或者一个 Issuer 管多个 zone,每个 zone 对应不同凭据。
实际中可以做如下设计:
- example.com 走 Cloudflare
- corp.internal.example.com 走 Route53
- test.example.net 走另一个 CloudDNS 项目
- 某些域名还可以单独用不同凭据账户
提示:这意味着 DNS01 在 cert-manager 中并不是"单一固定 provider",而是支持生产级别的多供应商、多账户、多域路由能力。本质上:一个 ACME Issuer 可以成为"多 DNS 平台统一入口"。
DNS01使用场景
在 cert-manager 的实际使用中,DNS01 是非常重要的一类 Challenge Solver,尤其在以下场景里几乎是首选:
- 申请通配符证书,如:*.example.com,这是 DNS01 最常见、最有价值的典型使用场景
- 没有公网 Ingress / 没有公网 Web 入口,如内网集群、私有网络环境
- 不想暴露 80 端口
- 多域名、多子域名自动化证书签发
- 复杂 DNS 拓扑,统一通过 DNS API 自动完成验证
设置 DNS01 判断
- 自检过程
cert-manager 在执行 DNS01 challenge前会验证正确的 DNS 记录是否存在。
即在 cert-manager 正式告诉 ACME CA"可以来验证了"之前,它会先自己检查一下对应的 TXT 记录是否已经真的能查到了。这样做的优点是:
- 避免 DNS 记录还没生效,就让 Let's Encrypt 去查
- 降低 challenge 失败率
- 减少无意义重试
- 查询过程
- 读取 Pod/容器里的
/etc/resolv.conf,拿到递归解析器(recursive nameserver) - 通过这些递归 DNS,找到目标域名对应的权威 DNS
- 再直接查询权威 DNS,确认 TXT 记录是否存在
默认情况下,cert-manager 将使用取自 /etc/resolv.conf 的递归 DNS 服务器查询权威名称服务器,随后直接向权威服务器发起查询以验证 DNS 记录。
提示:cert-manager 默认并不是只信任本地递归 DNS 的缓存结果,而是会尽量直接向权威源确认。
- 特殊情况
在某些环境里,默认直接查权威 DNS 反而不合适,例如:
场景 1:多个权威 nameserver 行为不一致,某些复杂 DNS 环境中,不同权威 DNS 返回结果可能临时不同
场景 2:split-horizon DNS,这是企业环境中很常见的情况,即:内网解析一个结果,外网解析另一个结果,如果不控制 cert-manager 自检使用的 DNS 服务器,可能导致:
- cert-manager 认为 TXT 已经存在
- 但 Let's Encrypt 实际看到的是另一套 DNS 视图
- 最终 challenge 失败
因此cert-manager 给出了禁用此行为的两个标志用于修改验证方式:--dns01-recursive-nameservers 由递归名称服务器的主机和端口组成的逗号分隔字符串,cert-manager 应查询该服务器。
--dns01-recursive-nameservers-only 强制 cert-manager 仅通过递归名称服务器进行验证。单启用此选项可能导致 DNS01 自检耗时增加,因为递归 DNS 有缓存。
用法示例:--dns01-recursive-nameservers-only --dns01-recursive-nameservers=8.8.8.8:53,1.1.1.1:53
若使用 cert-manager Helm chart,可通过 .Values.extraArgs 设置递归 DNS,或在执行 helm install/upgrade 命令时使用 --set :--set 'extraArgs={--dns01-recursive-nameservers-only,--dns01-recursive-nameservers=8.8.8.8:53\,1.1.1.1:53}
DNS01 提供商
ACME Issuer 支持多种不同的 DNS 提供商。以下是可用提供商列表、其 .yaml 配置,以及关于使用这些提供商时需注意的 Kubernetes 和提供商特定说明:
- ACMEDNS
- Akamai
- AzureDNS
- CloudFlare
- Route53
- DigitalOcean
- RFC2136
注意 :虽然都属于官方 "支持 provider" 列表里的提供商,但不代表配置统一,虽然都叫 dns01,但不同 provider 的字段完全不同,比如:
Cloudflare 用 API Token / API Key
Route53 用 Access Key / Secret Key / IAM
Google CloudDNS 用 service account JSON
RFC2136 用传统 DNS 动态更新方式
因此:DNS01 的通用框架是统一的,但 provider 的细节是各自独立的。
cert-manager 还支持通过外部 webhook 使用上述 DNS 提供商之外的供应商,具体可参考:Webhook 。
实践建议
DNS01 的最佳实践,更多取决于 DNS 环境,而不是 cert-manager YAML,很多 DNS01 问题不是 "YAML 写错",使用DNS01验证方式更多应该关注:
- TXT 记录是否成功配置
- API 凭据权限是否具备
- zone 判断是否正确
- DNS 传播速度
- 递归 DNS / 权威 DNS 是否一致
- split-horizon 导致外部 ACME 查不到
- CNAME 委托配置完整性
完整的DNS01使用逻辑链是:
- 创建 Certificate
- cert-manager 发现它引用了 ACME Issuer
- ACME CA 返回 DNS01 challenge
- cert-manager 根据 solvers.dns01 选择对应的 DNS Provider
- cert-manager 用配置好的 Secret 调用 DNS API
- 自动创建 _acme-challenge.<domain> 的 TXT 记录
- cert-manager 先做 self-check
- self-check 成功后,通知 ACME CA 来验证
- ACME CA 查询 TXT 成功
- CA 签发证书
- cert-manager 将证书写入 Secret
- 通常清理 challenge 期间创建的临时 TXT 记录