#author("2018-11-10T00:03:08+09:00","default:nowsky","nowsky")
#author("2019-01-01T22:08:43+09:00","default:nowsky","nowsky")
*PowerDNS [#xe753079]
バックエンドにMySQL・PostgreSQLなどのデータベースを利用出来る権威DNSサーバ(PowerDNS Authoritative Server)と、
端末からのDNSクエリを中継するキャッシュDNSサーバ(PowerDNS Recursor)の二種類がある。
DNS専用リバースプロキシのdnsdistも組み合わせる事で、
BIND相当の権威DNS・キャッシュDNSの同居DNSサーバを構築する事も出来る。
 
PowerDNSはAPIも用意されており、スクリプトで直にAPIを叩いたり、WebGUIから間接的に操作する事も出来る。
BINDのテキストゾーンファイルを読み込んだりTinyDNSとの連携もでき、他の権威DNSサーバとの親和性も高い。
WebGUIでゾーン編集ができる事から、PowerDNSをHiddenPrimaryにして実クエリは別の権威DNSで処理させる構成が多い。
~
*参考サイト [#rf3adb39]
-[[PowerDNS:+https://www.powerdns.com/]]
-[[PowerDNS 3.1 On Debian 7 (Wheezy):+https://stacksetup.com/DNS/PowerDNSDebian]]
~
*構築環境 [#kd7a873d]
OSはopenSUSEを利用しているがプログラムはソースからビルドしているので、
他ディストリビューションでも同様の手順で構築する事が出来る。
- 共通環境
 OS  :openSUSE Leap 42.3
 PDNS:PowerDNS v4.1.4
 
#region(PowerDNS Authoritative Server)
今回は下記構成のPowerDNSをchrootモードで構築する。
バックエンドにはMySQLを利用するので事前にビルドしておく。
- [[Linux/Source/MySQL]]
 > PDNS Parameter
 user :pdns
 group:pdns
 ---
 > DB Parameter
 database:pdns_zone
 user    :pdns_user
 password:pdns_pass
#endregion
~
*インストール [#b38ee685]
-&size(16){&font(b){1. インストール};};
最近のOSはsystemdを使っている事が多いので、systemdモジュールを有効化する。
また、今回はバックエンドにMySQLを使うのでDBモジュールもビルドする。
luaは使う時が来そうなので一応ビルド。必要なければconfigureオプションから外す。
 # zypper install lua lua-devel systemd systemd-devel
 # zypper install lua53 lua53-devel systemd systemd-devel
 # wget https://downloads.powerdns.com/releases/pdns-4.1.4.tar.bz2
 # tar jxvf pdns-4.1.4.tar.bz2
 # cd pdns-4.1.4
 # ./configure --prefix=/usr/local/powerdns --enable-tools --enable-systemd --with-lua --with-mysql=/usr/local/mysql
 # make
 # make install
 # ln -s /usr/local/powerdns/etc /etc/powerdns
 # cp /etc/powerdns/pdns.conf-dist /etc/powerdns/pdns.conf
 
-&size(16){&font(b){2. コンフィグ作成};};
PowerDNSのコンフィグはテキストで作成する必要がある。
APIはPowerDNS単体では使わないので無効化しておき、APIを利用する外部ツールを使う時に有効化する。
DB接続は別ファイル化して必要に応じてパーミッションを絞っておく。
起動スクリプトについては、ソースコード同梱の物が上手く動かないので自作する。
 
#region(/etc/powerdns/pdns.conf)
 8bit-dns=no                        # 8bitDNSクエリを拒否
 allow-axfr-ips=127.0.0.1,::1       # DNSゾーン転送(AXFR)の許可IP
 # also-notify=                     # DNSゾーンに記載したNSサーバ以外にもゾーン更新(NOTIFY)を送信
                                    # 通常はコメント化するか、パラメータ未設定にする
 any-to-tcp=yes                     # TCPリモート参照に応答させる。DNSリフレクション攻撃の防止になる
 api=no                             # REST APIを無効化
 api-key=API-PASSWORD               # REST APIの事前共有キー
 cache-ttl=60                       # PowerDNSのDNSクエリ応答ローカルキャッシュ
                                    # この値はDNSゾーンのキャッシュとは違うので注意
 chroot=/var/powerdns/chroot        # PowerDNSをchroot動作させる時の起点ディレクトリ
 config-dir=/etc/powerdns           # コンフィグを読み取るディレクトリ
                                    # コンフィグ自体に設定しても読めないので、pdns.serviceにも設定
 
 disable-axfr=no                    # DNSゾーン転送を許可
 disable-syslog=no                  # ログをsyslog出力する。標準出力に出す時はyesに変更
 disable-tcp=no                     # TCPクエリにも応答させる
 dnsupdate=no                       # DNS Update(DynamicDNS)を無効化
 guardian=no                        # GuardianProcess内でのPDNS動作を無効化
                                    # 有効にした方がセキュリティが向上するが、chrootと組み合わせるとハマる
 
 include-dir=/etc/powerdns/extra    # 外部ファイルを保存するディレクトリ
 launch=gmysql                      # PowerDNSのバックエンドプログラム。2台のMySQLを参照させて冗長化も可能
 local-address=0.0.0.0              # PowerDNSでLISTENするIPv4アドレス
 local-ipv6=::                      # PowerDNSでLISTENするIPv6アドレス
 local-port=53                      # Listenする時に利用するポート番号
 
 log-dns-details=no                 # 詳細ログの出力を停止。Yesにするとログ出力が増えてパフォーマンスが下がる
 log-dns-queries=yes                # DNSクエリログを出力。 Yesにするとログ出力が増えてパフォーマンスが下がる
 log-timestamp=yes                  # ログにタイムスタンプを追加
 logging-facility=0                 # 出力ログのsyslog-facility番号。local[0-7]のみ設定可能
 loglevel=6                         # ログ出力レベル。1~3は基本的に使わない。デバッグ時は9を設定
 
 master=yes                         # PowerDNSをマスターとして動作
 slave=yes                          # PowerDNSをスレーブとして動作
 query-local-address=0.0.0.0        # PowerDNS自体が名前解決する時に利用する送信IPv4アドレス
 query-local-address6=::            # PowerDNS自体が名前解決する時に利用する送信IPv6アドレス
 query-logging=no                   # PowerDNS自体が名前解決したログ出力を無効化
 setgid=pdnsd                       # daemon実行グループ
 setuid=pdnsd                       # daemon実行ユーザ
 
 daemon=yes                         # daemonとして動作
 socket-dir=/var/run/powerdns       # PowerDNSのソケットファイルとPIDの保存先
                                    # chroot環境下ではchroot配下の絶体パスを設定
 version-string=unknown             # DNSのバージョン応答。秘匿する為にunknownに設定
 
 webserver=no                       # Webサーバ機能。REST API利用時は有効にする
 webserver-address=127.0.0.1        # WebサーバのLISTEN IPアドレス
 webserver-allow-from=127.0.0.1,::1 # Webサーバにアクセス出来るIPアドレス
 webserver-password=PASSWORD        # Webサーバにアクセスする際のパスワード
 webserver-port=8081                # Webサーバ/REST APIが待受けるポート番号
#endregion
#region(/etc/powerdns/extra/gmysql.conf)
 gmysql-host=localhost
 gmysql-port=3306
 gmysql-dbname=pdns_zone
 gmysql-user=pdns_user
 gmysql-password=pdns_pass
 gmysql-dnssec=no
#endregion
#region(/usr/lib/systemd/system/pdns.service)
 [Unit]
 Description=PowerDNS Authoritative Server
 Documentation=https://doc.powerdns.com/
 Wants=network-online.target
 After=network-online.target mysqld.service mariadb.service rsyslog.service
 
 [Service]
 Type=forking
 ExecStart=/usr/local/powerdns/sbin/pdns_server --config-dir=/etc/powerdns
 ExecStop=/usr/local/powerdns/bin/pdns_control quit
 ExecReload=/usr/local/powerdns/bin/pdns_control reload
 ## OPTION
 Restart=on-failure
 RestartSec=1
 StartLimitInterval=0
 PrivateTmp=true
 PrivateDevices=true
 NoNewPrivileges=true
 ProtectSystem=full
 ProtectHome=true
 
 [Install]
 WantedBy=multi-user.target
#endregion
 
-&size(16){&font(b){3. 起動準備};};
chrootディレクトリの作成、パーミッション設定、DBスキーマの流し込みを行う。
PowerDNSはログ出力をsyslog経由でしか出来ない為、ログを書き出せる様にsyslogサーバの設定も変更する。
ただし、chroot環境下でPowerDNSのログをsyslog出力させるには、
PowerDNSのログを&color(#ff0000){syslog側でフックさせる為に、&font(b){ソケット(ログ出力デバイス)を作成する};};必要がある。
 ・ユーザ作成と起動スクリプト設定
 ---
 # groupadd pdnsd
 # useradd -g pdnsd -s /sbin/nologin -d /var/powerdns pdnsd
 # chmod 644 /usr/lib/systemd/system/pdns.service
 # chown root.root /usr/lib/systemd/system/pdns.service
 # systemctl enable pdns
 
 ・chrootディレクトリ作成
 ---
 # mkdir -p /var/powerdns/chroot
 # mkdir -p /var/powerdns/chroot/dev
 # mkdir -p /var/powerdns/chroot/var/log
 # mkdir -p /var/powerdns/chroot/var/run/pdnsd
 # chmod 755        /var/powerdns/chroot/var/run/pdnsd
 # chown root.pdnsd /var/powerdns/chroot/var/run/pdnsd
 
 # cd /var/powerdns/chroot
 # touch                ./var/log/api
 # chmod -R 755         ./var/log
 # chown -R pdnsd.pdnsd ./var/log
 
 # cd /var/powerdns/chroot/dev
 # mknod -m 644 ./null c 1 3
 # mknod -m 644 ./zero c 1 5
 # mknod -m 644 ./full c 1 7
 # mknod -m 644 ./random c 1 8
 # mknod -m 644 ./urandom c 1 9
 
 ・DBスキーマ登録
 ---
 MariaDB [(none)]> create database pdns_zone;
 MariaDB [(none)]> grant all on pdns_zone.* to pdns_user identified by 'pdns_pass';
 MariaDB [(none)]> flush privileges;
 MariaDB [(none)]> quit
 ---
 # cd ${PDNS_SRC}/modules/gmysqlbackend/
 # mysql -u pdns_user -p pdns_zone < schema.mysql.sql
 
 ・rsyslog設定変更
 ---
 # vi /etc/rsyslog.conf
 ---
 ## PowerDNS chroot log device
 $AddUnixListenSocket    /var/powerdns/chroot/dev/log
 local0.*                /var/log/powerdns
 & stop
~
*DNSゾーン登録 [#oe42fac7]
バックエンドにMySQLを使っている場合、SQLコマンドでDNSゾーンを流し込むか、
BINDテキスト形式でゾーンを作った後に変換しながらDBに登録する方法がある。
今回はテスト用にDNSゾーンを登録する為、SQLコマンドで登録を行う。
 # vi example.com-sql
 ---
 INSERT INTO domains (name,type) values ('example.com','NATIVE');
 INSERT INTO records (domain_id,name,content,type,ttl,prio) VALUES (1,'example.com','localhost postmaster@example.com 1','SOA',86400,NULL);
 INSERT INTO records (domain_id,name,content,type,ttl,prio) VALUES (1,'example.com','ns1.example.com','NS',86400,NULL);
 INSERT INTO records (domain_id,name,content,type,ttl,prio) VALUES (1,'ns1.example.com','127.0.0.1','A',120,NULL);
 
 # mysql -u pdns_user -p pdns_zone < example.com-sql
 # dig @127.0.0.1 ns1.example.com
~
*起動テスト [#e739e825]
起動テストを行う場合、『pdns_server』コマンドをそのまま実行するとログが出てくる。
コンフィグを書き換えれば、ログを標準出力にしながらdaemon起動させる事も出来る。
 ・起動
 ---
 systemctl start pdns
 
 ・停止
 ---
 systemctl stop pdns
 
 ・リロード
 ---
 systemctl reload pdns
 
PowerDNSに登録したゾーン情報の書式確認を行う場合、チェックユーティリティを利用する。
セカンダリサーバへのゾーン転送が出来ない時は、書式間違いが多いので都度確認すること。
 # /usr/local/powerdns/bin/pdnsutil check-all-zones
 ---
 Nov 09 23:32:41 Reading random entropy from '/dev/urandom'
 Checked 3 records of 'example.com', 0 errors, 0 warnings.
 Checked 1 zones, 0 had errors.
~
*PDNS Manager [#m5c0f702]
PowerDNSをGUIで操作するフロントWebアプリケーション。
PHPで出来ているので、LAMPを構築してあれば大抵の環境で動作する。
&color(#ff0000){アプリの構造上、&font(b){サブディレクトリを掘ってPDNS Managerを動かす事が出来ない};};ので、
他にもWebアプリを動かしている環境下では、VirtualHostで別FQDNにホスティングする必要がある。
 
なお、PowerDNSのバックエンドDBをPDNS Manager用に作り直す必要があるので注意。
頑張れば、DB設定を直書きしたり個別にInsertすれば既存DBでも動くが説明は割愛。
- [[PDNS Manager:+https://pdnsmanager.org/]]
 
#region(インストール)
 # wget https://dl.pdnsmanager.org/pdnsmanager-2.0.1.tar.gz
 # tar zxvf pdnsmanager-2.0.1.tar.gz
 # mv pdnsmanager-2.0.1 /var/www/pdnsmanager
 # chown -R root.www    /var/www/pdnsmanager
 # chmod -R g-w,o-rwx   /var/www/pdnsmanager
 # chown www.www        /var/www/pdnsmanager/backend/config
#endregion
#region(VirtualHost設定)
 Listen 10080
 <VirtualHost *:10080>
     ServerAdmin  postmaster@localhost
     ServerName   pdnsmanager.example.com
     DocumentRoot /var/www/pdnsmanager/frontend
 
     RewriteEngine On
     RewriteRule ^index\.html$ - [L]
     RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
     RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d
     RewriteRule !^/api/\.* /index.html [L]
 
     <Directory /var/www/pdnsmanager/frontend>
         Require all granted
     </Directory>
 
     Alias /api /var/www/pdnsmanager/backend/public
     <Directory /var/www/pdnsmanager/backend/public>
         Require all granted
         RewriteEngine On
         RewriteCond %{REQUEST_FILENAME} !-f
         RewriteCond %{REQUEST_FILENAME} !-d
         RewriteRule ^ index.php [QSA,L]
     </Directory>
 </VirtualHost>
#endregion
#region(データベース再生成)
DBにDNSゾーン情報が登録されていると、PDNS Managerからスキーマを流し込め無くなる。
そんな時はデータベースを別名で作成して、PowerDNSとPDNS ManagerのDB設定を切り替えるか、
既存のデータベースを一度削除した上で再登録を行う。
 MariaDB [(none)]> drop database pdns_zone;
 MariaDB [(none)]> create database pdns_zone;
 MariaDB [(none)]> quit
#endregion
#region(データベース登録)
今回設定したFQDNを用いて、
Webブラウザで『h++p://pdnsmanager.example.com:10080/setup』を開く
細かい設定内容は[[公式ドキュメント:+https://pdnsmanager.org/quickstart/]]を確認しつつ設定する事。
 
#ref(Linux/Source/PowerDNS/wiki_powerdns_01.png,70%,left,nowrap)
#endregion