
两个月前的一个凌晨三点,位于葵涌的数据中心忽然响起红色报警:某金融 SaaS 域名的 A 记录被篡改,部分解析指向境外钓鱼站。虽然 10 分钟内手动回滚了主备区,但我彻底被“缓存污染”惊醒:仅靠 IP 访问控制、TSIG 和监控告警,远不足以保护权威 DNS。
当天上午,我决定在整条香港线路把权威 DNS 全量切换到 DNSSEC,并顺便给早已规划却始终没上线的 Anycast + RRL + NSEC3 Opt-Out 做一次“梳一次、上一次”。以下是完整落地笔记。
1 场景与威胁图谱
| 攻击面 | 典型手段 | 影响 |
|---|---|---|
| 缓存投毒 | 伪造响应、延迟应答 | 劫持用户流量、钓鱼 |
| 区域传输劫持 | 未加密 AXFR | 泄露内网拓扑、被动域传 |
| DNS 放大 | 反射 + 大幅响应 | DDoS 骚扰权威集群 |
| BGP 劫持 | Anycast 前缀被截 | 全球解析漂移 |
DNSSEC 的签名链能从协议层堵死前两者,配合 RRL/TCP fallback 则能抑制后两者。
2 方案总览
权威服务器栈选型
- BIND 9.20(LTS,4 年支持)
- Knot DNS ≥3.4(线程锁极少,推送式接管签名)
- PowerDNS 4.9.5(REST API + LMDB 优化写入)
算法策略
- ZSK / KSK:ECDSA-P256 (算法 13),签名小、验证快,获主流解析器支持
- Anycast +BGP FlowSpec:本地 HKIX / Equinix HK3 双机房,各 2 × 10 GbE,上游清洗到 2 Tbit/s。
- 监控链路:Prometheus + named_exporter,DS 提交和签名过期定时告警;Grafana 7 × 24 NOC 大屏。
3 环境准备
| 组件 | 规格 | 说明 |
|---|---|---|
| 服务器 | 2 × E-2388G / 256 GB RAM / 2 × 1.92 TB NVMe | 同款硬件便于冷备镜像 |
| OS | Alma Linux 9.4 (kernel 5.14) | 提供 FIPS 模块与 nftables |
| BGP 堆栈 | FRR 9.0 + eBPF XDP ACL | 配合 FlowSpec 打静态封包 |
实测 BIND 9.20 的 in-memory mapdb 在 NVMe 上签 1 M RR/秒,瓶颈是单核 RSA;切换 ECDSA 后 CPU 使用降至 43 %。
4 DNSSEC 部署步骤(以 BIND 9.20 为例)
4.1 安装并启用 FIPS 模块
dnf install -y bind bind-utils bind-exporter
fips-mode-setup --enable && reboot
4.2 生成密钥
# 生成 KSK(有效期 365 d)
dnssec-keygen -a ECDSAP256SHA256 -b 256 -f KSK -L 360d -K /var/named/keys example.com
# 生成 ZSK(有效期 30 d,自动滚动)
dnssec-keygen -a ECDSAP256SHA256 -b 256 -L 30d -K /var/named/keys example.com
4.3 区域签名与自动续签
cat >> /etc/named/zones/example.com.db <<'EOF'
$INCLUDE "/var/named/keys/Kexample.com.+013+*.key"
EOF
# 开启 automatic-dnssec 与 inline-signing
options {
dnssec-validation auto;
dnssec-enable yes;
dnssec-lookaside no;
allow-query { any; };
...
};
zone "example.com" IN {
type master;
file "zones/example.com.db";
auto-dnssec maintain;
inline-signing yes;
};
systemctl reload named
BIND 会在首次加载时创建 example.com.signed,并按 sig-validity-interval 14 7 预留 7 天重签缓冲。
4.4 提交 DS 记录
dig +multi DNSKEY example.com @127.0.0.1 | dnssec-dsfromkey -f - example.com
将生成的 DS 上传给域名注册局(HKDNR/Epag),等待父区链路生效后即完成部署。
5 密钥生命周期与 RFC 5011 自动滚动
- 设定 managed-keys,启用 RFC 5011 检测;
- 通过 Ansible 每月例行 dnssec-rekey,7 天后自动激活新 KSK;
- Prometheus 规则:dnssec_ksk_expiry_seconds < 604800 触发告警。
6 加固细节
| 模块 | 配置 | 目的 |
|---|---|---|
| RRL | rate-limit responses-per-second 200 |
抑制放大反射 |
| TCP fallback | tcp-only no; minimal-responses yes; |
缓解 UDP 分片 |
| NSEC3 | nsec3param 1 0 10 a1b2c3d4 |
防止区域枚举 |
| XDP ACL | eBPF drop >512 byte EDNS flood | 降低畸形报文负载 |
| HSTS for DoT | offload 至 HAProxy-SSL | 防 MITM 升级 |
7 高可用拓扑
┌─────────┐ Anycast 203.92.70.0/24
│ Edge1 │──────┐
└─────────┘ │ BGP
│
用户 ─── Internet ──┬──────┴─────┬──────┐
│ │ │
┌─────────┐ ┌─────────┐ │
│ HK1 │ │ HK2 │ BGP FlowSpec
│ BIND │ │ BIND │ DDoS Scrubber
└─────────┘ └─────────┘
- 同前缀多活:HK1/HK2 同时对外 Anycast;
- RPKI ROA:所有前缀已签 ROA,降低 BGP 劫持面;
- 冷备站:深圳 GZ-SZ 机房做二级隐藏主,异机 rsync 区域文件。
8 监控与可观测
- named_exporter → Prometheus:dnssec_signature_expiring、dns_query_failures;
- Grafana 世博盘:日签名 QPS、RRL 命中率、UDP vs TCP 占比;
- Loki 日志:结合 Grafana Tempo 链路追踪签名延迟。
9 自动化脚本片段(Ansible)
- hosts: dns_auth
roles:
- role: isc.bind
vars:
bind_dnssec_enable: true
bind_dnssec_algo: 'ECDSAP256SHA256'
bind_auto_dnssec: 'maintain'
bind_inline_signing: true
tasks:
- name: Trigger ZSK roll if 25 days old
shell: >
/usr/sbin/dnssec-checkds -f /var/named/zones/{{ zone }}.db ||
dnssec-keygen -K /var/named/keys -S -A -P -n ZONE
10 故障案例与排查
| 现象 | 根因 | 快速定位 |
|---|---|---|
SERVFAIL 大量出现 |
上游未同步 DS | dig +dnssec example.com 检查 AD 位 |
| 小量终端解析失败 | UDP 分片被丢 | tcpdump 'udp[6:2] > 512' |
| RRL 命中率过高 | 攻击 or 监控重复探测 | rndc stats 查看 rrl counter |
| KSK 过期前 12 h 警报 | Ansible playbook 未跑 | dnssec-settime -p 验证 key 时间戳 |
通过三周灰度 + 两次演练,95% 的解析流量在 DNSSEC 启用后依旧保持 <25 ms RTT;ECDSA-P256 把签名包从 1.2 KB 压到 740 B,CPU 峰值下降 37%。结合 Anycast、RRL 与 eBPF ACL,我们再未遇到缓存污染或域名劫持告警。
如果你的业务同样依赖香港出口、且面向全球用户,我强烈建议尽早把 权威 DNS → DNSSEC 提上日程,并一次性把“签名、密钥滚动、高可用、防放大”全部融入 CI/CD。攻击者的窗口期只有一次,而我们必须 365 × 24 守住解析链的最后一公里。










