Skip to content

赛博堡垒的绝对通行证:Cert-manager 自动化签发泛域名证书 (GitOps 版)

🌱 创建: 2026/04/26 ⏱️ 更新: 2026/05/22

This content is not available in your language yet.

📖 认识自动化签证官:为什么拒绝手动管理证书?

Section titled “📖 认识自动化签证官:为什么拒绝手动管理证书?”

在 100% 自动化的赛博堡垒中,任何手动的证书申请与替换操作,都是对 GitOps 理念的亵渎。我们需要引入 cert-manager 作为全自动的“赛博签证官”,通过高级的 DNS 验证机制,优雅且无感地为整个集群拿下通用的泛域名 HTTPS 证书

📜 核心能力白皮书 (Core Capabilities)

Section titled “📜 核心能力白皮书 (Core Capabilities)”

🛡️ 颁发机构的无缝代理 (Issuer Abstraction) 将外部 CA 机构(如 Let’s Encrypt)的复杂 API 抽象为 Kubernetes 原生资源,实现声明式的代码管理。

🤖 7x24 小时自动续期 (Automated Renewal) 在证书过期前 30 天自动触发无感续期流程,实现“一次部署,终身加密”。

🌍 突破封锁的 DNS-01 验证 (DNS-01 Challenge) 无需你在公网暴露内网的 80/443 端口,直接通过 API 临时修改外部 DNS 记录来证明域名所有权。这是内网 Homelab 环境申请泛域名证书的最优解。


在让签证官入驻集群之前,请确保你已经准备好了以下赛博资产:

  • 自动化基础设施:集群中已经安装并配置好 ArgoCD(我们将继续使用纯正的 GitOps 方式下发图纸)。
  • 域名资产托管:拥有一个属于自己的域名,并且该域名的 DNS 解析必须已经托管在 Cloudflare

    💡 本期工程演示说明: 在接下来的所有代码示例中,我们将以 k3s.besthomelab.tech 这个域名为例。 请各位包工头在抄作业时,务必注意寻找带有 ⚠️ 替换为你的真实域名 的注释,并将其替换为你自己的专属资产。


🎬 施工演示录像 (Video Walk-through)

Section titled “🎬 施工演示录像 (Video Walk-through)”
正在嗅探浏览器语言并加载赛博录像...

🔨 赛博流水线施工 (GitOps Workflow)

Section titled “🔨 赛博流水线施工 (GitOps Workflow)”

依托于我们已经建成的总控图纸库,所有的安装与配置都已在 Git 中模块化。

👉 情报中心:besthomelab/k3s-homelab-gitops 图纸库

我们将通过 ArgoCD 拉起 Cert-manager。这份合同指示监工从官方拉取骨架,从我们的 Git 拉取参数。

💡 如何精准截获最新版本号?

永远不要在图纸里抄写过期的版本号!在你的终端执行以下“侦查指令”,强制刷新官方情报网,并精准截获最新的前 5 个版本记录:

Terminal window
helm repo add jetstack https://charts.jetstack.io && helm repo update
helm search repo jetstack/cert-manager --versions | head -n 5

(提取输出结果中第一行的 CHART VERSION,将其更新至下方图纸的 targetRevision 字段中)

👉 获取 Application 图纸:bootstrap/cert-manager-app.yaml

为了让 Cert-manager 能够自主安装并管理其所需的 CRD(自定义资源定义),我们已经在 Git 仓库中锁定了必要参数。

👉 获取核心参数:infrastructure/cert-manager/values.yaml

步骤 3:锻造 Cloudflare 门禁卡 (Sealed Secret)

Section titled “步骤 3:锻造 Cloudflare 门禁卡 (Sealed Secret)”

签证官(Cert-manager)需要 Cloudflare 的 API 令牌才能去帮你修改 DNS 记录。在 GitOps 纪元,我们绝不允许任何明文凭证流入公开或私有的 Git 仓库

  1. 潜入 Cloudflare 提取 Token

    • 登录 Cloudflare 控制台,点击右上角头像进入 My Profile -> API Tokens
    • 点击 Create Token,拉到底部选择 Create Custom Token
    • 精准授权(权限给多了一旦泄露就是毁灭性打击):
      • Zone - Zone - Read
      • Zone - DNS - Edit
    • 锁定领空:在 Zone Resources 选项中,指定 Include - Specific zone - 你的域名 (例如 besthomelab.tech)
    • 点击生成,复制并妥善保管那串 API Token。
  2. 单向加密处理 (kubeseal)

    • 💡 前置条件:如果你还没在集群中部署加解密控制器,请务必先完成 纯正 GitOps 密码管理:Sealed Secrets 的前置基建。

    • 找到图纸库中的 01-cloudflare-secret.template.yaml 文件,将刚才获取的 Token 填入 api-token 字段。 👉 获取加密模版:infrastructure/cert-manager/01-cloudflare-secret.template.yaml

    • 打开你的终端,进入你克隆到本地的赛博堡垒工程目录,并执行加密指令:

      Terminal window
      # 1. 深入你本地克隆的基础设施目录 (请替换为你自己的实际路径)
      cd <你的本地仓库根目录>/k3s-homelab-gitops/infrastructure/cert-manager
      # 2. 召唤 kubeseal,将明文模版单向加密为安全的生产图纸
      kubeseal --format=yaml < 01-cloudflare-secret.template.yaml > 01-cloudflare-secret.yaml
  3. ⚠️ 销毁明文痕迹

    • 加密完成后,新生成的 01-cloudflare-secret.yaml 里的数据已经变成了只有你的 K3s 集群才能解开的乱码,可以放心推送到 GitHub。
    • 最高安全警告: 绝对不要执行 git add 01-cloudflare-secret.template.yaml!建议将其内容清空还原为 REPLACE_ME,或确保你的 .gitignore 中已经拦截了 *.template.yaml 格式的文件。

