Knot DNSによるDNSSECの自動署名

概要

Knot DNSは、knot.confのzoneセクションでdnssec-signing: onと設定すると、鍵の生成とロールオーバ、ゾーンデータへの署名を自動的にやってくれます。アルゴリズムやロールオーバの周期などのポリシをデフォルトから変更したければ、その内容に沿ったpolicyを定義して適用できます。また、新規にネームサービスの提供や署名しての運用を開始するのではなく、既に他のツールで署名して運用しているゾーンをKnot DNSに移行するときは、BIND形式やPEM形式の鍵をインポートして、その時点で公開している鍵を次のロールオーバまで引き継いで使えます。

おことわり

このページは、手許のUbuntu 23.10上で動作するKnot DNS Version 3.3.4を用いて行った実験の結果をお伝えするものであって、内容の正確さは一切保証しませんので、自己責任でご利用下さい。

また、このページは自動署名のご説明に主眼を置いているので、それ以外の事項は意図的に端折り気味に記述しています。必要に応じてKnot DNS 2.4.0と2.6.5に触ってみたや他の方が公開なさっている情報などをご覧下さい。

署名前のゾーンデータ

knot.confのzoneセクションdnssec-signingonにすると、fileに指定した、あるいはデフォルトのパスのゾーンファイルには、DNSSEC関連のレコードが直接書き込まれます。

ゾーンデータを更新するためには

などの方法が考えられますが、ここでは署名前のゾーンデータはzoneセクションfileパラメータとは別の場所に置き、そちらを編集してからfileパラメータのパスにコピーして署名させることにします。

準備

今まではそのゾーンに署名しておらず、これから署名するとき

Knot DNSではknot.confのzoneセクションserial-policyパラメータで自動署名でゾーンデータが更新されるときに、SOAレコードのserialフィールドの更新後の値をどのように設定するのかを

から選ぶことができ、デフォルトはincrementalです。

ゾーンデータが変化したときにはserialは(2^32を法として)増えなければいけないので、serial-policyunixtimedateserialを指定していても、初回の署名をするときに与える署名前のゾーンデータのserialが、その時点のunixtimedateserialを超えていると、serialを逆戻りさせないためにincrementalで動作します。

いろいろな状況や要件が考えられますが、例えば、これまではdateserial形式で運用してきたが、署名を始めるのを機にunixtimeに切り替えたいとか、incrementalに切り替えるが心機一転1から始めたい、というときは、serialを逆戻りさせなければなりません。そのようなときはserialが2147483648( == 2^31)以下であれば、一度2147483647( == 2^31 - 1)を足してセカンダリに伝搬するのを待ちます。2147483648を超えていれば、この操作は要りません。それから目的の値に設定すればserialを(人間にとっては)減らす(ネームサーバにとっては2^32を法として増えている)ことができます。この操作は自動署名を有効にする前に済ませておきましょう。定期的に再署名や鍵のロールオーバが行われると、serialは署名前のゾーンデータを変更した日時とは関係なく増えていくので、具体的な番号はどうでもいい、という境地に達した方は、ここで何もする必要はありません。

既に他のツールで鍵管理して対象のゾーンに署名しているとき

keymgrコマンドimport-bindサブコマンドでBIND形式の鍵ファイルをインポートして引き継ぐことができます。知識がなくってご説明できませんがimport-pemサブコマンドでPEM形式の鍵ファイルをインポートすることもできるようです。既に署名して運用しているゾーンでは、この手順を踏まないと、ロールオーバの手順を踏まず、いきなり鍵が変わってしまうことになり、recursiveサーバのキャッシュの状況によっては署名の検証に失敗してしまいます。

状況によりけりなので一概には言えませんが、鍵のインポートは、knot.confに対象ゾーンのzoneセクションを追加する前に済ませておかないと、署名前のゾーンデータが外部にリークして署名の検証に失敗することも想定されますので、注意して下さい。

現在、publishされている鍵のファイルを用意します。秘密鍵のファイル(*.private)のパーミッションは通常-rw-------ですが、次の操作ではknotdのプロセスが動作するuidに読み取り許可が必要なので、必要に応じてchownやchmodで属性を調整して下さい。また、以下ではrootの権限でkeymgrコマンドを実行していますが、knot.confのserverセクションでuserパラメータを与えて特権を放棄しているときは、keymgrコマンドも、そのユーザで実行して下さい。


$ ls
Kexample.jp.+013+02969.key	Kexample.jp.+013+51751.key
Kexample.jp.+013+02969.private	Kexample.jp.+013+51751.private
$
$ sudo keymgr example.jp import Kexample.jp.+013+02969
e8003d9384465086d6546eafda7209bfddd3144f
OK
$ 
$ sudo keymgr example.jp import-bind Kexample.jp.+013+51751
fa12bd09a42605f2c02bd4fd2c4c278e9d05f1ab
OK
$ 
$ sudo keymgr example.jp list iso
e8003d9384465086d6546eafda7209bfddd3144f  2969 KSK ECDSAP256SHA256 created=2024-02-20T03:43:53Z publish=2024-02-20T03:43:53Z active=2024-02-20T03:43:53Z
fa12bd09a42605f2c02bd4fd2c4c278e9d05f1ab 51751 ZSK ECDSAP256SHA256 created=2024-02-20T03:43:56Z publish=2024-02-20T03:43:56Z active=2024-02-20T03:43:56Z

