DNSのレプリケーション設定と運用
目次
検証環境
- 以下のソフトウェアの利用を前提に検証を実施した。いずれも現時点で最新のリリースに基づいて検証しているが、BIND 9.11以上および、より新しい環境でも問題無いと思われる。
- OS: FreeBSD 11.2-R
- DNSコンテンツサーバー: BIND 9.13.3
- 上記以外の環境では、以下の点に相違が発生する。当該環境に応じて読み替えたし。
- インストール方法
- インストールされるディレクトリ
- 逆に以下の点は参考にできる。
- 設定パラメータとその意味
- 運用事例
検証内容
- DNSコンテンツサーバーの構築。以下の3台のDNSサーバーを構築する。
- マスターDNSサーバー ns0.example.jp
- スレーブDNSサーバー ns1.example.jp
- スレーブDNSサーバー ns2.example.jp
- いわゆる ns0.example.jp を隠れ(hidden)マスターとし、ns1.example.jp, ns2.exmaple.jp が対外的なサービスを提供する。
- またキャッシュ機能は使用しないし、有効化しない。
- 構成に当り、以下の機能を使用してゾーン転送(レプリケーション)を行う。
- AFXR/IFXRによるゾーン転送。
- TSIGキーによるマスター/スレーブの認証。
- カタログゾーン機能による、スレーブDNSサーバーの設定フリー(設定フリーとは言ったが検証フリーとは言ってない)。
- なおカタログゾーン機能はBIND 9.11以降の機能であるため、それ未満のサーバー上では運用できない(残念)。
- 他の実装については不明。現在ドラフト状態にあり、RFCに移行するかどうかと関わってくると思われる。
レプリケーションについて
- この手の設定を調べてみると、あまり「レプリケーション」という「言葉」が出てこない。
- では何かというと「セカンダリDNSサーバー」「ゾーン転送」となる。
- 言わんとすることわかるけど、レプリケーションじゃないかなぁということで、ここではそのように表現しておく。
- マスター・スレイブ、プライマリ・セカンダリ、今回は関係ないけど、権威サーバー・コンテンツサーバー、キャッシュサーバー・フルリゾルバ、色々と表現あるけど、適度な使い分けで。
DNSコンテンツサーバーの基本設定(準備)
DNSコンテンツマスターサーバーの基本設定
DNSサーバーとして ports/dns/bind913 をインストールする。
- ここでは特にカスタムする要素は無いので、デフォルトのままとする。
- 説明のため、稼働に必要な最低限の設定とする。
/etc/rc.conf
以下の設定を追加する。
named_enable="YES" named_chrootdir="/var/named" altlog_proglist="named"
※altlog_proglist が既に設定済みの場合、「 named」を追加する。
あるいは下記コマンドを実行する(結果は同じ)。
sysrc named_enable=YES sysrc named_chrootdir=/var/named sysrc altlog_proglist+=named
/usr/local/etc/namedb/named.conf
1 --- /usr/local/etc/namedb/named.conf.orig 2018-09-25 03:54:24.724317000 +0900
2 +++ /usr/local/etc/namedb/named.conf 2018-11-10 21:38:31.343856000 +0900
3 @@ -16,15 +16,22 @@
4 dump-file "/var/dump/named_dump.db";
5 statistics-file "/var/stats/named.stats";
6
7 + recursion no;
8 + allow-query { none; };
9 + allow-recursion { none; };
10 + allow-query-cache { none; };
11 +
12 + allow-new-zones yes;
13 +
14 // If named is being used only as a local resolver, this is a safe default.
15 // For named to be accessible to the network, comment this option, specify
16 // the proper IP address, or delete this option.
17 - listen-on { 127.0.0.1; };
18 + listen-on { any; };
19
20 // If you have IPv6 enabled on this system, uncomment this option for
21 // use as a local resolver. To give access to the network, specify
22 // an IPv6 address, or the keyword "any".
23 -// listen-on-v6 { ::1; };
24 + listen-on-v6 { any; };
25
26 // These zones are already covered by the empty zones listed below.
27 // If you remove the related empty zones below, comment these lines out.
28 @@ -378,3 +385,23 @@
29 };
30 };
31 */
32 +
33 +include "/usr/local/etc/namedb/ns0-nsN.key";
34 +
35 +zone "catalog.example" {
36 + type master;
37 + file "/usr/local/etc/namedb/master/catalog.example.db";
38 + notify explicit;
39 + allow-query {
40 + { !{ !ns1のIPアドレス; any; }; key "ns0-nsN."; };
41 + { !{ !ns2のIPアドレス; any; }; key "ns0-nsN."; };
42 + };
43 + allow-transfer {
44 + { !{ !ns1のIPアドレス; any; }; key "ns0-nsN."; };
45 + { !{ !ns2のIPアドレス; any; }; key "ns0-nsN."; };
46 + };
47 + also-notify {
48 + ns1のIPアドレス key "ns0-nsN.";
49 + ns2のIPアドレス key "ns0-nsN.";
50 + };
51 +};
52
- DNS隠れコンテンツマスターサーバーとして、以下の設定を行うものとする。
- IPv4/IPv6問わず、全てのクエリを受け付けない。
- 原則クエリは受け付けないけど、再帰問い合わせには答えないものとする。
- DNSSEC設定/運用、ログ出力設定、ビュー設定といった機能については説明しない。
※カタログゾーン運用のための設定
- 「allow-new-zones yes;」を設定する。
- カタログゾーン(catalog.example)を定義する。
- このゾーンはゾーンのフリしたカタログ管理用データベースを意味し、その具体性はゾーンファイル(/usr/local/etc/namedb/master/catalog.example.db)にて定義される。
- よって named.conf レベルの設定では他のマスターゾーン定義と変わらない。
- ゾーンの命名規則については「catalog.組織名」辺りが妥当と思われる(本サイトで言うなら catalog.ninth-nine など)。
- 「catalog.localhost」辺りはどこかに実在しそうなゾーンっポイので止めておいた方がいいと思われ。
※catalog.exmaple ゾーンに関する諸設定
- マスターゾーン変更に対する通知(Notification)は明示的に指定する(notify および also-notify 設定)。
- スレイブサーバーからのSOAクエリがあるので答えられるように設定(allow-query 設定)。
- スレイブサーバーからのゾーン転送に答えられるように設定(allow-transfer 設定)
- いずれも、内容に改ざんが無いことを証明するため、TSIGキーで保護する(暗号化を意味するわけでは無い)。
/usr/local/etc/namedb/ns0-nsN.key
以下のコマンドを使用してTSIGキーを作成する。内容例については特に記載しない。
tsig-keygen -a hmac-sha256 ns0-nsN. > /usr/local/etc/namedb/ns0-nsN.key chown bind:wheel /usr/local/etc/namedb/ns0-nsN.key chmod 0400 /usr/local/etc/namedb/ns0-nsN.key
/usr/local/etc/namedb/master/catalog.example.db
$TTL 3600 @ IN SOA . . ( 1 86400 3600 86400 3600 ) IN NS invalid. version IN TXT "1"
- ゾーン定義ではSOAとNSレコードの指定が必須なので、以下のように設定する。
- 特に意味を持たないのでSOAの指定はシンプルに(だそうで)。
- NSレコードも参照されないのでテキトーに(だそうで)。
- よってカタログゾーン運用のための本質的に必要なレコード「version」(つまり version.catalog.example.)が最低でも必須となる。
- これはテキストレコードで、現時点で「1」だけとなる。
- 今後カタログゾーン自体の仕様変更があれば、この「version」の指定が変わることが予定されている。
- なお「1」以外の指定の場合の振る舞いは知らないし、調べる気もない。
DNSコンテンツスレーブサーバーの基本設定
DNSサーバーとして ports/dns/bind913 をインストールする。
- ここでは特にカスタムする要素は無いので、デフォルトのままとする。
- 説明のため、稼働に必要な最低限の設定とする。
/etc/rc.conf
以下の設定を追加する。
named_enable="YES" named_chrootdir="/var/named" altlog_proglist="named"
※altlog_proglist が既に設定済みの場合、「 named」を追加する。
あるいは下記コマンドを実行する(結果は同じ)。
sysrc named_enable=YES sysrc named_chrootdir=/var/named sysrc altlog_proglist+=named
/usr/local/etc/namedb/catalog/ ディレクトリ
install -d -o bind -g wheel -m 0755 /usr/local/etc/namedb/catalog
/usr/local/etc/namedb/named.conf
1 --- /usr/local/etc/namedb/named.conf.orig 2018-10-11 00:09:07.998066000 +0900
2 +++ /usr/local/etc/namedb/named.conf 2018-11-10 22:10:47.557521000 +0900
3 @@ -16,15 +16,28 @@
4 dump-file "/var/dump/named_dump.db";
5 statistics-file "/var/stats/named.stats";
6
7 + recursion no;
8 + allow-query { any; };
9 + allow-recursion { none; };
10 + allow-query-cache { none; };
11 +
12 + allow-new-zones yes;
13 + catalog-zones {
14 + zone "catalog.example"
15 + zone-directory "/usr/local/etc/namedb/catalog"
16 + in-memory no
17 + default-masters { ns0のIPアドレス key "ns0-nsN."; };
18 + };
19 +
20 // If named is being used only as a local resolver, this is a safe default.
21 // For named to be accessible to the network, comment this option, specify
22 // the proper IP address, or delete this option.
23 - listen-on { 127.0.0.1; };
24 + listen-on { any; };
25
26 // If you have IPv6 enabled on this system, uncomment this option for
27 // use as a local resolver. To give access to the network, specify
28 // an IPv6 address, or the keyword "any".
29 -// listen-on-v6 { ::1; };
30 + listen-on-v6 { any; };
31
32 // These zones are already covered by the empty zones listed below.
33 // If you remove the related empty zones below, comment these lines out.
34 @@ -378,3 +391,20 @@
35 };
36 };
37 */
38 +
39 +include "/usr/local/etc/namedb/ns0-nsN.key";
40 +
41 +zone "catalog.example" {
42 + type slave;
43 + file "/usr/local/etc/namedb/slave/catalog.example.db";
44 + notify no;
45 + masters {
46 + ns0のIPアドレス key "ns0-nsN.";
47 + };
48 + allow-query {
49 + !{ !ns0のIPアドレス; any; }; key "ns0-nsN.";
50 + };
51 + allow-transfer {
52 + !{ !ns0のIPアドレス; any; }; key "ns0-nsN.";
53 + };
54 +};
55
- DNSコンテンツスレーブサーバーとして、以下の設定を行うものとする。
- IPv4/IPv6問わず、全てのクエリを受け付ける。
- 再帰問い合わせには答えないものとする。
- DNSSEC設定/運用、ログ出力設定、ビュー設定といった機能については説明しない。
※カタログゾーン運用のための設定
- 「allow-new-zones yes;」を設定する。
- カタログゾーン設定(catalog-zones)を行う。
- zone 設定によりカタログゾーンを指定する(指定されたゾーンの内容は別途定義)。
zone-directory 設定により追加されたゾーンファイルの収容先ディレクトリを指定する(デフォルトで /usr/local/etc/namedb/working/)。
- in-memory 設定によりファイルに保存するか決める(no の場合ファイルに保存)。
- default-masters 設定によりカタログゾーンで定義されるゾーンのデフォルト masters が指定される。
※catalog.exmaple ゾーンに関する諸設定
- このスレーブゾーンを更にマスターにするような運用はしない(notify, allow-transfer 設定による明示的な無効化)。
- 特に必要ないのだが、マスターからの問い合わせ(クエリおよびゾーン転送)に回答できるようにしておく(気が向いた時のデバッグ用)。
- 繰り返しとなるが、このゾーン自体はサービスゾーンではないので、外部からのクエリに答える必要は無い。
/usr/local/etc/namedb/ns0-nsN.key
ns0.example.jp サーバーよりTSIGキーをコピーする。
scp -p root@ns0.example.jp:/usr/local/etc/namedb/ns0-nsN.key /usr/local/etc/namedb/ chown bind:wheel /usr/local/etc/namedb/ns0-nsN.key chmod 0400 /usr/local/etc/namedb/ns0-nsN.key
ゾーンの追加
- example.jp ゾーンを追加してみる。
- マスターサーバーにおいて、以下の4つ作業を実施する。
- 当該ゾーンファイル(/usr/local/etc/namedb/master/example.jp.db)の作成。
- ゾーン設定の追加(named.conf の zone 設定)。
- カタログゾーン(catalog.example)への当該ゾーン情報追加。
- リロード(rndc reload)。
※実際に作業を実施してみるとわかるが、確認以外のいわゆる上記作業内容において、マスターサーバーでのみ作業すれば良いことが理解できると思う。
/usr/local/etc/namedb/master/example.jp.db
$TTL 300 @ IN SOA ns0.example.jp. domain.example.jp. ( 2018111101 ; serial 7200 ; refresh (2 hours) 900 ; retry (15 minutes) 2419200 ; expire (4 weeks) 86400 ; minimum (1 day) ) IN NS ns1 IN NS ns2 ns1 IN A ns1のIPアドレス ns2 IN A ns2のIPアドレス
/usr/local/etc/namedb/named.conf
1 --- /usr/local/etc/namedb/named.conf.orig 2018-11-11 20:34:01.464258000 +0900
2 +++ /usr/local/etc/namedb/named.conf 2018-11-11 20:50:14.935238000 +0900
3 @@ -405,3 +405,21 @@
4 ns2のIPアドレス key "ns0-nsN.";
5 };
6 };
7 +
8 +zone "example.jp" {
9 + type master;
10 + file "/usr/local/etc/namedb/master/example.jp.db";
11 + notify explicit;
12 + allow-query {
13 + { !{ !ns1のIPアドレス; any; }; key "ns0-nsN."; };
14 + { !{ !ns2のIPアドレス; any; }; key "ns0-nsN."; };
15 + };
16 + allow-transfer {
17 + { !{ !ns1のIPアドレス; any; }; key "ns0-nsN."; };
18 + { !{ !ns2のIPアドレス; any; }; key "ns0-nsN."; };
19 + };
20 + also-notify {
21 + ns1のIPアドレス key "ns0-nsN.";
22 + ns2のIPアドレス key "ns0-nsN.";
23 + };
24 +};
25
/usr/local/etc/namedb/master/catalog.example.db
1 --- /usr/local/etc/namedb/master/catalog.example.db.orig 2018-11-11 19:22:56.198224000 +0900
2 +++ /usr/local/etc/namedb/master/catalog.example.db 2018-11-11 21:32:18.140863000 +0900
3 @@ -1,4 +1,5 @@
4 $TTL 3600
5 -@ IN SOA . . ( 1 86400 3600 86400 3600 )
6 +@ IN SOA . . ( 2 86400 3600 86400 3600 )
7 IN NS invalid.
8 version IN TXT "1"
9 +eb7b38678a581b9e32078e8b009d0c5c789bce7a.zones IN PTR example.jp.
10
※カタログゾーン機能の一番の肝がこの行に集約される。
「eb7b38678a581b9e32078e8b009d0c5c789bce7a」というハッシュ値と思われる文字列の作り方は、 『「example.jp」のワイヤーフォーマット(wire format)をSHA1通して16進変換したもの』 というまさに正統なハッシュ値だったのである。
意味不明なので個別に作業工程を分解する。
- 「example.jp」を「.」で分解する(最後に暗黙の「.」がある前提)。結果は「example」「jp」「」の3つに分かれる。
- それぞれの文字数をカウントする。「example」=「7」、「jp」=「2」、「」=「0」。
- 文字数をバイナリとして各文字列破片に対するプレフィックスとして、分解した文字列破片を結合する。
- 得られたバイナリデータ(「0x07 0x65 0x78 0x61 0x6d 0x70 0x6c 0x65 0x02 0x6a 0x70 0x00」)、これがワイヤーフォーマットと言われるものである。
- バイナリの編集は難しいので、コマンドで実行する場合は、以下の通り。
printf '\7example\2jp\0'
- 文字数をバイナリにする時は「先行0でない」「10進数で」プレフィックスとして「\」を指定する(先行0は8進数と解釈されてしまうため)。
- また上記ではシングルクォートでくくっているがダブウルクォートの場合「\\」と重ねる必要がある。
- 詳しくはシェルについて調べてください。
- これをさらにSHA1通して16進数に変換する。
printf '\7example\2jp\0' | openssl sha1
リロード
マスターサーバーにて、以下のコマンドで再読み込みする。
rndc reload
コマンド実行後のログの振る舞いを以下に示す。
マスターサーバーのログ
named[12189]: received control channel command 'reload' named[12189]: loading configuration from '/usr/local/etc/namedb/named.conf' : named[12189]: reloading configuration succeeded named[12189]: reloading zones succeeded named[12189]: zone example.jp/IN: loaded serial 2018111101 named[12189]: all zones loaded named[12189]: zone example.jp/IN: sending notifies (serial 2018111101) named[12189]: zone catalog.example/IN: loaded serial 2 named[12189]: zone catalog.example/IN: sending notifies (serial 2) named[12189]: running named[12189]: client @0x802b09800 ns1のIPアドレス#38989/key ns0-nsn (catalog.example): transfer of 'catalog.example/IN': AXFR-style IXFR started: TSIG ns0-nsn (serial 2) named[12189]: client @0x802b09800 ns1のIPアドレス#38989/key ns0-nsn (catalog.example): transfer of 'catalog.example/IN': AXFR-style IXFR ended : named[12189]: client @0x802b0a600 ns1のIPアドレス#58236/key ns0-nsn (example.jp): transfer of 'example.jp/IN': AXFR started: TSIG ns0-nsn (serial 2018111101) named[12189]: client @0x802b0a600 ns1のIPアドレス#58236/key ns0-nsn (example.jp): transfer of 'example.jp/IN': AXFR ended named[12189]: client @0x802b01a00 ns1のIPアドレス#51278: received notify for zone 'example.jp'
スレーブサーバーのログ
named[38318]: client @0x802b02800 ns0のIPアドレス#61756/key ns0-nsn: received notify for zone 'example.jp': TSIG 'ns0-nsn': not authoritative named[38318]: client @0x802b01a00 ns0のIPアドレス#55618/key ns0-nsn: received notify for zone 'catalog.example': TSIG 'ns0-nsn' named[38318]: zone catalog.example/IN: notify from ns0のIPアドレス#55618: serial 2 named[38318]: zone catalog.example/IN: Transfer started. named[38318]: transfer of 'catalog.example/IN' from ns0のIPアドレス#53: connected using ns1のIPアドレス#38989 TSIG ns0-nsn named[38318]: catz: updating catalog zone 'catalog.example' with serial 2 named[38318]: zone catalog.example/IN: transferred serial 2: TSIG 'ns0-nsn' named[38318]: transfer of 'catalog.example/IN' from ns0のIPアドレス#53: Transfer status: success named[38318]: transfer of 'catalog.example/IN' from ns0のIPアドレス#53: Transfer completed: 1 messages, 15 records, 578 bytes, 0.001 secs (578000 bytes/sec) named[38318]: catz: adding zone 'example.jp' from catalog 'catalog.example' - success named[38318]: zone example.jp/IN: Transfer started. named[38318]: transfer of 'example.jp/IN' from ns0のIPアドレス#53: connected using ns1のIPアドレス#58236 TSIG ns0-nsn named[38318]: zone example.jp/IN: transferred serial 2018111101: TSIG 'ns0-nsn' named[38318]: transfer of 'example.jp/IN' from ns0のIPアドレス#53: Transfer status: success named[38318]: transfer of 'example.jp/IN' from ns0のIPアドレス#53: Transfer completed: 1 messages, 6 records, 259 bytes, 0.003 secs (86333 bytes/sec) named[38318]: zone example.jp/IN: sending notifies (serial 2018111101)
スレーブサーバーで運用しているゾーン情報の確認
ゾーン転送された内容はバイナリ化されてるので、named-compilezone コマンドを使用してゾーンファイル(テキストフォーマット)に変換できる。
named-compilezone -f raw -F text -o /dev/stdout catalog.example /usr/local/etc/namedb/slave/catalog.example.db
※なお -f と -o オプションは必須である。-F オプションは体裁整えただけ(-f, -F オプションともに text がデフォルト)、ということで。
これに例えば | awk '/PTR/{ print $3 }' とフィルタしてしまえば、運用ゾーンの一覧が取得できたりする。
スレーブサーバーでのゾーン個別の転送状態の確認
カタログゾーンにより転送されたゾーン情報は /usr/local/etc/namedb/catalog/__catz___default_catalog.example_example.jp.db というファイルに保存される。
「/usr/local/etc/namedb/catalog/」は zone-directory で指定したディレクトリ。
「__catz__」はカタログゾーンを示すプレフィックス。
「_default」はデフォルトビュー(view _default)を示す(今回 view は未使用のため)。
「catalog.example」はカタログゾーン名を示す。
「example.jp」は転送されたゾーン名となる。
この事から、スレーブサーバーでは、複数のマスターサーバーからの同期を想定していることが予想される。 今回 view は使わなかったけど、view を使わないとできない使い方については後述。
またゾーン転送された内容はバイナリ化されてるので、named-compilezone コマンドを使用してゾーンファイル(テキストフォーマット)に変換できる。
named-compilezone -f raw -F text -o /dev/stdout example.jp /usr/local/etc/namedb/catalog/__catz___default_catalog.example_example.jp.db
※なお -f と -o オプションは必須である。-F オプションは体裁整えただけ(-f, -F オプションともに text がデフォルト)、ということで。
スレーブサーバーでのマスターサーバーの状態の確認
マスターサーバーのゾーン定義で許可された allow-query 設定により、スレーブサーバーからマスターサーバーの状態を確認できる。
dig -k /usr/local/etc/namedb/ns0-nsN.key +short example.jp soa @ns0のIPアドレス dig -k /usr/local/etc/namedb/ns0-nsN.key +short catalog.example soa @ns0のIPアドレス
ゾーン転送もお手の物。これと先のファイルの内容と比較して転送されているかを確認する。
dig -k /usr/local/etc/namedb/ns0-nsN.key example.jp axfr @ns0のIPアドレス dig -k /usr/local/etc/namedb/ns0-nsN.key catalog.example axfr @ns0のIPアドレス
マスターサーバーでのスレーブサーバーの状態の確認
本例ではそれができるよう設定を行ったため、スレーブからマスターを見た先の例と同じく、マスターからスレーブの状態を確認することができる。
※なお下記例でのnsNはns1またはns2を示す。
dig -k /usr/local/etc/namedb/ns0-nsN.key +short example.jp soa @nsNのIPアドレス dig -k /usr/local/etc/namedb/ns0-nsN.key +short catalog.example soa @nsNのIPアドレス
ゾーン転送もお手の物。これとオリジナルのファイルの内容と比較して転送されているかを確認する。
dig -k /usr/local/etc/namedb/ns0-nsN.key example.jp axfr @nsNのIPアドレス dig -k /usr/local/etc/namedb/ns0-nsN.key catalog.example axfr @nsNのIPアドレス
ゾーンの削除
- 先に追加した example.jp ゾーンを削除してみる。基本的には追加工程の反対の作業となる。
- マスターサーバーにおいて、以下の4つ作業を実施する。
- カタログゾーン(catalog.example)への当該ゾーン情報の削除。
- ゾーン設定の削除(named.conf の zone 設定の削除)。
- 当該ゾーンファイル(/usr/local/etc/namedb/master/example.jp.db)の削除。
- リロード(rndc reload)。
- 本質的には1と4だけ実行すればスレーブサーバーからは消える。
- よって本例では1と4の工程だけ説明する。もちろん運用上は2と3も作業すること(少なくともコメントアウトはしよう)。
※実際に作業を実施してみるとわかるが、確認以外のいわゆる上記作業内容において、マスターサーバーでのみ作業すれば良いことが理解できると思う。
/usr/local/etc/namedb/master/catalog.example.db
1 --- /usr/local/etc/namedb/master/catalog.example.db.orig 2018-11-11 21:32:18.140863000 +0900
2 +++ /usr/local/etc/namedb/master/catalog.example.db 2018-11-11 23:44:01.315413000 +0900
3 @@ -1,5 +1,4 @@
4 $TTL 3600
5 -@ IN SOA . . ( 2 86400 3600 86400 3600 )
6 +@ IN SOA . . ( 3 86400 3600 86400 3600 )
7 IN NS invalid.
8 version IN TXT "1"
9 -eb7b38678a581b9e32078e8b009d0c5c789bce7a.zones IN PTR example.jp.
10
- とりあえず消したいゾーンは「ハッシュ値.zones」かつPTRなレコードを確認して、<<当該ハッシュ値を含むレコード>>を削除、かな。
- ハッシュ値は、わざわざ計算しなくてもいいです。
リロード
マスターサーバーにて、以下のコマンドで再読み込みする。
rndc reload
あるいは本ケース(手抜き)の場合、以下の手順でもよい。
rndc reload catalog.example
マスターサーバーのログ
named[12189]: received control channel command 'reload' named[12189]: loading configuration from '/usr/local/etc/namedb/named.conf' : named[12189]: zone catalog.example/IN: loaded serial 3 named[12189]: zone catalog.example/IN: sending notifies (serial 3) named[12189]: client @0x802b03600 ns1のIPアドレス#26365/key ns0-nsn (catalog.example): transfer of 'catalog.example/IN': AXFR-style IXFR started: TSIG ns0-nsn (serial 3) named[12189]: client @0x802b03600 ns1のIPアドレス#26365/key ns0-nsn (catalog.example): transfer of 'catalog.example/IN': AXFR-style IXFR ended
スレーブサーバーのログ
named[38318]: client @0x802b01a00 ns0のIPアドレス#51757/key ns0-nsn: received notify for zone 'catalog.example': TSIG 'ns0-nsn' named[38318]: zone catalog.example/IN: notify from ns0のIPアドレス#51757: serial 3 named[38318]: zone catalog.example/IN: Transfer started. named[38318]: transfer of 'catalog.example/IN' from ns0のIPアドレス#53: connected using ns1のIPアドレス#26365 TSIG ns0-nsn named[38318]: catz: updating catalog zone 'catalog.example' with serial 3 named[38318]: zone catalog.example/IN: transferred serial 3: TSIG 'ns0-nsn' named[38318]: transfer of 'catalog.example/IN' from ns0のIPアドレス#53: Transfer status: success named[38318]: transfer of 'catalog.example/IN' from ns0のIPアドレス#53: Transfer completed: 1 messages, 9 records, 358 bytes, 0.005 secs (71600 bytes/sec) named[38318]: catz: deleting zone 'example.jp' from catalog 'catalog.example' - success named[38318]: catz: catz_delzone_taskaction: zone 'example.jp' deleted
マスターサーバーによるスレーブサーバーへのポリシーの強制
物々しいタイトルではあるが、カタログゾーンを通じて、いくつかのポリシーをスレーブ側に強制することができる。 このポリシーは、スレーブ側の設定によらず、マスター側の設定が正となる(設定の上書き)。 更にそのポリシーはゾーン毎に制御可能で、以下の優先度で設定がオーバーライドできる。
- ゾーン毎の個別設定
- カタログゾーンのデフォルト設定
- スレーブサーバーのグローバル設定
上記優先順位の意味するところは以下の通りである。よってこれらポリシーが混ざることはない。
- 「ゾーン個別設定」が【無ければ】「カタログゾーンデフォルト設定」に従う。
- 「カタログゾーンデフォルト設定」が【無ければ】「スレーブサーバーのグローバル設定」に従う。
また当然だが、このポリシ-の強制はカタログゾーン「catalog.example」自体には適用されない。
ポリシーの種類
- マスターサーバーの指定(masters 設定)2種
- クエリ許可の指定(allow-query 設定)
- ゾーン転送許可の指定(allow-transfer 設定)
allow-query、allow-trasnfer 設定についてはよく見る設定なので特に説明の必要は無いと思う。
マスターサーバーの「デフォルト」の指定は今までのBINDには無かった設定で、 「catalog-zones」中の「default-masters」設定で行う1。
よって設定において masters のデフォルトと聞いた時は「catalog-zones 中の default-masters」であることを意味する。
素のマスターサーバーの指定
レコード名としては「masters」。つまり「masters.catalog.example」レコードはカタログゾーンにおける masters 設定のデフォルトを意味する2。
- 先にも説明したが、これは下記設定と同じ意味になる。
options { catalog-zones { : default-masters { ns0のIPアドレス; }; }; };
- ゾーン毎の設定も同じく「masters」となるが、「ハッシュ値.zones.catalog.example」レコードに対しての設定となるため、これは「masters.ハッシュ値.zones.catalog.example」となる。
- 設定例としては下記の通りとなる。
$TTL 3600 @ IN SOA . . ( 1 86400 3600 86400 3600 ) IN NS invalid. version IN TXT "1" masters IN A ns0のIPv4アドレス
- あるいはゾーン毎の設定例としては下記の通りである。
$TTL 3600 @ IN SOA . . ( 1 86400 3600 86400 3600 ) IN NS invalid. version IN TXT "1" eb7b38678a581b9e32078e8b009d0c5c789bce7a.zones IN PTR example.jp. masters.eb7b38678a581b9e32078e8b009d0c5c789bce7a.zones IN A ns0のIPv4アドレス
- 上記設定は両方指定してもかまわない。その場合、ゾーン毎の設定が優先される。
- また「Aレコード」の代わりに「AAAAレコード」を指定することも問題無い。
- 複数設定した場合、「複数のマスターサーバーを指定」することになるが、「masters」設定と同じく機能する。
TSIGキー付きマスターサーバーの指定
- レコード名としては「label.masters」。つまり「label.masters.catalog.example」レコードはカタログゾーンにおけるTSIGキー付き masters 設定のデフォルトを意味する。
- 先にも説明したが、これは下記設定と同じ意味になる。
options { catalog-zones { : default-masters { ns0のIPアドレス key "TSIGキー名"; }; }; };
- ゾーン毎にも同じく「label.masters」となるが、「ハッシュ値.zones.catalog.example」レコードに対しての設定となるため、これは「label.masters.ハッシュ値.zones.catalog.example」となる。
- 設定例としては下記の通りとなる。
$TTL 3600 @ IN SOA . . ( 1 86400 3600 86400 3600 ) IN NS invalid. version IN TXT "1" label.masters IN A ns0のIPv4アドレス label.masters IN TXT "TSIGキー名"
- あるいはゾーン毎の設定例としては下記の通りである。
$TTL 3600 @ IN SOA . . ( 1 86400 3600 86400 3600 ) IN NS invalid. version IN TXT "1" eb7b38678a581b9e32078e8b009d0c5c789bce7a.zones IN PTR example.jp. label.masters.eb7b38678a581b9e32078e8b009d0c5c789bce7a.zones IN A ns0のIPv4アドレス label.masters.eb7b38678a581b9e32078e8b009d0c5c789bce7a.zones IN TXT "TSIGキー名"
- 上記設定は両方指定してもかまわない。その場合、ゾーン毎の設定が優先される。
- また「Aレコード」の代わりに「AAAAレコード」を指定することも問題無い。
- 複数設定した場合、「複数のマスターサーバーを指定」することになるが、「masters」設定と同じく機能する。
二種類のマスターサーバー指定の振る舞いについての注意
- masters レコードと label.masters レコードを同時に指定した場合の振る舞いは奇妙になる。
- ゾーン転送はTSIGキー無しで始め、リトライにより初めてTSIGキーを使用する。
- これは複数マスター指定時のラウンドロビン的振る舞いを意味する。
- スレーブからマスターへの定期的な更新確認クエリはTSIGキー無しで行われる。
- これはマスターからの応答が拒絶であったとは言え、一応応答するので他のマスターに切り替わらないことを意味する。
- 以上のことから、「masters」→「label.masters」の順で解釈していることがわかる。
- よってマスターサーバー側のTSIGキーによる保護の有り無しにより、成功したり失敗したりする。
- 本例ではTSIGキーによる保護を徹底しているため、masters と label.masters の混在は事実上機能しないと言ってよい。
- 本例をベースに設定する場合、label.masters のみ指定しよう。
クエリ許可の指定
- レコード名としては「allow-query」。つまり「allow-query.catalog.example」レコードはカタログゾーンにおけるクエリ許可リスト(ACL)のデフォルトを意味する。
- 先にも説明したが、これは下記設定と同じ意味になる。
options { allow-query { ACLs: }; };
- ゾーン毎にも同じく「allow-query」となるが、「ハッシュ値.zones.catalog.example」レコードに対しての設定となるため、これは「allow-query.ハッシュ値.zones.catalog.example」となる。
- 設定例としては下記の通りとなる。
$TTL 3600 @ IN SOA . . ( 1 86400 3600 86400 3600 ) IN NS invalid. version IN TXT "1" allow-query IN APL 1:0.0.0.0/0 2:0:0:0:0:0:0:0:0/0
- あるいはゾーン毎の設定例としては下記の通りである。
$TTL 3600 @ IN SOA . . ( 1 86400 3600 86400 3600 ) IN NS invalid. version IN TXT "1" eb7b38678a581b9e32078e8b009d0c5c789bce7a.zones IN PTR example.jp. allow-query.eb7b38678a581b9e32078e8b009d0c5c789bce7a.zones IN APL 1:0.0.0.0/0 2:0:0:0:0:0:0:0:0/0
- 上記設定は両方指定してもかまわない。その場合、ゾーン毎の設定が優先される。
また特殊な「APLレコード」を使用する。「1:」はIPv4に対する設定、「2:」はIPv6に対する設定となる。
- 0.0.0.0/0 および 0:0:0:0:0:0:0:0/0 からのアクセス許可となるため、これは「any」を意味する。つまり全てのクエリを許す。
- 複数設定した場合の振る舞いは不明。あまり凝った設定はしない方が良いと思われ。
ゾーン転送許可の指定
- レコード名としては「allow-transfer」。つまり「allow-transfer.catalog.example」レコードはカタログゾーンにおけるクエリ許可リスト(ACL)のデフォルトを意味する。
- 先にも説明したが、これは下記設定と同じ意味になる。
options { allow-transfer { ACLs: }; };
- ゾーン毎にも同じく「allow-transfer」となるが、「ハッシュ値.zones.catalog.example」レコードに対しての設定となるため、これは「allow-transfer.ハッシュ値.zones.catalog.example」となる。
- 設定例としては下記の通りとなる。
$TTL 3600 @ IN SOA . . ( 1 86400 3600 86400 3600 ) IN NS invalid. version IN TXT "1" allow-transfer IN APL !1:0.0.0.0/0 !2:0:0:0:0:0:0:0:0/0
- あるいはゾーン毎の設定例としては下記の通りである。
$TTL 3600 @ IN SOA . . ( 1 86400 3600 86400 3600 ) IN NS invalid. version IN TXT "1" eb7b38678a581b9e32078e8b009d0c5c789bce7a.zones IN PTR example.jp. allow-transfer.eb7b38678a581b9e32078e8b009d0c5c789bce7a.zones IN APL !1:0.0.0.0/0 !2:0:0:0:0:0:0:0:0/0
- 上記設定は両方指定してもかまわない。その場合、ゾーン毎の設定が優先される。
また特殊な「APLレコード」を使用する。「!」は後で指定した設定に対する「拒否」を意味し、「1:」はIPv4に対する設定、「2:」はIPv6に対する設定となる。
- 0.0.0.0/0 および 0:0:0:0:0:0:0:0/0 からのアクセス不可となるため、これは「none」を意味する。つまり全てのゾーン転送要求を拒絶する。
- 複数設定した場合の振る舞いは不明。あまり凝った設定はしない方が良いと思われ。
よくある質問とその答え
Q.ポリシーの強制はどこまで設定すればいいですか?
A.カタログゾーンのデフォルトとして定義しておけば、以下の理由でメリットあると思われ。
- スレーブサーバーの設定参照せずともカタログゾーンの内容確認すれば済む。
- 後日変更があってもスレーブサーバーの設定変更せずに済む。
よってマスターサーバーで最初に作る /usr/local/etc/namedb/master/catalog.example.db の内容は下記の通りにしておけばよい。
$TTL 3600 @ IN SOA . . ( 1 86400 3600 86400 3600 ) IN NS invalid. version IN TXT "1" label.masters IN A ns0のIPv4アドレス label.masters IN TXT "TSIGキー名" allow-query IN APL 1:0.0.0.0/0 2:0:0:0:0:0:0:0:0/0 allow-transfer IN APL !1:0.0.0.0/0 !2:0:0:0:0:0:0:0:0/0
またスレイブサーバーの catalog-zones 設定は下記の通り default-masters 設定を削除する。
catalog-zones { zone "catalog.example" zone-directory "/usr/local/etc/namedb/catalog" in-memory no; };
Q.カタログゾーン内でTSIGキー名の指定はできる、つまりTSIGキー名は配布できるようですが、TSIGキー自体は配布できないのですか?
A.おっと。ゾーン転送はTSIGキーそのもの(これは秘密鍵です)を配布できるほど、安全な通信経路ではないです。 TSIGキーを配布したければ、SCP/RSYNCを使用するか、 さらにマスターサーバーで実行するかスレーブサーバーで実行するか、 といった点を検討の上、運用する必要があります。
あるいはSIG(0)(公開鍵暗号ベースの鍵共有プロトコル)やGSS-TSIG(Generic Security Service Algorithm for TSIG)といったDNS内に閉じた鍵配布する仕組みが用意されているようですが、 軽くググってでも出てこないことからお察しで。
Q.allow-query/allow-transfer の指定が意味不明です。まずは解説を!
A.BIND9のACL(Access Controll Lists)の癖となります。詳しくは参考文献をお読みください。 というのは不親切なので、解説すると、
- ACLの処理はリストの左から右へ評価されます。これはAND結合であるということを意味しません。
- よってブール論理で解釈するのではなく、ファーストマッチ・ファーストアウトで解釈する必要があります。
- 接続元IPアドレスに対して、以下の3つが判断されます。
- match and accept(一致かつ受諾)
- match and reject(一致かつ拒絶)
- no match(一致しない、なので次のリストに委ねる)
- これは「!」(reject)と「 」(accept、「!」が指定されてない)のニュアンスが直感的に違うことを意味します(今まで一致・不一致に見えませんでしたか?)。
- ネスト({・・・})されていた場合、その内容について下記の2つの評価を行い(ここでは一致・不一致の直感とマッチする)、その結果に対して上記3つの判断が実施されます。
- match(一致)
- no match(不一致)
- 当然ネストの中に更にネストできるので、それは上記2評価(match または no match)の繰り返しとなる。
上記ルールを踏まえ、問題のルールを解析すると・・・。
- 大枠は2つのリストに分かれる(「!」の意味に注意)。
- !{ !IPv4アドレス; !IPv6アドレス; any; } → match and reject
- key "TSIGキー名." → accept or reject
- 最初のネストを分解すると、3つのリストに分かれる。
- !IPv4アドレス → 一致した場合「no match」という評価で完了
- !IPv6アドレス → 一致した場合「no match」という評価で完了
- any → 一致(常に一致する)した場合「match」という評価で完了
上記をまとめて解釈すると、
- 最初のネスト内では以下の評価を行う(「!」の評価に注意)。
- 「IPv4アドレス『ではない』」の評価をする。
- 指定された「IPv4アドレス」であれば「no match」として評価完了。
- そうでないなら「match」として次の評価。
- 「IPv6アドレス『ではない』」の評価をする。
- 指定された「IPv6アドレス」であれば「no match」として評価完了。
- そうでないなら「match」として次の評価。
- 「any」(任意の全てのアドレス)に・・・とここまで来ると常に match と解釈され、評価が終了する。
- また any の時点で既に、「match」評価されてるので、この場合の「any」の指定のあり/無しに意味はない
- ※人間の直感には反するから入れておいた方がいい。
- 「IPv4アドレス『ではない』」の評価をする。
- このネストでの結果を全体「!」=match and reject で評価することから、「no match」(つまり次のリストの評価)の時は、次のリスト key が評価される。
Q.最初に allow-* の設定を明示してるのは何故ですか?デフォルトでも十分だと思いますが。
A.ポリティカル・コレクトネスです。以下の4つの設定のデフォルトは下記の通りとなります。
設定 |
デフォルト値 |
今回の設定値 |
備考 |
recursion |
yes |
no |
|
allow-query |
any |
any(none) |
隠れマスター運用なので none を指定しただけ |
allow-recursion |
localnets, localhost |
none |
|
allow-query-cache |
localnets, localhost |
none |
|
- localhost はインターフェースに割り当てられたIPアドレスを意味します。
- localnets はそのIPが所属するネットワークを意味します。
よって「recursion」設定以外は「対インターネット」向けサービスとして見た場合、 意味はあまり変わりません。もちろんローカルネットワーク内での不用意なアクセスに 対して防御する意味合いはありますので、そこを含めて「ポリコレ」的に設定を実施します。
詳しくは参考文献をご確認ください。
Q.参考文献にある「やってみた」系サイトの解説を見たところ、ダイナミックDNSアップデートしてるけど、実際のところどうなの?
A.カタログゾーン機能の運用に当たり、ダイナミックDNSアップデートによる更新は必須ではありません。 ただし、本例で解説したカタログゾーンであるところ「catalog.example」については、 ダイナミックDNSアップデートによる設定および運用は推奨されています。
これはSOAレコードのシリアル番号更新忘れ対策として一番のメリットがあります。 またデメリットであるところのNSUPDATEスクリプトを書いてのコマンド実行については、 シェルスクリプトによる工で運用負荷を下げることができます。
いずれにせよ追加ゾーン(本例では example.jp)の設定までダイナミックDNSアップデートするかは、 今までの運用を見て判断するところだと思います。 全てを頑張る必要はありません。
ダイナミックDNSアップデートについては、ダイナミックDNSサーバーの設定を参照して欲しい。
Q.なぜBIND9で?オワコンでは?
A.ええ。オワコンでしょうね。キャッシュサーバーとしてはUnbound使えば十分で、 唯一コンテンツサーバーとして生きる道しか残ってないと思います。
そのコンテンツサーバーとしても、PowerDNS、NSD等がより有力な存在としてリストアップされてるようですが、 その辺りは 参考文献をご覧ください。 「結論」については自分もそう思います。
ただBIND9を出て行った先は今時AWS Rotue53ではないでしょうか。 費用面(1ゾーン百数十円/月)、運用面(管理画面の存在、APIのよる外部アクセス)、 セキュリティ面(たくさんのDNSサーバーにゾーンを分散、AWSへの運用委託)。
最近になって自社運用からRoute53へ切り替えましたが、これらを理由として上げられて、否定できる要素は全くありませんでした。
こんな話もありますが(賛同しますが)、 同時に自ら運用することの是非について考えるべきだと思います。
参考文献
付録1.APLレコード
- APLレコードは早々見ないレコードなので簡単に解説。
- 1レコード中に複数指定可能。
[ |!]<1|2>:<IPv4|IPv6>/<プレフィックス> という4つの構成からなる。
- 先頭の「!」が無い場合はマッチ、ある場合は「マッチしない」を意味する。
- 次の「1」または「2」はアドレスファミリーを意味し、1=「IPv4」、2=「IPv6」となる。
- プレフィックスにより指定されたアドレスの範囲が指定される。