CentOS Stream 9にBIND9を内部DNSサーバーとして構築する:ゾーンファイル、フォワードDNS、SELinuxとfirewalld

CentOS tutorial - IT technology blog
CentOS tutorial - IT technology blog

内部ネットワーク向けDNSサーバーの3つの選択肢

約半年間、約50台のサーバーが稼働する本番環境で内部DNSシステムを運用してきました。BIND9に落ち着く前に3つの異なるソリューションを試した経験から、実際の現場で得た知見をまとめます。

CentOS Stream 9での内部DNSサーバーとして最も一般的な3つの選択肢:

  • BIND9 (Berkeley Internet Name Domain) — 最も機能が豊富な従来型DNSソリューション
  • dnsmasq — 軽量で設定が簡単、小規模ネットワーク向け
  • Unbound — 再帰的DNSに特化し、セキュリティが高いが権威DNS機能は限定的

各ソリューションのメリット・デメリット分析

dnsmasq — シンプルだが制限あり

設定が15分で完了するため、最初はdnsmasqから始めました。しかしホスト数が増え、複数のゾーン(lab.company.localdb.company.localなど)を管理する必要が生じると、dnsmasqの弱点が露わになってきました。実際のゾーンファイルがなく、プライマリとセカンダリDNS間の同期に必要なAXFRも非対応です。また、ログが少ないため障害発生時のデバッグも非常に不便でした。

適しているケース: 個人ラボ、家庭ネットワーク、20台以下のホスト、プライマリ・セカンダリ間のレプリケーションが不要な場合。

Unbound — セキュリティは高いが権威DNS機能が不足

Unboundは再帰的DNS(インターネットへのクエリ転送)に非常に優れています。しかし、権威DNSサーバー(自社ネットワーク内の内部ホスト名を解決するサーバー)としては設計されていません。server01.company.localの名前解決にUnboundを使うのは適切なユースケースではなく、複雑な回避策が必要になります。

適しているケース: 再帰的リゾルバーのみが必要で、DNSSECバリデーションによるセキュリティを優先する場合。

BIND9 — 複雑だが価値あり

最終的にBIND9を選択しました。設定は複雑ですが、その分ゾーンファイルが明確で、フォワードとリバースルックアップの両方に対応し、プライマリ・セカンダリ間のレプリケーション設定も可能で、公式ドキュメントも充実しています。SELinux enforcingのCentOS Stream 9では、BIND9の方がより徹底的にテストされており、namedのSELinuxポリシーがシステムにあらかじめ定義されています。

適しているケース: 企業ネットワーク、複数ゾーンの管理、権威DNSが必要な場合、高可用性のためのプライマリ・セカンダリ構成が必要な場合。

BIND9を選んだ実際の理由

弊社にはまだCentOS 7で動いているサーバーが数台あり、AlmaLinuxへの移行は実際に取り組んだ課題でした。移行期間中、旧環境と新環境の両方を並行して扱える強力なDNSサーバーが必要でした。複数のゾーンを個別に設定できるBIND9が最も自然な選択です。さらに、インフラ全体がSELinux enforcing(CentOS Stream 9のデフォルト)で動いている環境では、ファイルを正しい場所に配置さえすれば、BIND9はほとんど問題を起こしません。

CentOS Stream 9へのBIND9の導入

ステップ1:パッケージのインストール

sudo dnf install -y bind bind-utils
sudo systemctl enable --now named
sudo systemctl status named

ステップ2:named.confの設定

メインの設定ファイルは/etc/named.confです。内部ゾーンcompany.localの権威DNSとしてBIND9を設定し、残りのクエリはパブリックDNSに転送するように構成します:

sudo nano /etc/named.conf
options {
    listen-on port 53 { 127.0.0.1; 192.168.1.10; };  # DNSサーバーのIPアドレス
    listen-on-v6 port 53 { none; };
    directory "/var/named";
    dump-file "/var/named/data/cache_dump.db";
    statistics-file "/var/named/data/named_stats.txt";

    allow-query { localhost; 192.168.1.0/24; };  # 内部サブネットのみ許可

    # DNSクエリを外部インターネットに転送
    forwarders {
        8.8.8.8;
        8.8.4.4;
    };
    forward only;

    recursion yes;
    dnssec-validation yes;
};

logging {
    channel default_debug {
        file "data/named.run";
        severity dynamic;
    };
};

# 内部ゾーン(フォワード)
zone "company.local" IN {
    type master;
    file "company.local.zone";
    allow-update { none; };
};

# 192.168.1.0/24サブネットのリバースゾーン
zone "1.168.192.in-addr.arpa" IN {
    type master;
    file "company.local.rev";
    allow-update { none; };
};

include "/etc/named.rfc1912.zones";
include "/etc/named.root.key";

ステップ3:フォワードゾーンファイルの作成

