Skip to content

Nuface Blog

隨意隨手記 Casual Notes

Menu
  • Home
  • About
  • Services
  • Blog
  • Contact
  • Privacy Policy
  • Login
Menu

用 BIND 9.21 打造「內外分流 + DNSSEC」權威/遞迴混合 DNS:完整實戰筆記

Posted on 2025-11-052025-11-05 by Rico

本文將我在容器內部署 BIND 9.21 的完整過程整理成一篇教學。為保護實際環境,所有網域以 domainA、domainB 代稱,IP 也以示例地址(如 203.0.113.0/24)呈現。


目標架構

  1. 單一 BIND 服務,分內外 view:
  • internal view:提供內網權威 + 遞迴(轉送至外部 DNS),不做 DNSSEC 驗證,簡單穩定。
  • external view:只提供對外權威(不對外遞迴),對 zone 進行 DNSSEC 簽名;為了讓 KASP 自動健康檢查父網域 DS,僅對 127.0.0.1 開啟遞迴與驗證。
  1. 安全邊界
  • 對外 拒絕遞迴、僅提供權威回覆。
  • AXFR/NOTIFY 使用 TSIG,只允許指定次 DNS 抓取 external 區。
  • 停用 IPv6 監聽(僅 IPv4)。
  1. 容器友善的檔案佈局
  • 設定檔在 /etc/bind/(唯讀)。
  • 所有會被 BIND 寫入 的檔案(簽名、journal、金鑰、KASP 狀態、trust anchor)集中在 /var/cache/bind(可寫、持久化)。

目錄佈局(建議)

/etc/bind/
  ├─ named.conf
  ├─ named.conf.options
  ├─ named.conf.logging
  ├─ named.conf.acl
  ├─ named.conf.views
  └─ keys/
       └─ rndc.key            # RNDC 控制通道 TSIG

/var/cache/bind/               # options { directory } 指到這裡
  ├─ zones/
  │   └─ ext/                  # external view 的 zone 檔(會產生 .signed/.jnl/tmp-*)
  │       ├─ db.domainA
  │       └─ db.domainB
  ├─ keys/                     # key-directory:DNSSEC K* 金鑰與 .state
  │   ├─ KdomainA.+013+11652.{key,private,state}
  │   └─ KdomainB.+013+51162.{key,private,state}
  ├─ managed-keys.bind{,.jnl}  # 根信任錨(自動)
  └─ external.mkeys{,.jnl}     # external view 的 trust anchor 狀態(自動)

重點:K* 金鑰與 .state 一律放 /var/cache/bind/keys;managed-keys.bind*、*.mkeys* 放 /var/cache/bind 根目錄;external 區檔放 /var/cache/bind/zones/ext。


關鍵設定片段

1) options:工作目錄、金鑰目錄、僅 IPv4 監聽

// /etc/bind/named.conf.options
options {
    directory "/var/cache/bind";
    key-directory "/var/cache/bind/keys";

    listen-on { any; };
    listen-on-v6 { none; };           // 不在 IPv6 聽 53

    recursion no;                      // 由各 view 覆寫
    // 不在全域寫 dnssec-validation,改由各 view 控制
};

2) RNDC 控制通道(只綁 127.0.0.1)

// /etc/bind/named.conf
include "/etc/bind/named.conf.options";
include "/etc/bind/named.conf.logging";
include "/etc/bind/named.conf.acl";
include "/etc/bind/keys/rndc.key";

controls {
  inet 127.0.0.1 port 953 allow { 127.0.0.1; } keys { "rndc-key"; };
};

include "/etc/bind/named.conf.views";

如果容器外要下 rndc,要能讀到同一把 rndc.key,或在容器內執行。

3) internal view:內網權威 + 遞迴(不做 DNSSEC 驗證)