これで現在publishされている鍵がKnot DNSにインポートできました。

設定ファイル

ゾーンファイルはKnot DNSがアクセスしない場所であればどこでもいいんですが、ここでは/srv/dnsというディレクトリの下にexample.jp.zoneというファイル名で置くことにします。


$TTL 1d
@       IN      SOA     ns.example.jp. hostmaster.example.jp. (
                        0       ; serial
                        20m
                        15m
                        4w
                        15m)
                NS      ns.example.jp.
ns              A       192.0.2.53

小細工ですが、後の都合でserialの箇所にコメントを入れておきます。

設定ファイルはデフォルトである/etc/knot/knot.confというパス名に


policy:
  - id: mypolicy
    cds-cdnskey-publish: none

zone:
  - domain: example.jp
    dnssec-signing: on
    dnssec-policy: mypolicy

という内容で作ります。ここでは上位ゾーンへのDSレコードの登録はCDSレコードによらず手動で行うという想定で、cds-cdnskey-publishパラメータをデフォルトのrolloverからnoneに変更するポリシをmypolicyというidで定義して、zoneセクションで適用してみました。policyセクションで設定できる他のパラメータについてはwww.knot-dns.czをご覧下さい。

ネームサービスへの反映

自動署名の対象となる/var/lib/knot/example.jp.zoneの種として/srv/dnsから署名前のexample.jp.zoneをコピーします。


$ sudo cp /srv/dns/example.jp.zone /var/lib/knot

knot.confをチェックして


$ sudo knotc conf-check
Configuration is valid

knotdの動作に反映させます。状況に応じて


$ sudo systemctl enable --now knot

などでknotdを新たに起動するか


$ sudo knotc reload

により動作中のknotdにknot.confとexample.jp.zoneを読み込ませます。

するとlogには


2024-02-21T17:09:33.523073+09:00 ns knotd[7442]: info: Knot DNS 3.3.4 starting
2024-02-21T17:09:33.523169+09:00 ns knotd[7442]: info: loaded configuration file '/etc/knot/knot.conf', mapsize 500 MiB
2024-02-21T17:09:33.523203+09:00 ns knotd[7442]: info: using UDP reuseport, incoming TCP Fast Open
2024-02-21T17:09:33.523239+09:00 ns knotd[7442]: info: binding to interface 192.0.2.53@53
2024-02-21T17:09:33.523269+09:00 ns knotd[7442]: info: loading 1 zones
2024-02-21T17:09:33.523300+09:00 ns knotd[7442]: info: [example.jp.] zone will be loaded
2024-02-21T17:09:33.523330+09:00 ns knotd[7442]: info: starting server
2024-02-21T17:09:33.523709+09:00 ns knotd[7442]: info: [example.jp.] zone file parsed, serial 0
2024-02-21T17:09:33.523878+09:00 ns knotd[7442]: info: [example.jp.] DNSSEC, key, tag  2969, algorithm ECDSAP256SHA256, KSK, public, active
2024-02-21T17:09:33.523921+09:00 ns knotd[7442]: info: [example.jp.] DNSSEC, key, tag 51751, algorithm ECDSAP256SHA256, public, active
2024-02-21T17:09:33.523970+09:00 ns knotd[7442]: info: [example.jp.] DNSSEC, signing started
2024-02-21T17:09:33.524625+09:00 ns knotd[7442]: info: [example.jp.] DNSSEC, successfully signed, serial 1
2024-02-21T17:09:33.528433+09:00 ns knotd[7442]: info: [example.jp.] loaded, serial none -> 0 -> 1, 1119 bytes
2024-02-21T17:09:33.528547+09:00 ns knotd[7442]: info: [example.jp.] DNSSEC, next signing at 2024-03-05T06:33:18+0900
2024-02-21T17:09:33.528996+09:00 ns knotd[7442]: info: [example.jp.] zone file updated, serial 0 -> 1
2024-02-21T17:09:33.529655+09:00 ns knotd[7442]: info: control, binding to '/run/knot/knot.sock'
2024-02-21T17:09:33.529729+09:00 ns knotd[7442]: info: server started in the foreground, PID 7442

というメッセージが記録されました。インポートしたKSKとZSKを使って署名し、serialが/srv/dnsからコピーした署名前のゾーンデータに設定されていた0から1に増えていることがわかります。

ゾーンデータの変更

自動署名を有効にしているときにゾーンデータを変更するには、外部からの書き換えと自動署名による書き換えが競合しないように、一時的に自動署名の動作を停止します。


$ sudo -s
# knotc zone-freeze example.jp
OK

