DNSサーバー、BINDについて学ぶ

DNSの設定は非常にめんどくさい。
普段、Route53を利用しているが、マネージドサービスは優秀だと思う。



# ステートメント

|ステートメント|説明|
|---|---|
|acl|ACLの定義|
|controls|namedを操作できるホストの指定|
|include|外部ファイルの読み込み|
|key|認証情報の設定|
|options|namedの動作に関する詳細設定|
|zone|ゾーンの定義|

## acl

次の例では、192.168.0.0/24 を、locals というACL名で設定しています。

```
acl locals {
 192.168.0.0/24;
};
```

|アドレスマッチリスト|説明|
|---|---|
|any|すべてのIP|
|localhost|ローカルホストが使用しているIP|
|localhosts|ローカルネットワークで使用しているIP|
|none|いずれのIPともマッチしない|

## include

次の例では、/etcrndc.key ファイルを読み込んでいます。

```
include "/etcrndc.key"
```

## options

|オプション|説明|
|---|---|
|directory|ゾーンファイルを格納するディレクトリ|
|datasize|データセグメントサイズの制限|
|coresize|コアファイルのサイズの上限|
|max-cache-size|最大キャッシュサイズ（バイト単位）|
|recursion|再帰的問い合わせを受け付けるかどうか|
|recursive-clients|再帰的問い合わせの最大同時接続数|
|allow-query|問い合わせを受け付けるホスト|
|allow-recursion|再帰的な問い合わせを受け付けるホスト|
|alow-transfer|ゾーン転送を許可するホスト|
|blackhole|問い合わせを受け付けないホスト|
|fowarders|問い合わせの回送先DNSサーバー|
|foward|fowardersの回送方法|
|notify|ゾーンデータの更新をセカンダリサーバーに通知するか否か|
|version|バージョン情報|

## controls

```:named.conf
contorols {
 inet 127.0.0.1 allow { localhost; };
};
```

## zone

|タイプ|説明|
|---|---|
|hint|ルートDNSサーバー|
|master|プライマリDNSサーバー|
|slave|セカンダリDNSサーバー|

```:named.conf
zone "example.com" {
 type master;
 file "example.com.zone";
};
```

```:named.conf
zone "example.com" {
 type slave;
 file "example.com.zone";
 masters { 192.168.1.63; };
};
```

# named.conf

## プライマリDNSサーバー

```/etc/named.conf
options {
        directory "/var/named";
        version "DNS Server";
        notify yes;      
        allow-transfer { 192.168.1.5; };      
        recursion no;
};

zone "example.com" IN {
        type master;
        file "example.com.zone";
};
zone "1.168.192.in-addr.arpa" IN {
        type master;
        file "rev.example.com.zone";
};
```

## セカンダリDNSサーバー

```/etc/named.conf
options {
        directory "/var/named";
        version "DNS Server";  
        recursion no;
};

zone "example.com" IN {
        type slave;
        file "example.com.zone";
};
zone "0.20.172.in-addr.arpa" IN {
        type slave;
        master { 192.168.1.63; };
        file "rev.example.com.zone";
};
```

## キャッシュサーバー

```/etc/named.conf
options {
        directory "/var/named";
        recursion yes;
        recursive-clients 300;
        allow-query { 192.168.0.0/24; localhost; };
        allow-recursion { 192.168.0.0/24; localhost; };
        max-cache-size unlimited;
        max-cache-ttl 86400;
        max-ncache-ttl 7200;
        version "DNS Server";
};

zone "." IN {
        type hint;
        file "named.root";

zone "localdomain" IN {
        type master;
        file "localdomain.zone";
};

zone "localhost" IN {
        type master;
        file "localhost.zone";
};

zone "0.0.127.in-addr.arpa" IN {
        type master;
        file "named.local";
};
```

# コマンド

## named-checkconf

構文チェックをする。

```
# named-checkconf /etc/named.conf
```

chroot をしている場合は、-tオプションで chrootディレクトリを指定する。

```
# named-checkconf -t /varnamed/chroot /etc/named.conf
```

## rndc

|サブコマンド|説明|
|---|---|
|stop|終了する|
|refresh|ゾーンデータベースをリフレッシュする|
|status|ステータスを表示する|
|dumpdb|キャッシュの内容をファイルに出力する|
|reload|指定したゾーンファイルを再読み込みする|
|halt|停止する|
|flush|キャッシュをクリアする|

# ゾーンファイル

ゾーンを配置するディレクトリは、optionsステートメントで、
ゾーンファイル名は、zoneステートメントで指定します。

|ゾーンファイルの種類|説明|
|---|---|
|hint情報ファイル|ルートDNSサーバーの一覧|
|正引きファイル|ホスト名からIPアドレス|
|逆引きファイル|IPアドレスからホスト名|

# セキュリティ

## ゾーン転送の制限

セカンダリDNSサーバーは、プライマリDNSサーバーからゾーン情報を転送する必要があります。
しかし、セカンダリDNSサーバー以外のDNSサーバーにはゾーンを転送する必要がありません。
従って、次のようにゾーン転送はセカンダリDNSサーバーに限定するように記述します。

```
zone "example.com" {   
        allow-transfer { 192.168.1.5; };   
```

## DNS問い合わせの制限

192.168.0.0/24 からの問い合わせ、再帰問い合わせの許可に限定する

```
options {   
        allow-query { 192.168.0.0/24; };
        allow-recursion { 192.168.0.0/24; };
};
```

以下のゾーンに置いては、すべてのホストからの問い合わせを許可する。

```
zone "local.example.com" {   
        allow-query { any; };
};
```

## バージョン番号の隠蔽

バージョンを無くしたからと言ってセキュリティホールがなくなる訳ではありませんが、バージョが知られれば直ぐに攻撃を受けてしまう場合があります。

```:named.conf
options {   
        version "unknown DNS Server";
};
```

# リソースレコード

ゾーンファイルには、$ORIGINディレクティブ、$TTLディレクティブ、リソースレコードが含まれます。

- $ORIGINディレクティブ: ドメイン名が明示されていないレコードで補完するドメイン名を指定します

- $TTLディレクティブ:他のDNSサーバーがゾーンデータをキャッシュに保存しておく時間を指定します

```
$ORIGIN example.com
$TTL 86400
```

- リソースレコード
  - ＠は、そのドメイン自身を表します
  - ドメイン名は、FQDNで指定します
  - ドメイン名の最後は.でで記述する
  - .でがない場合は、$ORIGINで指定されたドメイン名が末尾に追加される

## SOA

ゾーンに関する基本的な情報を記述する。

`名前 IN SOA DNSサーバー メールアドレス`

```
@ SOA ns.example.com. root.example.com. (
 2020080501 ; Serial
 10800 ; Refresh
 600 ; Retry
 86400 ; Expire
 3600 ) ; Negative TTL
```

## NS

DNSサーバーをFQDNで指定します。

`名前 IN NS サーバー名`

```
examle.com. IN NS ns.example.com
examle.com. IN NS ns2.example.com
```

## MX

メールサーバーがメールを送る際に参照します。

`名前 IN MX プリファレンス値 メールサーバー名`

```
examle.com. IN MX 10 mx.example.com
examle.com. IN MX 20 mx2.example.com
```

## A

ホスト名に対応するIPアドレスを指定します。

`ホスト名 IN A IPアドレス`

```
ns.example.com. IN A 192.168.0.100
```

## AAAA

IPv6の場合は、Aレコードではなく、AAAAレコードを指定します。

`ホスト名 IN AAAA IPv6アドレス`

```
ns.example.com. IN AAAA fe80.....
```

## CNAME

別名を指定する。

`host1.example.com. IN CNAME ホスト名`

```
host2.example.com. IN CNAME host1.example.com.
```

## PTR

Aレコードの逆。IPアドレスに対応するホスト名を記述する。

`IPアドレス IN PIR ホスト名`

```
100.0.168.192.in-addr.arpa. IN PTR mx.example.com.
```

## ゾーンファイルの設定例

### 正引きゾーン

```
$ORIGIN example.com
$TTL 86400
example.com       IN      SOA     ns.example.com. root.example.com. (
                  2000122401 ; Serial
                  10800      ; refresh
                  600        ; retry
                  86400      ; expire
                  86400 )    ; Negative

example.com.      IN NS        ns.example.com.
example.com.      IN MX 10     mx.example.com.
example.com.      IN MX 20     mx2.example.com. 
ns.example.com.   IN A         192.168.0.100
mx.example.com.   IN A         192.168.0.101
mx2.example.com.  IN A         192.168.0.102
www.example.com.  IN CNAME     mx.example.com.
os.example.com.   IN CNAME     ns.example.com.
```

### 逆引きゾーン

```
$ORIGIN example.com
$TTL 86400
1.168.192.in-addr.arpa.       IN      SOA     ns.example.com. root.example.com. (
                  2000122401 ; Serial
                  10800      ; refresh
                  600        ; retry
                  86400      ; expire
                  86400 )    ; Negative

1.168.192.in-addr.arpa.          IN NS        ns.example.com.
63.1.168.192.in-addr.arpa.       IN PTR       ns.example.com.
63.1.168.192.in-addr.arpa.       IN PTR       mx.example.com.
63.1.168.192.in-addr.arpa.       IN PTR       mx2.example.com.
```

### named-checkzone

ゾーンファイルのチェックを行うには、**named-checkzone** を使います。
**-t** で、chrootしている場合にはそのディレクトリを指定します。
**-w** で、ゾーンファイルを置いてあるディレクトリを指定する。

# DNSSECとTSIG

## DNSSEC

### 概要

DNSサーバーにあるDNS応答を保証する仕組み。

- 動作
  - ゾーン情報のハッシュ値をDNSサーバーの秘密鍵で暗号化したものを電子署名とする
  - DNS問い合わせがあると、ゾーン情報と電子署名がクライアントに送られる
  - クライアントは電子署名を、DNSサーバーの公開鍵を使って、復号化する
  - ゾーン情報のハッシュ値と、電子署名を復号したハッシュ値が一致すればOK

