DNS サーバの設定

【概要】Ubuntu 24.04 LTS 環境での BIND 9 DNS サーバ構築手順。view 機能で内部向けと外部向けの名前解決を分離する設定。ゾーンファイルと named.conf の記述方法。rndcsystemd による管理操作。dig などによる動作確認。UFWAppArmor によるアクセス制御。

BIND DNS サーバを動かし、順引き、逆引きができるようにする。

関連する外部ページ】: Ubuntu Server ドキュメント「Domain Name Service (DNS)」: https://ubuntu.com/server/docs/how-to/networking/install-dns/

関連する外部ページ】: BIND 9 Administrator Reference Manual: https://bind9.readthedocs.io/en/latest/

設定内容

設定内容は次の通りである。

Ubuntu 24.04 LTS の bind9 パッケージでのディレクトリ構成は次の通りである。

/etc/bind                設定ファイルの置き場
  +-- named.conf                 主設定ファイル(各ファイルを include する)
  +-- named.conf.options         全体のオプション
  +-- named.conf.local           自分で定義するゾーンや view
  +-- named.conf.default-zones   localhost、その逆引き、ルートヒント
  +-- rndc.key                   rndc 用の鍵
  +-- zones                      本手順で作成するゾーンファイルの置き場
/var/cache/bind          named が書き込む作業用ディレクトリ
/var/log/named           本手順で作成するログの置き場

事前に調べておく事項

DNS サーバ構築に際して、以下の事項を確認しておく。

  1. DNS サーバ兼 MX のホスト名

    (以下、ホスト名は「dnsmail」のように記述する)

  2. DNS サーバ兼 MX の IP アドレス (以下、「XXX.YYY.ZZZ.160」のように記述する)。
  3. Web サーバのホスト名

    (以下、ホスト名は「www」のように記述する)

  4. Web サーバの IP アドレス (以下、「XXX.YYY.ZZZ.167」のように記述する)。
  5. DNS サーバ兼 MX がある「内部」のネットワークアドレス

    (以下、ネットワークアドレスは「XXX.YYY.ZZZ」のように記述する)

  6. DNS ドメイン名 (NIS ドメイン名とは別物であるため混同しないこと)

    (以下、DNS ドメイン名は「mydomain.hoge.com」と記述する)

  7. 上流の DNS サーバの IP アドレス

    (以下、上流の DNS サーバの IP アドレスは「AAA.BBB.CCC.10」と記述する)

DNS サーバソフトのインストール

  1. 時刻あわせ

    時刻が大きくずれていると DNSSEC の検証などが失敗する。Ubuntu 24.04 LTS では systemd-timesyncd が時刻を同期する。同期状況を確認する。

    timedatectl status
    

    「System clock synchronized: yes」と表示されることを確認する。

  2. インストール

    bind9 がサーバ本体、bind9-utilsnamed-checkconf, named-checkzone, rndcbind9-dnsutilsdig, host, nslookup を提供する。

    sudo apt update
    sudo apt install bind9 bind9-utils bind9-dnsutils
    
  3. サービス名の確認

    Ubuntu 24.04 LTS では、サービス名は named.service である(bind9.service はその別名として使える)。実行ユーザは bind である。

    systemctl status named.service
    
  4. systemd-resolved との共存の確認

    Ubuntu 24.04 LTS では systemd-resolved127.0.0.53:53 で待ち受ける。named が全アドレスの 53 番ポートで待ち受けるとポートが衝突することがある。衝突する場合は、systemd-resolved のスタブリスナを止める。

    sudo vi /etc/systemd/resolved.conf
    # [Resolve] セクションに次の行を設定する
    ----------------------------------------------------------------------------
    DNSStubListener=no
    ----------------------------------------------------------------------------
    sudo systemctl restart systemd-resolved
    

仮のゾーンファイルの作成とチェック

ここでは、仮のゾーンファイル public.zone, public.rev, db.zone, db.rev を作成する。次に named.conf.local を設定して、内部向けの view と外部向けの view を定義する。その後、DNS サーバを起動して動作をチェックする。

まず、ゾーンファイルを置くディレクトリを作成する。

sudo mkdir -p /etc/bind/zones

正引き

