📋️

BINDについて(LinuC202学習)

2024/07/21に公開

BINDとは

https://www.isc.org/bind/

Berkeley Internet Name Domain、略してBIND。DNS権威サーバーおよびキャッシュサーバーとして機能するソフトウェア。
DNSソフトウェアとしては最もトラディショナルかつ一般的だが、インターネットの前面に位置するサーバーという性質と近年の脆弱性の多発と、Amazon Route53やAzure DNSというマネージドサービスを利用したそれらDNS起因のセキュリティ責任のオフロードの動機から、触れる機会は減っていると思われる。
一方で触れることでDNSの内部の働きを体感し、理解を深めることには意義があるとして、触れてみる。

余談:現在BINDなどのセルフホスティングが採用される経緯の考察

プライベートネットワーク上での名前解決を行う際はオンプレミス上ではActive Directoryが出番になることが多かっただろう。
一方でクラウド時代においては認証をOktaなどIDaaSで行うとした場合、名前解決をADに任せっぱなしにしてクラウドリフトすると、片手落ちになる。

もちろんハイパースケーラーはそれらのニーズにも対応している。Amazon Route53 Resolver、Azure プライベートDNSなどがあたる。
これらは各種IaCに対応しており、前述のようなマネージドサービスとしてのメリットが有る一方、高い。
特段考慮せずにポンっと立てた来月のBillingはギャップがすごい。
AWS料金表を確認して比較すると、Resolverエンドポイントあたり0.125 USD/h。これはVPCエンドポイント(インターフェース型)の12.5倍である。

https://aws.amazon.com/jp/route53/pricing/

https://aws.amazon.com/jp/privatelink/pricing/

PoC利用において間接的なリソースにお金がかけれない場合はEC2インスタンスでセルフホスティングするのは候補に上げていいと考えられる。
m7a.mediumの料金は USD 0.05796/h、半額未満である。

構築

環境は以下の通り

$ cat /etc/os-release
PRETTY_NAME="Ubuntu 24.04 LTS"
NAME="Ubuntu"
VERSION_ID="24.04"
VERSION="24.04 LTS (Noble Numbat)"
VERSION_CODENAME=noble
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=noble
LOGO=ubuntu-logo 

以下はrootユーザーで動作。

apt install bind9
cd /etc/bind
nano named.conf.options

以下記述を追加。実験としてlisten-onの値をローカルループバックアドレスとし、自身のマシンのみで受け付けるようにしている。

named.conf.options
 options {
+     listen-on { 127.0.0.1; }; #ローカルループバックアドレスを指定
+ 
+     forwarders {
+             8.8.8.8; # googleパブリックDNSを指定。
+    };
 };

named.serviceデーモンを再起動してステータスを確認し、failedが出ていないことを確認する。

systemctl restart named
systemctl status named
● named.service - BIND Domain Name Server
     Loaded: loaded (/usr/lib/systemd/system/named.service; enabled; preset: enabled) # 導入時点で自動有効化が設定されていることが見える
     Active: active (running) since Sat 2024-07-13 08:03:19 UTC; 6min ago # activeとなっていれば設定が適用されている
       Docs: man:named(8)
   Main PID: 2675 (named)
     Status: "running"
      Tasks: 5 (limit: 1068)
     Memory: 5.4M (peak: 5.7M)
        CPU: 99ms
     CGroup: /system.slice/named.service
             └─2675 /usr/sbin/named -f -u bind

Jul 13 08:03:21 bind-server named[2675]: network unreachable resolving './DNSKEY/IN': 2001:7fe::53#53
Jul 13 08:03:21 bind-server named[2675]: network unreachable resolving './DNSKEY/IN': 2001:500:2d::d#53
Jul 13 08:03:21 bind-server named[2675]: network unreachable resolving './DNSKEY/IN': 2001:500:1::53#53
Jul 13 08:03:21 bind-server named[2675]: network unreachable resolving './DNSKEY/IN': 2001:7fd::1#53
Jul 13 08:03:29 bind-server named[2675]: managed-keys-zone: Unable to fetch DNSKEY set '.': timed out
Jul 13 08:03:29 bind-server named[2675]: resolver priming query complete: timed out
Jul 13 08:05:02 bind-server named[2675]: network unreachable resolving './NS/IN': 2001:7fd::1#53
Jul 13 08:05:02 bind-server named[2675]: network unreachable resolving './NS/IN': 2801:1b8:10::b#53
Jul 13 08:05:02 bind-server named[2675]: network unreachable resolving './NS/IN': 2001:500:9f::42#53