🛠️ 架构师排障指南:验证门禁卡状态

当 ArgoCD 把加密图纸下发给集群后,底层的 Sealed Secrets 控制器会自动将其“拆封”还原。日后如果发现证书迟迟签发不下来,第一时间用以下指令去施工现场核实 Secret 是否被成功还原:

Terminal window
# 检查 cert-manager 园区内是否成功生成了原生的 Secret
kubectl get secret cloudflare-api-token -n cert-manager
# 如果没找到,或者想看具体的解密报错(比如集群公钥不匹配),执行以下指令查看报错日志:
kubectl describe sealedsecret cloudflare-api-token -n cert-manager
kubectl get secret cloudflare-api-token -n cert-manager -o jsonpath='{.data.api-token}' | base64 -d

最后,我们定义签发机构与最终的泛域名证书请求。注意:这张证书将被存放在 traefik 命名空间中,供traefik的城门网关直接调用。 官方文档

👉 获取签发图纸:infrastructure/cert-manager/02-cluster-issuer-and-cert.yaml

👉 如何安全地测试并申请 Let’s Encrypt 泛域名证书


👀 竣工验收:实时监控签发进度

Section titled “👀 竣工验收:实时监控签发进度”

将包含上述 SecretClusterIssuerCertificate 的赛博图纸 Commit 并推送到 GitHub。ArgoCD 总监工察觉到更新后,会自动将它们下发到施工现场进行部署。

此时,掏出你的终端,使用以下指令实时盯盘:

Terminal window
# 持续监听 traefik 命名空间下的证书状态
kubectl get certificate -n traefik -w

当看到 READY 的状态从 False 最终转变为刺眼的 True 时,恭喜你!你的赛博堡垒已经成功拿下了最高权限的泛域名 TLS 通行证!


🔍 高阶巡检:验证全自动续订机制 (Renewal Time)

Section titled “🔍 高阶巡检:验证全自动续订机制 (Renewal Time)”

众所周知,Let’s Encrypt 签发的免费证书有效期只有 90 天。难道我们以后每隔三个月都要手动操作一次吗?当然不是!自动化,才是咱们赛博堡垒的灵魂。

口说无凭,我们直接查看刚才生成的证书底层细节,看看“签证官”Cert-manager 是如何安排续期计划的:

Terminal window
# 查看证书详细信息
kubectl describe certificate k3s-besthomelab-tech-tls -n traefik

在输出的日志中,直接将目光锁定到 Status 区域最底部的这几个时间字段(这是我现场抓取的真实数据):

Status:
Conditions:
Last Transition Time: 2026-04-28T11:05:48Z
Message: Certificate is up to date and has not expired
Reason: Ready
Status: True
Not Before: 2026-04-28T10:07:13Z # 证书生效起始时间
Not After: 2026-07-27T10:07:12Z # 证书最终过期时间
Renewal Time: 2026-06-27T10:07:12Z # 自动续订触发时间
  • Not After (死亡倒计时):可以看到,这张证书原定于 7 月 27 日过期,满打满算 90 天。
  • Renewal Time (自启闹钟):这就是 Cert-manager 设定的“苏醒时间”。在证书过期前整整 30 天(6 月 27 日),它就会自动在后台重启 DNS 验证流程,续签新证书。

最优雅的是,由于 Traefik 网关具备动态监听 (Hot Reload) 能力,它一旦发现底层 Secret 更新,会瞬间完成证书热重载。整个过程不需要重启任何服务,实现真正的零宕机无感续期。

只要有这套机制兜底,咱们赛博堡垒的 HTTPS 绿锁将永远在线!


🛠️ 排障指南:证书签发链路侦查

Section titled “🛠️ 排障指南:证书签发链路侦查”

如果你盯着屏幕看了 5 分钟,READY 依然死死卡在 False,不要慌张。

在 Kubernetes 中,Cert-manager 的签发是一个严格的**“链式反应”**:Certificate (证书声明) -> CertificateRequest (请求) -> Order (订单) -> Challenge (DNS 挑战验证)。 排查问题必须顺藤摸瓜,逐级深挖底层的报错日志。

