😎

DNSサーバー構築-権威DNS後編-

に公開

はじめに

これは、前回のDNSサーバー構築-権威DNS前編-の続きである。今回は、実際に借りたVPSを権威DNSにして、運用化するまでの軌跡を送っていきたいと思う。

サーバーに実際にファイルを入れる。

今回は、Dockerを使ってコンテナ化してDNSサーバーを運用していくのだが、それに伴ってDockerをサーバーにインストールしていかなければならない。なのでインストールする。インストールについては今回この記事では割愛するが、そのうち出したい。

今回は、githubからcloneしてファイルを移動させた。

すでに前編でローカルで確認&本番ファイルは完成済みなのであとはdockerのコマンドを打つだけである。(Dockerって便利だね)

コンテナを動かす

sudo docker compose up -d←これやった時

Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint bind-auth (50e9c5f9c4acea3c51386cbad5bba72e78578e76c06be3d0140603a080ff425f): failed to bind host port for 0.0.0.0:53:172.18.0.2:53/tcp: address already in use

エラーの意味は「ホストの53番ポートを誰かがもう使ってるので、コンテナで公開できない」です。Ubuntuだとsystemd-resolvedやホストのbind9が犯人なことが多いです。

systemd-resolved が 53 番ポートを掴んでいる場合

Ubuntu では、デフォルトで systemd-resolved という DNS スタブリゾルバが動いている。

これはローカルの 127.0.0.53:53 で DNS サービスを提供しているため、Docker で BIND9 を 53 番ポートで起動しようとすると衝突が発生する。

つまり、

DockerのBIND9 ←(奪いたい)→ 53番ポート ←(掴んでる)→ systemd-resolved

という状況になっているわけだ。

これを解消するには、Stub Listener を停止して 53 番ポートを空ける必要がある。

犯人を特定する

まず、どのプロセスが 53 番ポートを占有しているかを調べる。

# 53/TCP と 53/UDP を誰が掴んでいるかを確認
sudo ss -lptn 'sport = :53'
sudo ss -lpun 'sport = :53'

よくある犯人は以下の3つである:

代表的なプロセス 内容 備考
systemd-resolved Ubuntu系のDNSスタブ 127.0.0.53 でリッスンしている
bind9 ホスト側にBINDが入っている Dockerと競合する
別のDockerコンテナ 既存のDNSコンテナなど 再利用されている可能性あり

解説

  • ss はソケットの状態を確認するコマンド(netstat の後継)
  • l は「リッスン中のソケット」を表示
  • p は「プロセス情報」を表示
  • t は TCP
  • n は「名前解決をしない(IPで表示)」
  • 'sport = :53' は 53 番ポートを指定

この結果に例えば以下のような表示が出る:

LISTEN 0 128 127.0.0.53:53 ... users:(("systemd-resolve",pid=xxx,fd=xx))

systemd-resolve が 53 番を掴んでいることがわかる。


systemd-resolved が入っている場合

systemctl status systemd-resolved

resolvectl status

解説

  • systemctl status はサービスの起動状態を確認
  • resolvectl statussystemd-resolved の詳細情報(どのIPでリッスンしているかなど)を表示
  • 127.0.0.53 が出ていれば、Stub Listener が動作中である

Stub Listener を無効化する

systemd-resolved は /etc/systemd/resolved.conf の中で Stub Listener の ON/OFF を管理している。

この中の以下の設定を変更する:

# /etc/systemd/resolved.conf
DNSStubListener=yes

これを no に変える。

コマンドで直接編集する場合:

sudo sed -i 's/^#\?DNSStubListener=.*/DNSStubListener=no/' /etc/systemd/resolved.conf

解説

  • sed -i はファイルを直接上書き編集するコマンド
  • s/パターン/置換/ は置換
  • ^#\? は「行頭に # がある or ない」両方にマッチ
  • DNSStubListener=.* は既存の値を全て対象
  • DNSStubListener=no に置き換える

これで、次回の起動以降 Stub Listener が無効化される。


上流DNSを設定しておく

systemd-resolved/etc/systemd/resolved.conf の中で Stub Listener の ON/OFF を管理している。

このファイルの DNSStubListenerno に変更することで、ローカルの 53 番ポートのリッスンを止めることができる。

# /etc/systemd/resolved.conf
[Resolve]
DNSStubListener=yes

これを以下のように書き換える。

# /etc/systemd/resolved.conf
[Resolve]
DNSStubListener=no

この設定によって、systemd-resolved は 127.0.0.53:53 での待ち受けを行わなくなり、

Docker 側で BIND9 を 53 番ポートで起動できるようになる。


あわせて、この段階で 上流 DNS サーバー(フォワーダー) を設定しておくとよい。

Stub Listener を無効化すると OS 側の名前解決が行えなくなるため、

明示的に DNS サーバーを指定することで解決不能な状態を防げる。

以下は Cloudflare と Google の DNS を設定する例である。

# /etc/systemd/resolved.conf
[Resolve]
DNS=1.1.1.1 8.8.8.8
DNSStubListener=no
  • DNS= に複数の DNS サーバーを指定可能
  • 先頭のサーバーが優先され、障害時は順にフォールバックする
  • 自社や学内 DNS がある場合は、そのアドレスを指定してもよい

設定を反映する

sudo systemctl restart systemd-resolved

解説

  • 設定を反映するため systemd-resolved を再起動
  • この時点で 53 番ポートのリッスンが消える

再度確認:

sudo ss -lptn 'sport = :53'

何も表示されなければ 53 番ポートが解放された


resolv.conf を差し替える

Ubuntu では /etc/resolv.conf127.0.0.53 を指していることが多い。

確認:

ls -l /etc/resolv.conf

出力例:

/etc/resolv.conf -> ../run/systemd/resolve/stub-resolv.conf

つまり今 OS は「自分の Stub(127.0.0.53)」を名前解決先にしている。

Stub Listener を止めたので、このままだと名前解決ができなくなる

本体の resolv.conf に切り替える:

sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf

解説

  • ln -sf はシンボリックリンクの強制張り替え
  • /run/systemd/resolve/resolv.conf は Stub ではなく上流DNS直結の設定
  • これにより OS 自体も問題なく名前解決可能になる

動作確認

cat /etc/resolv.conf

nameserver 1.1.1.1
nameserver 8.8.8.8

となっていればOK。

さらに、

ping google.com

で名前解決ができれば設定成功🎉


bind9 が入っている場合

sudo systemctl stop bind9
sudo systemctl disable bind9

他のコンテナが掴んでいる場合

docker ps
# 該当コンテナを停止/削除
docker stop <NAME_OR_ID>

その後、compose を 53 に戻して再起動:

# composeの ports を 53 に戻す
docker compose up -d
docker ps  # (healthy) になってるか確認

Docker の 53 ポートが使えるか再チェック

sudo ss -lptn 'sport = :53'

何も出なければポートが空いた状態。

そのまま Docker で BIND9 を 53 番で起動可能になる。


FWの確認

53番ポートのフォワーディングが空いていないとダメなので以下のコマンドで開ける。

UFWについても今度記事をあげる。

sudo ufw allow 53/udp
sudo ufw allow 53/tcp
sudo ufw reload

起動確認コマンド(ローカル53番内)

docker compose up -d

dig @127.0.0.1 exmaple.com SOA +norecurse         # 53で動かすなら -p は不要

ドメインの設定

次に、ドメイン(レジストリ)の設定を変えていく。今回、使ったのはvalue-domainというドメインレジストリ。結構おすすめ。

なぜドメイン側で設定しないといけないかというと、元々、買ったドメインはドメインのレジストリのものである。そのため、レジストリのDNSから自作DNSに変えていかないといけない。そのため、最初にドメインと自作DNSの紐付けを行わないといけない。それをこれから行っていく

Glueレコード設定

value-domainでは以下のような画面があると思う
以下の画面のドメイン設定操作

のなかの

登録済みドメイン一覧を選択し、

任意のドメインのネームサーバーのタグを選択



そしたら、ネームサーバーの変更という画面が出てくると思うので、そのページの下の方にスクロールをする

次に、自前ネームサーバーとあると思うので、そこの中の”このドメインでネームサーバーを作成する”があると思うので選択すると


次のような画面になる。ここに、ns1.example.com(自分のドメイン)を記入し、DNSのIPアドレスを振る。

そして、追加を押す。

(ns1.example.comとns2.example.comの二つ追加してください)

そして、次のページもどり以下のように追加した二つを上位に置く。
(最初の初期設定はns11.value-domain.com,ns12.value-domain.com,ns13.value-domain.comになっていると思うので消してください)

以上!!これにて終了です!!!!

終わりに

今回、権威DNSをVPSをたてて、どのようなルートで名前解決ができているのかがわかった。whoisコマンドだったり、digコマンドだったり、多くのコマンドだったりを知ることができたので本当にいい勉強になった。DNS関連のセキュリティに関してはまた今度調べて記事にしてさらに自分の権威DNSを強固にしていきたい。

Discussion