// /etc/bind/named.conf.views
view "internal" {
    match-clients { "internal_nets"; };      // 在 named.conf.acl 定義你的內網,例如 192.168.10.0/24
    recursion yes;
    dnssec-validation no;                    // 內網遞迴不驗證,體驗最單純

    allow-recursion   { "internal_nets"; 127.0.0.1; };
    allow-query       { "internal_nets"; 127.0.0.1; };
    allow-query-cache { "internal_nets"; 127.0.0.1; };

    // 轉送遞迴,降低外連風險與雜訊
    forwarders { 1.1.1.1; 8.8.8.8; };
    forward first;

    // 內部權威區(未簽名)
    zone "domainA" { type master; file "/etc/bind/zones/int/db.domainA"; };
    zone "domainB" { type master; file "/etc/bind/zones/int/db.domainB"; };

    // localhost 與內網反解可放在這個 view
    zone "localhost"        { type master; file "/etc/bind/db.local"; };
    zone "127.in-addr.arpa" { type master; file "/etc/bind/db.127";  };

    // 根提示(僅 internal 用得到)
    zone "." { type hint; file "/etc/bind/root.hints.v4"; };
};

4) external view:對外權威(簽名),只對本機開遞迴+驗證供 KASP 使用

view "external" {
    match-clients { any; };

    // 只給本機遞迴 + 驗證,讓 KASP 能 checkds(外部客戶端看不到遞迴)
    recursion yes;
    allow-recursion   { 127.0.0.1; };
    allow-query-cache { 127.0.0.1; };
    dnssec-validation auto;

    forwarders { 1.1.1.1; 8.8.8.8; };  // 避免直接打 root
    forward only;

    allow-query       { any; };        // 對外可查權威資料
    // 不對外提供快取:未列入 allow-query-cache

    // 對外權威區(簽名)
    zone "domainA" {
        type master;
        file "zones/ext/db.domainA";   // 相對於 /var/cache/bind
        notify yes;
        allow-transfer { key xfr-key; 203.0.113.53; };           // 次 DNS
        also-notify   { 203.0.113.53 key xfr-key; };
        dnssec-policy default;
        inline-signing yes;
    };

    zone "domainB" {
        type master;
        file "zones/ext/db.domainB";
        notify yes;
        allow-transfer { key xfr-key; 203.0.113.53; };
        also-notify   { 203.0.113.53 key xfr-key; };
        dnssec-policy default;
        inline-signing yes;
    };
};

TSIG:請用 tsig-keygen -a hmac-sha256 xfr-key > /etc/bind/keys/xfr-key.key 產生,主從兩邊都 include,從伺服器 zone { masters { <MASTER_IP> key xfr-key; }; }。


Zone 檔小細節:TXT 長度與 $ORIGIN

  • DKIM TXT 常超過 255 bytes,需 拆成多段字串(BIND 會自動串接): selector._domainkey IN TXT ( "v=DKIM1; k=rsa; p=MIIBI..." "......剩餘段落......" )
  • $ORIGIN domainA. 時,結尾若不加點會被展成 name.domainA.。DMARC 建議用 _dmarc IN TXT ...(相對名),或 _dmarc.domainA. IN TXT ...(絕對名)。

常見錯誤與修復

  • .private: file not found
    金鑰不在 key-directory;把 K*(.key/.private/.state)移至 /var/cache/bind/keys,chown bind:bind,chmod 640,再 rndc loadkeys <zone>。
  • permission denied 在 .jnl/.signed/tmp-*
    external 的 file 指到只讀位置(例如 /etc/bind)。把 external 區檔放到 /var/cache/bind/zones/ext。
  • dnssec-validation redefined
    同一個 scope 設兩次。建議不要在全域 options 設,改由各 view 寫一次。
  • KASP 噪音:Invalid NS RRset for 'tw' ... no valid RRSIG
    external view 關遞迴/驗證時,KASP 無法 checkds。解法:只對 127.0.0.1 開遞迴+dnssec-validation auto,並加 forward only;。

驗證清單(貼上即跑)

變數:
主 DNS(外部)= 203.0.113.10,次 DNS = 203.0.113.53

內部(從內網主機)

dig @203.0.113.10 www.domainA A                 # 內部權威
dig @203.0.113.10 example.com A                 # 內部遞迴(應有答案)

外部(從外網主機)

dig @203.0.113.10 www.domainA A +norecurse      # flags: aa;不遞迴
dig @203.0.113.10 example.com A                 # 應 REFUSED(無遞迴)
dig @203.0.113.10 www.domainA A +dnssec +norecurse +multiline  # 看到 RRSIG

DNSSEC 鏈路(需已在註冊商發布 DS)

