こんにちは。サービスシステム運用課の上曽山です。
検証環境では非公開ドメインを使う機会も多く、メインはインターネット側のDNS、一部のドメインはイントラネットに置いてあるDNSを使うようにしたい、と思うことがままあります。
/etc/hostsを使ったり、イントラのDNSですべての名前解決を行うようにすれば良いのですが、設定の手間とか、負荷分散やアクセス制限のことも考えないといけなくなって面倒です。
ドメイン名ごとにDNSの問い合わせ先を変更できないものか、と調べてみたところ、systemd-resolvedを使うことで解決出来そうだったので試してみました。
主なパッケージ
| 用途 | 名前 | バージョン |
|---|---|---|
| OS | Rocky Linux | 9.7 |
| DNSクライアント | systemd-resolved | 252-55.8 |
| networkサービス | NetworkManager | 1.54.0-4 |
systemd-resolvedの起動
- パッケージインストール
# dnf install systemd-resolved
- グローバル設定
デフォルトの設定ファイルは残しておきたいのでドロップインファイルを追加します。
ディレクトリが存在しない場合、作成してから設定ファイルを作成しましょう。
# mkdir /etc/systemd/resolved.conf.d # vi /etc/systemd/resolved.conf.d/global.conf
設定内容は以下のようにしました。
[Resolve] DNS=8.8.8.8 1.1.1.1 Domains=~. MulticastDNS=no LLMNR=no
| 設定内容補足 | |
|---|---|
| DNS | DNSサーバーの指定。 GoogleとCloudflareのパブリックDNSサーバーを指定しています。 |
| Domains | 検索ドメインの指定。 すべてのドメインがマッチするようにしています。 |
| MulticastDNS | どちらもマルチキャストを使った名前解決方法。 これらが有効になっているとローカルホストが所属するネットワーク範囲の逆引き問い合わせを行う際、DNSサーバーにクエリを投げなくなるため明示的に無効化しておきます。 |
| LLMNR | |
- systemd-resolved起動
# systemctl start systemd-resolved.service
- 起動確認
# resolvectl status
Global
Protocols: -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
resolv.conf mode: stub
Current DNS Server: 8.8.8.8
DNS Servers: 8.8.8.8 1.1.1.1
DNS Domain: ~.
Link 2 (eth0)
Current Scopes: none
Protocols: -DefaultRoute -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
Link 3 (eth1)
Current Scopes: none
Protocols: -DefaultRoute -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
- NetworkManagerの設定
NetworkManagerのDNSバックエンドを指定するため設定ファイルを追加します。
# echo -e "[main]\ndns=systemd-resolved" > /etc/NetworkManager/conf.d/10-dns.conf
サービスをリロードして設定を反映します。
# systemctl reload NetworkManager.service
- /etc/resolv.confの置換
DNSを使う際、systemd-resolvedの設定を参照させるため/etc/resolv.confをシンボリックリンクに置き換えます。
# ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
ネットワークIFごとのDNS設定
- 構成イメージ
検証環境のeth0をインターネット側に接続。eth1側をイントラネット側に接続しているものとします。
インターネット側のDNSはグローバル設定で指定してあるので、イントラネット側の設定を追加します。
- 設定追加
ネットワークIFごとのDNS設定はsystemd-resolvedの設定ファイルに記述する方法がありません。
NetworkManagerのCLIを使ってイントラネットに繋がっているeth1にDNS設定を追加します。
# nmcli connection modify eth1 ipv4.dns 192.168.1.101 ipv4.dns-search intra.example.jp
IFをupして設定を反映します。
# nmcli connection up eth1
systemd-resolvedに設定が反映されているか確認しておきましょう。
# resolvectl status eth1
Link 3 (eth1)
Current Scopes: DNS
Protocols: +DefaultRoute -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
DNS Servers: 192.168.1.101
DNS Domain: intra.example.jp
動作確認
期待通りの動作になるか確認します。
- ログレベル変更
systemd-resolvedのログレベルを「debug」に変更して詳細なログを出力させます。
# resolvectl log-level debug
- ログ抽出準備
DNS問い合わせ時にどのサーバーにクエリを投げたか確認するため、ログ抽出コマンドをバックグラウンド実行します。
# journalctl -f -u systemd-resolved.service |grep "Using DNS server" &
- 名前解決テスト
まずはgmail.comのレコードを取得してみます。
ここではコマンドの実行結果とログを分かりやすく色分けして記載します。
# resolvectl query gmail.com
gmail.com: 2404:6800:400a:1000::11 -- link: eth0
2404:6800:400a:1000::13 -- link: eth0
2404:6800:400a:1000::12 -- link: eth0
2404:6800:400a:1000::53 -- link: eth0
172.217.209.18 -- link: eth0
172.217.209.17 -- link: eth0
172.217.209.83 -- link: eth0
172.217.209.19 -- link: eth0
-- Information acquired via protocol DNS in 48.9ms.
-- Data is authenticated: no; Data was acquired via local or encrypted transport: no
-- Data from: network
# May 24 18:48:31 localhost systemd-resolved[764]: Using DNS server 8.8.8.8 for transaction 27750.
May 24 18:48:31 localhost systemd-resolved[764]: Using DNS server 8.8.8.8 for transaction 58507.
名前解決出来たこと、レコード取得の際8.8.8.8に問い合わせたことが確認出来ました。
クエリを2回投げているのは、AレコードとAAAAレコードを取得するためです。
続いて192.168.1.101のレコードを取得してみます。
# resolvectl query 192.168.1.101 192.168.1.101: dns.intra.example.jp -- link: eth1 -- Information acquired via protocol DNS in 2.9ms. -- Data is authenticated: no; Data was acquired via local or encrypted transport: no -- Data from: network # May 24 19:00:41 localhost systemd-resolved[764]: Using DNS server 8.8.8.8 for transaction 43918. May 24 19:00:41 localhost systemd-resolved[764]: Using DNS server 192.168.1.101 for transaction 61957.
名前解決は出来たもののグローバル設定のDNS(8.8.8.8)にもクエリを投げています。
検索ドメインにマッチする設定が無かったため、すべてのDNSサーバーに問い合わせを行った形になりました。
出来れば余計なクエリを飛ばしたくないのでeth1に検索ドメインを追加します。
# nmcli connection modify eth1 +ipv4.dns-search 1.168.192.in-addr.arpa # nmcli connection up eth1
eth1の設定はこのようになりました。
# resolvectl status eth1
Link 3 (eth1)
Current Scopes: DNS
Protocols: +DefaultRoute -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
DNS Servers: 192.168.1.101
DNS Domain: 1.168.192.in-addr.arpa intra.example.jp
テストの前に一旦DNSのキャッシュを削除します。
# resolvectl flush-caches
再度192.168.1.101のレコードを取得してみます。
# resolvectl query 192.168.1.101 192.168.1.101: dns.intra.example.jp -- link: eth1 -- Information acquired via protocol DNS in 5.1ms. -- Data is authenticated: no; Data was acquired via local or encrypted transport: no -- Data from: network # May 24 19:32:03 localhost systemd-resolved[764]: Using DNS server 192.168.1.101 for transaction 29678.
非公開DNSサーバー(192.168.1.101)のみにクエリを投げていることが確認出来ました。
正引き問い合わせも同様にイントラ側で名前解決が行われることを確認します。
# resolvectl query dns.intra.example.jp dns.intra.example.jp: 192.168.1.101 -- link: eth1 -- Information acquired via protocol DNS in 6.5ms. -- Data is authenticated: no; Data was acquired via local or encrypted transport: no -- Data from: network # May 24 19:44:22 localhost systemd-resolved[764]: Using DNS server 192.168.1.101 for transaction 65502. May 24 19:44:22 localhost systemd-resolved[764]: Using DNS server 192.168.1.101 for transaction 45286.
- 後片付け
テストが終わったのでログレベルをinfoに戻し、ログの抽出を止めます。
# resolvectl log-level info # jobs -p |xargs kill [1]+ Done journalctl -f -u systemd-resolved.service | grep --color=auto "Using DNS server"
最後に
systemd-resolvedを使うことでネットワークIF単位でDNSの設定を行う事が出来、クエリを振り分けられることが分かりました。
しかし、リンクごとのDNSを使うにはNetworkManager側で設定を行う必要があって、一元的に管理出来ない部分に少し不満もあります。
また、このマニュアルに書いてあるDNSのルーティングルール。これが肝なのにすごく分かりにくい。もう少し読みやすくまとめられなかったものか。