- key
  - ZSK:ゾーン情報に電子署名を行う鍵
  - KSK:ZSKに電子署名を行う鍵

### 設定

ZSK鍵ペアを作成する。（この作業はゾーンファイルを格納しているディレクトリで行う必要があります。）
 
```
# dnssec-keygen -r /dev/random -a RSASHA256 -b 1024 -n zone example.com
```

KSK鍵ペアを作成する。

```
# dnssec-keygen -r /dev/urandom -f KSK -a RSASHA256 -b 2048 -n zone example.com
```

ゾーンファイルに署名します。

```
# dnssec-signzone -S -K keys/ -o example.com example.com.zone
```

署名が完了すると、「ゾーン.signed」という署名済ファイルが出来上がるので、/etc/named.confの設定を変更し、これらのゾーンファイルを指定します。

## TSIG

### 概要

ゾーン転送の安全性を保証する仕組みです。

### 設定

共有鍵を作成します。

```
# dnssec-keygen -a HMAC-MD5 -b 128 -n HOST tsig-key
```

作成された ktsig-key.+.private ファイルの中にある key （共有秘密鍵）を named.conf に記述します。

# 設定例1

同一セグメント内のクライアントから、正引き、逆引きができるようにする。

## インストール

```
# yum -y install bind bind-chroot
```

## named.conf

```/etc/named.conf
options {
        listen-on port 53 { 10.0.0.69; };
	listen-on-v6 port 53 { ::1; };
	directory 	"/var/named";
	dump-file 	"/var/named/data/cache_dump.db";
	statistics-file "/var/named/data/named_stats.txt";
	memstatistics-file "/var/named/data/named_mem_stats.txt";
	recursing-file  "/var/named/data/named.recursing";
	secroots-file   "/var/named/data/named.secroots";
        allow-query     { 10.0.0.0/8; };

	/* 
	 - If you are building an AUTHORITATIVE DNS server, do NOT enable recursion.
	 - If you are building a RECURSIVE (caching) DNS server, you need to enable 
	   recursion. 
	 - If your recursive DNS server has a public IP address, you MUST enable access 
	   control to limit queries to your legitimate users. Failing to do so will
	   cause your server to become part of large scale DNS amplification 
	   attacks. Implementing BCP38 within your network would greatly
	   reduce such attack surface 
	*/
	recursion yes;

	dnssec-enable yes;
	dnssec-validation yes;

	/* Path to ISC DLV key */
	bindkeys-file "/etc/named.root.key";

	managed-keys-directory "/var/named/dynamic";

	pid-file "/run/named/named.pid";
	session-keyfile "/run/named/session.key";
};

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

zone "naata-69.cf" IN {
        type master;
        file "test.local";
        allow-update { none; };
};

zone "0.0.10.in-addr.arpa" IN {
        type master;
        file "test.local.rev";
        allow-update { none; };
};

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

## 正引きファイル

```/var/named/test.local
$TTL      86400
@         IN       SOA     ns01.naata-69.cf.  root.test.local.(
                                        2020020501 ; Serial
                                        28800      ; Refresh
                                        14400      ; Retry
                                        3600000    ; Expire
                                        86400 )    ; Minimum
            IN NS ns01.naata-69.cf.
ns01   IN A 10.0.0.69
ns02   IN A 10.0.0.78
```

## 逆引きファイル

```/var/named/test.local.rev
$TTL      86400
@         IN       SOA     ns01.naata-69.cf.  root.test.local.(
                                        2020020501 ; Serial
                                        28800      ; Refresh
                                        14400      ; Retry
                                        3600000    ; Expire
                                        86400 )    ; Minimum
     IN NS ns01.naata-69.cf.
69   IN PTR ns01.naata-69.cf.
78   IN PTR ns02.naata-69.cf.                                 
```

## クライアントからテスト

```
# yum install bind-utils
```

```/etc/resolv.conf
nameserver 10.0.0.69
domain naata-69.cf
```

```
$ nslookup 10.0.0.69
69.0.0.10.in-addr.arpa	name = ns01.naata-69.cf.

$ nslookup ns01
Server:		10.0.0.69
Address:	10.0.0.69#53

Name:	ns01.naata-69.cf
Address: 10.0.0.69
```

# BIND以外のDNSサーバ

|DNSサーバー|説明|
|---|---|
|dnsmasq|DNSサーバー機能（コンテンツサーバー機能およびキャッシュサーバー機能）とDHCPサーバー機能を提供する計量なSW|
|unbound|キャッシュサーバーに特化したSWで、BINDに比べると設定が容易なSW|
|NSD|コンテンツサーバーに特化したSWで、BINDと同じゾーンファイルを利用することができる。|
|PowerDNS|コンテンツサーバ及びキャッシュサーバー機能を提供するSW。バックエンドにRDBなどを利用できるのが特徴です。|