/etc/bind/zones/public.zone, /etc/bind/zones/db.zone は仮に次のように設定する。ドメイン名の末尾の「.」は必要である。Serial は「YYYYMMDDNN」(更新した年月日+その日の更新回数)の形式で設定する。

cd /etc/bind/zones
sudo vi public.zone
# 以下のように設定
----------------------------------------------------------------------------
$TTL 86400
@ IN SOA dnsmail.mydomain.hoge.com. root.mydomain.hoge.com. (
2024073001 ; Serial
28800      ; Refresh
14400      ; Retry
3600000    ; Expire
86400 )    ; Minimum
  IN NS dnsmail.mydomain.hoge.com.
  IN MX 10 dnsmail.mydomain.hoge.com.
@ IN A XXX.YYY.ZZZ.160
dnsmail IN A XXX.YYY.ZZZ.160
www     IN A XXX.YYY.ZZZ.167
hohoge  IN A AAA.BBB.CCC.10
----------------------------------------------------------------------------
sudo cp public.zone db.zone

逆引き

/etc/bind/zones/public.rev, /etc/bind/zones/db.rev は仮に次のように設定する。

cd /etc/bind/zones
sudo vi public.rev
# 以下のように設定
----------------------------------------------------------------------------
$TTL 86400
@ IN SOA dnsmail.mydomain.hoge.com. root.mydomain.hoge.com. (
2024073001 ; Serial
28800      ; Refresh
14400      ; Retry
3600000    ; Expire
86400 )    ; Minimum
    IN NS dnsmail.mydomain.hoge.com.
160 IN PTR dnsmail.mydomain.hoge.com.
167 IN PTR www.mydomain.hoge.com.
----------------------------------------------------------------------------
sudo cp public.rev db.rev

オーナとパーミッションの設定

ゾーンファイルは named の実行ユーザ bind が読めればよい。書き込み権限は与えない。