按照以下“骇客侦查”指令依次执行,直到找出真凶:

1. 查证书事件 (Level 1) 看看最表层的报错是什么。

Terminal window
kubectl describe certificate k3s-besthomelab-tech-tls -n traefik
# 重点看最下面 Events 里的描述。

2. 查 DNS 挑战订单 (Level 2 - 90% 的案发现场) 如果在 Level 1 发现是验证卡住了,直接去查正在排队的 Challenge。

Terminal window
# 查看是否有挂起的 Challenge
kubectl get challenges -A
# 提取挂起的 Challenge 名称,并查看详细处决日志
kubectl describe challenge <你的-challenge-名称> -n traefik

⚠️ 致命报错拦截库 (官方避坑指南):

  • 🛑 白嫖党末日 (Generic API Error):如果报错提示 POST "/zones/<id>/dns_records generic error",请检查你的域名是否为 .cf, .ga, .gq, .ml.tk。Cloudflare 官方已经物理封杀了这批免费域名的 API 修改权限,放弃挣扎,去买个正规域名吧。
  • 🛑 视野盲区 (Zone.List Permission Error):如果报错提示 requires permission 'com.cloudflare.api.account.zone.list'Reason: Found no Zones for domain _acme-challenge.k3s.besthomelab.tech. (neither in the sub-domain nor in the SLD) please make sure your domain-entries in the config are correct and the API key is correctly setup with Zone.read rights,说明你在第一步配置 Token 时,漏选了 Zone - Zone - Read 权限,导致签证官无权读取你的域名列表。
  • 🛑 身份伪造 (Authentication Error):说明你用 kubeseal 加密的 Token 不对,或者集群公钥匹配失败导致密码箱未能被正确拆封。
  • 🛑 内网 DNS 幻象 (Self-Check 失败):这是 Homelab 玩家最容易踩的巨坑!你在 Cloudflare 后台明明看到了 TXT 记录,外网也能查到,但 K3s 就是一直卡在 Waiting for dns-01 challenge propagation
    • 案发原因:Cert-manager 默认会先使用集群内部的 DNS (CoreDNS) 或你家路由 (OPNsense/OpenWrt) 进行自检。如果你的路由器开启了诸如 filterwin2k 的拦截选项,或者丢弃了 SOA 记录,签证官就会彻底“眼瞎”。
    • 破局方案:在 Git 仓库的 infrastructure/cert-manager/values.yaml 中追加以下硬核参数,强制让它通过外网(如 1.1.1.1)进行自检:
      extraArgs:
      - --dns01-recursive-nameservers-only
      - --dns01-recursive-nameservers=1.1.1.1:53,8.8.8.8:53
  • 🛑 53 端口劫持死局 (高阶网络黑洞)
    • 报错现象:即使你已经加了上面强制指定 1.1.1.1:53 的参数,证书依然死死卡在 Waiting for propagation。执行kubectl logs deploy/cert-manager -n cert-manager --tail=100 提示报错 :“propagation check failed” err=“DNS record for “k3s.besthomelab.tech” not yet propagated” logger=“cert-manager.controller” resource_name=“k3s-besthomelab-tech-tls-1-2079479554-3318087665” resource_namespace=“traefik” resource_kind=“Challenge” resource_version=“v1” dnsName=“k3s.besthomelab.tech” type=“DNS-01”
    • 核心排查法 (真伪对比)
      1. 查源头:登录 Cloudflare 网页后台,查看该域名的 DNS 记录,发现 _acme-challenge 的 TXT 记录已经成功生成
      2. 查本地:在你的电脑或集群节点上执行终端命令:dig _acme-challenge.你的域名 TXT @1.1.1.1(例如dig -t txt _acme-challenge.k3s.besthomelab.tech @1.1.1.1 +short)。如果你发现查不到任何结果,或者查出来的是旧的缓存记录,说明你的 DNS 请求被劫持了!
    • 案发原因:你家网络里的“保安”(比如 OpenClash、AdGuard Home 的 DNS 重定向,或 OPNsense 的强制 53 端口转发规则)无差别地把所有通往外部 53 端口的请求全部截胡,转交给了本地的缓存 DNS 处理。本地 DNS 压根不知道 CF 上刚刚生成了新记录。
    • 破局方案 (赛博穿透):不要硬刚 53 端口,改走非标准端口。将 values.yaml 中的自检服务器改为支持非 53 端口的公共 DNS(如 OpenDNS 的 5353 端口),完美绕过国内运营商和本地网关的无差别劫持:
      extraArgs:
      - --dns01-recursive-nameservers-only
      # 放弃 53 端口,改用 OpenDNS 的 5353 端口进行穿透自检
      - --dns01-recursive-nameservers=208.67.222.222:5353,208.67.220.220:5353

3. 查签证官系统日志 (Level 3 - 终极手段) 如果上面都查不出原因,直接调取 Cert-manager 核心控制器的底层运行日志:

Terminal window
kubectl logs deploy/cert-manager -n cert-manager --tail=100

Last updated: