![Let's Encrypt 究竟使用哪条 DNS 记录来执行 DNS-01 挑战验证?](https://linux22.com/image/777719/Let's%20Encrypt%20%E7%A9%B6%E7%AB%9F%E4%BD%BF%E7%94%A8%E5%93%AA%E6%9D%A1%20DNS%20%E8%AE%B0%E5%BD%95%E6%9D%A5%E6%89%A7%E8%A1%8C%20DNS-01%20%E6%8C%91%E6%88%98%E9%AA%8C%E8%AF%81%EF%BC%9F.png)
我有一些 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
不同(因为在证书中,名称不会覆盖,因此证书需要同时列出两者,因此两者都需要验证,才能对两者有效)。TXT
example.net
example.net
*.example.com
example.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;
};