sudo chown -R root:bind /etc/bind/zones
sudo chmod 750 /etc/bind/zones
sudo chmod 640 /etc/bind/zones/*

named.conf の設定

view を使う場合、すべてのゾーンをいずれかの view の中に書く必要がある。そのため、/etc/bind/named.conf にある named.conf.default-zonesinclude をコメントアウトし、各 view の中で include する。

sudo vi /etc/bind/named.conf
# 次の行をコメントアウトする
----------------------------------------------------------------------------
//include "/etc/bind/named.conf.default-zones";
----------------------------------------------------------------------------

次に、全体のオプションを設定する。forwarders に上流の DNS サーバを設定し、統計情報などの出力先を設定する。

sudo vi /etc/bind/named.conf.options
# options ブロックに次を設定
----------------------------------------------------------------------------
options {
        directory "/var/cache/bind";

        forwarders { AAA.BBB.CCC.10; };

        dump-file "/var/cache/bind/cache_dump.db";
        statistics-file "/var/cache/bind/named_stats.txt";

        dnssec-validation auto;
        listen-on-v6 { any; };
};
----------------------------------------------------------------------------

次に、内部向けと外部向けの view、およびログ出力を設定する。match-clients により、問い合わせ元の IP アドレスで参照するゾーンが切り替わる。view は上から順に評価されるため、内部向けを先に書く。

sudo vi /etc/bind/named.conf.local
# 次のように設定
----------------------------------------------------------------------------
acl internal-net {
        127.0.0.1;
        XXX.YYY.ZZZ.0/24;
};

view "internal" {
        match-clients { internal-net; };
        recursion yes;

        zone "mydomain.hoge.com" {
                type master;
                file "/etc/bind/zones/db.zone";
        };
        zone "ZZZ.YYY.XXX.in-addr.arpa" {
                type master;
                file "/etc/bind/zones/db.rev";
        };
        include "/etc/bind/named.conf.default-zones";
};

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

        zone "mydomain.hoge.com" {
                type master;
                file "/etc/bind/zones/public.zone";
        };
        zone "ZZZ.YYY.XXX.in-addr.arpa" {
                type master;
                file "/etc/bind/zones/public.rev";
        };
};

logging {
        channel named_log {
                file "/var/log/named/named.log" versions 3 size 10m;
                severity info;
                print-time yes;
        };
        channel security_log {
                file "/var/log/named/security.log" versions 3 size 10m;
                severity info;
                print-time yes;
        };
        category default  { named_log; };
        category security { security_log; };
};
----------------------------------------------------------------------------

ログの出力先ディレクトリを作成し、named が書き込めるようにする。

sudo mkdir -p /var/log/named
sudo chown bind:bind /var/log/named

チェック

設定ファイルの書き間違いを下記の手順でチェックする。

  1. チェックツールを使って、named.conf の内容をチェックする

    -z を付けると、設定されているゾーンファイルの読み込みまで行う。エラーが出たら、named.conf.options, named.conf.local を書き直す。

    named-checkconf -z /etc/bind/named.conf
    
  2. チェックツールで、ゾーンファイルを個別にチェックする

    named-checkzone <ゾーン名> <ゾーンファイルパス> の形式で使用する。エラーが出たら、ゾーンファイルを書き直す。

    # 正引きゾーンのチェックにはゾーン名 (ドメイン名) を指定する
    named-checkzone mydomain.hoge.com /etc/bind/zones/public.zone
    named-checkzone mydomain.hoge.com /etc/bind/zones/db.zone
    # 逆引きゾーンのチェックには逆引きゾーン名 (.in-addr.arpa) を指定する
    named-checkzone ZZZ.YYY.XXX.in-addr.arpa /etc/bind/zones/public.rev
    named-checkzone ZZZ.YYY.XXX.in-addr.arpa /etc/bind/zones/db.rev
    
  3. 起動チェック (デバッグモード)

    起動チェックのため、最初はフォアグラウンドのデバッグモードで起動してみる。起動の前に named の停止を行う。エラーメッセージが端末に表示される。確認できたら「Ctrl+C」で終了する。

    sudo systemctl stop named.service
    sudo named -u bind -g -d 1
    

    参考:

    • -u: named の実行ユーザ (Ubuntu 24.04 LTS では bind)
    • -g: フォアグラウンドで実行し、ログを標準エラー出力に出す
    • -d 1: デバッグレベルの指定
  4. DNS サーバの起動

    下記の手順で、DNS サーバを起動する。起動時にエラーが出たら、関係する設定ファイル (ここでは named.conf.options, named.conf.local, public.zone, public.rev, db.zone, db.rev) を見直し、もう 1 度再起動する。

    sudo systemctl restart named.service
    sudo systemctl enable named.service
    systemctl status named.service
    
  5. ログの確認

    systemd のログと、設定したログファイルの両方を確認する。/var/log/namednamed.log, security.log の 2 つのログファイルが作成されるため確認し、エラーが無いことを確認する。

    journalctl -u named.service -n 50
    sudo ls -la /var/log/named
    sudo tail /var/log/named/named.log
    
  6. rndc との通信ができていることのチェック
    sudo rndc status
    # エラーが無く、「server is up and running」という行が出てくることを確認する
    
  7. ファイアウォールの設定

    53/UDP は通常の名前解決に使われ、53/TCP は 512 バイトを超える応答やゾーン転送に使われる。bind9 パッケージは UFW 用のアプリケーションプロファイルを提供する。53/UDP は全体に開き、53/TCP は XXX.YYY.ZZZ.* のネットワークのみに許可する例を示す。

    sudo ufw allow 53/udp
    sudo ufw allow from XXX.YYY.ZZZ.0/24 to any port 53 proto tcp
    sudo ufw status
    

rndc についての補足説明

rndcnamed をローカルまたはリモートから制御するツールである。制御には共有鍵による認証を用いる。Ubuntu 24.04 LTS では、bind9 のインストール時に /etc/bind/rndc.key が生成され、/etc/bind/named.conf から読み込まれるため、そのまま使用できる。鍵を作り直す場合は rndc-confgen を使う。

アクセス制御と AppArmor に関する補足説明

Ubuntu 24.04 LTS の bind9 パッケージは chroot を構成せず、named プロセスの権限を AppArmor のプロファイル /etc/apparmor.d/usr.sbin.named で制限する。このプロファイルにより、named が読み書きできるファイルが /etc/bind, /var/cache/bind, /var/lib/bind, /var/log/named などに限定される。named が乗っ取られた場合の被害を、これらの範囲に抑制することが目的である。

プロファイルが有効であることは次のコマンドで確認する。

sudo aa-status | grep named

上記以外の場所にゾーンファイルやログを置くと、AppArmor により拒否されて named が起動しない。その場合は、/etc/apparmor.d/local/usr.sbin.named に読み書きを許可する行を追加し、sudo systemctl reload apparmor を実行する。

クライアント側の設定

DNS クライアントとしての設定についても確認しておく。

  1. 名前解決に使うサーバの確認

    Ubuntu 24.04 LTS では /etc/resolv.confsystemd-resolved が管理するため、実際に問い合わせ先となっているサーバは resolvectl で確認する。DNS がうまく動かないと思った時は、まずこれを確認する。

    resolvectl status
    cat /etc/resolv.conf
    

    問い合わせ先を変更するときは、netplan の設定ファイル (/etc/netplan/*.yaml) の nameservers に DNS サーバの IP アドレスを記述し、sudo netplan apply を実行する。

  2. /etc/nsswitch.conf

    次のように、hosts の行に dns を含むこと。これにより、名前解決の際に hosts ファイル、次に DNS を参照する順序が定義される。

    hosts: files dns
    

上記の設定後、MX, Web サーバの順引き、逆引きができることを確認する(下記の「演習項目」を参照すること)。

演習項目

設定した DNS サーバの動作確認方法について説明する。

dig, host, nslookup の使い方の練習

dig

dig は DNS の問い合わせに広く使われる標準的なツールである。

  1. 下記の手順で、正引きをテストする。
    dig @<DNSサーバのIPアドレス> <調べたいホスト名>
    
  2. 下記の手順で、逆引きをテストする。
    dig @<DNSサーバのIPアドレス> -x <調べたいIPアドレス>
    
  3. チェック項目について述べる。
    ;; ->>HEADER<<- の部分で
     ・status: が NOERROR である。
       status: はサーバからの応答の状態を表す。
        NOERROR :DNSサーバが正常に応答したことを示す。
        NXDOMAIN:問い合わせたドメインが存在しないことを示す。
        SERVFAIL:DNSサーバが正しく応答しなかったことを示す。
     ・flags: に qr, aa があるか確認する。内部マシンから dig をした場合は ra もあるはずである。
       flags: には次の5つがある。
        qr:クエリに対する回答であることを示す。
        aa:回答が権限のある回答であることを示す。
        tc:回答が長くて切り捨てられたことを示す。
        ra:サーバが再帰可能であることを示す。
        rd:再帰希望のフラグが設定されていることを示す。
     ・ANSWER: が1以上であるか確認する。
       ANSWER: は問い合わせに対する回答の数を示す。
    ;; ANSWER SECTION: がゾーンファイルに設定した通りであるかどうかを確認する。
    

host

host は簡単な名前解決の確認に使う。

# 正引き
host <調べたいホスト名> <DNSサーバのIPアドレス>

# 逆引き
host <調べたいIPアドレス> <DNSサーバのIPアドレス>

nslookup

nslookup は対話的に問い合わせ先を切り替えられる。dig と同じく bind9-dnsutils パッケージが提供する。

  1. 下記の手順で、ゾーンファイルに記述したホスト名と IP との対応をテストする。
    nslookup                              <-- nslookup を起動
    > server <DNSサーバのIPアドレス>      <-- 問い合わせるDNSサーバを指定
    
    // 正引きのテスト方法
    > <ホスト名>                          <-- ゾーンファイルに記述したホスト名
    Server:  <DNSサーバのIPアドレス>
    Address: <DNSサーバのIPアドレス>#<ポート番号>
    
    Name:    <ゾーンファイルに記述したホスト名>
    Address: <対応するIPアドレス>          <-- ゾーンファイルに記述したIPが返れば良い
    
  2. 下記の手順で、逆引きをテストする。
    > <IPアドレス>                         <-- 逆引きゾーンファイルに記述したIP
    Server:  <DNSサーバのIPアドレス>
    Address: <DNSサーバのIPアドレス>#<ポート番号>
    
    <IPアドレスの逆順>.in-addr.arpa name = <対応するホスト名>
                                           <-- 逆引きゾーンファイルに記述したホスト名が
                                               FQDN形式で返れば良い
    

nslookupexit で終了する。

ゾーンファイル db.zone, db.rev のメンテナンス

ゾーンファイル db.zone, db.rev のメンテナンス手順は以下の通りである (マシンの追加・削除を行う場合)。

  1. ゾーンファイルに変更を加える前に、バックアップを取得しておく。
    cd /etc/bind/zones
    sudo cp db.zone db.zone.back20240730   <-- その日の日付
    sudo cp db.rev  db.rev.back20240730    <-- その日の日付
    
  2. db.zone の A レコードを追加・削除する。
    // Aレコードの記述例
    hostname IN A XXX.YYY.ZZZ.200
    
  3. db.rev の PTR レコードを追加・削除する。
    // PTRレコードの記述例
    200 IN PTR hostname.mydomain.hoge.com.
    
  4. SOA レコードのシリアル番号を更新する。 シリアル番号は
     YYYYMMDDNN (例: 2024073001)
     "更新した年月日+その日の更新回数"
    
    のように設定する。シリアル番号を増やすことで、セカンダリサーバがゾーンの更新を検知できるようになる。
  5. ゾーンファイルをチェックし、変更を反映させる。
    named-checkzone mydomain.hoge.com /etc/bind/zones/db.zone
    named-checkzone ZZZ.YYY.XXX.in-addr.arpa /etc/bind/zones/db.rev
    sudo rndc reload
    

rndc 関係

  1. 設定ファイルとゾーンファイルを再読み込みする。キャッシュデータは保持される。
    sudo rndc reload
    # ログファイルを見てエラーが無いことを確認する
    sudo tail /var/log/named/named.log
    
  2. キャッシュをファイルにダンプする。出力先は named.conf.optionsoptions 中の dump-file で定義する。出力先を定義していない場合は作業ディレクトリの named_dump.db に出力される。
    sudo rndc dumpdb
    # 出力結果を確認
    sudo cat /var/cache/bind/cache_dump.db
    
  3. キャッシュをすべてフラッシュする。
    sudo rndc flush
    # キャッシュをファイルに出力してクリアされたことを確認する
    sudo rndc dumpdb
    sudo cat /var/cache/bind/cache_dump.db
    
  4. サーバの統計情報をファイルにダンプする。出力先は named.conf.optionsoptions 中の statistics-file で定義する。出力先を定義していない場合は作業ディレクトリの named.stats に出力される。
    sudo rndc stats
    # 出力結果を確認
    sudo cat /var/cache/bind/named_stats.txt
    

    出力結果の意味について述べる。

     success   問い合わせに成功したクエリー数である。
     referral   問い合わせに対し参照となったクエリー数である。
     nxrrset   問い合わせに対するレコード型が存在しなかったクエリー数である。
     nxdomain   問い合わせに対するドメイン名やホスト名が存在しなかったクエリー数である。
     recursion  再帰問い合わせを行ったクエリー数である。
     failure   エラーとなったクエリー数である。
    
  5. 問い合わせのログを一時的に取得する。
    sudo rndc querylog on
    sudo tail -f /var/log/named/named.log
    sudo rndc querylog off
    

内部向けのゾーンと外部向けのゾーンが正しく動いていることの確認

内部ネットワークのクライアントと、外部ネットワークのクライアントから、それぞれ同じ名前を問い合わせ、返る内容が異なることを確認する。

  1. 内部ネットワーク (XXX.YYY.ZZZ.0/24) のクライアントから問い合わせる。internalview が使われ、db.zone に記述したホストが返る。
    dig @XXX.YYY.ZZZ.160 hostname.mydomain.hoge.com
    
  2. 外部ネットワークのクライアントから問い合わせる。externalview が使われ、public.zone に記述した 3 つのホスト以外は返らない。
    dig @XXX.YYY.ZZZ.160 hostname.mydomain.hoge.com
    dig @XXX.YYY.ZZZ.160 www.mydomain.hoge.com
    
  3. どちらの view が使われたかは、rndc querylog on を実行してからログを確認すると判別できる。
    sudo rndc querylog on
    sudo tail -f /var/log/named/named.log
    

以上の演習が済んだら、仮に設定されたゾーンファイルを本格的なものに書き換える。その後、DNS 管理コマンドについての練習及び DNS サーバの動作確認を再度行う。