PowerDNS 权威服务器基于 LUA Records 实现 CNAME Flattening
1. 背景与问题
在 DNS 中,CNAME 记录不能设置在 zone apex(根域名)上,例如 example.com 本身不能是 CNAME,只有子域名如 www.example.com 可以。这是 DNS 标准的限制。
CNAME Flattening 是一种技术手段,允许在根域名上实现类似 CNAME 的效果,即将根域名指向另一个域名,并动态解析出真实 IP 返回给客户端。
PowerDNS 提供了 ALIAS 记录类型来解决这个问题,但 ALIAS 类型存在一个缺陷:不支持 DNSSEC live-signing(实时签名)。
使用 LUA Records 可以同时解决 CNAME Flattening 和 DNSSEC 签名两个问题。
2. 环境要求
在开始之前,请确认以下条件:
•PowerDNS Authoritative Server 4.x 及以上版本
•编译时包含 lua-records 支持(运行 pdns_server --version 确认 Features 中包含 lua-records)
•使用 gmysql 或其他数据库后端
•DNSSEC 使用 live-signing 模式(不是预签名模式)
验证 LUA records 支持:
pdns_server --version
输出的 Features 字段中应包含 lua-records。
3. PowerDNS 配置
3.1 启用 LUA Records
编辑 PowerDNS 配置文件(通常是 /etc/powerdns/pdns.conf 或 /etc/powerdns/pdns.d/ 目录下的配置文件),添加以下配置:
enable-lua-records=yes
同时确保配置了 resolver,LUA records 解析目标域名时需要用到:
resolver=8.8.8.8:53
重启 PowerDNS 使配置生效:
systemctl restart pdns
3.2 完整配置示例
以下是一份包含 LUA records 的完整配置示例:
launch=gmysql gmysql-host=localhost gmysql-user=root gmysql-dbname=powerdns gmysql-password=yourpassword gmysql-dnssec=yes enable-lua-records=yes resolver=8.8.8.8:53 local-address=0.0.0.0 :: local-port=53
4. 创建 Zone 并添加 LUA 记录
4.1 创建 Zone
使用 pdnsutil 创建 zone(如果已存在可跳过):
pdnsutil create-zone example.com ns1.example.com
4.2 添加 LUA CNAME 记录
使用 pdnsutil 在根域名上添加 LUA 类型的 CNAME 记录:
pdnsutil add-record example.com @ LUA "CNAME \";return 'target.example.net.'\""
实际命令示例(将 example.com 指向 hicairo.com):
pdnsutil add-record example.com @ LUA "CNAME \";return 'hicairo.com.'\""
注意:LUA 记录中的域名需要用单引号包裹,作为 Lua 字符串返回。末尾的点(.)表示绝对域名,建议保留。
4.3 验证记录
查看 zone 中的所有记录:
pdnsutil list-zone example.com
预期输出应包含:
example.com 3600 IN LUA CNAME ";return 'hicairo.com.'"
5. 启用 DNSSEC
5.1 对 Zone 签名
使用 pdnsutil 对 zone 启用 DNSSEC:
pdnsutil secure-zone example.com
更新 NSEC 排序信息:
pdnsutil rectify-zone example.com
5.2 查看签名信息
查看 zone 的 DNSSEC 详情,包括 DS 记录(需要提交到上级域):
pdnsutil show-zone example.com
输出示例:
ID = 1 (CSK), flags = 257, tag = 52822, algo = 13, bits = 256 Active Published DS = example.com. IN DS 52822 13 2 99ebc97b...
注意:需要将 DS 记录提交到域名注册商,才能完成 DNSSEC 信任链的建立。
6. 测试验证
6.1 测试 CNAME 查询
直接查询权威服务器:
dig @127.0.0.1 example.com CNAME
预期返回:
example.com. 3600 IN CNAME hicairo.com.
6.2 测试 A 记录查询
查询 A 记录,递归解析器会自动跟随 CNAME 解析出 IP:
dig @8.8.8.8 example.com A
预期返回 CNAME 记录以及目标域名的 A 记录(IP 地址)。
6.3 测试 DNSSEC 签名
使用 +dnssec 参数验证签名:
dig @127.0.0.1 example.com CNAME +dnssec
预期返回中应包含 RRSIG 记录:
example.com. 3600 IN CNAME hicairo.com. example.com. 3600 IN RRSIG CNAME 13 2 3600 ...
通过公网 DNS(如 8.8.8.8)验证,响应 flags 中应包含 ad(Authenticated Data)标志,表示 DNSSEC 验证通过:
dig @8.8.8.8 example.com CNAME +dnssec ;; flags: qr rd ra ad;
7. LUA Records 语法说明
7.1 基本格式
LUA records 的存储格式为:
LUA <DNS类型> "<Lua代码>"
其中 Lua 代码需要用双引号包裹,代码本身返回一个字符串作为 DNS 记录的内容。
7.2 固定 CNAME 示例
将域名固定指向另一个域名:
LUA CNAME ";return 'target.example.net.'"
7.3 与 ALIAS 类型的区别
特性 | ALIAS 类型 | LUA 类型 |
CNAME Flattening | 支持 | 支持 |
DNSSEC live-signing | 不支持 | 支持 |
zone apex 使用 | 支持 | 支持 |
灵活性 | 固定指向 | 可编程,支持条件逻辑 |
PowerDNS 版本要求 | 4.x+ | 4.x+ |
8. 常见问题
8.1 查询返回 SERVFAIL
检查 LUA 代码语法是否正确,查看 PowerDNS 日志:
journalctl -fu pdns.service
日志中会显示 Lua record reported 错误信息,根据提示修正 Lua 代码。
8.2 A 记录查询只返回 CNAME 不返回 IP
这是正常行为。PowerDNS 作为权威服务器返回 CNAME,客户端的递归解析器会自动继续解析目标域名的 A 记录。使用 8.8.8.8 等公共递归解析器测试可以看到完整结果。
8.3 DNSSEC 验证失败
确认已执行以下步骤:
•pdnsutil secure-zone 对 zone 签名
•pdnsutil rectify-zone 更新 NSEC 排序
•DS 记录已提交到域名注册商
•等待 DS 记录在全球 DNS 传播(通常需要几小时到 24 小时)
9. 总结
使用 LUA Records 实现 CNAME Flattening 的优势:
•完全支持 DNSSEC live-signing,解决了 ALIAS 类型的历史遗留问题
•只需要 gmysql 单后端,无需额外的 HTTP 后端服务
•配置简单,只需一条 LUA 记录即可实现
•支持复杂的条件逻辑(如按地理位置返回不同的目标域名)
关键命令速查:
# 添加 LUA CNAME 记录 pdnsutil add-record example.com @ LUA "CNAME \";return 'target.example.net.'\"" # 启用 DNSSEC pdnsutil secure-zone example.com pdnsutil rectify-zone example.com # 验证 dig @127.0.0.1 example.com CNAME +dnssec
本文出处:HiFeng's Blog
本文链接:https://www.hicairo.com/post/83.html
版权声明:本博客所有文章除特别声明外,均采用CC BY-NC-SA许可协议。转载请注明出处!