DNS DNSSEC BIND Unbound 網路基礎設施

DNSSEC 根金鑰 10 月 11 日第二次換手:自架 BIND、Unbound、Knot 不能只靠 RFC 5011 自動更新賭

2026 年 10 月 11 日 KSK-2024(key tag 38696)正式接手簽署根區 DNSKEY,取代 KSK-2017(key tag 20326)。RFC 5011 自動更新機制常在容器映像檔、黃金映像、災備快照這些場景靜默失效,自架 validating resolver 的運維必須驗證 loaded trust anchor、而不是只看 config 檔。

2026 年 10 月 11 日,網際網路根區(root zone)會把簽署 DNSKEY record set 的金鑰從 KSK-2017(key tag 20326)換成 KSK-2024(key tag 38696)。這是根 KSK 歷史上第二次換手,上一次是 2018 年。對一般網域擁有者、使用 Cloudflare 1.1.1.1、Google 8.8.8.8、Quad9 這類公共 resolver 的終端使用者來說,這天不會發生任何事。真正要盯緊的是自架 validating resolver 的運維人員:那些跑 BIND、Unbound、Knot Resolver、PowerDNS Recursor 的機器,trust anchor 這一週必須手動驗證,不能只假設 RFC 5011 自動更新機制幫忙把事情做掉。

這件事值得單獨拉出來講,是因為自動更新的靜默失效模式比大部分文件寫的多很多。KSK-2024 其實早在 2025 年 1 月 11 日就已經公開發布進根區,RFC 5011 的「add hold-down」機制要求新金鑰連續被看到 30 天才會被 resolver 接受為 trust anchor。理論上從 2025 年 2 月 10 日起所有正確運作的 resolver 都應該信任新金鑰。問題是「正確運作」這四個字包含了太多前提,而每一個前提都容易在實際運維環境裡被打破。

不是檔案對就代表 loaded 的金鑰對

這是整個 KSK rollover 準備工作裡最常被跳過的一步。工程師看一眼 /etc/bind/bind.keys 或 /var/lib/unbound/root.key 發現檔案裡有 key tag 38696,就把這臺機器勾掉。這個檢查其實只能證明「檔案存在時的狀態是對的」,不能證明「daemon 當下載入的 trust anchor 是對的」。

兩個典型失誤情境。第一個是 daemon 啟動後檔案被覆蓋。常見於跑在容器裡的 Unbound,映像檔 build 時烘進去的 root.key 用的是 2024 年之前的版本,容器啟動後 unbound-anchor 工具沒權限寫進唯讀的掛載點,自動更新機制靜默失敗,記憶體裡載入的仍然是舊 anchor。第二個是進程重啟時機問題。validating resolver 跑了半年沒重啟,期間 RFC 5011 流程把 trust anchor 檔案更新到正確狀態,但正在跑的進程記憶體裡還是當初啟動時讀到的那份舊內容。10 月 11 日 UTC 17:00 之後根區用 KSK-2024 簽的 DNSKEY response 送進來,進程還拿 KSK-2017 想驗證,一驗就失敗。

正確的驗證對象是「跑著的 daemon 現在信任哪些 key tag」,不是「磁碟上的檔案長什麼樣」。BIND 用 rndc managed-keys status,可以把當前所有 managed key 的 state、key tag、next refresh time 列出來。Unbound 用 unbound-control get_option trust-anchor-file 配合 unbound-anchor -l 看磁碟載入狀態,但要確定記憶體狀態得重啟或重載。Knot Resolver 在 Lua config 裡暴露 trust_anchors.summary() 這個函式。PowerDNS Recursor 從 4.5 開始支援 RFC 5011,用 rec_control get-tas 列出當前載入的 trust anchor。

RFC 5011 的 30 天 hold-down 遇上現代運維常常失靈

RFC 5011 的設計假設 resolver 是長壽的進程,每天至少啟動一次並持續運作,持續觀察根區的 DNSKEY response。這個假設在 1990 年代到 2010 年代尚稱合理,但現在的環境充滿違反它的場景。

容器化 resolver 是重災區。一個每週 rebuild 的 Alpine 加 Unbound 容器,auto-trust-anchor-file 寫在 /var/lib/unbound/ 底下,如果這個路徑沒 persist 到 host volume,每次 rebuild 都從烘進 image 的舊 root.key 開始。RFC 5011 的 hold-down 時間重新歸零,30 天後才會信任 KSK-2024。這一個月期間遇上根 KSK 真的切換,resolver 直接開始回 SERVFAIL。

黃金映像和災備快照是第二類陷阱。半年前打的 base image,裡面的 bind.keys 可能是半年前某個 BIND 版本自帶的那份;DR 演練從一年前的 LVM snapshot 恢復起來的 Unbound,root.key 更舊。這些實例日常用不到,一出事就上線,接管流量當下 trust anchor 已經過期。驗證不能只盯主機群,所有可能在 10 月 11 日之後被 provision 起來的映像檔、snapshot、backup 都得掃過一遍。

Pi-hole 這類打包 DNS stack 的場景也值得單獨提。預設 Pi-hole 本身不做 DNSSEC validation,但在設定裡勾了「Use DNSSEC」之後它會啟用 dnsmasq 的 DNSSEC 功能,/etc/dnsmasq.d/01-pihole.conf 底下用的 trust anchor 寫死在 dnsmasq binary 裡。Pi-hole 的版本若落在 2024 年中以前,裡面的 dnsmasq 就不會包含 KSK-2024。升級 Pi-hole 這一週是必要動作,不能等日常升級排程。

