bindを脱却するためにDockerでNSDとUnboundを動かした話

# 注意

DNSサーバのDの字も知らない素人がとりあえず実験目的で書いたあまりにも雑な Dockerfile & docker-compose.yaml です．
間違っても本番環境では使わないでください．

# 背景

筆者が所属するグループで10年以上にわたり代々引き継がれてきたローカルDNSサーバ（本当です）がとうとう不良セクタにより亡くなりかけたので
知識0の状態から急いで新しいマシンにDNSサーバを移行することになりました．
もぅマジ無理…

## なんでbindじゃ駄目なの？

新しいマシンにbindをインストールすれば，設定ファイルを移すだけで一応は解決する．が

- 基本設計が古い
- 脆弱性が指摘されている
- 脆弱性が指摘されている
- 脆弱性が指摘されている

という問題が有るため，NSDとUnboundというツールに移行することにした．

## bindとは

bindとはかなり昔から存在するDNSツールである．（10年もののサーバーに入ってるくらい）

そのため，流石に今日では旧式化しており大量の脆弱性が指摘されるなど，新しく導入するのはおすすめできない代物となっている．
そんなbindであるが，依然として様々な所で使われ続けているようだ．
理由は単純で，bindは

- 権威DNSサーバ（IPアドレスとドメインの対応関係を知っている偉いサーバ）
- キャッシュサーバ（権威DNSサーバにお伺いをたてる中間管理職みたいなサーバ）

という2つの機能を内包しているのである．これは，bind9の功罪とも呼べる．
現在の常識ではセキュリティ的な観点からこの2つのサーバを分けることが推奨されている．
しかしながら，昔からbindを使い続けた環境では

- 権威DNSサーバとキャッシュサーバを分けないといけないのは知っている
- でも面倒くさいからbind9のままで良いや

という先延ばしスパイラルが発生するのだ．

## 幼年期の終わり

別にbindが悪いということが言いたいのではない．
使い勝手が良いのは確かだし，今ほどセキュリティリスクに頭を痛める必要のなかった時代ではbindが最良の選択だったのだろう．

bindは言わばゆりかごである．
居心地は良いがいつまでもそこに留まっているわけにはいかない．
bindというゆりかごから自分の足で立ち上がるときがきたのだ．

# やったこと

- UnboundとNSDのDockerイメージを組み合わせて走らせようとした
- 失敗したので自分でDockerイメージを作った

## 失敗した方法

### 既存のDockerイメージを組み合わせる

NSDもUnboundも名の知れたツールであるので当然Dockerイメージが配布されている．
特に

- [hardware/nsd-dnssec](https://hub.docker.com/r/hardware/nsd-dnssec)
- [mvance/unbound](https://hub.docker.com/r/mvance/unbound)

がそれぞれ覇権を握っているようだ．

### docker-compose.yaml

こんな感じで組み合わせようとした．名前解決には53ポートが使われる．
ここで重要なのは権威サーバ(NSD)のポートを53以外にすることである．
あえて権威サーバを外部にさらさず，キャッシュサーバ(Unbound)に外部対応を
させることでなんかこう，セキュリティがいい感じになるのだ．

```
version: "3"
services:
  nsd:
    image: hardware/nsd-dnssec:latest
    container_name: nsd
    ports:
      - "10053:53"
      - "10053:53/udp"
    volumes:
      - ./conf/nsd:/etc/nsd
      - ./db:/var/db/nsd

unbound:
    image: mvance/unbound:latest
    container_name: unbound
    ports:
      - "53:53"
      - "53:53/udp"
    volumes:
      - ./conf/unbound:/opt/unbound/etc/unbound
```

```
僕が考えた最強のdnsサーバ/
├── conf
│   ├── nsd
│   │   ├── nsd.conf
│   │   └── zones
│   │       └── zonefile
│   └── unbound
│       ├── root.hints
│       └── unbound.conf
├── db
│   └── nsd.db
└── docker-compose.yaml
```

ちなみにUnboundからNSDへの問い合わせはstubzoneという設定を使う．

```
stub-zone:
    name: "hogehoge.jp."
    stub-addr: 192.168.314.159@10053
```


### 結果

NSDとUnbond単体では動いているようだが
これを組み合わせると何故か動かない．

具体的にはUnboundからNSDへの問い合わせがうまく行かないようだ．

```
nslookup www.google.com
Server:		192.168.724.106
Address:	192.168.724.106#53

Non-authoritative answer:
Name:	www.google.com
Address: 216.58.199.228
Name:	www.google.com
Address: 2404:6800:400a:80b::2004
```
外部のサイトは解決できる

```
nslookup www.hogehoge.jp
# 応答なし
```

NSDは俺に何も言ってはくれない……教えてくれ，teratail！

```
nslookup #引数を与えないと対話モードで起動する
server 192.168.724.106
Default server: 192.168.724.106
Address: 192.168.724.106

set port=10053 #ポート番号を指定できる

www.hogehoge.jp
Server:		192.168.724.106
Address:	192.168.724.106#10053

www.hogehoge.jp	canonical name = fuga.hogehoge.jp.
Name:	fuga.hogehoge.jp
Address: 210.144.214.7
```
NSDはちゃんと動いている．なんでそんないけずするの？

この後も試行錯誤したが解決はできなかった．

## うまくいった方法

### 自分でDockerイメージを作る

```
FROM ubuntu:latest

RUN apt-get update && apt-get install -y \
    nsd \
    unbound

COPY run.sh /

RUN chmod +x /run.sh
EXPOSE 53 53/udp
CMD ["/run.sh"]
```
Dockerfile本体．

```
#!/bin/bash

/usr/sbin/nsd && /usr/sbin/unbound && /bin/tail -f /dev/null
```
run.sh．　/bin/tail -f /dev/null　がミソ．

```
version: "3"
services:
  dns:
    build: .
    container_name: dns
    ports:
      - "53:53"
      - "53:53/udp"
    volumes:
      - ./nsd:/etc/nsd
      - ./db:/var/db/nsd
      - ./unbound:/etc/unbound
```

多分1番目の方法でもできるんだろうけど貧弱なDNS力ではできませんでした．

# 結論
誰か詳しい人がいたら教えて下さい．

# 参考文献
[Unbound + NSD で DNS](http://www.magic-object.mydns.jp/fedora20withunboundnsd/)
[NSD](https://wiki.archlinux.jp/index.php/NSD)
[Unbound](https://wiki.archlinux.jp/index.php/Unbound)
[Dockerで権威DNSサーバーのNSDを動かす](https://qiita.com/ohhara_shiojiri/items/39cb9c3a632676c7b33d)
[Unbound 設定
](https://qiita.com/shirakawa4756/items/4f86c0f0c01f8fa12877)