Let's Encrypt 究竟使用哪条 DNS 记录来执行 DNS-01 挑战验证?

Let's Encrypt 究竟使用哪条 DNS 记录来执行 DNS-01 挑战验证?

我有一些 SMTP 服务器(以及其他服务器)位于 NAT 后面,无法为 HTTP 配置 DNAT 或为它们配置反向代理。这意味着 HTTP-01 和 TLS-ALPN-01 不可用,因此DNS-01 挑战对于这种情况来说,这是一个自然的选择。

对于其他系统,我希望有一个通配符证书,同样可以仅使用 DNS-01 质询进行验证。

所以我使用certbot-dns-rfc2136插件配置了一切,根据文档。我生成了一个密钥,在 BIND 中配置了一个更新策略以允许它更新记录_acme-challenge.example.net。(实际上我有一个通用策略,允许密钥<name>.example.net更新任何具有相同名称的记录,因此该密钥可能不仅更新TXT记录。)

以下脚本按预期工作(创建记录):

nsupdate -k dns-01.key -v << END
server 192.0.2.1
zone example.net
update add _acme-challenge.example.net 60 TXT "abrakadabra"
send
END

(密钥_acme-challenge.example.net存储在文件中dns-01.key)。

然后我删除了这个 abrakadabra 记录并将这个密钥放入插件凭证文件中。

dns_rfc2136_server = 192.0.2.1
dns_rfc2136_port = 53
dns_rfc2136_name = _acme-challenge.example.net
dns_rfc2136_secret = <some base64 string>
dns_rfc2136_algorithm = HMAC-SHA256

通配符的 DNS-01 质询*.example.net成功完成:

# certbot certonly --dns-rfc2136 --dns-rfc2136-credentials /path/to/credentials/file.ini -d *.example.net --test-cert
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator dns-rfc2136, Installer None
Requesting a certificate for *.example.net

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/example.net/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/example.net/privkey.pem
   Your certificate will expire on 2022-09-05. To obtain a new or
   tweaked version of this certificate in the future, simply run
   certbot again. To non-interactively renew *all* of your
   certificates, run "certbot renew"

如果我为单个根域(... -d example.net)申请证书,它也能起作用。

问题是,相同的凭据不适用于子域名(... -d www.example.net):

# certbot certonly --dns-rfc2136 --dns-rfc2136-credentials /path/to/credentials/file.ini -d www.example.net --test-cert
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator dns-rfc2136, Installer None
Requesting a certificate for www.example.net
Performing the following challenges:
dns-01 challenge for www.example.net
Cleaning up challenges
Encountered exception during recovery: certbot.errors.PluginError: Received response from server: REFUSED
Received response from server: REFUSED

检查调试日志:

...
2022-06-07 11:35:38,275:DEBUG:certbot_dns_rfc2136._internal.dns_rfc2136:No authoritative SOA record found for _acme-challenge.www.example.net
2022-06-07 11:35:38,276:DEBUG:certbot_dns_rfc2136._internal.dns_rfc2136:No authoritative SOA record found for www.example.net
2022-06-07 11:35:38,277:DEBUG:certbot_dns_rfc2136._internal.dns_rfc2136:Received authoritative SOA response for example.net
2022-06-07 11:35:38,279:ERROR:certbot._internal.error_handler:Encountered exception during recovery: certbot.errors.PluginError: Received response from server: REFUSED
2022-06-07 11:35:38,280:DEBUG:certbot._internal.log:Exiting abnormally:
Traceback (most recent call last):
...

我还用另一个 DNS 密钥测试了同样的事情,该密钥被允许在区域内创建任何记录。相同的命令对此密钥起作用,这只能意味着插件certbot-dns-rfc2136不会尝试创建_acme-challenge.example.net,而是使用另一条记录_acme-challenge.www.example.net。我在等待 DNS 传播时通过 DNS 请求确认了这一点,并且还通过查看 DNS 服务器日志确认了这一点。在这种情况下,拒绝是意料之中的,因为前一个受限制的密钥只允许更改_acme-challenge.example.net而不允许更改_acme-challenge.www.example.net

但为什么它使用了我意想不到的记录名称?文档中哪里涵盖了这一点?我的理解是_acme-challenge.example.net应该将其用于验证example.net*.example.net对于<name>.example.net任何<name>,这在文档页面的第二个使用示例中给出。我遗漏了什么吗?

答案1

Let's Encrypt 究竟使用哪条 DNS 记录来执行 DNS-01 挑战验证?

dns-01验证在 ACME 的 RFC 中有详细说明,又名RFC 8555“自动证书管理环境 (ACME)”

它指出:

8.4. DNS 质询

当正在验证的标识符是域名时,客户端可以通过提供包含特定验证域名的指定值的 TXT 资源记录来证明对该域的控制。

提供给 DNS 的记录包含此摘要的 base64url 编码。客户端通过将标签“_acme-challenge”添加到要验证的域名来构造验证域名,然后在
该名称下提供带有摘要值的 TXT 记录。例如,如果要验证的域名是
“www.example.org”,则客户端将提供以下 DNS
记录:

_acme-challenge.www.example.org.300 IN TXT“gfj9Xq...Rg85nM”

所有公共 CA 都遵循 CABForum 指南,该指南还指出:

3.2.2.4.7 DNS 变更

通过确认 DNS CNAME、TXT 或 CAA 记录中是否存在随机值或请求令牌来确认申请人对 FQDN 的控制,该记录适用于 1) 授权域名;或 2) 带有以下划线字符开头的域标签前缀的授权域名。

并添加了以下重要信息:

注意:使用此方法验证 FQDN 后,CA 还可以为以已验证 FQDN 的所有域标签结尾的其他 FQDN 颁发证书。此方法适用于验证通配符域名。

Let's Encrypt 自己的文档位于https://letsencrypt.org/docs/challenge-types/

DNS-01 挑战

此挑战要求您通过在该域名下的 TXT 记录中放置特定值来证明您控制该域名的 DNS。

回到你的问题,你说:

但为什么它使用了一个我没有想到的记录名称?

如果您尝试验证名称www.example.net,则根据以上所有内容,TXT记录必须处于开启状态_acme-challenge.www.example.net

我的理解是,_acme-challenge.example.net 应该用于验证 example.net、*.example.net 和 .example.net,这是在文档页面上的第二个使用示例中给出的。

首先,您说的是哪个文档页面?其次,不是,一般来说,每个名称都必须有自己的验证令牌。通配符*.example.net还需要一个特定的单独 TXT 记录,该记录在名称上,但其值与名称上的记录example.net不同(因为在证书中,名称不会覆盖,因此证书需要同时列出两者,因此两者都需要验证,才能对两者有效)。TXTexample.netexample.net*.example.comexample.net

答案2

Patrick 提供了很好的背景信息,但作为对问题的更直接的看法:

certbot 文档中的示例配置有以下更新策略:

 update-policy {
      grant keyname. name _acme-challenge.example.com. txt;
 };

这使得 DNS-01 质询能够确切地名字example.com

但是,在您的命令行中您指定了-d www.example.net

如果您想要证书,则www.example.com需要调整示例策略以反映这一点。
例如,您想要两者example.com,并且www.example.com(很可能)您需要在策略中允许两者。

例如这样的:

 update-policy {
      grant keyname. name _acme-challenge.example.com. txt;
      grant keyname. name _acme-challenge.www.example.com. txt;
 };

相关内容