部署DNSsec权威域名服务
初始条件
- 域名注册商必须支持DNSsec。(直接找他们问,或者看是否提供DS记录)
- 上级域名必须支持DNSsec,用 dig +short dnskey 上级域名来测试。(如果不支持,则只能用 DLV)。
- 主域名服务器必须支持DNSsec。(自己搞)
- 从域名服务器必须也支持DNSsec。
概念
每一个域需要两组用于签名的密钥对。一组称为密钥签名密钥(Key Signing Key,KSK),一般而言较长,需要到域名注册商处备案(以便通过上级域名发布)。由于密钥较长,因此其强度更高,因此也可以使用更久的时间。
用来签署本域的域签名密钥(Zone Signing Key,ZSK),后者通常较短,并且需要经常更换。(不推荐使用长 ZSK,因为长 ZSK 的签名尺寸较大,会导致 DNS 流量增加并降低可靠性;未来基于椭圆曲线的算法普及之后,这一情况将有所改观)。
ZSK 和 KSK 都是可以用来签名的密钥,因此 DNS 服务器理论上可以两者都用来签名。实践上,一般来说,为了减少不必要的 DNS 流量(因为查询DNS的时候不可能告诉对方一个key的ID再去问),通常的配置中 KSK 只用于签署用来签署域名的域签名密钥,而不用来签名普通地址记录。
BIND 的实现中,如果 KSK 与 ZSK 采用的加密算法不同,会出现以两个密钥同时签署域的情况。
用作从域名服务器的 DNS 服务器并不需要相关密钥。一般来说,为了分散风险,DNSsec 的配置应以 “hidden master” (隐藏主DNS:主DNS并不对公众直接提供服务)。
推荐的部署步骤
以下是个人推荐的部署步骤。
- 收集必要的相关信息,如 zone 文件等等。设计部署方案。
- 配置全部的从 DNS 服务器(启用其上的 DNSsec 配置)确认服务正常。
- 如果目前使用的不是 hidden master,将 DNS 集群改为 hidden master 方式。(非常简单,本文暂略)
- 生成相关密钥。
- 将 hidden master 配置为使用 DNSsec 签名,测试 (dig +dnssec soa 域名 @服务器)。
- 如果无问题,在域名注册商处发布 DS 记录。
- 进一步生产环境测试。
DNSsec需要持续维护。持续维护阶段,需要每隔一段时间生成并轮换密钥,在轮换 KSK 时需要在注册商那里发布。
生成相关密钥
假定在我们希望的配置中,KSK和KSK均使用P-384的椭圆曲线DSA和 SHA384,并每季度轮转一次,且今天是2015年5月1日,那么:
dnssec-keygen -K keys -a ECDSAP384SHA384 -3 -f KSK -I 20160501 -D 20160507 域名 dnssec-keygen -K keys -a ECDSAP384SHA384 -3 -I 20151201 -D 20151207 域名
以上,第一个命令生成KSK,并将过期时间设置为2016年5月1日(这之后新的记录将不再使用这个key签名),并约定2016年5月7日从域中剔除(这之后查询该key将不再返回结果)。 XXX 此处重叠时间应继续查看文档了解。
注意,运行 BIND 的用户必须能够访问这些 key 文件(chown bind:bind keys/*)。
在生成了密钥之后,还必须生成与之对应的 DS 记录。假定我们的 KSK 的id是52874,那么对应的密钥文件就是 K域名.+014+52874.key 和 K域名.+014+52874.private(其中,014的意思是ECDSA P384 SHA384),那么具体的命令是:
dnssec-dsfromkey K域名.+014+52874.key dnssec-dsfromkey -a SHA-384 K域名.+014+52874.key
第一个命令会生成SHA1和SHA2的DS记录,第三个会生成SHA384的DS记录。实际操作中,我认为如果支持 ECDSA P384 SHA384 的解析器一定已经支持了 SHA384 的hash,因此只要有最后一个记录即可。
如果使用旧式的 RSA 2048/1024 配合 SHA1/SHA256 算法,则应使用与之对应的 SHA1 或 SHA256 的 DS 记录。本着不升级的人死了活该的精神,我认为完全不应该考虑这些用户的感受,使用 ECDSA 签名既节省流量,又更加安全。
配置 DNSsec 域名
本质上,DNSsec 服务器提供的是一组经过签名的地址记录,这些签名以 RRSIG 记录的形式发给请求者。传统的 DNSsec 配置方法是静态的:从现有的 zone 文件,使用特定的key来签署它,并让BIND来将其服务出去。这种方法在安全上有一定的优势:key可以完全脱离DNS服务器保存在安全的地方,但由于签名有一定的有效期,因此维护比较麻烦。
新式的 BIND 服务器支持一种称作 inline signing 的技术。这种方法是告诉 DNS 服务器key在哪里去找,并且在key上设定过期时间等等,然后DNS服务器自己决定在合适的时间去做更新相关的操作。这种方式维护起来比较方便。
配置 hidden master 服务器全局配置
主要配置如下:
key-directory "/usr/local/etc/namedb/keys"; sig-validity-interval 21 16;
以上主要是配置密钥的位置,以及签名的有效时间 XXX 需查证这一做法是否最佳实践。
定义允许传输域的ACL:
acl trusted { 1.2.3.0/25; };
以上设置一名为 trusted 的 ACL,其中包含 1.2.3.0/25 网段。
配置 hidden master 服务器域 example.com 的配置
zone "example.com" { type master; file "/usr/local/etc/namedb/dynamic/example.com"; auto-dnssec maintain; inline-signing yes; allow-transfer { trusted; }; also-notify { 1.2.3.4; }; };
以上基本可原样照抄(改掉其中 example.com)。1.2.3.4是需要通知的首席辅DNS服务器(它可以进一步通知其他DNS服务器),如果需要也可以写上多个DNS服务器。
这里我们(误)用了 dynamic 目录,因为这个目录是 BIND 可写的,而 BIND 需要在其中写入一系列文件(修改日志、签名)。
启动 BIND 后,BIND 会自动对原有的 example.com 根据需要进行签名,并通知我们指定的辅 DNS 服务器,后者会到 hidden master 来拉,具体可以看 DNS 服务器的日志。
NSEC3
DNSsec 是对域名地址记录进行签名,那么如何知道一个域名不存在呢?假如每一次请求都需要 DNS 服务器签署一个类似(张三不存在)这样的消息的话,无疑会成为 DNSsec 服务器的一处软肋。
假定一个域名中有 alice, bob 和 carol 三个名字,那么,在签署 alice, bob, carol 对应的地址记录时,我们可以同时签署这样的消息:以字典序排列域名时, alice 和 bob 之间没有其他名字。这种方法称作 NSEC。
NSEC 有一项明显的缺点:我们可以向 DNSsec 故意询问不存在的名字,这时可以知道两个存在的端点;持续这一过程,就可以遍历整个 DNSsec 域了。这未必是一个安全问题(攻击者能够攻击,意味着这些机器在公网上),但是许多系统管理员会因此感到不安,因为域名往往会提供一些其他信息,例如某个特定的机器叫 db,那么这台机器很可能是运行数据库的比较关键的服务器,等等。
为了解决这个问题, https://tools.ietf.org/html/rfc5155 定义了 NSEC3。简而言之,NSEC3 并不告诉查询者 “alice和bob之间没有人”而是告诉查询者“hash ALICE和hash BOB之间没有人”。由于采用的hash函数是不可逆的,并且通常是进行多轮加salt,因此NSEC3避免了NSEC的域名遍历问题。
BIND中启用NSEC3需要设置一个NSEC3参数,方法是:
rndc signing -nsec3param 1 0 10 `dd if=/dev/random bs=4 count=1 | od -An -vtx` 域名
启用 NSEC3 之后,zone 将不再是正常人类所能理解的形式。使用下面的命令可以将其转换为人类可以勉强阅读的格式:
named-compilezone -D -f raw -o - example.net example.net.signed
(以上将 example.net.signed 转换为裸奔格式)。
维护 DNSsec 域名
ZSK和PSK的轮换
前面我们已经用 inline signing 解决了 ZSK 签名的轮转问题(代价是隐蔽的主 DNS 服务器必须能够访问 ZSK 和 KSK),但 DNSsec 域名仍然需要经常轮转 ZSK 和定期轮转 KSK。
BIND 可以自动完成轮转所需的大部分工作,但用户仍然需要生成相关的 key。前面我们的例子中,ZSK 将在 20150801 过期,一般来说我们希望有至少1周时间来发布一个新的key(这样有7天重叠),并从7月31日开始以新的key来签署域名。 XXX 确认这是否最佳实践
dnssec-keygen -K keys -a ECDSAP384SHA384 -3 -P 20150725 -A 20150731 -I 20151101 -D 20151107 域名
KSK 的轮转与此类似。需要注意的是,KSK 的发布是需要在注册商那里进行的。轮转 KSK 的方法略微复杂一些,因此这里展开说一下。
- 首先,要把新的 key 添加到域里。简而言之,按照前面 生成相关密钥 的部分做就行了,注意激活时间最好比当前时间稍微提前一点,这样下次 BIND 扫描时便会注意到这些 key。注意一定要把权限配对。
- 假设有足够的耐心,可以等 BIND pickup 相关的变化。然而很多人并没有足够的耐心,可以用 rndc reload 来踹它一脚,确认所有的 slave 都获得了同步的数据。
- 检查 DNSsec 中的签署情况。此时,你应该看到两个 KSK 互相签署,而且签署了所有的 ZSK。
- 如果没有问题,可以进一步去注册商那里,先添加新的 KSK 的 DS 记录,确认无误后,再删除旧 KSK 的 DS 记录。
- 最后,使用 dnssec-settime 修正旧 KSK 的 inactive 和 delete 时间,最终它们会从域中剔除掉。
以上过程的考虑是:根域名的同步是需要时间的,在过渡期内,应该同时用两个key签署ZSK。此外,先添加新的DS再删去旧的DS比较不容易出问题。
修改域名中的记录
其他话题
SSHFP
DANE
DANE记录可以从证书中提取公钥来生成。DANE记录有4个字段:
- 用途 Usage 字段,允许的数值有:
- 0 - PKIX-TA: Certificate Authority Constraint 指定一个CA,服务器必须使用该CA签发的证书,并且受用户信任。
- 1 - PKIX-EE: Service Certificate Constraint 指定服务器证书,服务器必须使用这个证书,并且该证书必须通过PKIX的验证。
- 2 - DANE-TA: Trust Anchor Assertion 指定一个CA,服务器必须使用该CA签发的证书,但该证书不必为用户信任。
- 3 - DANE-EE: Domain Issued Certificate 指定服务器证书,服务器必须使用这个证书,但证书不必通过PKIX验证。
- 选择器 Selector 字段,允许的数值有:
- 0 - Cert: Use full certificate 使用完整的证书。
- 1 - SPKI: Use subject public key 只使用证书的公钥部分。
- 匹配类型 Matching Type 字段,允许的数值有:
- 0 - Full: No Hash 不进行hash。(并无必要,通常应选择以下两种之一)
- 1 - SHA-256: SHA-256 hash。(回应尺寸小,但计算较慢)
- 2 - SHA-512: SHA-512 hash。(回应尺寸大,但计算较快)
- TLSA 数据(参见下面的生成命令)
举个例子:3 1 2 表示我们的 TLSA 记录将指明服务器所用的证书的公钥的 SHA-512 hash。用途字段(目前是3)选1时,客户端需要进行更严格一些的验证(例如确认域名匹配等)。
TLSA 数据是根据上述选择器指定的内容产生的,通常来说我们匹配公钥的SHA-512 hash就可以了,下面的命令可以生成需要的数据。
openssl x509 -noout -pubkey -in domainname.cer | \ openssl rsa -pubin -outform DER | sha512 | \ tr "a-f" "A-F"
最后将数据写到DNS TLSA记录里。BIND的写法类似下面这样:
_443._tcp.www.example.org TLSA (3 1 2 <上面命令生成的结果>)
参考文献
- NIST Publication SP-800-81 NIST SP