前書き
この2017年に投稿した内容では古くてそのままでは動作しなくなっているので2021年版を別に投稿しました。
背景
DNSの実装と言えば古くからBINDが使われていますが、昨今では脆弱性が度々発覚してセキュリティ的に運用が難しい状況にあります。
BINDに代わるDNSの実装が他にもあり主要なLinuxディストリビューションでも公式パッケージ化されて最新バージョンにも追随しています。
Dockerでコンテナ化もし易い状況なのでサービス例として記録しておきます。
権威DNSサーバー NSD
コンテンツサーバーとも呼ばれる自組織や他組織のゾーンを管理しているDNSサーバーです。
一般の利用者がドメイン検索で使用するキャッシュDNSサーバーと呼ばれるフルリゾルバーのDNSサーバーが権威DNSサーバーのルートサーバーから順繰りに問い合わせてドメイン検索する仕組みがDNSです。
今回はBINDではなくNSDを使用します。世界に13箇所あるルートサーバーの一部でも採用されています。
スレーブサーバー
権威DNSサーバーはマスターとスレーブの2つ以上で構成されます。
マスターはゾーン編集をフロントエンドに出しやすいPowerDNSにして、NSDはスレーブとして運用するのが良いかと思います。
DNSでは多様性も言われてますので、マスターとスレーブで異なる環境と実装を組み合わせましょう。
マスタ・プライマリ側でPowerDNSの場合は以下の投稿で紹介しています。
Docker環境
ホストOSには、CentOS 7を使用、Docker CEとDocker-composeでコンテナを作成します。
インストール方法は公式ガイドを参照下さい。一例も記録しておきます。
Docker CE インストール
https://docs.docker.com/engine/installation/linux/centos/
$ sudo yum install -y yum-utils
$ sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
$ sudo yum-config-manager --enable docker-ce-edge
$ sudo yum makecache fast
$ sudo yum install -y docker-ce
$ sudo systemctl start docker
$ sudo systemctl enable docker
$ sudo docker run hello-world
Docker Compose インストール
https://docs.docker.com/compose/install/
$ sudo -i
# curl -L https://github.com/docker/compose/releases/download/1.25.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
# chmod +x /usr/local/bin/docker-compose
# exit
$ docker-compose --version
Docker Image
Docker Hubを検索するとNSDのDocker Imageもありますので利用しましょう。
ただし中にはバージョンの古いものもあるので、NSD4の最新バージョンに追随しているDocker Imageを選びました。
https://hub.docker.com/r/hardware/nsd-dnssec/
https://github.com/hardware/nsd-dnssec
NSDコンテナの設定
適当なディレクトリにDocker-composeファイルを作成します。
$ mkdir nsd
$ cd nsd
$ vi docker-compose.yml
version: "3"
services:
nsd:
image: hardware/nsd-dnssec:latest
container_name: nsd
ports:
- "5353:53"
- "5353:53/udp"
volumes:
- ./conf:/etc/nsd
- ./zones:/zones
- ./db:/var/db/nsd
投稿時version:"2"でしたがversion:"3"に変更確認
ボリュームの場所はホスト側の適当な所にします。
設定ファイルをコンテナの外側に配置して可用性を図ります。
これでコンテナを入れ替えても設定ファイルやゾーンのデータベースファイルが再利用出来ます。
$ mkdir conf
$ cd conf
$ vi nsd.conf
server:
server-count: 1
ip4-only: yes
hide-version: yes
identity: ""
zonesdir: "/zones"
remote-control:
control-enable: yes
zone:
name: domain.tld
zonefile: db.domain.tld.signed
allow-notify: 192.168.254.254 sec_key
request-xfr: AXFR 192.168.254.254 sec_key
zoneの項目で各ドメインを設定します。
nameでドメイン名、zonefileでゾーンファイルが指定出来ます。
例ではIPアドレスの所はマスター側のIPアドレスになります。
ただ管理するゾーンが追加される度に設定ファイルを修正する必要があるので、以下の様にパターン形式に変更しましょう。
pattern:
name: "slave"
zonefile: "%s.zone"
allow-notify: 192.168.254.254 NOKEY
request-xfr: 192.168.254.254 NOKEY
zone形式からpattern形式にするとドメイン毎のゾーンを記述する必要はありません。
#NSDコンテナの起動と操作
それでは、Docker-composeでNSDのコンテナを起動させてみます。
$ cd ..
$ docker-compose up -d
無事にDockerコンテナが起動していれば、以下のような状態になります。
NSDのコンテナnsdは外部に対してTCP/UDP:5353でLISTENしています。
ローカルDNSとの競合を避けるためですが、docker-compose.ymlファイルを編集する事でポート番号は変更出来ます。
このままポート番号を変更せずにローカルDNSと共存させてポートフォワードで運用する方法もあります。
$ docker-compose ps
Name Command State Ports
-------------------------------------------------------------------
nsd run.sh Up 0.0.0.0:5353->53/tcp, 0.0.0.0:5353->53/udp
ユーザーとグループのIDが991なので環境に応じで設定変更しておきましょう。
$ sudo groupadd -g 991 -r nsd
$ sudo useradd -g nsd -s /sbin/nologin -M -u 991 -r nsd
$ sudo chown nsd:nsd zones
NSDコンテナに入ってゾーンを登録してみましょう。
$ docker exec -i -t nsd /bin/sh
# nsd-control reconfig
# nsd-control addzone domain.tld slave
# nsd-control zonestatus
# nsd-control write
# exit
nsd-controlで設定ファイルの再読込やゾーンの登録が出来ます。
詳しくは公式ガイドを参照して下さい。
https://www.nlnetlabs.nl/projects/nsd/nsd-control.8.html
あと、writeする時にディレクトリ属性でファイル出力出来なかったので適切に設定しておきましょう。
ゾーンの追加自体を自動化する例が以下にあります。参考にしてください。
PowerDNS + NSD で DNS を構築する
DNSのツールをインストールして動作確認してみましょう。
$ sudo yum -y install bind-utils
$ dig @localhost chaos version.bind txt
DNSはTCP/53 UDP/53を使用しますので、ファイヤーウォールを適切に設定しましょう。
ただし権威DNSサーバーは外部公開する必要がある為、フルリゾルバーの様に制限しないように。
また、ubuntuなどでローカルのdnsmasqとかに競合して起動しない場合もあります。
ローカルDNSの停止(Ubuntu 16.04)
ubuntu 16.04 ではローカルDNSのdnsmasqが動作しています。
当然にTCP/UDP:53番ポートをLISTENするのでポート番号が競合する為に事前に停止します。
$ sudo lsof -i:53
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
dnsmasq 1107 nobody 4u IPv4 20801 0t0 UDP localhost:domain
dnsmasq 1107 nobody 5u IPv4 20802 0t0 TCP localhost:domain (LISTEN)
DNS設定をコメントアウト
#dns=dnsmasq
NetworkManagerを再起動
$ sudo service network-manager restart
このままだとDNS名前解決できないので、DNSリゾルバを設定します。
#nameserver 127.0.1.1
nameserver 8.8.8.8
NetworkManager経由のサブデーモンとしてdnsmasqが起動している為か、
ホスト自体を再起動しないとdnsmasqが無効になりませんでした。
ローカルDNSの停止(Ubuntu 18.04)
ubuntu 18.04ではローカルDNSのsystemd-resolveが動作しています。
当然にTCP/UDP:53番ポートをLISTENするのでポート番号が競合する為に事前に停止します。
$ sudo lsof -i:53
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
systemd-r 685 systemd-resolve 12u IPv4 18787 0t0 UDP localhost:domain
systemd-r 685 systemd-resolve 13u IPv4 18788 0t0 TCP localhost:domain (LISTEN)
DNSStubListener=no
$ sudo systemctl restart systemd-resolved
$ sudo lsof -i:53
sudo: unable to resolve host vuls: Resource temporarily unavailable
このままだとDNS名前解決できないので、DNSリゾルバを設定します。
#nameserver 127.0.0.53
nameserver 8.8.8.8
しかしsystemd-resolvedにより
/etc/resolv.conf -> ../run/systemd/resolve/stub-resolv.conf
とシンボリックリンクされていて元に戻ってしまいます。
やはりsystemd-resolvedを停止させます。
$ sudo systemctl stop systemd-resolved
$ sudo systemctl disable systemd-resolved
シンボリックリンクを消して設定ファイルを作成します。
$ sudo rm /etc/resolv.conf
nameserver 8.8.8.8
NSDバージョンアップ
投稿後にNSD 4.2.1がリリースされたのでコンテナの更新方法を記録しておきます。
通常、docker-compose upコマンドでイメージの更新があればコンテナは再作成されます。
しかしローカルには取得時のイメージをキャッシュして使用する為、最新のイメージをDocker Hubから再取得する必要があります。
新しいイメージをDocker Hubから再取得します。
$ docker pull hardware/nsd-dnssec:latest
ローカルのイメージを再確認します。
REPOSITORY TAG IMAGE ID CREATED SIZE
hardware/nsd-dnssec latest b0034ab6cdde 2 months ago 12.2MB
hardware/nsd-dnssec <none> 1f4023f05f4f 3 months ago 9.03MB
作成日時の新しいイメージがローカルに保存されました。
不要ならば消してもいいですが何かあった場合に以前のイメージに戻せます。
以前のイメージのタグからlatestが外れたので、バージョンを指定しておきます。
$ docker tag 1f4023f05f4f hardware/nsd-dnssec:4.2.1
ローカルのイメージを再確認します。
REPOSITORY TAG IMAGE ID CREATED SIZE
hardware/nsd-dnssec latest b0034ab6cdde 2 months ago 12.2MB
hardware/nsd-dnssec 4.2.1 1f4023f05f4f 3 months ago 9.03MB
これでコンテナのイメージ更新準備が出来ました。
コンテナの再作成をしましょう。
$ docker-compose up -d
Recreating nsd
コンテナの中に入ってNSDのバージョンを確認してみます。
$ docker exec -i -t nsd /bin/sh
# nsd-control status
version: 4.2.1
NSDのバージョンアップが出来ました。
また、ゾーンの設定が継承されている事を動作確認しておきましょう。