Knot DNS でゾーン転送（AXFR / IXFR） with TSIG

Knot DNS -> Knot DNS の構成です。
プライマリサーバー: `192.168.182.10` は以下の手順で構築が行われたと仮定します。

https://qiita.com/ahra_/items/273394cf29fbfb546ce1

また、実際には以下の手順で DDNS を有効化済みのプライマリサーバー上で本記事の設定を行っていますが、簡単のためこの記事では DDNS 用の定義は記載していません。

https://qiita.com/ahra_/items/c468d896b2bc8f2c318a

セカンダリサーバー: `192.168.182.11` の環境は以下の通りです。
OS: Rocky Linux 9.5
Knot DNS 3.4.6
SELinux 有効
## プライマリサーバーの設定
セカンダリサーバーの NS レコードを追加します。
```
# knotc zone-begin --
# knotc zone-set example.com @ 3600 NS dns2
# knotc zone-set 182.168.192.in-addr.arpa @ 3600 NS dns2.example.com.
# knotc zone-commit --
```
TSIG 鍵を生成します。
生成した TSIG 鍵はこの後セカンダリサーバーにも追加します。必ずメモしましょう。
（実行結果の secret: <この文字列> がTSIG 鍵です）
```
# keymgr -t xfr_notify hmac-sha512
```
TSIG 鍵、notify の通知先アドレス、transfer 要求を受け付ける ACL を追加します。
```diff:/etc/knot/tsig-keys.conf
key:
  - id: xfr_notify
    algorithm: hmac-sha512
    secret: <TSIG 鍵>
```
```diff:/etc/knot/knot.conf
server:
    rundir: "/run/knot"
    user: knot:knot
    listen: [ 127.0.0.1@53, 192.168.182.10@53 ]
    identity:
    version:

log:
  - target: /var/log/knot.log
    any: info

database:
    storage: "/var/lib/knot"

mod-queryacl: # 通常の DNS クエリを受け付ける範囲を制限
  - id: default
    address: [192.168.182.0/24,192.168.207.0/24,127.0.0.0/8]
    interface: [192.168.182.10,127.0.0.1]

+ include: tsig-keys.conf

+ remote:
+  - id: dns2
+    address: 192.168.182.11
+    key: xfr_notify

+ acl:
+  - id: allow_xfr                       
+    address: 192.168.182.11
+    action: transfer
+    key: xfr_notify

template:
  - id: default
    storage: "/var/lib/knot/zonefile"
    file: "%s.zone"
    semantic-checks: on
    module: mod-queryacl/default
+    notify: dns2
+    acl: allow_xfr 
    
zone:
  - domain: example.com

  - domain: 182.168.192.in-addr.arpa
    file: 182.168.192.in-addr.arpa.zone
    reverse-generate: example.com # example.com ゾーンの A/AAAA から PTR を生成
```
TSIG 鍵が意図しないユーザーに確認されないよう、所有者とパーミッションを変更します。
その後、設定をリロードします。
```
# chown knot:knot /etc/knot/tsig-keys.conf
# chmod 600 /etc/knot/tsig-keys.conf
# knotc -b reload
```
## セカンダリサーバーの設定
インストール、ログ設定についてはプライマリサーバーと同じですが、定義ファイルは以下のものを使用するようにします。
notify を受け入れる設定や、Primary サーバーを明示的に指定しています。
```/etc/knot/tsig-keys.conf
key:
  - id: xfr_notify
    algorithm: hmac-sha512
    secret: <TSIG 鍵>
```
```/etc/knot/knot.conf
server:
    rundir: "/run/knot"
    user: knot:knot
    listen: [ 127.0.0.1@53, 192.168.182.11@53 ]
    identity:
    version:
    
log:
  - target: /var/log/knot.log
    any: info

database:
    storage: "/var/lib/knot"
    
mod-queryacl: # 通常の DNS クエリを受け付ける範囲を制限
  - id: default
    address: [192.168.182.0/24,192.168.207.0/24,127.0.0.0/8]
    interface: [192.168.182.11,127.0.0.1]

include: tsig-keys.conf

acl:
  - id: allow_notify                     
    address: 192.168.182.10
    action: notify
    key: xfr_notify

remote:
  - id: primary
    address: 192.168.182.10
    key: xfr_notify      

template:
  - id: default
    storage: "/var/lib/knot/zonefile"
    file: "%s.zone"
    semantic-checks: on
    module: mod-queryacl/default
    master: primary
    acl: allow_notify  
    
zone:
  - domain: example.com
    
  - domain: 182.168.192.in-addr.arpa
```
設定出来たら FW に通信許可を設定して Knot DNS を起動します。
```
# chown knot:knot /etc/knot/tsig-keys.conf
# chmod 600 /etc/knot/tsig-keys.conf
# chown knot:knot -R /var/lib/knot/zonefile/
# knotc conf-check
# firewall-cmd --add-service=dns --permanent
# firewall-cmd --reload
# systemctl enable knot
# systemctl start knot
```
## 確認
セカンダリサーバーの Knot DNS を起動するとすぐに AXFR によってゾーン転送が実行されていることがわかります。
```
2025-05-09T11:29:00+0900 info: [182.168.192.in-addr.arpa.] AXFR, incoming, remote 192.168.182.10@53 TCP, key xfr_notify., started
2025-05-09T11:29:00+0900 info: [182.168.192.in-addr.arpa.] AXFR, incoming, remote 192.168.182.10@53 TCP, key xfr_notify., finished, remote serial 16, 0.00 seconds, 1 messages, 707 bytes
2025-05-09T11:29:00+0900 info: [example.com.] AXFR, incoming, remote 192.168.182.10@53 TCP, key xfr_notify., started
2025-05-09T11:29:00+0900 info: [example.com.] AXFR, incoming, remote 192.168.182.10@53 TCP, key xfr_notify., finished, remote serial 13, 0.00 seconds, 1 messages, 507 bytes
2025-05-09T11:29:00+0900 info: [example.com.] refresh, remote 192.168.182.10@53, key xfr_notify., zone updated, 0.05 seconds, serial none -> 13, expires in 691200 seconds
2025-05-09T11:29:00+0900 info: [example.com.] zone file updated, serial 13
2025-05-09T11:29:00+0900 info: [182.168.192.in-addr.arpa.] refresh, remote 192.168.182.10@53, key xfr_notify., zone updated, 0.05 seconds, serial none -> 16, expires in 86400 seconds
2025-05-09T11:29:00+0900 info: [182.168.192.in-addr.arpa.] zone file updated, serial 16
```
プライマリサーバーと同じ内容が返ります。
```
Resolve-DnsName dns1.example.com -server 192.168.182.11

Name                                           Type   TTL   Section    IPAddress
----                                           ----   ---   -------    ---------
dns1.example.com                               A      3600  Answer     192.168.182.10


Resolve-DnsName example.com. -server 192.168.182.11

Name                        Type TTL   Section    PrimaryServer               NameAdministrator           SerialNumber
----                        ---- ---   -------    -------------               -----------------           ------------
example.com                 SOA  3600  Authority  dns1.example.com            hostmaster.example.com      13


Resolve-DnsName example.com. -server 192.168.182.11 -type NS

Name                           Type   TTL   Section    NameHost
----                           ----   ---   -------    --------
example.com                    NS     3600  Answer     dns1.example.com
example.com                    NS     3600  Answer     dns2.example.com

Name       : dns1.example.com
QueryType  : A
TTL        : 3600
Section    : Additional
IP4Address : 192.168.182.10


Name       : dns2.example.com
QueryType  : A
TTL        : 3600
Section    : Additional
IP4Address : 192.168.182.11


Resolve-DnsName 192.168.182.10 -server 192.168.182.11

Name                           Type   TTL   Section    NameHost
----                           ----   ---   -------    --------
10.182.168.192.in-addr.arpa    PTR    3600  Answer     dns1.example.com


Resolve-DnsName 182.168.192.in-addr.arpa -server 192.168.182.11

Name                        Type TTL   Section    PrimaryServer               NameAdministrator           SerialNumber
----                        ---- ---   -------    -------------               -----------------           ------------
182.168.192.in-addr.arpa    SOA  900   Authority  dns1.example.com            hostmaster.example.com      16
```
## ACL、TSIG の確認
セカンダリサーバーから TSIG 鍵無しの AXFR 要求を送ると失敗しますが、
```
# dig example.com. @192.168.182.10 axfr

; <<>> DiG 9.16.23-RH <<>> example.com. @192.168.182.10 axfr
;; global options: +cmd
; Transfer failed.
```
TSIG 鍵を付与すればゾーンが転送されます。
```
# dig example.com. -y hmac-sha512:xfr_notify:<TSIG 鍵>  @192.168.182.10 axfr

; <<>> DiG 9.16.23-RH <<>> example.com. -y hmac-sha512:xfr_notify:<TSIG 鍵> @192.168.182.10 axfr
;; global options: +cmd
example.com.            3600    IN      SOA     dns1.example.com. hostmaster.example.com. 13 86400 900 691200 3600
example.com.            3600    IN      NS      dns1.example.com.
example.com.            3600    IN      NS      dns2.example.com.
dhcp-test.example.com.  28800   IN      A       192.168.182.16
dhcp-test.example.com.  28800   IN      DHCID   <DHCID>
dns-r.example.com.      3600    IN      A       192.168.182.12
dns1.example.com.       3600    IN      A       192.168.182.10
dns2.example.com.       3600    IN      A       192.168.182.11
test.example.com.       3600    IN      A       192.168.182.21
test2.example.com.      3600    IN      A       192.168.182.22
test3.example.com.      3600    IN      A       192.168.182.23
example.com.            3600    IN      SOA     dns1.example.com. hostmaster.example.com. 13 86400 900 691200 3600
xfr_notify.             0       ANY     TSIG    hmac-sha512. 1746757890 300 64 tOc2pR61b9bCJpz3WFmuSNqzTPtjH3irPnPo57uU1tcyrfIUcR80ybzm j+Ejb0ycYq3duX2oUaD24nDxbFcWTA== 28284 NOERROR 0
;; Query time: 0 msec
;; SERVER: 192.168.182.10#53(192.168.182.10)
;; WHEN: Fri May 09 11:31:30 JST 2025
;; XFR size: 12 records (messages 1, bytes 499)
```
これを他サーバーから要求すると失敗します。（以下は `192.168.207.132` 上の Ubuntu から要求した例）
```
# dig example.com. -y hmac-sha512:xfr_notify:<TSIG 鍵>  @192.168.182.10 axfr
;; Couldn't verify signature: expected a TSIG or SIG(0)

; <<>> DiG 9.18.30-0ubuntu0.22.04.2-Ubuntu <<>> example.com. -y hmac-sha512:xfr_notify:<TSIG 鍵> @192.168.182.10 axfr
;; global options: +cmd
; Transfer failed.
```
## ゾーンを更新してみる(手動)
プライマリサーバーでゾーンを更新してみます。
```
# knotc zone-begin example.com
# knotc zone-set example.com test5 3600 A 192.168.182.25
# knotc zone-commit example.com
```
セカンダリサーバーのログを確認すると、notify が送られ、IXFR によるゾーン転送が実行されていることがわかります。
```
2025-05-09T11:34:44+0900 info: [example.com.] notify, incoming, remote 192.168.182.10@33152 TCP, key xfr_notify., serial 14
2025-05-09T11:34:44+0900 info: [182.168.192.in-addr.arpa.] notify, incoming, remote 192.168.182.10@33168 TCP, key xfr_notify., serial 17
2025-05-09T11:34:44+0900 info: [example.com.] refresh, remote 192.168.182.10@53, key xfr_notify., remote serial 14, zone is outdated
2025-05-09T11:34:44+0900 info: [182.168.192.in-addr.arpa.] refresh, remote 192.168.182.10@53, key xfr_notify., remote serial 17, zone is outdated
2025-05-09T11:34:44+0900 info: [example.com.] IXFR, incoming, remote 192.168.182.10@53 TCP, key xfr_notify., started
2025-05-09T11:34:44+0900 info: [example.com.] IXFR, incoming, remote 192.168.182.10@53 TCP, key xfr_notify., finished, remote serial 14, 0.00 seconds, 1 messages, 393 bytes
2025-05-09T11:34:44+0900 info: [182.168.192.in-addr.arpa.] IXFR, incoming, remote 192.168.182.10@53 TCP, key xfr_notify., started
2025-05-09T11:34:44+0900 info: [182.168.192.in-addr.arpa.] IXFR, incoming, remote 192.168.182.10@53 TCP, key xfr_notify., finished, remote serial 17, 0.00 seconds, 1 messages, 462 bytes
2025-05-09T11:34:44+0900 info: [182.168.192.in-addr.arpa.] refresh, remote 192.168.182.10@53, key xfr_notify., zone updated, 0.01 seconds, serial 16 -> 17, expires in 86400 seconds
2025-05-09T11:34:44+0900 info: [182.168.192.in-addr.arpa.] zone file updated, serial 16 -> 17
2025-05-09T11:34:44+0900 info: [example.com.] refresh, remote 192.168.182.10@53, key xfr_notify., zone updated, 0.01 seconds, serial 13 -> 14, expires in 691200 seconds
2025-05-09T11:34:44+0900 info: [example.com.] zone file updated, serial 13 -> 14
```
以下の通り、更新されたレコードがセカンダリサーバー側にも存在しており、またゾーンのシリアルナンバーがカウントアップされていることがわかります。
```
Resolve-DnsName test5.example.com. -server 192.168.182.11

Name                                           Type   TTL   Section    IPAddress
----                                           ----   ---   -------    ---------
test5.example.com                              A      3600  Answer     192.168.182.25


Resolve-DnsName example.com. -server 192.168.182.11

Name                        Type TTL   Section    PrimaryServer               NameAdministrator           SerialNumber
----                        ---- ---   -------    -------------               -----------------           ------------
example.com                 SOA  3600  Authority  dns1.example.com            hostmaster.example.com      14


Resolve-DnsName 192.168.182.25 -server 192.168.182.11

Name                           Type   TTL   Section    NameHost
----                           ----   ---   -------    --------
25.182.168.192.in-addr.arpa    PTR    3600  Answer     test5.example.com


Resolve-DnsName 182.168.192.in-addr.arpa -server 192.168.182.11

Name                        Type TTL   Section    PrimaryServer               NameAdministrator           SerialNumber
----                        ---- ---   -------    -------------               -----------------           ------------
182.168.192.in-addr.arpa    SOA  900   Authority  dns1.example.com            hostmaster.example.com      17
```
## ゾーンを更新してみる(DDNS)
IP アドレスのリースが発生すると、DDNS によりプライマリサーバーのゾーンが更新され、notify による通知から IXFR によるゾーン転送が発生していることがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3900965/9ca8e9f4-c67b-4f8a-9cfe-7467b763d4a3.png)
```
2025-05-09T11:48:13+0900 info: [182.168.192.in-addr.arpa.] notify, incoming, remote 192.168.182.10@50946 TCP, key xfr_notify., serial 19
2025-05-09T11:48:13+0900 info: [182.168.192.in-addr.arpa.] refresh, remote 192.168.182.10@53, key xfr_notify., remote serial 19, zone is outdated
2025-05-09T11:48:13+0900 info: [182.168.192.in-addr.arpa.] IXFR, incoming, remote 192.168.182.10@53 TCP, key xfr_notify., started
2025-05-09T11:48:13+0900 info: [182.168.192.in-addr.arpa.] IXFR, incoming, remote 192.168.182.10@53 TCP, key xfr_notify., finished, remote serial 19, 0.00 seconds, 1 messages, 643 bytes
2025-05-09T11:48:13+0900 info: [182.168.192.in-addr.arpa.] refresh, remote 192.168.182.10@53, key xfr_notify., zone updated, 0.01 seconds, serial 17 -> 19, expires in 86400 seconds
2025-05-09T11:48:13+0900 info: [182.168.192.in-addr.arpa.] zone file updated, serial 17 -> 19
2025-05-09T11:48:14+0900 info: [example.com.] notify, incoming, remote 192.168.182.10@50960 TCP, key xfr_notify., serial 15
2025-05-09T11:48:14+0900 info: [example.com.] refresh, remote 192.168.182.10@53, key xfr_notify., remote serial 15, zone is outdated
2025-05-09T11:48:14+0900 info: [example.com.] IXFR, incoming, remote 192.168.182.10@53 TCP, key xfr_notify., started
2025-05-09T11:48:14+0900 info: [example.com.] IXFR, incoming, remote 192.168.182.10@53 TCP, key xfr_notify., finished, remote serial 15, 0.00 seconds, 1 messages, 445 bytes
2025-05-09T11:48:14+0900 info: [example.com.] refresh, remote 192.168.182.10@53, key xfr_notify., zone updated, 0.00 seconds, serial 14 -> 15, expires in 691200 seconds
2025-05-09T11:48:14+0900 info: [example.com.] zone file updated, serial 14 -> 15
```
もちろんセカンダリサーバーで解決できます。
```
Resolve-DnsName dhcp-test2.example.com. -server 192.168.182.11

Name                                           Type   TTL   Section    IPAddress
----                                           ----   ---   -------    ---------
dhcp-test2.example.com                         A      28800 Answer     192.168.182.17


Resolve-DnsName 192.168.182.17 -server 192.168.182.11

Name                           Type   TTL   Section    NameHost
----                           ----   ---   -------    --------
17.182.168.192.in-addr.arpa    PTR    28800 Answer     dhcp-test2.example.com
```