Azure上でAzureプライベートDNSを使うDNSキャッシュサーバ(Unbound)を動かす

前回のDNSプロキシサーバ（DNSキャッシュサーバ）の構築が雑すぎたので、Unboundの勉強がてらに試した。OSはUbuntu 18.0.4。
また、おまけでAzureの仮想ネットワークゲートウェイを使ったP2S接続時のDNSにこのDNSキャッシュサーバを指定するにはどうするか、の確認も行った。


参考文献
------------------------

日本Unboundユーザー会のドキュメント

- https://unbound.jp/unbound/howto_setup/
- https://unbound.jp/unbound/howto_optimise/
- https://unbound.jp/unbound/unbound-conf/

Azure docs

- https://docs.microsoft.com/ja-jp/azure/vpn-gateway/point-to-site-about

スライド

- [DNSキャッシュサーバ チューニングの勘所](https://www.slideshare.net/hdais/dns-32071366)
- [Unboundの追加パラメーターチューニング](https://dnsops.jp/event/20190628/LT_simamura_unbound.pdf)


事前準備
------------------------

- Azure プライベートDNSを用意し、仮想ネットワークにリンクしておく(今回は`fukasawah.example`ゾーンにした。)
- DNSキャッシュサーバとなるVMを立てておく


Unboundを動かす
-------------------------

選定理由は機能十分なところと脆弱性の少なさ。JVNで見た感じでは、Unboundは10件ぐらい、dnsmasqは20件弱。ちなみにPowerDNSは40件ぐらい、BINDはたくさん。比較的若いからというのもあると思うけども。

### unboundを導入

``` bash
sudo apt update
sudo apt install unbound
```

起動に失敗しますが、`Systemd-resolved`が起動しているせいです。いったん無視してかまいません。

### unboundの設定を書く


Ubuntu 18.04.4 LTSのリポジトリには libevent対応版のunboundが配布されていたので、設定はlibevent向けにしています。メモリは512MBの環境の上でunboundだけ動かす想定。

``` /etc/unbound/unbound.conf.d/sample.conf
server:
        interface: 0.0.0.0
        access-control: 10.0.0.0/8 allow
        # ちょっとログを出す
        verbosity: 1
        # リソースレコードセット(RRSet)のラウンドロビンを有効にする
        rrset-roundrobin: yes
        # レスポンスでAUTHORITY/ADDITIONAL SECRIONを省略できるときは省略する機能を有効にする
        minimal-responses: yes

        # クエリの結果のTTLをこの値を超えないようにすることで、少なくともこの時間でキャッシュ切れにさせる
        cache-max-ttl: 86400

        # Tuning
        num-threads: 1
        msg-cache-slabs: 2
        rrset-cache-slabs: 2
        infra-cache-slabs: 2
        key-cache-slabs: 2
        rrset-cache-size: 100m
        msg-cache-size: 50m
        so-rcvbuf: 4m
        so-sndbuf: 4m
        infra-cache-numhosts: 1000

        # use libevent
        outgoing-range: 4096
        num-queries-per-thread: 4096

        # security配慮
        hide-version: yes

        # DNSSECを無視する必要があったのでホストを明示している
        domain-insecure: "fukasawah.example"

# 全部Azure内部DNS(168.63.129.16)へ丸投げする
forward-zone:
        name: "."
        forward-addr: "168.63.129.16"
```

「AzureプライベートDNSを使う」とタイトルに入れているけども、AzureプライベートDNSを仮想ネットワークにリンクしておけば、Azure内部DNSが良しなにしてくれるので丸投げしているだけ。

`rrset-roundrobin`はちゃんと分散するように有効にしておくとよいと思う。

`access-control`は省略すると`localhost`しか許可されないので、明示的に幅広く許可しています。複数指定できるのでレンジを跨ぐ場合は複数書きます。セキュリティをガバガバにするつもりはないのですが、AzureのNetworkSecurityGroupで制御するので。

`# Tuning`の部分は https://unbound.jp/unbound/howto_optimise/ を読むとよいでしょう。実際は計測しながらCPUのコア数に合わせて値を調整します。


また、今回は`fukasawah.example`というゾーン値を実際に使ったのですが、DNSSECのチェックにひっかかりSERVFAILしました。そのため`domain-insecure`でDNSSECのチェックを無視しています。
（DNSSECの仕組みを理解していないのでよくわかっていない・・・実在しないTLDを使っているのでchain of trustになっていないからか、`fukasawah.example`ゾーンにDNSSECに必要なレコードを入れてないからか、[Azure DNSがDNSSECに対応していない](https://docs.microsoft.com/ja-jp/azure/dns/dns-faq#does-azure-dns-support-dnssec
)からか...）


### Kernelのパラメータ調整

```
sudo tee /etc/sysctl.conf << EOF 

# 受信バッファを4M確保
net.core.rmem_max = 4194304
# 送信バッファを4M確保
net.core.wmem_max = 4194304
EOF 

# 設定の再読み込み
sudo sysctl -p
```

ちなみに調整しないとこんな感じのログが出る。

> Mar  3 15:23:26 vm-0 unbound[30872]: [1583249006] unbound[30872:0] warning: so-rcvbuf 4194304 was not granted. Got 425984. To fix: start with root permissions(linux) or sysctl bigger net.core.rmem_max(linux) or kern.ipc.maxsockbuf(bsd) values.


### 既存のDNSサービスを止め、unboundを起動


``` bash
# /etc/reslov.confを書き換える
sudo sed -i 's/127\.0\.0\.53/127.0.0.1/g' /etc/resolv.conf

# Systemd-resolvedを使わないようにする
sudo systemctl disable systemd-resolved
sudo systemctl stop systemd-resolved

# unbound起動
sudo systemctl start unbound
```

以上。これでUnbound→Azureの内部DNSに問い合わせるDNSキャッシュサーバになる。ローカルでnslookupをしたりして確認。

まずは自宅運用してみて変なところがあったら直して記事もアップデートしたい。特に設定周りはかなり怪しい。。。


おまけ
--------------


### Ubuntu周りのメモ

```
# ソフトリミット/ハードリミットを確認
cat /proc/`pidof unbound`/limits 
```

UnboundのServiceファイルの場所は `/lib/systemd/system/unbound.service` だった。

DNSSECの対応はunbound-anchorを使ってサービス起動時におこなっているっぽい（起動しっぱなしの時は大丈夫なんだろうか？）


### Unboundあたりの気になる設定

気になったけど使ってない機能

```
server:
   # 統計情報を出す間隔。デフォルトは出力されない。
   statistics-interval: 300
   # 期限切れになる前に再度取得することでキャッシュ切れにさせなくする
   prefetch: yes
   # 大文字小文字の区別をしない。実験的機能。
   use-caps-for-id: yes
```


### Azureの仮想ネットワークゲートウェイ(VPN)のP2S接続時のあれこれ

- 仮想ネットワークのDNSサーバの設定を行うと、ダウンロードできるVPNクライアントのインストーラに埋め込まれ、VPN接続時はそちらのDNSサーバを使うようになるようです。（なので、DNSサーバのアドレスが変更されたりした場合はVPNクライアントの再インストールが必要）
   - ドキュメントでこのことを触れているのは [このドキュメントぐらいな気がする？](https://docs.microsoft.com/ja-jp/azure/vpn-gateway/vpn-gateway-howto-point-to-site-classic-azure-portal#to-troubleshoot-an-rdp-connection-to-a-vm)。
- 仮想ネットワークゲートウェイ(VPN)のSKU=Basicの場合はSSTP接続になり、IKEv2やOpenVPN接続はサポートされていないようです。Windows以外を使う場合は注意。
- 仮想ネットワークゲートウェイ(VPN)のP2SのVPNクライアントを導入しても接続時に「リモート コンピューターへの接続を確立できませんでした。この接続用にネットワーク設定の変更が必要である可能性があります。 (エラー 720)」というエラーが出たとき。
    1. VPNの接続情報を削除
    2. デバイスマネージャを開いて以下のように「WAN Miniport」を全部してから削除
        - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52527/5b093a2e-7060-2733-ffb7-9a19240aa27f.png)
    3. 再度インストーラでVPN接続情報をインストールする。これでつながるかもしれない。なお、SSTPのものだけ消してもダメだった。
- ほかのエラーでつながらないときは多分凡ミスなので [ドキュメントのトラブルシューティング](https://docs.microsoft.com/ja-jp/azure/vpn-gateway/vpn-gateway-troubleshoot-vpn-point-to-site-connection-problems)でチェックする
    - `certmgr.msc`などでルート証明書が「信頼されたルート証明機関」としてインストールされているか確認するなど