delv @1.1.1.1 www.domainA A                     # 預期 secure(或 DS 未上時為 insecure)
dig  @1.1.1.1 domainA DS +dnssec +multiline     # 應看到與 KSK 對應的 key tag/alg/digest

主/次同步(TSIG)

# 次 DNS 上測(帶 TSIG)
dig @203.0.113.10 domainA AXFR -y hmac-sha256:xfr-key:<BASE64_SECRET>
# 未帶 TSIG(任意主機)應 Transfer failed
dig @203.0.113.10 domainA AXFR
# SOA 序號一致
dig @203.0.113.10 domainA SOA +short
dig @203.0.113.53 domainA SOA +short

RNDC 與簽名狀態

rndc -c /etc/bind/keys/rndc.key status
rndc -c /etc/bind/keys/rndc.key signing -list domainA
rndc -c /etc/bind/keys/rndc.key signing -list domainB

NAT/轉發小記(選讀)

  • 若你在 Gateway A(如 203.0.113.1)上用 DNAT 把外部 53 → 主 DNS(203.0.113.10:53),請確保 UDP/TCP 53 都轉。
  • 內網客戶端建議 直接指向主 DNS(少一層 DNAT,降低複雜度);若一定要經由跳板,避免對 LAN→LAN 做 SNAT,否則 BIND 看不到真實來源 IP。

例行健康檢查(建議)

  • 每天跑一次:
    • delv @1.1.1.1 www.domainA A 看 secure/insecure。
    • dig @203.0.113.10 domainA DNSKEY +dnssec +short 比對 key tag 是否與註冊商 DS 相符。
    • 主/次 SOA 序號是否一致。
  • 觀察 dnssec.log 的 next key event 與是否仍出現 Invalid NS RRset 類訊息(若按本文做法 A,應消失)。

收尾

這套佈局與設定重點在於:

  • 「設定與動態檔分離」:/etc/bind 放純設定;所有會寫入的檔案統一到 /var/cache/bind(含 KASP、簽名、journal、trust anchor)。
  • 「view 策略清楚」:internal 簡化(不驗證)、external 嚴謹(簽名,僅對本機遞迴/驗證以滿足 KASP)。
  • 「邊界明確」:對外拒絕遞迴、AXFR 綁 TSIG、IPv6 可關閉監聽。

按照本文調整後,你就能在單一 BIND 服務裡,同時滿足內外不同需求,且具有可維運、可自動輪替的 DNSSEC 能力。

Recent Posts

  • Postfix + Let’s Encrypt + BIND9 + DANE Fully Automated TLSA Update Guide
  • Postfix + Let’s Encrypt + BIND9 + DANE TLSA 指紋自動更新完整教學
  • Deploying DANE in Postfix
  • 如何在 Postfix 中部署 DANE
  • DANE: DNSSEC-Based TLS Protection

Recent Comments

  1. Building a Complete Enterprise-Grade Mail System (Overview) - Nuface Blog on High Availability Architecture, Failover, GeoDNS, Monitoring, and Email Abuse Automation (SOAR)
  2. Building a Complete Enterprise-Grade Mail System (Overview) - Nuface Blog on MariaDB + PostfixAdmin: The Core of Virtual Domain & Mailbox Management
  3. Building a Complete Enterprise-Grade Mail System (Overview) - Nuface Blog on Daily Operations, Monitoring, and Performance Tuning for an Enterprise Mail System
  4. Building a Complete Enterprise-Grade Mail System (Overview) - Nuface Blog on Final Chapter: Complete Troubleshooting Guide & Frequently Asked Questions (FAQ)
  5. Building a Complete Enterprise-Grade Mail System (Overview) - Nuface Blog on Network Architecture, DNS Configuration, TLS Design, and Postfix/Dovecot SNI Explained

Archives

  • December 2025
  • November 2025
  • October 2025

Categories

  • AI
  • Apache
  • Cybersecurity
  • Database
  • DNS
  • Docker
  • Fail2Ban
  • FileSystem
  • Firewall
  • Linux
  • LLM
  • Mail
  • N8N
  • OpenLdap
  • OPNsense
  • PHP
  • QoS
  • Samba
  • Switch
  • Virtualization
  • VPN
  • WordPress
© 2025 Nuface Blog | Powered by Superbs Personal Blog theme