やり方は色々あるでしょうが、ここでは/srv/dnsにある署名前のexample.jp.zoneを編集して、初回と同じように/var/lib/knotにコピーすることにします。そのときに、/var/lib/knotに置く署名前のゾーンデータに現時点でのserialを埋め込みます。


# sed 's/[0-9].*; serial/'`kdig @localhost +short example.jp SOA | awk '{print $3}'`'/' /srv/dns/example.jp.zone > /var/lib/knot/example.jp.zone

serialの埋め込み方は一例なので、それぞれのアイディアでやって下さい。

ゾーンデータを読み込みます。


# knotc zone-reload example.jp
OK

ログを見るとzone-reloadを実行した時点でzone-signは実行しなくても署名が動作していることがわかります。


2024-02-26T16:19:41.768244+09:00 ns knotd[7442]: info: [example.jp.] control, received command 'zone-freeze'
2024-02-26T16:19:41.768611+09:00 ns knotd[7442]: info: [example.jp.] zone updates frozen
2024-02-26T16:20:02.639975+09:00 ns knotd[7442]: info: [example.jp.] control, received command 'zone-reload'
2024-02-26T16:20:02.640246+09:00 ns knotd[7442]: info: [example.jp.] zone file parsed, serial 1
2024-02-26T16:20:02.640390+09:00 ns knotd[7442]: info: [example.jp.] DNSSEC, key, tag  2969, algorithm ECDSAP256SHA256, KSK, public, active
2024-02-26T16:20:02.640442+09:00 ns knotd[7442]: info: [example.jp.] DNSSEC, key, tag 51751, algorithm ECDSAP256SHA256, public, active
2024-02-26T16:20:02.640513+09:00 ns knotd[7442]: info: [example.jp.] DNSSEC, signing started
2024-02-26T16:20:02.641623+09:00 ns knotd[7442]: info: [example.jp.] DNSSEC, successfully signed, serial 2
2024-02-26T16:20:02.646187+09:00 ns knotd[7442]: info: [example.jp.] loaded, serial 1 -> 1 -> 2, 1119 bytes
2024-02-26T16:20:02.646284+09:00 ns knotd[7442]: info: [example.jp.] DNSSEC, next signing at 2024-03-10T05:43:47+0900
2024-02-26T16:20:09.728007+09:00 ns knotd[7442]: info: [example.jp.] control, received command 'zone-thaw'
2024-02-26T16:19:41.768244+09:00 ns knotd[7442]: info: [example.jp.] control, received command 'zone-freeze'
2024-02-26T16:19:41.768611+09:00 ns knotd[7442]: info: [example.jp.] zone updates frozen
2024-02-26T16:20:02.639975+09:00 ns knotd[7442]: info: [example.jp.] control, received command 'zone-reload'
2024-02-26T16:20:02.640246+09:00 ns knotd[7442]: info: [example.jp.] zone file parsed, serial 1
2024-02-26T16:20:02.640390+09:00 ns knotd[7442]: info: [example.jp.] DNSSEC, key, tag  2969, algorithm ECDSAP256SHA256, KSK, public, active
2024-02-26T16:20:02.640442+09:00 ns knotd[7442]: info: [example.jp.] DNSSEC, key, tag 51751, algorithm ECDSAP256SHA256, public, active
2024-02-26T16:20:02.640513+09:00 ns knotd[7442]: info: [example.jp.] DNSSEC, signing started
2024-02-26T16:20:02.641623+09:00 ns knotd[7442]: info: [example.jp.] DNSSEC, successfully signed, serial 2
2024-02-26T16:20:02.646187+09:00 ns knotd[7442]: info: [example.jp.] loaded, serial 1 -> 1 -> 2, 1119 bytes
2024-02-26T16:20:02.646284+09:00 ns knotd[7442]: info: [example.jp.] DNSSEC, next signing at 2024-03-10T05:43:47+0900
2024-02-26T16:20:09.728007+09:00 ns knotd[7442]: info: [example.jp.] control, received command 'zone-thaw'
2024-02-26T16:20:09.733606+09:00 ns knotd[7442]: info: [example.jp.] zone updates unfrozen
2024-02-26T16:20:09.733677+09:00 ns knotd[7442]: info: [example.jp.] zone file updated, serial 1 -> 2

zone-freezeで停止していた自動署名の動作を復帰させます。


# knotc zone-thaw example.jp
OK

ログにもその旨が出力されました。


2024-02-21T18:02:20.120229+09:00 ns knotd[7442]: info: [example.jp.] control, received command 'zone-thaw'
2024-02-21T18:02:20.120330+09:00 ns knotd[7442]: info: [example.jp.] zone updates unfrozen
2024-02-21T18:02:20.120458+09:00 ns knotd[7442]: info: [example.jp.] zone file updated, serial 0 -> 2


Copyright(c) 2024 Koh-ichi Ito, All rights reserved
Last update: $Date: 2024-02-26 16:49:37 +0900 (Mon, 26 Feb 2024) $
[DNS関連情報へ]