BIND9 DNS Challenge自动配置Letsencrypt通配符(Wildcard)HTTPS证书

不得不说Letsencrypt的免费SSL数字证书确实大力促进了加密HTTP(HTTPS)的普及,使用HTTPS的好处自然有很多,比如防止登录凭据等敏感信息被第三方窃取、防止电信运营商的ISP劫持等,Google Chrome和Mozilla Firefox也在逐步将明文HTTP标识为不安全,这也在一定程度上加快了HTTPS的推广。

但是由于一些条件限制,国内的HTTPS推广普及一直不温不火,虽然大部分主流网站已经采用了HTTPS,但是大量的中小型网站、政府门户依然使用的是明文HTTP,给个人信息带来安全隐患,不使用HTTPS的理由总是有千百种,比如虚拟主机限制、CDN限制、老旧浏览器兼容、服务器资源消耗等,但是我们不能因为这些缘故而放弃HTTPS带来的优势,从长远来看HTTPS的全面普及是势不可挡的。

今天我要介绍的就是使用Letsencrypt免费证书的服务为网站提供HTTPS连接,当然这类文章网上也有很多,尤其是各种便捷自动化部署工具的出现使得专门写一篇文章介绍显得没有必要,但是我今天介绍的是今年Letsencrypt刚推出的通配符(Wildcard)证书的申请。什么是通配符证书,通配符证书也称为泛域名证书,一般情况下我们申请的证书可能只包含两个域名比如主域名wangye.org和子域名www.wangye.org,这对于大部分网站用户来说已经足够,但是需要注意的是这种证书的缺点就是需要把所有可能的子域名加入证书域名别名列表中,否则一旦你开展新业务,比如启用域名mail.wangye.org,这时候使用不包含该域名的证书将会导致浏览器提醒安全风险,甚至拒绝访问。难不成重新申请证书再把mail.wangye.org加入?又或者单独为mail.wangye.org配置证书?这些都是解决方案,不过这可能带来的是管理上麻烦和配置问题,如果一开始我们申请的证书能够包含任意的子域名那就一劳永逸了,是的,通配符证书正是为了解决这个问题而诞生的,我看了一些收费SSL证书,对于DV型证书,支持通配符的证书价格甚至比普通证书要高,这一点可以看出Letsencrypt开放通配符证书的申请还是很有良心的。

本文仅作备忘笔记,内容为事后回忆,可能会有所出入,仅供参考,配置通配符证书的第一步需要确定你的域名权威DNS的动态更新权限,对于一些第三方服务这个是通过API提供的,因为各家配置不同本文不作叙述,关于域名权威DNS可以通过WHOIS查询到,本文介绍的是使用BIND9自建服务器的配置,操作具体涉及到三台服务器分别是域名DNS服务器、网站主机服务器、Letsencrypt证书签发服务器,其中DNS服务器安装的是最新版BIND9软件。

1. 配置DNS服务器

首先使用apt更新系统环境:

sudo apt-get update
sudo apt-get upgrade

使用下面的命令生成SHA512 TSIG密钥,此操作可以在home目录下,不需要root权限:

dnssec-keygen -a HMAC-SHA512 -b 512 -n HOST keyname.

(注意keyname.可以任意定义,但是我查阅资料发现名字基本上都有最后那个点)

上面的命令将创建两个形如Kkeyname.+165+XXXXX.keyKkeyname.+165+XXXXX.private文件,这两个文件都是可以直接用cat命令显示出来的,我们需要的是保存于Kkeyname.+165+XXXXX.private的key字段数据,使用grep命令抓取:

grep -e Key Kkeyname.+165+XXXXX.private | cut -d' ' -f2-

这里将生成形如以下的key字符串(每次命令生成的字符串是不同的,这里仅举例说明):

i/KJzuKiYGbWlZ7x3qR6OxXjEX3L8XdeOy90F3aFYtRaGJp/8Ig4HmP/WfG6WsFqoe+a31emvJWeapxmNbnDmA==

由于接下来会多次用到这个key,请记住并复制这个key留作备用。

将key加入我们的BIND9配置,编辑配置文件/etc/bind/named.conf文件,并写入key的配置如下:

key "keyname." {
  algorithm hmac-sha512;
  secret "i/KJzuKiYGbWlZ7x3qR6OxXjEX3L8XdeOy90F3aFYtRaGJp/8Ig4HmP/WfG6WsFqoe+a31emvJWeapxmNbnDmA==";
};

编辑配置文件/etc/bind/named.conf.local,配置DNS区域(zone)如下以启用DNS的动态更新权限(这里以wangye.org为例):

zone "wangye.org" {
  type master;
  file "/etc/bind/zones/master/db.wangye.org";

  update-policy {
    grant keyname. name _acme-challenge.wangye.org. txt;
  };
};

增加BIND9对于配置文件的修改权限,因为动态更新是需要BIND9自主更新,如果BIND9没有修改权限,那么动态更新必然会失败,失败消息可以通过日志看到。

chown -R root:bind /etc/bind/zones/master
chmod -R 775 /etc/bind/zones/master

完成上述操作后使用service bind9 restart重启BIND9服务使得DNS生效,至此域名DNS服务器配置结束,接下来需要完成的是网站主机的配置。

2. 托管网站主机配置

这里是网站主机是指运行Ubuntu或者类似Linux系统的主机或者VPS,其中Web服务器软件使用的是nginx,不包括虚拟主机。使用SSH登入网站主机,安装certbot对Letsencrypt证书进行管理:

sudo apt-get update
sudo apt-get install software-properties-common
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install python-certbot-nginx

安装插件dns_rfc2136 ,此插件通过dns-01 challenge 实现对DNS服务器上TXT的动态更新(刚才我们BIND9配置过):

sudo apt-get install pip3

如果上面的命令失败的话请尝试下面的命令替代:

sudo apt-get install python3-pip
pip3 install certbot-dns-rfc2136

/etc/letsencrypt路径下新建配置文件rfc2136.ini,内容如下:

dns_rfc2136_server = 203.119.25.5
dns_rfc2136_name = keyname.
dns_rfc2136_secret = i/KJzuKiYGbWlZ7x3qR6OxXjEX3L8XdeOy90F3aFYtRaGJp/8Ig4HmP/WfG6WsFqoe+a31emvJWeapxmNbnDmA==
dns_rfc2136_algorithm = HMAC-SHA512

值得注意的是上述配置中dns_rfc2136_server配置节所指示的IP地址请替换成你自己的DNS服务器IP地址(之前配置BIND9的那台),dns_rfc2136_namedns_rfc2136_secret请替换成和刚才BIND9 DNS服务器相同的配置。

假设你的nginx已经配置有可以正常运行的网站且防火墙已经放行TCP 443的端口流量,下面可以申请新的证书了:

sudo certbot certonly --dns-rfc2136 \
  --dns-rfc2136-credentials /etc/letsencrypt/rfc2136.ini \
  --server https://acme-v02.api.letsencrypt.org/directory \
  --agree-tos --no-eff-email \
  --domain 'wangye.org' --domain '*.wangye.org'

最后采用此自动Challenge方式申请证书必然每次续期会修改DNS记录,这个与DNSSEC功能有冲突,如果使用该方式,则需要放弃DNSSEC特性。

参考资料

《BIND9 DNS Challenge自动配置Letsencrypt通配符(Wildcard)HTTPS证书》有10个想法

  1. 配置DNS区域(zone)中的, /etc/bind/zones/master/db.wangye.org 怎么写呢, 空文件的话启动时候会报bad zone
    能否向您请求一下?

    1. 你好,这个一般是你的域名DNS配置文件,如果你的域名之前托管在第三方DNS服务平台上,那么这个文件内容通常可以导出(需要联系第三方DNS托管方),如果不能导出则需要按照规范手动编辑这个文件,文件内容通常包含SOA,解析记录等等(包括不限于NS、A记录)

          1. 非常感谢能向您请教,
            我搭建了bind9 并严格按照您的教程进行配置, 在用certbot申请正式时候产生了异常:
            Unable to determine base domain for _acme-challenge.testcert.marlinos.com using names: [‘_acme-challenge.testcert.marlinos.com’, ‘testcert.marlinos.com’, ‘marlinos.com’, ‘com’].

            我的邮件****@qq.com(为保护隐私特隐藏地址).

  2. 非常感谢能向您请教,
    我搭建了bind9 并严格按照您的教程进行配置, 在用certbot申请正式时候产生了异常:
    Unable to determine base domain for _acme-challenge.testcert.marlinos.com using names: [‘_acme-challenge.testcert.marlinos.com’, ‘testcert.marlinos.com’, ‘marlinos.com’, ‘com’].

    我的邮件****@qq.com(为保护隐私特隐藏地址).

    1. 抱歉,因为我已经不使用这种方式申请证书,而且也没有遇到过这个错误,因此只能提供有限的帮助信息:检索网络后判断此类错误一般是因为letsencrypt无法确认你是此域名的所有者,或者你的托管主机无法通过DNS challenge更新你的DNS服务器上的TXT记录。那么依照我的处理方式,建议如下:

      1.检查域名信息的Name Server是否已经配置为你的自建DNS服务器,遗憾的是我检查了你的域名MARLINOS.COM的WHOIS信息,Name Server仍然是阿里云的服务(我有点怀疑你把DNS的Bind9和需要更新证书的Web部署在一台服务器上了)。

      2. 如果域名Name Server配置正确,那么请检查你的申请证书的主机(一般是托管Web的服务器)与DNS服务器通讯是否正常,DNS 更新数据包能否正常发送到DNS服务器上,一般检查防火墙是否拦截相应的数据包。

        1. 你好,看样子你是理解错了本文的用途了,本文适用于独立DNS服务器,也就是说你自己另外使用BIND9搭建DNS服务器实现类似阿里云DNS功能,然后域名Name Server配置为你自建的DNS,不是在本地安装BIND9就能实现的。

          如果你使用了阿里云DNS并且需要实现申请泛域证书,那么不需要参考本篇文章,也不需要另行安装BIND9,阿里云提供了相应的API,直接按照相应文章操作即可:
          利用阿里云云解析DNS API快速申请Let’s Encrypt泛域名SSL证书
          使用阿里云域名api申请Let’s Encrypt泛域名免费ssl证书

          祝你成功!

          1. 看样子应该是我搞错了, 我理解的 dns-rfc2136是 letsencrypt 到rfc配置中指定的dns自建服务器去验证txt解析记录, 而不用管域名Cname 记录是否解析到自建服务器上. 看样子应该是我搞错了, 非常感谢您的帮助,非常感谢.

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据