restart時にエラーが出てきてしまう場合、構文エラーは標準エラー出力されないため/var/log/syslogなどから特定する必要がある。

確認

キャッシュサーバーとしての動作

構築時点で8.8.8.8のキャッシュサーバーとして機能できる。

dig @127.0.0.1 www.isc.org
; <<>> DiG 9.18.24-0ubuntu5-Ubuntu <<>> @127.0.0.1 www.isc.org

...
;; Query time: 561 msec # 0.561秒かかっている
;; SERVER: 127.0.0.1#53(127.0.0.1) (UDP)
;; WHEN: Sat Jul 13 08:25:02 UTC 2024
;; MSG SIZE  rcvd: 167

dig @127.0.0.1 www.isc.org

; <<>> DiG 9.18.24-0ubuntu5-Ubuntu <<>> @127.0.0.1 www.isc.org

;; Query time: 0 msec # 応答時間が前回より少ない。キャッシュによるもの。
;; SERVER: 127.0.0.1#53(127.0.0.1) (UDP)
;; WHEN: Sat Jul 13 08:25:29 UTC 2024
;; MSG SIZE  rcvd: 167
named.conf.options
 options {
    // listen-on { 127.0.0.1; }; # コメントアウト

    forwarders {
            8.8.8.8; # googleパブリックDNSを指定。
   };
 };
ip addr show eth1
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:34:76:c7 brd ff:ff:ff:ff:ff:ff
    altname enp0s8
    inet 192.168.2.10/24 brd 192.168.2.255 scope global eth1 # 192.168.2.0/24ネットワークにいるのがわかる
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe34:76c7/64 scope link
       valid_lft forever preferred_lft forever
systemctl restart named
ufw allow from 192.168.2.0/24 to any port 53 proto tcp
ufw allow from 192.168.2.0/24 to any port 53 proto udp
ufw status
Status: active

To                         Action      From
--                         ------      ----
53/tcp                     ALLOW       192.168.2.0/24
53/udp                     ALLOW       192.168.2.0/24

今度はクライアントとして別マシンからアクセスしてみる。
以下は別途用意したクライアント用マシンのネットワークデバイスのステータス。サーバーと同じ192.168.2.0/24ネットワークにいるのがわかる。

vagrant@bind-client:~$ ip a show eth1
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:13:bd:0f brd ff:ff:ff:ff:ff:ff
    altname enp0s8
    inet 192.168.2.20/24 brd 192.168.2.255 scope global eth1 # 192.168.2.0/24ネットワークにいるのがわかる
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe13:bd0f/64 scope link
       valid_lft forever preferred_lft forever

暫定的な設定として、/etc/resolve.confでサーバーのIPアドレスを設定する。
念の為他のネームサーバーの設定は消しておくのが吉だろう。

/etc/resolve.conf
+ address 192.168.2.10

クライアント側でdigる。きちんとインターネットのドメイン情報を返してくれる。

vagrant@bind-client:~$ dig www.isc.org

; <<>> DiG 9.18.24-0ubuntu5-Ubuntu <<>> www.isc.org
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 59271
;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 58d288cde36de473010000006692484babcff5495443d440 (good)
;; QUESTION SECTION:
;www.isc.org.                   IN      A

;; ANSWER SECTION:
www.isc.org.            4       IN      CNAME   isc.map.fastlydns.net.
isc.map.fastlydns.net.  60      IN      A       151.101.2.217
isc.map.fastlydns.net.  60      IN      A       151.101.66.217
isc.map.fastlydns.net.  60      IN      A       151.101.130.217
isc.map.fastlydns.net.  60      IN      A       151.101.194.217

;; Query time: 450 msec
;; SERVER: 192.168.2.10#53(192.168.2.10) (UDP)
;; WHEN: Sat Jul 13 09:26:35 UTC 2024
;; MSG SIZE  rcvd: 167

権威サーバーとしての動作

ここまではキャッシュサーバーとしての動作だが、今日ネームサーバーを自前で作る動機はプライベートネットワーク内の名前解決だろう。
特にクラウドにおけるVPC内DNSはAmazon Route53 Resolverのようなマネージドサービスも存在しているが、イン/アウトバウンドエンドポイントの料金が高い。稼働率よりもコストに軍配が上がる要件においては、自前のDNSをホストするケースもあるはずだ。
権威サーバーとして動作のさせかたを記載する。

ここではBINDサーバー、クライアント、名前解決先のWebサーバーを用意して行う。

