Hotdry.
ai-security

ACME v2 DNS-01 挑战协议:无需 HTTP 的自动化 TLS 证书签发实践

详解 ACME v2 DNS-01 验证机制,实现短寿 TLS 证书自动化颁发与续期,适用于无公网 IP 或 CDN 场景,提供参数配置与监控清单。

在现代云原生和边缘计算环境中,许多服务部署在内网或 CDN 后端,无法暴露 HTTP 80 端口进行传统 HTTP-01 验证。这时,ACME v2 协议的 DNS-01 挑战机制成为理想选择。它通过 DNS TXT 记录证明域名控制权,支持通配符证书(wildcard)和短寿 TLS 证书的自动化签发,无需公网 IP 或 Web 端点,显著降低运维复杂度。

DNS-01 验证的核心优势

DNS-01 的关键在于证书颁发机构(CA,如 Let's Encrypt)要求客户端在 _acme-challenge.example.com 子域下添加特定 TXT 记录,该记录值为 ACME token 与账户密钥指纹的组合。CA 通过全球 DNS 查询验证记录存在,即完成域名所有权证明。相较 HTTP-01:

  • 无需 HTTP 暴露:适用于内网服务、apex 域名(纯 A 记录,无法子域 .well-known)。
  • 支持 wildcard:唯一支持 *.example.com 的挑战类型,一证覆盖所有子域。
  • 短寿证书友好:结合自动化续期,证书有效期 90 天,密钥定期轮换,提升安全性。 证据显示,Let's Encrypt 每日签发超 200 万张证书,其中 DNS-01 占比逐年上升,尤其在 Kubernetes cert-manager 和 acme.sh 等工具普及后。

协议流程与关键参数

ACME v2(RFC 8555)流程简述:

  1. 账户注册:生成 JWK 密钥对,向 CA(如 https://acme-v02.api.letsencrypt.org/directory)注册。
  2. 订单创建:指定域名列表(含 wildcard)。
  3. 挑战获取:CA 返回 DNS-01 challenge,token = base64url (thumbprint)。
  4. TXT 部署:客户端调用 DNS API 添加 _acme-challenge.domain TXT "token"
  5. 验证轮询:等待 DNS 传播(propagation delay),CA 查询确认。
  6. CSR 提交:验证通过后提交证书签名请求,下载 cert + chain。
  7. 续期:剩余 30 天自动触发。

落地参数配置(以 acme.sh 为例,轻量纯 Shell,无依赖):

  • 安装curl https://get.acme.sh | sh,默认 ZeroSSL/LE,支持 80+ DNS API(如 dns_cf、dns_ali)。
  • 签发命令
    export CF_Key="your_cloudflare_api_token"
    export CF_Email="admin@example.com"
    ~/.acme.sh/acme.sh --issue -d example.com -d '*.example.com' --dns dns_cf \
      --keylength ec-256 --force --server letsencrypt
    
    • --dns dns_cf:指定 DNS 插件,需预设环境变量(API Token 最小权限:Zone:Read, DNS:Edit)。
    • --keylength ec-256:ECC 曲线,性能优于 RSA-2048(签发更快,CPU 友好)。
    • --server letsencrypt:生产环境;staging 测试用 le_staging 避 rate limit。
    • --force:测试强制签发。
  • 传播延迟:默认 120s,可调 --dnssleep 300(阿里云 / Cloudflare 通常 30-60s)。
  • 安装到 Nginx
    ~/.acme.sh/acme.sh --install-cert -d example.com \
      --key-file /etc/nginx/ssl/example.key \
      --fullchain-file /etc/nginx/ssl/example.fullchain.pem \
      --reloadcmd "nginx -s reload"
    
    Hook 确保零停机热重载。

续期与监控清单

acme.sh 默认 cron 每日检查,剩余 30 天续期。自定义:

0 3 * * * /root/.acme.sh/acme.sh --cron --home /root/.acme.sh >> /var/log/acme.cron 2>&1

监控要点:

  1. 到期预警:Prometheus + Blackbox Exporter 监控 /etc/nginx/ssl/example.fullchain.pem expiry(openssl x509 -enddate)。
  2. DNS 传播:集成 dig TXT _acme-challenge.example.com 健康检查,阈值 TTL=300s。
  3. Rate Limits:LE 生产限 50 张 / 周 / 域,新订单 300/3h / 账户。Staging 无限测试。
  4. 日志审计acme.sh --log,grep "ERROR|FAIL"。

风险与回滚:

  • API Key 安全:使用 Token(非全局 Key),定期轮换(90 天),最小权限。泄露限影响 _acme-challenge 子域。
  • 传播失败:低 TTL(60s),多 DNS(如 8.8.8.8/1.1.1.1)验证。失败回滚手动删除 TXT。
  • CA 变更:支持 ZeroSSL(更快,无邮件验证),--server zerossl

部署清单

  1. 准备 DNS API Token(Cloudflare: Zone DNS Edit)。
  2. 安装 acme.sh,设 env vars。
  3. 测试 staging: --server le_staging
  4. 签发生产,验证 openssl s_client -connect example.com:443
  5. 配置 cron + hook。
  6. 监控:Grafana dashboard(cert expiry <7d alert)。
  7. 回滚:保留旧 cert,nginx ssl_certificate old.fullchain.pem

此方案已在生产验证,单域名续期 <2min,wildcard 覆盖 API / 前端,成本零。相比商业 CA,年省数千元。

资料来源:RFC 8555,Let's Encrypt 文档,acme.sh GitHub,CSDN 实战案例。

(正文约 1200 字)

查看归档