Certbot 的 RFC 2136 DNS 认证插件:基于 BIND 动态更新的 dns-01 挑战自动化实战 📅 发布时间:2026/9/20 1:37:23 👁 浏览次数: Certbot 的 RFC 2136 DNS 认证插件基于 BIND 动态更新的 dns-01 挑战自动化实战【免费下载链接】certbotCertbot is EFFs tool to obtain certs from Lets Encrypt and (optionally) auto-enable HTTPS on your server. It can also act as a client for any other CA that uses the ACME protocol.项目地址: https://gitcode.com/gh_mirrors/ce/certbot导读certbot-dns-rfc2136是 EFF 的 Certbot 项目提供的一个 DNS Authenticator 插件它通过 RFC 2136 Dynamic Updates 协议在 BIND 等支持动态更新的权威 DNS 服务器上自动创建、随后删除用于完成 ACMEdns-01挑战的 TXT 记录从而实现通配符证书的自动化签发与续期。阅读本文后你将掌握该插件的安装与命令行参数、凭证文件INI的完整配置字段、BIND 侧 TSIG 密钥与update-policy的配置方法以及多视图split-viewBIND 环境下的典型故障与两种解决方案并能结合仓库源码理解其 SOA 探测、TSIG 签名与增删记录的完整内部流程。一、插件定位与安装本插件属于 Certbot 生态中的 DNS 插件家族专门面向使用 BIND或任何实现 RFC 2136 动态更新的权威 DNS 服务器的用户。插件自身的description字段将其定位为Obtain certificates using a DNS TXT record (if you are using BIND for DNS).与 HTTP-01 等基于 80/443 端口的验证方式不同dns-01挑战通过写入 DNS TXT 记录来证明域名的控制权因此天然支持通配符证书例如*.example.com且不依赖对外暴露的 Web 服务。该插件正是通过 RFC 2136 规定的 DNS UPDATE 消息来完成 TXT 记录的写入与清理。从打包元数据可以看到插件通过 Certbot 插件入口点注册[project.entry-points.certbot.plugins] dns-rfc2136 certbot_dns_rfc2136._internal.dns_rfc2136:Authenticator插件默认不随 Certbot 安装需要单独安装。以 pip 为例pip install certbot-dns-rfc2136其运行时依赖在 setup.py 中声明dnspython2.6.1dnspython 提供 RFC 2136 消息构造与 TSIG 签名能力以及不低于插件版本号的acme与certbot包。项目要求 Python 3.10并在元数据中标记为 Production/Stable支持 Linux 环境。二、命令行参数插件的两个命令行参数定义在 dns_rfc2136.py 的add_parser_arguments方法中继承自基类 dns_common.py 的propagation-seconds参数并新增credentials参数参数含义必填默认值--dns-rfc2136-credentials指向 RFC 2136 凭证 INI 文件的路径是无--dns-rfc2136-propagation-seconds等待 DNS 记录传播后再请求 ACME 服务器验证 TXT 记录的秒数否60关于传播等待时间基类实现dns_common.py给出了明确的工程理由DNS 更新后本机可能比 ACME 服务器更早看到新记录因此插件选择直接睡眠propagation-seconds指定的秒数而不是尝试探测传播状态。若验证失败auth_hint还会提示用户增大该参数值。三、凭证文件配置使用插件前需要准备一个包含目标 DNS 服务器信息与 TSIG 密钥的 INI 凭证文件。插件通过_setup_credentials方法见 dns_rfc2136.py读取该文件要求包含name、secret、server三个必填项并支持可选的port、algorithm、sign_query。完整的示例凭证文件节选自模块文档路径可自行命名# Target DNS server (IPv4 or IPv6 address, not a hostname) dns_rfc2136_server 192.0.2.1 # Target DNS port dns_rfc2136_port 53 # TSIG key name dns_rfc2136_name keyname. # TSIG key secret dns_rfc2136_secret 4q4wM/2I180UXoMyN4INVhJNi8V9BCVjMw2mXgZw/CSuxUT8C7NKKFsAmKd7ak51vWKgSl12ib86oQRPkpDjg # TSIG key algorithm dns_rfc2136_algorithm HMAC-SHA512 # TSIG sign SOA query (optional, default: false) dns_rfc2136_sign_query false各字段说明dns_rfc2136_server目标 DNS 服务器地址。必须是 IPv4 或 IPv6 地址不能是主机名。_validate_credentials使用is_ipaddress校验若传入域名会抛出PluginError: The configured target DNS server (...) is not a valid IPv4 or IPv6 address. A hostname is not allowed.测试用例 dns_rfc2136_test.py 验证了这一行为IPv6 地址2001:db8:3333:4444:cccc:dddd:eeee:ffff也被测试覆盖。dns_rfc2136_port目标 DNS 端口默认为 53源码常量PORT 53。dns_rfc2136_nameTSIG 密钥名称。dns_rfc2136_secretTSIG 密钥的 Base64 编码秘密值。dns_rfc2136_algorithmTSIG 签名算法可选值见下表不填时默认为 HMAC-MD5。算法名大小写不敏感源码中统一.upper()处理但若填写了未知算法会直接抛出PluginError: Unknown algorithm: ...。算法dnspython 常量HMAC-MD5dns.tsig.HMAC_MD5默认HMAC-SHA1dns.tsig.HMAC_SHA1HMAC-SHA224dns.tsig.HMAC_SHA224HMAC-SHA256dns.tsig.HMAC_SHA256HMAC-SHA384dns.tsig.HMAC_SHA384HMAC-SHA512dns.tsig.HMAC_SHA512算法映射定义在源码的Authenticator.ALGORITHMS字典中dns_rfc2136.py。dns_rfc2136_sign_query可选默认false。设为true时插件在最初探测 SOA 记录的查询请求上也会附加 TSIG 签名详见下文多视图章节。凭证文件的路径可以在交互式提示中输入或通过--dns-rfc2136-credentials命令行参数传入。Certbot 会把该路径记录下来用于续期但不会保存文件内容。3.1 凭证文件的权限安全模块文档对 TSIG 密钥材料给出了明确的安全警告持有该文件内容的人可以添加、更新或删除目标 DNS 服务器上的任意记录能够让 Certbot 以这些凭证运行的攻击者甚至可以完成dns-01挑战为关联域名签发或吊销证书即使这些域名并非由该服务器托管。因此当 Certbot 检测到凭证文件可以被系统其他用户读取时会发出如下警告每次使用凭证时都会输出包括续期且无法通过配置静默Unsafe permissions on credentials configuration file解决方案是收紧文件权限例如chmod 600。四、使用示例4.1 为单个域名签发证书certbot certonly \ --dns-rfc2136 \ --dns-rfc2136-credentials ~/.secrets/certbot/rfc2136.ini \ -d example.com4.2 为多个域名签发一张证书certbot certonly \ --dns-rfc2136 \ --dns-rfc2136-credentials ~/.secrets/certbot/rfc2136.ini \ -d example.com \ -d www.example.com4.3 自定义 DNS 传播等待时间certbot certonly \ --dns-rfc2136 \ --dns-rfc2136-credentials ~/.secrets/certbot/rfc2136.ini \ --dns-rfc2136-propagation-seconds 30 \ -d example.com在perform阶段插件会打印Waiting N seconds for DNS changes to propagate并休眠对应秒数然后才向 ACME 服务器返回挑战响应见 dns_common.py。五、BIND 服务端配置5.1 生成 TSIG 密钥使用 BIND 自带的tsig-keygen工具生成 SHA-512 的 TSIG 密钥tsig-keygen -a HMAC-SHA512 keyname.注意BIND 9.10.0 之前的版本需要改用dnssec-keygen生成 TSIG 密钥。应尽量使用 DNS 服务器支持的最强算法。5.2 授权动态更新在 BIND 配置中声明密钥并通过update-policy将密钥权限严格限定为仅可增删_acme-challenge.example.com.的 TXT 记录key keyname. { algorithm hmac-sha512; secret 4q4wM/2I180UXoMyN4INVhJNi8V9BCVjMw2mXgZw/CSuxUT8C7NKKFsAmKd7ak51vWKgSl12ib86oQRPkpDjg; }; zone example.com. IN { type master; file named.example.com; update-policy { grant keyname. name _acme-challenge.example.com. txt; }; };这份配置遵循最小权限原则TSIG 密钥只能操作_acme-challenge.example.com.这一个主机名的 TXT 记录仅够完成dns-01挑战。如果 BIND 版本不支持update-policy指令可以退而使用安全性较弱的allow-update指令。六、BIND 多视图split-view场景的故障与解决如果 BIND 启用了多个视图view插件可能报错Unable to determine base domain for _acme-challenge.example.com6.1 故障原因该错误发生在插件无法联系到区域的权威名称服务器时。判定权威的依据是响应中设置了 AAAuthoritative Answer权威应答标志位。一个典型的多视图配置包含 external 与 internal 两个视图。若区域只存在于 external 视图而凭证中的dns_rfc2136_server指向本机如 127.0.0.1BIND 的match-clients视图选择规则会把 Certbot 的查询路由到 internal 视图internal 视图没有该区域因此响应不会带 AA 标志插件便无法确认权威区域最终抛出上述错误。6.2 解决方案一使用 in-view 复用区域将区域逻辑上放入 Certbot 所查询的那个视图。使用in-view区域选项后区域在两个视图中可见且内容完全一致key keyname. { algorithm hmac-sha512; secret 4q4wM/2I180UXoMyN4INVhJNi8V9BCVjMw2mXgZw/CSuxUT8C7NKKFsAmKd7ak51vWKgSl12ib86oQRPkpDjg; }; // adjust internal-addresses to suit your needs acl internal-address { 127.0.0.0/8; 10.0.0.0/8; 192.168.0.0/16; 172.16.0.0/12; }; view external { match-clients { !internal-addresses; any; }; zone example.com. IN { type master; file named.example.com; update-policy { grant keyname. name _acme-challenge.example.com. txt; }; }; }; view internal { zone example.com. IN { in-view external; }; };注意BIND 视图中顺序很重要in-view所引用的视图必须定义在其之前不能引用后面才定义的视图。6.3 解决方案二签名 SOA 查询并按密钥匹配视图在凭证文件中设置dns_rfc2136_sign_query true然后在 external 视图的match-clients中增加该密钥。所有用此密钥签名的查询无论来源 IP 如何都会被定向到 external 视图key keyname. { algorithm hmac-sha512; secret 4q4wM/2I180UXoMyN4INVhJNi8V9BCVjMw2mXgZw/CSuxUT8C7NKKFsAmKd7ak51vWKgSl12ib86oQRPkpDjg; }; // adjust internal-addresses to suit your needs acl internal-address { 127.0.0.0/8; 10.0.0.0/8; 192.168.0.0/16; 172.16.0.0/12; }; acl certbot-keys { key keyname.; } view external { match-clients { acl certbot-keys; !internal-addresses; any; }; zone example.com. IN { type master; file named.example.com; update-policy { grant keyname. name _acme-challenge.example.com. txt; }; }; };七、源码级原理一次 dns-01 挑战的完整链路理解内部实现有助于排查问题。插件核心代码集中在 dns_rfc2136.py由Authenticator对外门面与_RFC2136ClientDNS 通信封装两个类组成。7.1 挑战执行与清理Authenticator继承自 DNSAuthenticator基类perform为每个挑战计算验证域名如_acme-challenge.example.com与验证值随后回调子类的_perform验证失败时cleanup也会兜底调用_cleanup清理记录def _perform(self, _domain, validation_name, validation): self._get_rfc2136_client().add_txt_record(validation_name, validation, self.ttl) def _cleanup(self, _domain, validation_name, validation): self._get_rfc2136_client().del_txt_record(validation_name, validation)新增的 TXT 记录 TTL 固定为 120 秒类属性ttl 120。7.2 SOA 权威区域探测在写入记录之前客户端必须先确认记录所属的权威区域。_find_domain会基于记录名逐级生成候选域名复用dns_common.base_domain_name_guesses例如从_acme-challenge.foo.example.com依次尝试到example.com对每个候选发起 SOA 查询dns_rfc2136.py查询时关闭 RDRecursion Desired递归标志并要求响应设置 AA 标志、且 answer 中包含对应 SOA 记录才认定找到权威区域默认先走 TCP失败如OSError或超时时自动回退到 UDP测试 dns_rfc2136_test.py 验证了该回退路径若sign_query为 trueSOA 查询本身也会附加 TSIG 签名dns_rfc2136_test.py 验证了use_tsig的调用全部候选都无权威 SOA 时抛出Unable to determine base domain ...正是第六节多视图场景的错误来源。7.3 TXT 记录的增删消息add_txt_record/del_txt_record通过 dnspython 构造 DNS UPDATE 消息将记录名相对权威区域名做relativize得到相对名称用密钥环dns.tsigkeyring.from_text和所选算法创建dns.update.Update自动对消息签名经 TCP 发送到目标服务器默认超时 45 秒常量DEFAULT_NETWORK_TIMEOUT依据响应 RCODE 判定结果NOERROR视为成功仅记 debug 日志其他 RCODE如NXDOMAIN或任何通信异常都会被包装为PluginError抛出。测试用例dns_rfc2136_test.py可佐证消息内容新增时为bar. 42 IN TXT baz删除时为bar. 0 NONE TXT baz且无论正常响应、服务器错误还是网络异常最终都以PluginError形式暴露给 Certbot 上层。7.4 凭证校验_validate_credentials在每次使用凭证时执行两项校验server 必须是合法 IPv4/IPv6 地址若填写了 algorithm则必须在ALGORITHMS白名单内。对应的失败与成功路径均有单元测试覆盖dns_rfc2136_test.py。八、小结certbot-dns-rfc2136插件以最小的配置代价把 BIND 的 RFC 2136 动态更新能力接入 Certbot 的dns-01挑战流程一条--dns-rfc2136指令 一份含 TSIG 密钥的 INI 凭证文件即可实现通配符证书的自动签发与续期。生产环境落地时请务必牢记三点凭证文件权限收紧chmod 600、BIND 侧用update-policy将密钥权限限定到_acme-challengeTXT 记录、以及多视图环境下优先采用in-view或密钥级match-clients方案保证 SOA 探测可达。相关实现细节可继续阅读 dns_rfc2136.py 及其测试文件。【免费下载链接】certbotCertbot is EFFs tool to obtain certs from Lets Encrypt and (optionally) auto-enable HTTPS on your server. It can also act as a client for any other CA that uses the ACME protocol.项目地址: https://gitcode.com/gh_mirrors/ce/certbot创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考