example.comゾーンの設定(BINDサーバー)

/etc/bindnamed.conf.example-zoneを作成する。

zone "example.com" {
        type master;
        file "/etc/bind/example.com.zone";
        allow-query { any; };
        allow-transfer { none; };
};

/etc/bindexample.com.zoneを作成する。

nano /etc/bind example.com.zone

以下のように編集。

/etc/bind/example.com.zone
$ttl 60
@ IN SOA . examplemail.example.com. (
                          20240701   ; serial number
                          60       ; refresh period
                          60        ; retry period
                          60      ; expire time
                          60 )     ; minimum TTL
@               IN NS   .
www             IN A    192.168.2.30

wwwのAレコードとして設定しているIPアドレス192.168.2.30 はWebサーバーのIPアドレス。環境に応じて任意のアドレスに変更する。

SOAレコードでこのレコードのメール連絡先examplemail.example.com.を指定しているが、ここは特に指定はない。
それ以外のSOAレコードについては以下の通り

フィールド 説明
20240701 ; serial number ソーン情報のシリアル番号。単に識別番号のため、この値の変更による名前解決の性質変更はない
60 ; refresh period セカンダリサーバーがプライマリサーバーにゾーン情報の更新を確認する間隔。(今回はセカンダリサーバーは設けない)
60 ; retry period セカンダリサーバーがゾーン情報を更新できなかった場合に再試行する間隔。
60 ; expire time プライマリサーバーのダウンなどを理由にセカンダリサーバーがゾーン情報を更新できなかった場合、セカンダリサーバーが持っている情報で名前解決を継続できる時間
60 ; minimum TTL ネガディブキャッシュ(問い合わせに失敗したドメインに関するキャッシュ)の保持時間。

次に、/etc/bind/named.confを以下のように編集し、先程作成したする。

/etc/bind/named.conf
include "/etc/bind/named.conf.options";
include "/etc/bind/named.conf.local";
include "/etc/bind/named.conf.default-zones";
+ include "/etc/bind/named.conf.example-zone";

bindを再起動する。

systemctl restart named

Apacheのホスト(Webサーバー)

Aレコードとして設定した192.168.2.30であることを確認する。

ip addr show eth1
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:66:02:b0 brd ff:ff:ff:ff:ff:ff
    altname enp0s8
    inet 192.168.2.30/24 brd 192.168.2.255 scope global eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe66:2b0/64 scope link
       valid_lft forever preferred_lft forever

本筋ではないので以下のコマンドでサクッと建てる。

apt update
apt install apache2
systemctl start apache2
curl http://localhost # テストページの表示を確認
ufw allow http
ufw enable
ufw status # 80番の開放を確認

Curlでのドメインの名前解決を通したWebサーバーへのアクセス(BINDクライアント)

resolve.confの記述を確認してBINDサーバーをネームサーバーとして利用していることを確認する。
systemd-resolvedが動作している場合はresolve.confは自動的に書き換えられうるため、上書きされている場合がある。

resolve.conf
cat /etc/resolve.conf
...
nameserver 192.168.2.10
...

以下のコマンドを実行する。出力冒頭で名前解決が行われていることも確認する。

curl -v http://www.example.com
* Host www.example.com:80 was resolved.
* IPv6: (none)
* IPv4: 192.168.2.30
*   Trying 192.168.2.30:80...
* Connected to www.example.com (192.168.2.30) port 80
> GET / HTTP/1.1
> Host: www.example.com
> User-Agent: curl/8.5.0
...
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
... # 以下HTMLレスポンス

以上で、BINDネームサーバーによる名前解決と、それを通したドメイン指定によるWebアクセスが行えた。

代替ネームサーバーサービスについて

BIND以外にもネームサーバーサービスが存在しているので軽く紹介。

dnsmasq

小規模なDNSとDHCPサーバーを提供するソフトウェア。DNSとしてはキャッシュサーバーとしての動作と、内部のhostsファイルをもとにした簡易的な名前解決を提供する。

Unbound

DNSキャッシュサーバーとして動作するソフトウェア。キャッシュポイズニングはじめとした攻撃に対する耐性があり、BINDよりも処理性能が高い。

NSD

権威サーバーとして動作するソフトウェア。キャッシュDNSとしては動作しない。

PowerDNS

BINDの次世代的に利用されているDNSソフトウェア。ゾーン情報のデータソースにRDBMSを利用できるほか、WebUIに対応している。性能、攻撃耐性が高い。

参考

Discussion