第12章 DNSサーバーの基本設定とゾーン管理
LPIC-2 207.1〜207.2 相当
ここから202試験パートに入ります。まずは、名前とIPアドレスを結びつけるDNSの仕組みと、代表的なDNSサーバーソフトウェアBINDの基礎を扱います。
DNSの基本用語
| 用語 | 意味 |
|---|---|
| 権威DNSサーバー | 特定のドメインについて「正式な回答」を持つサーバー |
| ゾーン | あるサーバーが管理を任されているドメインの範囲 |
| キャッシュDNSサーバー(フルリゾルバ) | 問い合わせを受けて、権威サーバーに再帰的に問い合わせて回答するサーバー |
| Aレコード | ホスト名をIPv4アドレスに変換するレコード |
| MXレコード | そのドメイン宛のメールを受け取るサーバーを指定するレコード |
| NSレコード | そのゾーンを管理する権威DNSサーバーを指定するレコード |
| CNAMEレコード | あるホスト名を別のホスト名の別名(エイリアス)として定義するレコード |
| PTRレコード | IPアドレスからホスト名を引く「逆引き」に使うレコード |
| TXTレコード | 任意のテキスト情報を格納。SPFやDKIMなど送信ドメイン認証にも利用される |
| AAAAレコード | ホスト名をIPv6アドレスに変換するレコード(Aレコードの128ビット版) |
| SRVレコード | 特定のサービス(プロトコル)を提供するホストとポート番号を示すレコード |
| CAAレコード | そのドメインに証明書を発行してよい認証局(CA)を制限するレコード |
複数のAレコードを同じホスト名に登録すると、クライアント側は問い合わせのたびに異なる順序で結果を受け取ることが多く、簡易的な負荷分散(DNSラウンドロビン)として使われることがあります。ただし障害検知の仕組みは持たないため、あるサーバーが停止していてもそのIPアドレスを返し続けてしまう点には注意が必要です。
BIND(named)の設定ファイル
BINDは最も広く使われているDNSサーバーソフトウェアです。主要な設定ファイルは named.conf で、そこからゾーンファイルを読み込みます。
bind9パッケージ)は設定を /etc/bind/named.conf から named.conf.options・named.conf.local に分割し、ゾーンファイルも /etc/bind/ 配下に置く構成が標準です。一方RHEL系(bindパッケージ)は /etc/named.conf 1ファイルに設定をまとめ、ゾーンファイルは /var/named/ 配下に置くのが慣習です。本章のコード例は、設定を分割して見通しをよくできるDebian系の構成で統一しています。RHEL系で作業する場合は、パスの読み替えが必要です。
/etc/bind/named.conf.local(Debian系の例)
zone "example.com" {
type master;
file "/etc/bind/db.example.com";
};
/etc/bind/db.example.com(ゾーンファイルの例)
$TTL 86400
@ IN SOA ns1.example.com. admin.example.com. ( 2024010101 3600 900 604800 86400 )
@ IN NS ns1.example.com.
@ IN A 192.0.2.10
www IN A 192.0.2.10
mail IN MX 10 mail.example.com.
SOAレコードのカッコ内には、シリアル番号に続けて4つの時間パラメータが並びます。refresh(セカンダリがプライマリに更新確認を行う間隔)、retry(refreshに失敗した際の再試行間隔)、expire(それでもプライマリに接続できない場合、セカンダリが自身のデータを無効とみなすまでの期間)、minimum(否定応答=該当レコードが存在しないという回答をキャッシュしてよい時間、ネガティブキャッシュTTL)です。これらの値もLPIC-2の記述式設問で狙われやすいポイントです。
ns1.example.com. のように末尾にドットがある場合は「完全修飾ドメイン名(FQDN)」として扱われますが、ドットがないと$ORIGIN(既定ではゾーン名)が自動的に補われてしまい、ns1.example.com.example.com のような意図しないホスト名になってしまいます。named-checkzoneで警告が出ないか必ず確認しましょう。
逆引きゾーンとセカンダリDNS
IPアドレスからホスト名を求める「逆引き」も、通常のゾーンと同様に別ファイルとして定義します。IPv4の場合、オクテットを逆順にした in-addr.arpa というドメインを使います。
/etc/bind/named.conf.local に追記
zone "1.2.0.192.in-addr.arpa" {
type master;
file "/etc/bind/db.192.0.2";
};
/etc/bind/db.192.0.2(逆引きゾーンファイル)
$TTL 86400
@ IN SOA ns1.example.com. admin.example.com. ( 2024010101 3600 900 604800 86400 )
@ IN NS ns1.example.com.
10 IN PTR www.example.com.
可用性を高めるため、権威DNSサーバーは通常1台のプライマリ(マスター)だけでなく、複数のセカンダリ(スレーブ)サーバーで構成します。セカンダリはゾーン転送(AXFR/IXFR)によってプライマリからデータを取得し、同じ内容を提供します。
セカンダリ側のnamed.conf.local
zone "example.com" {
type slave;
file "/var/cache/bind/db.example.com";
masters { 192.0.2.10; };
};
セカンダリはゾーン転送を受け取る際、SOAレコードのシリアル番号を見て「プライマリの方が新しいかどうか」を判断します。そのため、プライマリ側でゾーンファイルを書き換えたのにシリアル番号を上げ忘れると、セカンダリはいつまでも古い内容のままになってしまいます。運用ミスの中でも特に多い落とし穴です。
再帰的な問い合わせとキャッシュ
クライアント(スタブリゾルバ)は通常、キャッシュDNSサーバーに「再帰的問い合わせ」を行い、答えが見つかるまで全部おまかせします。一方、キャッシュDNSサーバー自身はルートサーバー→TLD(.comなどの)サーバー→権威サーバーへと、階層をたどりながら「反復的問い合わせ」を行い、最終的な回答を得てからクライアントに返します。
一度得られた回答は、レコードごとに設定されたTTL(Time To Live、生存時間)の間だけキャッシュされ、同じ問い合わせが来ても権威サーバーへ再度問い合わせずに済みます。TTLを短くするとレコード変更の反映が速くなる一方、権威サーバーへの問い合わせ頻度が増えて負荷が上がるというトレードオフがあります。サーバー移転など変更を予定している場合は、事前にTTLを短くしておくのが定石です。
DNSSECの基礎
DNSは元々、応答が本物かどうかを検証する仕組みを持たず、偽の応答を返す「キャッシュポイズニング」のような攻撃に弱い側面がありました。DNSSEC(DNS Security Extensions)は、ゾーンデータに電子署名を付与し、クライアント側がその署名を公開鍵で検証できるようにする拡張です。
$ sudo dnssec-keygen -a RSASHA256 -b 2048 example.com # 鍵ペアを生成
Generating key pair...........++++ ...++++
Kexample.com.+008+41234
$ sudo dnssec-signzone -o example.com db.example.com # ゾーンに署名
Fetching ZSK ... done
Signing zone...
Verifying the zone using the following algorithms: RSASHA256.
Zone signing complete:
Algorithm: RSASHA256: ZSKs: 1, KSKs: 0 active, 0 revoked
db.example.com.signed
この行のこの値に注目: dnssec-keygen実行後に表示されるKexample.com.+008+41234が、生成された鍵ファイル名(K+ドメイン名+アルゴリズム番号+キータグ)です。dnssec-signzone末尾のdb.example.com.signedが実際に署名済みゾーンファイルとして生成されたファイル名で、named.conf側のfile指定をこちらに切り替える必要があります。
DNSSECを導入したゾーンは、親ゾーン(上位のTLDなど)にDS(Delegation Signer)レコードを登録することで、信頼の連鎖(chain of trust)がルートサーバーまでつながります。設定はやや複雑ですが、LPIC-2では「DNSSECが何を解決する技術か」という概念レベルの理解が問われます。
設定の確認と反映
$ sudo named-checkconf # 設定ファイルの文法チェック(正常時は無出力)
$ sudo named-checkzone example.com /etc/bind/db.example.com # ゾーンファイルのチェック
zone example.com/IN: loaded serial 2026082101
OK
$ sudo systemctl reload bind9 # 設定を反映(正常時は無出力)
この行のこの値に注目: named-checkconfは/etc/bind/named.conf本体とそこからincludeされる全ファイルの文法を検査し、正常であれば何も表示しません。named-checkzoneは最後にOKと表示されればゾーンファイルの内容も問題なく、loaded serial ...で読み込んだシリアル番号を確認できます。
ゾーンファイルの記述を誤った場合、たとえばレコードの末尾にピリオドを付け忘れる(相対名として解釈されてしまう)ような典型的なミスがあると、次のようなエラーになります。
$ sudo named-checkzone example.com /etc/bind/db.example.com
dns_master_load: /etc/bind/db.example.com:12: www.example.com: no owner
zone example.com/IN: loading from master file db.example.com failed: no owner
zone example.com/IN: not loaded due to errors.
この行のこの値に注目: 12:という行番号がゾーンファイル内のどこに問題があるかを示します。not loaded due to errorsと表示された場合、この状態のままrndc reloadやsystemctl reloadを実行してもゾーンは反映されず、既存の(古い)ゾーンデータが使われ続けるため、エラーを解消してから反映操作を行う必要があります。
systemctl reload はプロセスを終了させずに設定・ゾーンファイルだけを再読み込みするため、名前解決サービスを止めずに変更を反映できます。設定ファイルの構文自体を大きく変えた場合や、reloadで反映されない項目を変更した場合のみ restart を使うとよいでしょう。動作確認
$ dig @192.0.2.10 www.example.com # 指定したDNSサーバーに直接問い合わせる
;; ANSWER SECTION:
www.example.com. 3600 IN A 203.0.113.10
;; SERVER: 192.0.2.10#53(192.0.2.10)
$ dig example.com MX # MXレコードだけを問い合わせる
;; ANSWER SECTION:
example.com. 3600 IN MX 10 mail.example.com.
$ dig +short www.example.com # 回答部分のIPアドレスだけを簡潔に表示
203.0.113.10
$ dig +trace example.com # ルートサーバーから順にたどる反復問い合わせの過程を表示
. 518400 IN NS a.root-servers.net.
com. 172800 IN NS a.gtld-servers.net.
example.com. 172800 IN NS ns1.example.com.
;; Received 65 bytes from 192.0.2.10#53(192.0.2.10) in 4 ms
$ host www.example.com # digより簡易な出力の名前解決コマンド
www.example.com has address 203.0.113.10
この行のこの値に注目: @192.0.2.10で問い合わせ先サーバーを明示すると、末尾のSERVER:行で実際にどのサーバーが応答したかを確認できます。+traceはルート→TLD→権威サーバーの順に段階を追って表示するため、どの階層で委任が切れているかをたどって障害切り分けができます。
dig の出力は ANSWER SECTION(実際の回答)、AUTHORITY SECTION(権威サーバーの情報)、ADDITIONAL SECTION(補足情報)に分かれています。トラブルシューティングの際は、まずANSWER SECTIONに期待したレコードが返っているかを確認し、返っていなければAUTHORITY SECTIONで委任先が正しいかを追いかけるのが基本的な流れです。
逆引き(PTRレコード)と正引きの違い
ここまで扱ってきたのは「ホスト名からIPアドレスを引く」正引きですが、その逆に「IPアドレスからホスト名を引く」逆引きという仕組みもあります。逆引きにはPTRレコードが使われ、専用のin-addr.arpaという特殊なドメイン階層で管理されます(IPアドレスのオクテットを逆順に並べた名前になります)。
$ dig -x 192.0.2.10 # IPアドレスからホスト名を逆引き
;; QUESTION SECTION:
;10.2.0.192.in-addr.arpa. IN PTR
;; ANSWER SECTION:
10.2.0.192.in-addr.arpa. 3600 IN PTR ns1.example.com.
この行のこの値に注目: QUESTION SECTIONにあるように、内部的にはIPアドレスのオクテットを逆順にしたin-addr.arpaドメインへのPTRレコード問い合わせに変換されています。ANSWER SECTIONのPTRレコードが実際に対応するホスト名です。
メールサーバーの送信元IPは、スパム対策の一環として逆引きが正しく設定されているかをチェックされることが多く、逆引きが未設定・不一致だと正当なメールでも迷惑メール判定を受けやすくなります。自社で運用するメールサーバーを構築する際は、正引き・逆引きの両方が正しく対応しているかを必ず確認しましょう。
フォワーダとキャッシュ専用サーバー
自社ネットワーク内に権威DNSサーバーとは別に、社内利用者向けのキャッシュ専用サーバー(フォワーダ)を1台立てておくと、外部への問い合わせを集約しつつ、既にキャッシュされた内容は高速に返せるようになります。named.conf.optionsでforwardersを指定すると、自身で反復問い合わせを行う代わりに、指定した上位のDNSサーバー(プロバイダのDNSやパブリックDNSなど)に問い合わせを委譲できます。
/etc/bind/named.conf.options の一部
options {
forwarders { 8.8.8.8; 1.1.1.1; };
forward only;
};
forward onlyを指定すると、フォワーダへの問い合わせが失敗した場合でも自前の反復問い合わせにフォールバックしなくなります。社内ネットワークのように、外向きの直接的な問い合わせを制限したい環境でよく使われる設定です。
options句の主要ディレクティブ
BINDの動作全体に関わる設定は、named.conf.options(またはnamed.confのoptions { }ブロック)にまとめます。ここまでで扱ったforwarders以外にも、セキュリティ・運用上重要なディレクティブが数多くあります。
| ディレクティブ | 意味 |
|---|---|
directory | ゾーンファイルなど相対パスで指定するファイルの基点ディレクトリ |
allow-query | 問い合わせを許可するクライアントの範囲(IPアドレス・ネットワーク) |
allow-transfer | ゾーン転送(AXFR/IXFR)を許可するセカンダリの範囲 |
allow-recursion | 再帰的な問い合わせを許可するクライアントの範囲 |
recursion yes/no | このサーバー自身が再帰的問い合わせを行うかどうか |
listen-on | 問い合わせを受け付けるIPv4アドレス・ポート |
listen-on-v6 | 問い合わせを受け付けるIPv6アドレス・ポート |
version | digなどのversion.bind問い合わせに対して返す文字列。実際のバージョンを隠すために変更することが多い |
dnssec-validation | 受け取った応答のDNSSEC署名を検証するかどうか(auto/yes/no) |
/etc/bind/named.conf.options の例
options {
directory "/var/cache/bind";
allow-query { any; };
allow-transfer { none; };
allow-recursion { trusted; };
recursion yes;
listen-on { any; };
listen-on-v6 { any; };
version "unknown";
dnssec-validation auto;
};
allow-recursionを無制限(any)にしたまま外部に公開してしまうと、第三者に再帰問い合わせを踏み台として使われる「オープンリゾルバ」状態になり、DNS増幅攻撃(DNS amplification attack)に加担してしまう危険があります。権威サーバーとキャッシュサーバーの役割を明確に分離し、権威サーバーではrecursion noとするのが基本です。
acl句による名前付きアクセスリスト
先ほどのallow-queryやallow-transferに、IPアドレスの集合をそのつど書き並べると、設定が長くなり保守しづらくなります。acl句を使うと、よく使うIPアドレスの集合に名前を付けて再利用できます。
named.conf.options(またはnamed.conf.local)の先頭付近
acl "trusted" {
192.0.2.0/24;
203.0.113.5;
localhost;
};
options {
allow-recursion { trusted; };
};
組み込みのany(すべて)、none(誰も許可しない)、localhost(このサーバー自身)、localnets(このサーバーが直接接続しているネットワーク)といったキーワードも、aclと同様に使えます。
view句によるsplit DNS
社内ネットワークからは内部向けのプライベートIPアドレスを、インターネットからは外部向けのグローバルIPアドレスを返したい、といった要件は「split DNS(またはsplit-horizon DNS)」と呼ばれ、BINDではview句で実現します。
named.conf.local の例
acl "internal-net" { 192.168.1.0/24; };
view "internal" {
match-clients { internal-net; };
zone "example.com" {
type master;
file "/etc/bind/internal/db.example.com";
};
};
view "external" {
match-clients { any; };
zone "example.com" {
type master;
file "/etc/bind/external/db.example.com";
};
};
この行のこの値に注目: match-clientsで指定した条件に、問い合わせ元のクライアントが一致するviewが上から順に評価され、最初に一致したviewのゾーン定義が使われます。この例ではinternal-netからの問い合わせには社内向けのdb.example.com(プライベートIPを含む)が、それ以外(any)からの問い合わせには社外向けのdb.example.com(グローバルIPのみ)が返されます。view句の定義順序が評価順序に直結するため、より限定的な条件のviewを先に、より広い条件(any)のviewを後に書くのが鉄則です。順序を逆にすると、内部ネットワークからの問い合わせも常に外部向けviewにマッチしてしまいます。
logging句によるログ出力の設定
BINDは既定でも基本的なログをsyslog経由で出力しますが、logging句を使うと、ログの出力先・種類・詳細度を細かく制御できます。
named.conf.options(またはnamed.conf)の例
logging {
channel "query-log" {
file "/var/log/named/query.log" versions 5 size 20m;
severity info;
print-time yes;
};
category queries { query-log; };
channel "security-log" {
file "/var/log/named/security.log" versions 3 size 10m;
severity warning;
print-time yes;
};
category security { security-log; };
};
この行のこの値に注目: channelは「どこに」「どの詳細度で」出力するかを定義する単位で、categoryは「どの種類のイベントを」そのchannelへ振り分けるかを定義します。versions 5 size 20mは、ログファイルが20MiBに達するたびにローテーションし、最大5世代分(query.log.0〜query.log.4)を保持することを意味します。severityは出力する詳細度のしきい値(critical・error・warning・notice・info・debugの順に詳しくなる)で、print-time yesは各ログ行の先頭にタイムスタンプを付与する設定です。
| 代表的なcategory | 記録される内容 |
|---|---|
queries | 受信したすべての問い合わせ(トラフィック量が多いため既定では無効) |
security | アクセス制御による拒否など、セキュリティに関わるイベント |
default | 個別のcategoryが指定されていないすべてのイベント |
queriesカテゴリのログは、すべての問い合わせを記録するためトラフィック解析やトラブルシューティングに有用ですが、負荷の高いサーバーではログの量が非常に大きくなります。常時有効にするのではなく、調査したいときだけrndc querylogで一時的に有効・無効を切り替える運用が実務的です。
rndc — BINDのリモート管理コマンド
rndc(remote name daemon control)は、稼働中のnamedプロセスに対して、設定の再読み込みやゾーンの操作などを指示するための管理コマンドです。rndcとnamedの間は共有鍵(HMAC)による認証が行われ、この鍵はrndc.keyファイルに保存されます。
$ sudo rndc-confgen -a # /etc/bind/rndc.key を生成(多くのディストリでは初期状態で自動生成済み。正常時は無出力)
$ cat /etc/bind/rndc.key
key "rndc-key" {
algorithm hmac-sha256;
secret "xxxxxxxxxxxxxxxxxxxxxxxxxx==";
};
named.conf側では、この鍵を使ってrndcからの接続を受け付けるようcontrols句で指定します。
named.conf の一部
include "/etc/bind/rndc.key";
controls {
inet 127.0.0.1 port 953 allow { 127.0.0.1; } keys { "rndc-key"; };
};
rndcには、運用でよく使う多数のサブコマンドが用意されています。
| サブコマンド | 効果 |
|---|---|
rndc status | 稼働状況(バージョン、稼働ゾーン数、再帰問い合わせの状況など)を表示 |
rndc reload | すべての設定・ゾーンファイルを再読み込みする(プロセスは再起動しない) |
rndc reconfig | named.confの変更のみを反映する(既存ゾーンの再読み込みは行わない、reloadより軽量) |
rndc flush | キャッシュされている全レコードを破棄する |
rndc freeze [ゾーン名] | 指定ゾーン(省略時は全ゾーン)を凍結し、動的更新を一時停止してゾーンファイルを手編集可能にする |
rndc thaw [ゾーン名] | freezeで凍結したゾーンの動的更新を再開する(ゾーンファイルも再読み込みされる) |
rndc querylog | 問い合わせログ(queryログ)の記録を切り替える(トグル動作) |
rndc retransfer ゾーン名 | セカンダリで、指定ゾーンの全体を強制的に再転送させる |
rndc notify ゾーン名 | プライマリから、そのゾーンのセカンダリへNOTIFYメッセージを再送する |
$ sudo rndc status
version: BIND 9.18.30-0ubuntu0.24.04.2-Ubuntu
number of zones: 3 (1 automatic)
recursive clients: 0/900/1000
tcp clients: 0/150
server is up and running
$ sudo rndc reload example.com
zone reload up-to-date
$ sudo rndc flush # 正常時は無出力
この行のこの値に注目: rndc statusのserver is up and runningで稼働状態を確認でき、number of zonesで実際に読み込まれているゾーン数を確認できます。rndc reload example.comのzone reload up-to-dateは、ゾーンファイルの内容(シリアル番号)に変更がなく再読み込みの必要がなかったことを示します。
rndc freeze ゾーン名でそのゾーンへの動的更新を一時停止し、編集後にrndc thaw ゾーン名で再開するという手順を踏みます。この手順はLPIC-2でも狙われやすいポイントです。
TSIG — トランザクション署名によるゾーン転送の保護
ゾーン転送を許可するセカンダリの範囲はallow-transferでIPアドレスによって制限できますが、IPアドレスは送信元詐称(スプーフィング)の対象になりうるため、それだけでは十分な保護とはいえません。TSIG(Transaction Signature)は、プライマリとセカンダリの間で共有鍵を使ってメッセージ全体に署名し、通信内容の改ざん・なりすましを検知できるようにする仕組みです。
$ tsig-keygen tsig-key > /etc/bind/tsig-key.conf # 正常時は無出力(結果はリダイレクト先のファイルに書き込まれる)
# または dnssec-keygen -a HMAC-SHA256 -b 256 -n HOST tsig-key でも生成可能
$ cat /etc/bind/tsig-key.conf
key "tsig-key" {
algorithm hmac-sha256;
secret "yyyyyyyyyyyyyyyyyyyyyyyyyy==";
};
生成した鍵は、プライマリ・セカンダリ双方のnamed.confに同一の内容で配置し、通信相手ごとにserver句で使用する鍵を指定します。
プライマリ側 named.conf
include "/etc/bind/tsig-key.conf";
server 192.0.2.20 { # セカンダリのIPアドレス
keys { "tsig-key"; };
};
zone "example.com" {
type master;
file "/etc/bind/db.example.com";
allow-transfer { key tsig-key; }; # IPアドレスではなく鍵の保持を条件にする
};
セカンダリ側 named.conf
include "/etc/bind/tsig-key.conf";
server 192.0.2.10 { # プライマリのIPアドレス
keys { "tsig-key"; };
};
zone "example.com" {
type slave;
file "/var/cache/bind/db.example.com";
masters { 192.0.2.10; };
};
TSIGを使った転送が正しく機能しているかは、digに鍵情報を渡すことで手動テストできます。
$ dig @192.0.2.10 example.com AXFR -y hmac-sha256:tsig-key:yyyyyyyyyyyyyyyyyyyyyyyyyy==
example.com. 3600 IN SOA ns1.example.com. admin.example.com. 2026082101 3600 900 604800 3600
example.com. 3600 IN NS ns1.example.com.
www.example.com. 3600 IN A 203.0.113.10
example.com. 3600 IN SOA ns1.example.com. admin.example.com. 2026082101 3600 900 604800 3600
;; TSIG: hmac-sha256, response signed successfully
この行のこの値に注目: ゾーン全体がSOAレコードで始まりSOAレコードで終わる(AXFRの規約通りの区切り)のが正常な転送結果です。末尾のTSIG: ... response signed successfullyで、応答が正しい鍵で署名されていたことを確認できます。鍵が一致しない場合はtsig verify failureというエラーになり、転送内容は返されません。
allow-transferによるIPアドレス制限は、送信元IPアドレスを偽装した攻撃(IPスプーフィング)や、正規のセカンダリと同じネットワークに侵入された場合には防御になりません。TSIGは、送信元がどのIPアドレスであっても、正しい共有鍵を持つ相手だけに応答するため、より強固な認証層を追加できます。実務では、IPアドレス制限とTSIGを併用する多層防御が推奨されます。
chroot jailでのBIND実行
namedプロセスがもし脆弱性を突かれて侵害された場合、通常のプロセスと同じ権限のままでは、システム全体のファイルにアクセスされてしまう危険があります。chroot(change root)は、あるプロセスから見えるルートディレクトリを、本来の/ではなく特定のディレクトリに限定する仕組みで、万が一侵害された場合の被害範囲を、そのディレクトリ配下に限定できます。
bind9をchroot環境で動かす場合、通常は/var/named/chroot(ディストリビューションにより異なる)のようなディレクトリの下に、通常のシステムルートに存在する最低限のディレクトリ構造を複製します。
| chroot内のディレクトリ | 用途 |
|---|---|
etc/ | named.conf、rndc.key、ゾーンファイルなどの設定一式 |
var/ | ログファイル、キャッシュ用ゾーンファイルなどnamedが書き込む領域 |
dev/ | namedが必要とするデバイスファイル(/dev/random、/dev/nullなど) |
/dev/random(または/dev/urandom)は、DNSSECの署名やクエリIDのランダム化に使う乱数を生成するために必要で、/dev/nullは出力を破棄する際に多くのプログラムが暗黙に利用します。chroot環境ではシステム本来の/devが見えなくなるため、これらのデバイスファイルをchroot内に個別に用意(mknodで作成するか、bind-mountで本来の/devの該当ファイルを持ち込む)しておかないと、namedの起動やDNSSEC関連の処理が失敗します。
ログについても同様の問題があり、chroot内のnamedからは通常の/dev/log(syslogのソケット)が見えなくなるため、syslogデーモン側でchroot内のdev/logにも追加でリッスンさせる設定(例:rsyslogの$AddUnixListenSocket)を行うか、BIND自身のファイル出力ログ(logging句)に切り替える必要があります。
RHEL系ではnamed-chroot.serviceという専用のsystemdユニットが用意されており、これを使うと上記のディレクトリ構造やマウント処理が自動化されます。Debian系では、パッケージ既定ではchroot構成が用意されておらず、必要に応じて管理者自身がディレクトリ構造を構築し、/etc/default/bind9の起動オプションに-t /var/named/chroot -u bindのように指定します。
ProtectSystem、ProtectHome、PrivateDevices、NoNewPrivilegesなどをユニットファイルの[Service]セクションに指定する方式)で、より柔軟かつ簡便に同様の隔離効果を得られるようになってきています。chrootの考え方自体は依然として試験範囲・実務知識として重要ですが、最新の環境ではこうしたsystemdの機能で代替されるケースも増えている点は理解しておきましょう。
DANEとTLSAレコードの概要
DANE(DNS-based Authentication of Named Entities)は、証明書の正当性を、既存の認証局(CA)階層とは独立に、DNSSECで保護されたDNS応答を使って検証できるようにする仕組みです。DANEではTLSAレコードという新しいレコードタイプを使い、特定のホスト・ポートで提供されるべきTLS証明書(またはその公開鍵)の情報をDNSに公開します。
TLSAレコードの例(_443._tcp.www.example.com)
_443._tcp.www.example.com. IN TLSA 3 1 1 (
d2abde240d7cd3ee6b4b28c54df034b9
7983a1d16e8a410e4561cb106618e971 )
クライアントは、通常のCA階層による証明書検証に加えて、DNSSECで保護されたこのTLSAレコードとサーバー証明書を突き合わせることで、不正な認証局から発行された偽の証明書を検知できます。TLSAレコードの信頼性はDNSSECの署名検証に依存しているため、DANEはDNSSECが正しく機能している環境でのみ意味を持つ点が前提条件です。LPIC-2では、概念(DNSSECを基盤にCA階層を補完・代替する仕組み)としての理解が問われます。
named-compilezoneとバイナリ形式のゾーンファイル
ここまで扱ってきたゾーンファイルは、人間が読み書きしやすいテキスト形式(マスターファイル形式)でした。named-compilezoneを使うと、このテキスト形式のゾーンファイルを、BIND内部で高速に読み込めるバイナリ形式に変換できます。
$ named-compilezone -f text -F raw -o db.example.com.raw example.com db.example.com
zone example.com/IN: loaded serial 2026082101
dump done
# -f text: 入力形式(テキスト)、-F raw: 出力形式(バイナリのraw形式)
この行のこの値に注目: named-checkzoneと同様にloaded serial ...で読み込んだシリアル番号を確認でき、最後のdump doneで変換が完了したことが分かります。生成されたdb.example.com.rawはバイナリ形式のため、テキストエディタで開いても内容は読めません。
変換したバイナリ形式のゾーンファイルを使うよう、named.conf側でmasterfile-format rawを指定します。
named.conf.local の例
zone "example.com" {
type master;
file "/etc/bind/db.example.com.raw";
masterfile-format raw;
};
バイナリ形式は、非常に多くのレコードを持つ大規模なゾーンで、named起動時のゾーン読み込み時間を短縮できるという利点がありますが、テキストエディタで直接内容を読めなくなるため、通常の運用ではテキスト形式のまま管理し、ゾーンファイルの編集履歴もテキスト形式で管理する(rawファイルはあくまで実行時の最適化として生成する)運用が一般的です。
代替DNSサーバーソフトウェアの認識
BINDは最も広く使われているDNSサーバーですが、用途に応じて他のソフトウェアが選ばれることもあります。LPIC-2では、それぞれの位置づけを認識しておくことが求められます。
| ソフトウェア | 位置づけ |
|---|---|
| dnsmasq | 小規模ネットワーク向けの軽量なDNS/DHCPサーバー。キャッシュ機能とDHCPサーバー機能を1つのプロセスで兼ねられる手軽さが特徴 |
| PowerDNS | ゾーンデータをMySQLやPostgreSQLなどのデータベースに保存できる権威DNSサーバー。Web管理画面や大規模なゾーン数の運用と相性がよい |
| Unbound | 再帰・キャッシュ専用に特化したDNSサーバー。権威サーバー機能を持たず、シンプルさとセキュリティを重視した設計 |
| djbdns | Daniel J. Bernstein氏が開発した、複数の独立した小さなプログラム群からなるDNSサーバー。歴史的にセキュリティ面で高く評価された |
試験対策としては、「権威サーバー専用」「キャッシュ専用」「DB連携が可能」「軽量・小規模向け」といった各ソフトウェアの主な特徴とBINDとの違いを対応付けて覚えておくと十分です。
digの出力の完全な読み方
ここまでdigコマンドを何度も使ってきましたが、その出力の各行が何を意味するかを体系的に押さえておくと、トラブルシューティングの精度が大きく上がります。
$ dig www.example.com
; <<>> DiG 9.18.1 <<>> www.example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 34521
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 2
;; QUESTION SECTION:
;www.example.com. IN A
;; ANSWER SECTION:
www.example.com. 86400 IN A 192.0.2.10
;; AUTHORITY SECTION:
example.com. 86400 IN NS ns1.example.com.
example.com. 86400 IN NS ns2.example.com.
;; ADDITIONAL SECTION:
ns1.example.com. 86400 IN A 192.0.2.10
ns2.example.com. 86400 IN A 192.0.2.11
;; Query time: 12 msec
;; SERVER: 192.0.2.10#53(192.0.2.10)
;; WHEN: Thu Aug 20 10:00:00 JST 2026
;; MSG SIZE rcvd: 123
この行のこの値に注目: HEADER行のopcodeは問い合わせの種類(通常はQUERY)、statusは応答結果を示すもっとも重要な情報です。
| status | 意味・疑うべき原因 |
|---|---|
NOERROR | 問い合わせは正常に処理された(ANSWER SECTIONが空でもNOERRORになりうる点に注意) |
NXDOMAIN | 問い合わせたドメイン自体が存在しない。タイプミスやドメイン未登録を疑う |
SERVFAIL | 権威サーバー側で何らかのエラーが発生した。ゾーンファイルの設定ミスやDNSSEC検証エラーを疑う |
REFUSED | 問い合わせ自体をサーバーに拒否された。allow-queryなどのアクセス制御による拒否を疑う |
flags行に並ぶアルファベットは、それぞれ意味を持つビットフラグです。
| フラグ | 意味 |
|---|---|
qr | Query/Response。このメッセージが応答であることを示す |
aa | Authoritative Answer。権威サーバー自身からの回答であることを示す(キャッシュ経由の回答には付かない) |
rd | Recursion Desired。クライアントが再帰的問い合わせを要求したことを示す |
ra | Recursion Available。応答したサーバーが再帰的問い合わせに対応していることを示す |
ad | Authenticated Data。DNSSECによる検証に成功したデータであることを示す |
cd | Checking Disabled。クライアント側がDNSSEC検証を行わないよう要求したことを示す |
続く4つのセクションは、それぞれ役割が異なります。QUESTION SECTIONには問い合わせ内容そのもの、ANSWER SECTIONには実際の回答レコード、AUTHORITY SECTIONにはそのゾーンを管理する権威サーバー(NSレコード)の情報、ADDITIONAL SECTIONには回答を補足する追加情報(NSレコードに対応するAレコードなど)が並びます。末尾には、応答にかかった時間(Query time)、問い合わせたサーバー(SERVER)、問い合わせ時刻(WHEN)、メッセージサイズ(MSG SIZE)が表示されます。
ゾーンの委任(親ゾーンでのNSレコードとグルーレコード)
あるドメインのDNS管理を、上位のドメインから切り離して別の権威サーバーに任せることを委任(delegation)と呼びます。たとえばexample.comを管理する組織が、社内システム用にdept.example.comというサブドメインを別チームに管理させたい場合、親ゾーン(example.com)側に、そのサブドメインを担当する権威サーバーを示すNSレコードを追加します。
親ゾーン db.example.com への追記
dept.example.com. IN NS ns1.dept.example.com.
dept.example.com. IN NS ns2.dept.example.com.
グルーレコード(委任先の権威サーバー自体が委任するドメインの中に存在する場合に必須)
ns1.dept.example.com. IN A 192.0.2.50
ns2.dept.example.com. IN A 192.0.2.51
この行のこの値に注目: 委任先の権威サーバー名(この例ではns1.dept.example.com)自体が、委任するドメイン(dept.example.com)の中に含まれている場合、「そのサーバーのIPアドレスを知るには、まずそのサーバーに問い合わせる必要がある」という循環参照が発生してしまいます。これを避けるため、親ゾーン側に委任先サーバーのIPアドレス(Aレコード)を直接記載しておく必要があり、これをグルーレコードと呼びます。委任先のネームサーバー名が委任するドメインの外にある場合は、グルーレコードは不要です。
ゾーン転送の失敗を診断する手順
セカンダリでゾーンデータが更新されない、あるいはセカンダリの起動時にゾーンが空のままになるといった問題が起きた場合、次の手順で原因を切り分けます。
- digで転送を直接試す:
dig @プライマリのIP ゾーン名 AXFRを実行し、実際にゾーン転送が成功するかを確認します。Transfer failedのようなエラーが出れば、プライマリ側のアクセス制御(allow-transfer)に問題がある可能性が高いといえます。 - namedのログを確認する: プライマリ・セカンダリ双方のログ(
journalctl -u bind9や、logging句で指定したログファイル)に、転送拒否やタイムアウトに関するメッセージが出ていないか確認します。 - シリアル番号を比較する:
dig @プライマリのIP ゾーン名 SOAとdig @セカンダリのIP ゾーン名 SOAを実行し、それぞれのシリアル番号を比較します。セカンダリの値がプライマリより古い場合、転送自体が行われていないか、プライマリ側でシリアル番号の更新を忘れている可能性があります。 - allow-transferの設定を確認する: プライマリ側の
allow-transferに、セカンダリのIPアドレス(またはTSIG鍵)が正しく含まれているかを再確認します。設定変更後はrndc reloadを忘れずに実行します。