#author("2019-04-28T23:30:33+09:00","default:nowsky","nowsky")
#author("2021-02-06T18:05:37+09:00","default:nowsky","nowsky")
*dnsdist [#n2d45d2d]
DNSに特化したリバース・フォワード兼用ロードバランサー。
バックエンド死活監視、ポリシールーティング、QoS制御などのLSLBが備える機能を実装している。
設定ファイルはLua言語で記述するので、環境に合わせてスクリプト主体の細かい制御も出来る。
DNSクエリ処理に限定すると、dnsdistはクエリ・フォワード動作に特化している為、
バックエンドに権威DNS・キャッシュDNSなどを構築する必要がある。
 
アプリケーションは単一バイナリ動作なので、機能を盛り過ぎるとバイナリが70MB程まで大きくなる。
必要な機能を抜粋して自前でソースビルドを行うと、バイナリ容量と使用メモリ容量の削減が出来る。
~
*参考サイト [#ma8ed405]
-[[powerdns+dnsdistの構築:+http://kyudy.hatenablog.com/entry/2016/12/27/193928]]
-[[自宅環境にdnsdist 1.1.0を導入してみた。:+https://kometchtech.blog.fc2.com/blog-entry-2049.html]]
~
*インストール [#x03f304c]
-&size(16){&font(b){1. ソースビルド};};
ソースビルドだと様々なディストリビューションで動作して汎用性が高いのでソースビルドする。
今回はopenSUSEでビルドを行っているが、CentOS/Debianでも同様の手順でビルド出来る。
下記のビルドオプションはフル機能を有効化している為、不必要な機能を削除するとバイナリが更に軽くなる。
 # zypper install libedit-devel libsodium-devel systemd-devel fstrm-devel protobuf-devel boost-devel re2-devel
 # wget "https://downloads.powerdns.com/releases/dnsdist-1.3.3.tar.bz2"
 # tar jxvf dnsdist-1.3.3.tar.bz2
 # cd dnsdist-1.3.3
 # ./configure --prefix=/usr/local/dnsdist-1.3.3 \
               --enable-dns-over-tls             \
               --enable-dnscrypt                 \
               --enable-fstrm                    \
               --enable-re2                      \
               --enable-systemd                  \
               --with-ebpf                       \
               --with-lua                        \
               --with-net-snmp                   \
               --with-protobuf                   \
               --with-systemd                    \
               --with-systemd-modules-load
 # make
 # make install
 # ln -s /usr/local/dnsdist-1.3.3 /usr/local/dnsdist
 
-&size(16){&font(b){2. 起動準備};};
dnsdist専用ユーザで動作させる為、実行ユーザの作成とサービスファイルの準備を行う。
さらに、今回はDNSクエリログのローカル出力を有効化する為、ログディレクトリ作成、ログローテート設定も実施する。
バージョン1.5以上の環境でsystemd-notifyを使う環境では、ユーザ・グループ指定が出来なくなった。
この制御は、systemdでchroot同等の制御をしている事からエラーメッセージを出力する仕様に変わったため。
エラーを回避するにはユーザ・グループ指定を止めるか、systemd-simpleに変更する必要がある。
--[[dnsdist: don't start as root within a systemd environment:+https://github.com/PowerDNS/pdns/pull/7820]]
:|
#region(&color(#ff0000){ディレクトリ作成};)
 # mkdir /var/log/dnsdist
 # mkdir /usr/local/dnsdist/etc
 # ln -s /usr/local/dnsdist/etc /etc/dnsdist
 # groupadd dnsdist
 # useradd -d /var/log/dnsdist -s /sbin/nologin dnsdist
 # chown dnsdist.dnsdist /var/log/dnsdist
 # cp ${SOURCE}/dnsdistconf.lua /etc/dnsdist/dnsdist.conf.sample
#endregion
#region(&color(#ff0000){サービスファイル};)
- systemd-notify
 # vi /usr/lib/systemd/system/dnsdist.service
 ---
 [Unit]
 Description=dnsdist DNS loadbalancer
 Documentation=https://dnsdist.org/
 After=local-fs.target remote-fs.target network.target
 
 [Install]
 WantedBy=multi-user.target
 
 [Service]
 Type=notify
 Restart=on-failure
 EnvironmentFile=/etc/sysconfig/dnsdist
 ExecStartPre=/usr/local/dnsdist/bin/dnsdist --disable-syslog --check-config $OPTIONS
 ExecStart=/usr/local/dnsdist/bin/dnsdist --disable-syslog --supervised $OPTIONS
 ExecStop=/bin/kill -s QUIT $MAINPID
 ExecReload=/bin/kill -s HUP $MAINPID
 
 ## TUNING
 TasksMax=8192
 LimitNOFILE=65536

- systemd-simple
 # vi /usr/lib/systemd/system/dnsdist.service
 ---
 [Unit]
 Description=dnsdist DNS loadbalancer
 Documentation=https://dnsdist.org/
 After=local-fs.target remote-fs.target network.target
 
 [Install]
 WantedBy=multi-user.target
 
 [Service]
 Type=simple
 Restart=on-failure
 EnvironmentFile=/etc/sysconfig/dnsdist
 ExecStartPre=/usr/local/dnsdist/bin/dnsdist --disable-syslog --check-config $OPTIONS
 ExecStart=/usr/local/dnsdist/bin/dnsdist --disable-syslog --supervised -u $USER -g $GROUP $OPTIONS
 ExecStop=/bin/kill -s QUIT $MAINPID
 ExecReload=/bin/kill -s HUP $MAINPID
 
 ## TUNING
 TasksMax=8192
 LimitNOFILE=65536
#endregion
#region(&color(#ff0000){起動オプション};)
 # vi /etc/sysconfig/dnsdist
 ---
 USER="dnsdist"
 GROUP="dnsdist"
 OPTIONS="-C /etc/dnsdist/dnsdist.conf"
#endregion
#region(&color(#ff0000){ログローテート};)
 # vi /etc/logrotate.d/dnsdist
 ---
 /var/log/dnsdist/dnsdist.log {
     weekly
     compress
     rotate 4
     missingok
     ifempty
     postrotate
         systemctl reload dnsdist > /dev/null
     endscript
 }
#endregion
~
*コンフィグ [#he433c1c]
構築例ではdnsdistのコンフィグを &color(#ff0000){"/etc/dnsdist/dnsdist.conf"}; としている為、
下記コンフィグ例も同じファイルに設定を行う。
dnsdistの設定は単純な為、単にDNSロードバランサーとして稼働させるならば、
「DNSクエリ・クエリタイプ・接続元IPアドレス・パケット制御」の4項目を抑えれば設定出来る。
 
複数のポリシーを組み合わせる時は、MatchingPackets(Selectors)の &color(#ff0000){"AndRule/NotRule/OrRule"}; 条件、
バックエンドのサーバ設定は、Servers/Poolsの &color(#ff0000){"newServer/getServer"}; を利用する。
その他、細かい設定内容は公式ドキュメントの下記3項目を読めば大体判る。
-[[Configuration Reference:+https://dnsdist.org/reference/config.html]]
-[[Loadbalancing and Server Policies:+https://dnsdist.org/guides/serverselection.html]]
-[[Packet Policies:+https://dnsdist.org/rules-actions.html]]
 
#region(&color(#ff0000){単純ロードバランサー};)
 ※ 実際の設定では頭の行番号("01: "など)を消す
 ============================================================================================
 01: -- BACKEND
 02: check01 = "ns1.example.com."
 03: check02 = "ns2.example.com."
 04: newServer({address="10.0.10.1:53", pool="example", checkName=check01, mustResolve=true})
 05: newServer({address="10.0.10.2:53", pool="example", checkName=check02, mustResolve=true})
 06: 
 07: -- LISTEN
 08: addLocal("10.0.0.1:53", {doTCP=true})
 09: 
 10: -- ACL
 11: setACL("0.0.0.0/0")
 12: 
 13: -- RULE
 14: internet = newSuffixMatchNode()
 15: internet:add(newDNSName("example.com."))
 16: 
 17: -- LOG
 18: addAction(AllRule(), LogAction("/var/log/dnsdist/dnsdist.log", false, true, false))
 19: 
 20: -- POLICY
 21: addAction(SuffixMatchNodeRule(internet), PoolAction("example"))
 22: addAction(QTypeRule(dnsdist.TXT),        PoolAction("example"))
 23: addAction(AllRule(),                     RCodeAction(dnsdist.REFUSED))
|LEFT:50|LEFT:250|LEFT:600|c
|CENTER:~LINE|CENTER:~PARAMETER|CENTER:~DESCRIPTION|h
|&color(#2020ff){02行目};|&color(#2020ff){check01};|newServerで設定する監視先DNSサーバのFQDN設定。IPアドレス記述も可能|
|&color(#2020ff){03行目};|&color(#2020ff){check02};|newServerで設定する監視先DNSサーバのFQDN設定。IPアドレス記述も可能|
|&color(#2020ff){04行目};|&color(#2020ff){newServer};|プール名(example)にバックエンド(10.0.10.1:53)を、監視先FQDN(check01)で追加&br;監視先から"NOERROR RCODE"以外が返ってきたらエラー(監視失敗)とする|
|&color(#2020ff){05行目};|&color(#2020ff){newServer};|プール名(example)にバックエンド(10.0.10.2:53)を、監視先FQDN(check02)で追加&br;監視先から"NOERROR RCODE"以外が返ってきたらエラー(監視失敗)とする|
|&color(#2020ff){08行目};|&color(#2020ff){addLocal};|dnsdistが待受けるUDP用IPアドレス&br;doTCPを設定すると、同IPアドレスでTCP待受けも有効化出来る|
|&color(#2020ff){11行目};|&color(#2020ff){setACL};|接続を許可するセグメント&br;setACLで複数記述、addACLで既存のACLに追加設定も出来る|
|&color(#2020ff){14行目};|&color(#2020ff){newSuffixMatchNode};|サフィックス名とインスタンスの定義|
|&color(#2020ff){15行目};|&color(#2020ff){newDNSName};|サフィックス名(internet)に、DNSドメイン名(example.com)を追加定義する|
|&color(#2020ff){18行目};|&color(#2020ff){addAction/LogAction};|dnsdistが処理したDNSクエリログ保存先。addActionの中で必ず最初に設定する&br;パラメータを "false/true/false" にすると見やすい形で保存される|
|&color(#2020ff){21行目};|&color(#2020ff){addAction/SuffixMatchNodeRule};|DNSクエリに "example.com(internetサフィックスで定義)" を含む時、&br;バックエンドの "example" プール(2~5行目で定義)に転送|
|&color(#2020ff){22行目};|&color(#2020ff){addAction/QTypeRule};|DNSクエリタイプが "TXT(dnsdist.TXTで定義)" の時、&br;バックエンドの "example" プール(2~5行目で定義)に転送|
|&color(#2020ff){23行目};|&color(#2020ff){addAction/AllRule};|上段の設定(addAction)で処理されなかったDNSクエリに対して、&br;REFUSED(リクエスト拒否)を返答する。設定の最後に記述する事を強く推奨|
#endregion