sudo nano /var/named/company.local.zone
$TTL 86400
@   IN  SOA     ns1.company.local.  admin.company.local. (
                2024010101  ; シリアル番号(YYYYMMDDNN形式 — 変更のたびに増やす)
                3600        ; Refresh
                1800        ; Retry
                604800      ; Expire
                86400 )     ; 最小TTL

; ネームサーバー
@       IN  NS      ns1.company.local.

; Aレコード
ns1         IN  A   192.168.1.10
gateway     IN  A   192.168.1.1
server01    IN  A   192.168.1.20
server02    IN  A   192.168.1.21
db01        IN  A   192.168.1.30
webserver   IN  A   192.168.1.40

; CNAME
www         IN  CNAME   webserver.company.local.

シリアル番号はよく見落とされる重要なポイントです:ゾーンファイルを変更するたびに必ず増やす必要があります。BIND9はこの値を使ってゾーンをリロードするかどうかを判断します。

ステップ4:リバースゾーンファイルの作成

sudo nano /var/named/company.local.rev
$TTL 86400
@   IN  SOA     ns1.company.local.  admin.company.local. (
                2024010101
                3600
                1800
                604800
                86400 )

@       IN  NS      ns1.company.local.

; PTRレコード(逆引き)
10      IN  PTR     ns1.company.local.
1       IN  PTR     gateway.company.local.
20      IN  PTR     server01.company.local.
21      IN  PTR     server02.company.local.
30      IN  PTR     db01.company.local.
40      IN  PTR     webserver.company.local.

ステップ5:再起動前の構文チェック

# named.confの構文チェック
sudo named-checkconf

# フォワードゾーンの確認
sudo named-checkzone company.local /var/named/company.local.zone

# リバースゾーンの確認
sudo named-checkzone 1.168.192.in-addr.arpa /var/named/company.local.rev

# エラーがなければ再起動
sudo systemctl restart named

SELinuxの対処 — 最も見落とされがちな部分

初回セットアップで最も時間を費やした部分です。SELinux enforcingは、ゾーンファイルのコンテキストが正しくない場合にBIND9をブロックします。ゾーンファイルは必ず/var/named/内に配置する必要があります — /etc/や独自に作成したディレクトリには置かないでください。

ゾーンファイルのSELinuxコンテキストを確認:

ls -lZ /var/named/company.local.zone

正しい出力にはnamed_zone_tが含まれている必要があります:

-rw-r--r--. 1 root named system_u:object_r:named_zone_t:s0 /var/named/company.local.zone

コンテキストが間違っている場合(例:別の場所からファイルをコピーした場合)は、以下のコマンドで修正します:

sudo restorecon -Rv /var/named/
sudo chown root:named /var/named/company.local.zone /var/named/company.local.rev

SELinuxがnamedをブロックしているか確認:

sudo ausearch -c 'named' -m avc --raw 2>/dev/null | head -20
sudo tail -f /var/log/audit/audit.log | grep named

firewalldの設定

内部サブネット向けにDNSポート(53/udpおよび53/tcp)を開放します:

# 方法1:DNSサービスを全体に開放
sudo firewall-cmd --permanent --add-service=dns
sudo firewall-cmd --reload

# 方法2:内部サブネットからのみ許可(推奨)
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" service name="dns" accept'
sudo firewall-cmd --reload

# 確認
sudo firewall-cmd --list-all

DNSサーバーのテスト

# フォワードルックアップのテスト
dig @192.168.1.10 server01.company.local

# リバースルックアップのテスト
dig @192.168.1.10 -x 192.168.1.20

# インターネットへのフォワードDNSテスト
dig @192.168.1.10 google.com

# 内部ネットワーク上のクライアントから
nslookup server01.company.local 192.168.1.10

NetworkManagerを使用してクライアントのDNS設定を更新:

sudo nmcli con mod "Wired connection 1" ipv4.dns "192.168.1.10"
sudo nmcli con mod "Wired connection 1" ipv4.dns-search "company.local"
sudo nmcli con up "Wired connection 1"

よくあるエラーとその対処法

  • namedが起動しない: まずSELinuxコンテキストを確認し、その後journalctl -u named -n 50を実行
  • クライアントからのクエリタイムアウト: 99%はfirewalldがポートを開放していない — firewall-cmd --list-all | grep dnsで確認
  • ゾーンファイルがリロードされない: シリアル番号が増加していない — シリアルを変更してからsudo rndc reload company.localを実行
  • ログにPermission denied: ゾーンファイルのグループがnamedになっていない — chown root:named /var/named/*.zoneで修正

次のステップ

このセットアップは本番環境で6ヶ月間安定稼働しています。最も難しい部分は実際には最初だけ — 特にSELinuxコンテキストとfirewalldの設定です。一度BIND9が正常に動き出せば、ほとんど手を加える必要はありません。

さらに高度な構成を目指すなら、次のステップはtype slaveとAXFRレプリケーションを使ったセカンダリDNSサーバーの構築です。プライマリDNSに障害が発生しても、内部ネットワークが引き続き正常に名前解決できるようになります。

Share: