CentOS7とbind9.9.4／bind-chroot9.9.4を利用したDNSサーバ構築

# CentOS7とbind9.9.4／bind-chroot9.9.4を利用したDNSサーバ構築

私自身はあまりインフラ・ネットワークが得意ではなく、なかなか勉強してこなかった分野です。
不足している知識領域を少しでも改善すべく、今回はbindを使ったDNSサーバの構築を行って、ネットワークの知識を少し身に着けられればと思って、勉強がてら実施した内容をQiitaの記事にまとめました。

## 環境
|＃|環境|概要|
|:--|:--|:--|
|1|IP|192.168.33.70|
|2|Vagrant|2.0.3|
|3|Oracle VM VirtualBox|5.2.8|
|4|CentOS|7.4|
|5|bind|9.9.4|
|6|bind-chroot|9.9.4|
|7|bind-utils|9.9.4|


## 事前準備
+ CentOS7の環境準備として、以下の記事を参考に、環境構築済みであること。  
[Vagrant2.0.3を使ったCentOS7.4の環境構築](https://qiita.com/You_name_is_YU/items/1bdf36270e9f594d1c7e)

## BINDを用いたDNSサーバ構築

### bindのインストール

```shell
sudo yum -y install bind bind-chroot bind-utils
```

### インストールしたbindのバージョン確認

```shell
yum list installed | grep bind

bind.x86_64                     32:9.9.4-51.el7_4.2             @updates
bind-chroot.x86_64              32:9.9.4-51.el7_4.2             @updates
bind-libs.x86_64                32:9.9.4-51.el7_4.2             @updates
bind-libs-lite.x86_64           32:9.9.4-51.el7_4.2             @updates
bind-license.noarch             32:9.9.4-51.el7_4.2             @updates
bind-utils.x86_64               32:9.9.4-51.el7_4.2             @updates
rpcbind.x86_64                  0.2.0-42.el7                    @anaconda
```

### rootにsuする

ここから先の手順で、例えば`/var/named`にcdし、chrootができていることを確認するなどの作業では、sudoで確認できないため、rootにsuします。

```shell
su -
```

### chrootができていることを確認する

以下のコマンド実行で、chrootというディレクトリが存在することを確認します。

```shell
cd /var/named/
ls
```

### namedの関連ファイルが存在しないことを確認

bindおよびbind-chrootインストール直後、まだbindおよびbind-chrootのサービスが起動していないため、設定ファイルが存在しないことを確認します。

```shell
cd /var/named/chroot/etc
ls -laF

drwxr-x---. 4 root named 30  4月 14 09:55 ./
drwxr-x---. 7 root named 61  4月 14 09:55 ../
drwxr-x---. 2 root named  6  1月 22 22:30 named/
drwxr-x---. 3 root named 25  4月 14 09:55 pki/

cd /var/named/chroot/etc/named/
ls -laF
drwxr-x---. 2 root named  6  1月 22 22:30 ./
drwxr-x---. 4 root named 30  4月 14 09:55 ../
```

### bind-chrootの役割

通常、bindのルートディレクトリは`/`ですが、bind-chrootを利用することで`/var/named/chroot`がルートディレクトリになり、bindのプロセスがアクセス可能なディレクトリ領域を制限することが出来ます。
※bindのプロセスが`/var/named/chroot`より上のディレクトリへアクセスできない状態で環境構築される。
セキュリティの観点から、bindでのDNSサーバ構築時には、bind-chrootの利用が推奨されているようです。

### bind-chrootのサービスを自動起動設定＋起動

以下ではnamedを意図的に`disable`にしていますが、通常yumでインストールした直後は`disable`のままなので不要な手順です。
bind-chrootを利用してセキュアなDNSサーバを構築する場合、namedのサービスは自動起動をOFFに設定するようなので、意図的に記述しています。

```shell
systemctl disable named.service
systemctl enable named-chroot
systemctl start named-chroot
```

### namedの関連ファイルが自動で生成されていることを確認

上記手順の、named-chrootサービスを起動したタイミングで`/var/named/chroot/etc`配下に設定ファイルなどが自動で生成されます。

```shell
cd /var/named/chroot/etc
ll

合計 688
-rw-r--r--. 2 root root     292  3月 28 01:13 localtime
drwxr-x---. 2 root named      6  1月 22 22:30 named
-rw-r-----. 1 root named   1705  3月 22  2016 named.conf
-rw-r--r--. 1 root named   3923  1月 22 22:30 named.iscdlv.key
-rw-r-----. 1 root named    931  6月 21  2007 named.rfc1912.zones
-rw-r--r--. 1 root named   1587  5月 22  2017 named.root.key
drwxr-x---. 3 root named     25  4月 14 09:55 pki
-rw-r--r--. 1 root root    6545  6月  7  2013 protocols
-rw-r-----. 1 root named     77  4月 14 10:13 rndc.key
-rw-r--r--. 1 root root  670293  6月  7  2013 services
```

### DNSの設定を行うための事前情報

bindを使ってDNSサーバを構築する練習用に、内部ドメイン名として`You-name-is-YU.local`というドメインを利用して以下の構成のDNS設定を行ってみようと思います。

|＃|IPアドレス|ドメイン名|役割（仮）|
|:--|:--|:--|:--|
|1|192.168.33.70|ns.You-name-is-YU.local|DNSサーバ
|2|192.168.33.80|mail.You-name-is-YU.local|メールサーバ
|3|192.168.33.90|proxy.You-name-is-YU.local|Proxyサーバ
|4|192.168.33.100|web.You-name-is-YU.local|Webサーバ
|5|192.168.33.110|app.You-name-is-YU.local|アプリケーションサーバ

### named.confの編集

`/var/named/chroot/etc/named.conf`ファイルを編集します。
編集前の`named.conf`は以下の状態です。（参考までに）

```shell
 11
 12 options {
 13         listen-on port 53 { 127.0.0.1; };
 14         listen-on-v6 port 53 { ::1; };
 15         directory       "/var/named";
 16         dump-file       "/var/named/data/cache_dump.db";
 17         statistics-file "/var/named/data/named_stats.txt";
 18         memstatistics-file "/var/named/data/named_mem_stats.txt";
 19         allow-query     { localhost; };
 20
 21         /*
 22          - If you are building an AUTHORITATIVE DNS server, do NOT enable recursion.
 23          - If you are building a RECURSIVE (caching) DNS server, you need to enable
 24            recursion.
 25          - If your recursive DNS server has a public IP address, you MUST enable access
 26            control to limit queries to your legitimate users. Failing to do so will
 27            cause your server to become part of large scale DNS amplification
 28            attacks. Implementing BCP38 within your network would greatly
 29            reduce such attack surface
 30         */
 31         recursion yes;
 32
 33         dnssec-enable yes;
 34         dnssec-validation yes;
 35
 36         /* Path to ISC DLV key */
 37         bindkeys-file "/etc/named.iscdlv.key";
 38
 39         managed-keys-directory "/var/named/dynamic";
 40
 41         pid-file "/run/named/named.pid";
 42         session-keyfile "/run/named/session.key";
 43 };
 44
 45 logging {
 46         channel default_debug {
 47                 file "data/named.run";
 48                 severity dynamic;
 49         };
 50 };
 51
 52 zone "." IN {
 53         type hint;
 54         file "named.ca";
 55 };
 56
 57 include "/etc/named.rfc1912.zones";
 58 include "/etc/named.root.key";
 59
```

ファイルを編集する前に必ずバックアップを取得しておいてください。

```shell
cp -p /var/named/chroot/etc/named.conf /var/named/chroot/etc/named.conf.org
```

`named.conf`の56行目に以下の記述を追加します。
以下の記述は`You-name-is-YU.local`のドメインに対し、ゾーンファイルの紐付け定義をしています。
ゾーンファイルとは、DNSの設定ファイルの一つで、DNSゾーンについての管理情報やホスト名、アドレス情報などを記述したファイルです。
DNSが管理する範囲をゾーンと呼ぶ。

```shell
zone "You-name-is-YU.local" IN {
  type master;
  file "You-name-is-YU.local.zone";
};
```
※最後のセミコロンを付け忘れると、named-chrootサービスを再起動するタイミングでエラーが発生するので注意しましょう。

### 正引きゾーンファイルの作成

bindをインストールすると、ゾーンファイルのサンプルが一緒に配置される。
そのサンプルをコピーして、必要なゾーンファイルを作成します。

```shell
cp -p /var/named/chroot/var/named/named.localhost /var/named/chroot/var/named/You-name-is-YU.local.zone
```

コピーしたゾーンファイルを以下のように修正します。

```shell
vim /var/named/chroot/var/named/You-name-is-YU.local.zone
```

```shell
1 $TTL 1D
2 @       IN SOA  ns.You-name-is-YU.local. root.You-name-is-YU.local. (
3                                         0       ; serial
4                                         1D      ; refresh
5                                         1H      ; retry
6                                         1W      ; expire
7                                         3H )    ; minimum
8         IN NS   ns.You-name-is-YU.local.
9 @       IN A    192.168.33.70
10 ns      IN A    192.168.33.70
11 mail    IN A    192.168.33.80
12 proxy   IN A    192.168.33.90
13 web     IN A    192.168.33.100
14 app     IN A    192.168.33.110
```

#### SOAレコードの設定

SOAレコードは、Start of Authorityの略で、ドメイン名からそのドメインに関する権威をもつホストやDNS管理者を定義するレコード。

|＃|設定値|概要|
|:--|:--|:--|:--|
|1|ns.You-name-is-YU.local.|プライマリDNSサーバ名|
|2|root.You-name-is-YU.local.|ドメイン管理者のメールアドレスを表す。<br>root.You-name-is-YU.local. ⇒ root@You-name-is-YU.local<br>メールアドレスの「@」は「.」に置き換えること。|
|3|0       ; serial|設定ファイルのシリアル番号を10桁以内の数字で記述。<br>日付＋通し番号（YYYYMMDDXX）の形式が一般的とのこと。|
|4|1D      ; refresh|セカンダリDNSサーバが、ゾーンデータの更新チェックをする間隔|
|5|1H      ; retry|プライマリDNSサーバが応答しないときに再度参照を行うまでの間隔|
|6|1W      ; expire|セカンダリDNSサーバが、プライマリDNSサーバへアクセスできない状態が続いた場合、そのゾーンデータを無効にするまでの期間|
|7|3H )    ; minimum|ネガティブキャッシュの生存期間<br>ネガティブキャッシュは、DNS問合せに失敗した情報|

#### NSレコード

NSレコードは、Name Serverの略で、下位（空白の場合はその）ドメインのネームサーバを表すレコード。

|＃|設定値|概要|
|:--|:--|:--|:--|
|1|        IN NS      ns.You-name-is-YU.local.|ドメインのネームサーバ。|

#### Aレコード

Aレコードは、Host Addressの「A」からきており、ホスト名からIPアドレスへの変換のためのレコード。
※**正引き**を表す。

|＃|設定値|概要|
|:--|:--|:--|:--|
|1|@       IN A    192.168.33.70|「@」は自ドメインを表している。ここでは`You-name-is-YU.local`に192.168.33.70を対応付けしていることと同義。|
|2|ns      IN A    192.168.33.70|ns.You-name-is-YU.localのIPアドレスが192.168.33.70であることを表す。|
※その他同様

### 正引きゾーンファイルの構文チェック

上記の設定が正しいか構文チェックを行います。
以下のような出力結果になっていればOKです。

```shell
named-checkzone You-name-is-YU.local /var/named/chroot/var/named/You-name-is-YU.local.zone

zone You-name-is-YU.local/IN: loaded serial 0
OK
```

### resolv.confを編集

`/etc/resolv.conf`は主にネームサーバ（DNSサーバ）のIPアドレスを記述するファイルです。
今回は検証のため、このファイルを以下のように修正します。

 ```shell
 nameserver 127.0.0.1
 ```

### named-chrootのサービスを再起動

```shell
systemctl restart named-chroot
```

### nslookupで名前解決のテスト

```shell
nslookup You-name-is-YU.local

Server:         127.0.0.1
Address:        127.0.0.1#53

Name:   You-name-is-YU.local
Address: 192.168.33.70
```

```shell
nslookup mail.You-name-is-YU.local

Server:         127.0.0.1
Address:        127.0.0.1#53

Name:   mail.You-name-is-YU.local
Address: 192.168.33.80
```

### digコマンドでも名前解決のテスト

digコマンドは、yumでインストールした`bind-utils`で利用可能なコマンドで、ネームサーバから情報を引き出すためのコマンドツールです。

以下のようにコマンドを実行することでネームサーバの設定情報を引き出し確認することが出来ます。

```shell
dig web.You-name-is-YU.local

; <<>> DiG 9.9.4-RedHat-9.9.4-51.el7_4.2 <<>> web.You-name-is-YU.local
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 57266
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;web.You-name-is-YU.local.      IN      A

;; ANSWER SECTION:
web.You-name-is-YU.local. 86400 IN      A       192.168.33.100

;; AUTHORITY SECTION:
You-name-is-YU.local.   86400   IN      NS      ns.You-name-is-YU.local.

;; ADDITIONAL SECTION:
ns.You-name-is-YU.local. 86400  IN      A       192.168.33.70

;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: 土  4月 14 12:46:21 JST 2018
;; MSG SIZE  rcvd: 102
```

素人には上記だと情報量が多く、ちょっとわかりづらいので、以下のようなオプションを付けて実行するとすっきりしていていいなと思いました。

```shell
dig web.You-name-is-YU.local +noall +an | cat -n
     1
     2  ; <<>> DiG 9.9.4-RedHat-9.9.4-51.el7_4.2 <<>> web.You-name-is-YU.local +noall +an
     3  ;; global options: +cmd
     4  web.You-name-is-YU.local. 86400 IN      A       192.168.33.100
```

### その他メモ

DNSで利用するポートは`53`なので、firewalldなどで対象のポートを開ける必要が出てくるかと思います。
今回はローカル環境でのみ検証したため特に気にしていませんが、必要に応じてその他設定が発生してくるのかと。