RFC 8509 sentinel 測試只能證半邊

ICANN 推 RFC 8509 的目的是給 resolver 一個標準化的「我信任哪個 key tag」自報告機制。測試方法是對任意 DNSSEC-signed 網域發兩個特殊 label 的查詢:root-key-sentinel-is-ta-<keytag>.<domain> 和 root-key-sentinel-not-ta-<keytag>.<domain>。resolver 若信任該 key tag,前者會解析成功、後者回 SERVFAIL;不信任的話結果相反。

1
2
dig +short root-key-sentinel-is-ta-38696.example.com
dig +short root-key-sentinel-not-ta-38696.example.com

這個測試有幾個不能忽略的限制。首先它只回報「resolver 的實作有不有實作 RFC 8509」加「有的話結果是什麼」,一個沒實作 RFC 8509 的 resolver 兩個查詢都會正常解析成功,結果是 inconclusive 不是 pass。dnsmasq 從 2.78 開始支援、BIND 從 9.11 開始支援、Unbound 從 1.7.1 開始支援,若 resolver 版本更舊得走別的路。其次它只測實際跑這個查詢的那條路徑。公司內部若有 VIP 後面掛一組 resolver farm、或者前端一臺 forwarder 後端換上游,單一次 sentinel 查詢打中的只是其中一臺,其他臺可能設定不同、或者 anchor 狀態不同。

Cloudflare 自己架了 https://dnstest.dev/ksk-2024/ 這個瀏覽器端測試頁,背後跑的就是 RFC 8509 sentinel。對一般使用者檢查家裡 router 的 DNS 設定夠用,但對運維 resolver farm 的場景,直接去 daemon 的 management interface 問 loaded anchor 才是可靠做法。

SERVFAIL 的範圍能幫忙定位問題

真的在 10 月 11 日之後遇到使用者抱怨「某些網站打不開」,SERVFAIL 的分佈範圍可以快速劃清責任。如果一臺 validating resolver 的 trust anchor 徹底過期,它會對所有 DNSSEC-signed 的網域回 SERVFAIL——根區是 signed 的,所有 TLD 的 chain of trust 從根開始,anchor 掛掉等於整條鏈斷掉。這種狀況下使用者連 google.com、github.com 都連不上,紅燈是全面的。

反過來若是某幾個特定網域有問題、其他網域正常,根 anchor 幾乎可以排除。常見的 per-zone 問題:RRSIG expired(zone 本身沒重簽)、DS/DNSKEY mismatch(zone 換過 KSK 但沒更新 registrar 的 DS record)、algorithm rollover 中途斷線。這些事件跟根 KSK rollover 無關但剛好撞在同一週容易被誤判,先用「廣泛失敗 vs 單點失敗」這條線切開。

TTL 也是個會延遲 observability 的因素。根 DNSKEY RRset 的 TTL 是 48 小時。10 月 11 日 UTC 當天切換之後,一支還在使用舊 cache 的 resolver 要等快取過期才會真的去抓新 RRset、才會真的驗證失敗。10 月 11 到 13 日之間,SERVFAIL 可能分批冒出來,監控系統在 10 月 12 日突然報警不代表當天才壞,可能是前一天就壞但 cache 撐著。建議 10 月 10 日先關掉所有 DNS resolver 的 cache 做一次強制刷新驗證,比等事後 debug 便宜太多。

升級路徑比手動改檔案可靠

ICANN 給的官方建議是「升級到當前版本」。BIND 9.18 以後、Unbound 1.19 以後、Knot Resolver 5.6 以後、PowerDNS Recursor 4.9 以後打包的 trust anchor 都已經包含 KSK-2024。這個路徑比手動從 IANA 下載 root-anchors.xml 自己放到正確位置可靠——後者容易放錯檔名、放錯權限、放錯使用者 context,RFC 5011 自動流程照樣看不到。

容器化部署特別要注意一點:映像檔若 pin 在舊版本,光升級 base image 不夠,必須重新 build 包含新版 daemon 的映像,再把 auto-trust-anchor-file 寫到有 persist 的 volume 上。這個 volume 必須是 daemon 執行使用者可寫的——Unbound 容器裡 user 通常是 unbound 或 65534,chown -R unbound:unbound /var/lib/unbound 這一步常常漏掉導致自動更新失敗沒被發現。

準備工作做到位這個換手就是個不會被注意到的 silent event。做不到位的話 10 月 11 日之後幾天會變成所有服務的「DNS 莫名其妙壞掉」的那種事故,而且因為快取和 TTL 的關係很難第一時間定位。

NCSE Network 的臺灣 VPS 跑自架 DNS resolver 剛好

想在 KSK rollover 這一週把家裡或公司的 DNS 架構重新測一遍、架一臺乾淨的 BIND 或 Unbound 來驗證 trust anchor 行為,直接開一臺 VPS 跑是最快的路徑。NCSE Network 提供的 VPS 主機跑在臺灣是方電訊機房、Intel Gold CPU 加 NVMe SSD,Debian 13、Ubuntu 26.04 預裝的 BIND 和 Unbound 都已經是包含 KSK-2024 的版本,IPv4 加 IPv6 原生雙棧,拿來做 DNSSEC validator 或 recursive resolver 都省掉自己調 kernel 參數的工作。想了解相關方案細節,可以到 ncse.tw 查看。

需要高品質的網路服務?

NCSE Network 提供 IP Transit、IP Tunnel 及 BGP 路由規劃,10M~100G 彈性頻寬,多上游備援確保穩定。

了解網路服務 →