057.Kubernetes cert-manager ACME方案介绍

文章目录

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)签发的证书:

  1. 通常被客户端系统默认信任
  2. 浏览器默认认可
  3. 不需要额外自己分发根证书
  4. 证书通常是免费的
  5. 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 表示:

  1. 申请者在某个 ACME CA 上的一个账户
  2. cert-manager 会自动生成该账户的私钥
  3. 这个账户私钥会保存在 Kubernetes Secret 中
  4. 后续所有通过这个 Issuer 申请的证书,都是以这个 ACME 账户身份去操作的
  5. 所以 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 配置段的形式存在。

字段 作用 说明
email 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 配置文件。

注意

  1. 若指定配置文件但连接的 ACME 服务器尚未支持 ACME 配置文件扩展功能,cert-manager 将在 CertificateRequest 资源上报错。
  2. 若指定的配置文件未被 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.comb.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 条件。

提示:排序依据大致是:

  1. 精确域名匹配优先(dnsNames)
  2. 再看区域匹配(dnsZones)
  3. 同等级匹配下,标签更多者优先
  4. 仍相同时,按声明顺序优先

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)过程自动创建或使用以下资源:

  1. challenge 对应的临时 Pod(acmesolver)
  2. challenge 对应的 Service
  3. challenge 对应的 Ingress 或 HTTPRoute
  4. 把 challenge 路径指向 acmesolver Pod

所以需要了解 cert-manager 如何把 /.well-known/acme-challenge/... 这条请求,安全地暴露到公网,并路由到 solver Pod 。

提示 :cert-manager 不是自己创建一套入口系统,它依赖集群里已有的 Ingress 控制器Gateway API 资源 来完成 HTTP-01 challenge 暴露。

对于入口的创建主要有两种方式:基于 IngressHTTP01 solver 和基于 Gateway APIHTTP01 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 可能带来:

  1. 与现有注解冲突
  2. 与 controller 特定行为冲突
  3. 影响业务路由规则
  4. 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.metadatapodTemplate.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 的行为大致是:

  1. 发现 ACME HTTP-01 challenge
  2. 创建临时 HTTPRoute
  3. 把 /.well-known/acme-challenge/... 路由到 solver Service/Pod
  4. 让已有 Gateway 对外暴露
  5. challenge 完成后删除 HTTPRoute

要使用 Gateway API solver,需要满足两个条件:提示:Gateway API CRDs 最好在 cert-manager 启动前就存在。

  1. 当前集群已安装Gateway API CRDs,具体安装参考:Gateway API
  2. 必须启用 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 提供商进行示例和讲解。配置示例模板如下:

配置模板释义:

  1. 不是在 Certificate 上直接写 DNS Provider
  2. 而是在 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 对应不同凭据。

实际中可以做如下设计:

提示:这意味着 DNS01 在 cert-manager 中并不是"单一固定 provider",而是支持生产级别的多供应商、多账户、多域路由能力。本质上:一个 ACME Issuer 可以成为"多 DNS 平台统一入口"。

DNS01使用场景

在 cert-manager 的实际使用中,DNS01 是非常重要的一类 Challenge Solver,尤其在以下场景里几乎是首选:

  1. 申请通配符证书,如:*.example.com,这是 DNS01 最常见、最有价值的典型使用场景
  2. 没有公网 Ingress / 没有公网 Web 入口,如内网集群、私有网络环境
  3. 不想暴露 80 端口
  4. 多域名、多子域名自动化证书签发
  5. 复杂 DNS 拓扑,统一通过 DNS API 自动完成验证

设置 DNS01 判断

  • 自检过程
    cert-manager 在执行 DNS01 challenge前会验证正确的 DNS 记录是否存在。
    即在 cert-manager 正式告诉 ACME CA"可以来验证了"之前,它会先自己检查一下对应的 TXT 记录是否已经真的能查到了。这样做的优点是:
  • 避免 DNS 记录还没生效,就让 Let's Encrypt 去查
  • 降低 challenge 失败率
  • 减少无意义重试
  • 查询过程
  1. 读取 Pod/容器里的 /etc/resolv.conf ,拿到递归解析器(recursive nameserver)
  2. 通过这些递归 DNS,找到目标域名对应的权威 DNS
  3. 再直接查询权威 DNS,确认 TXT 记录是否存在

默认情况下,cert-manager 将使用取自 /etc/resolv.conf 的递归 DNS 服务器查询权威名称服务器,随后直接向权威服务器发起查询以验证 DNS 记录。

提示:cert-manager 默认并不是只信任本地递归 DNS 的缓存结果,而是会尽量直接向权威源确认。

  • 特殊情况
    在某些环境里,默认直接查权威 DNS 反而不合适,例如:
    场景 1:多个权威 nameserver 行为不一致,某些复杂 DNS 环境中,不同权威 DNS 返回结果可能临时不同
    场景 2:split-horizon DNS,这是企业环境中很常见的情况,即:内网解析一个结果,外网解析另一个结果,如果不控制 cert-manager 自检使用的 DNS 服务器,可能导致:
  1. cert-manager 认为 TXT 已经存在
  2. 但 Let's Encrypt 实际看到的是另一套 DNS 视图
  3. 最终 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
  • Google
  • 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使用逻辑链是:

  1. 创建 Certificate
  2. cert-manager 发现它引用了 ACME Issuer
  3. ACME CA 返回 DNS01 challenge
  4. cert-manager 根据 solvers.dns01 选择对应的 DNS Provider
  5. cert-manager 用配置好的 Secret 调用 DNS API
  6. 自动创建 _acme-challenge.<domain> 的 TXT 记录
  7. cert-manager 先做 self-check
  8. self-check 成功后,通知 ACME CA 来验证
  9. ACME CA 查询 TXT 成功
  10. CA 签发证书
  11. cert-manager 将证书写入 Secret
  12. 通常清理 challenge 期间创建的临时 TXT 记录
相关推荐
危笑ioi2 小时前
基于Kubeconfig实现K8s节点免密登录
云原生·容器·kubernetes
木二_2 小时前
058.Kubernetes cert-manager 申请证书及ingress注解介绍
云原生·容器·kubernetes·cert-manager·证书管理
kabu_Charlie3 小时前
使用Docker运行python程序
运维·docker·容器
骥龙3 小时前
第五篇:运行时安全——Docker沙箱与命令审批机制
安全·docker·容器
会算数的⑨4 小时前
演进——从查日志到 AI 自治,企业监控体系的变迁
人工智能·分布式·后端·微服务·云原生
南山十一少5 小时前
docker的安装及使用
运维·docker·容器
道清茗5 小时前
【Kubernetes知识点问答题】PriorityClass、HPA、Argo CD 与 CI/CD 流水线
ci/cd·容器·kubernetes
yuezhilangniao6 小时前
大白话AI运维K8S整体思路和相关名词-结合腾讯云
运维·人工智能·kubernetes
DJ斯特拉6 小时前
Docker基本使用
运维·docker·容器