Power DNSで権威サーバを構築する

# 概要
NAT64/DNS64の検証をしたい。そのために好きに使えるDNSサーバを立てたい。DNSといえばBIND。 でも、設計が古く複雑とのことで、脆弱性がよく報告されている。「オープンソースソフトウェアで」「比較的メンテナンスされており」「GUIもあるもの」として[Power DNS](https://www.powerdns.com/) を選んだ。

Power DNS は、Version 4.0系から
1. 権威サーバ（Authoritative Server）
2. 名前解決サーバ（Recursive Server）
の二つに分離された。
この記事では権威サーバを構築する。二つ目の記事は以下で用意。

https://qiita.com/Shakapon/items/c460a674f1289924fbd8

# 検証環境
Power DNSはバックエンドにDatabaseを持つ。PostgreSQL/MySQL/SQLite3どれでも利用できる、ハズ。PowerDNSのインストレーションガイドではSQLiteを例に、Power DNS AdminではMySQLをベースにしていた。Power DNS Adminは相当にStepが多く複雑。今回はSQLite3を使用する。

| 種別 | ソフトウェア | バージョン | 備考 |
|:-:|:-:|:-:|:-:|
| OS  | Ubuntu Server  | 20.04.2  |  |
| DNSサーバ | Power DNS | 4.2.1-1build2  | APTでいれる |
| DBサーバ  | SQLite3 | - | APTでいれる|

# PowerDNSの構築
## PowerDNSのインストール
```sh
sudo apt install pdns-server pdns-tools
```

Ubuntuの場合、```systemd-resolved```がUDP/53を使用しているため、PowerDNSを入れた段階では起動に失敗する。サービスを止めておけば動きそうだが、今度は名前解決できず、aptでパッケージを入れられない。ここは気にしない方向で進む。

## Databaseの用意（SQLite3の場合）
### 必要なパッケージのインストール
```sh
sudo apt install pdns-backend-sqlite3 sqlite3 libsqlite3-dev
```

### Database作成
```/usr/share/doc/pdns-backend-sqlite3/schema.sqlite3.sql``` にあるスキーマファイルを流し込んで作成する。

```sh
sudo mkdir /var/lib/powerdns
sudo sqlite3 /var/lib/powerdns/pdns.sqlite3 < /usr/share/doc/pdns-backend-sqlite3/schema.sqlite3.sql
sudo chown -R pdns:pdns /var/lib/powerdns
```
## Databaseの用意（PostgreSQLの場合）
### 必要なパッケージのインストール
```sh
sudo apt install pdns-backend-pgsql postgresql
```
### PostgreSQL ユーザ pdns を作成
```sh
sudo -u postgres createuser -P -s -e pdns
```

| オプション | 意味 |
|:-:|:-:|
|-P| 新しいユーザのパスワードプロンプトを表示 |
|-s| 新しいユーザをスーパーユーザにする|
|-e| サーバに送ったコマンドをエコー表示する |

https://www.postgresql.jp/document/8.2/html/app-createuser.html

パスワードなしでも作れはするが、PowerDNSからアクセスするにはPasswordを設定しないと動いてくれなかった。

### Databaseの作成
```/usr/share/pdns-backend-pgsql/schema/schema.pgsql.sql``` にあるスキーマファイルを流し込んで作成する。

```sh
sudo -u pdns createdb pdns
sudo -u pdns sh -c "psql -U pdns -d pdns -a -f /usr/share/pdns-backend-pgsql/schema/schema.pgsql.sql"
```

## 初期設定の変更（pdns.conf）
利用するデータベースを指定する。オプション設定が結構違う。

```sh
sudo vi /etc/powerdns/pdns.conf
```
### 変更前
```sh
#################################
# launch        Which backends to launch and order to query them in
#
# launch=
```

### 変更後（SQLiteの場合）
```sh
#################################
# launch        Which backends to launch and order to query them in
#
launch=gsqlite3
gsqlite3-database=/var/lib/powerdns/pdns.sqlite3
```

### 変更後（PostgreSQLの場合）
```sh
#################################
# launch        Which backends to launch and order to query them in
#
launch=gpgsql
gpgsql-host=/run/postgresql # 多分不要。ソケット通信を利用している場合のみ
gpgsql-host=127.0.0.1
gpgsql-port=5432
gpgsql-dbname=pdns
gpgsql-user=pdns
gpgsql-password="PostgreSQLにログインする際のパスワード"
```

## サービス開始
UbuntuではDNS Clientとして```systemd-resolved```が動いており、このままだとPower DNSと競合するため停止する。停止すると、そのままではaptできなくなるので注意。

```sh
sudo systemctl stop systemd-resolved
sudo systemctl start pdns.service
```

## 起動確認
うまくいけばこんな感じ。Active の項目が active (running) になってくれる。

```sh
systemctl status pdns
● pdns.service - PowerDNS Authoritative Server
     Loaded: loaded (/lib/systemd/system/pdns.service; enabled; vendor preset: enabled)
     Active: active (running) since Fri 2021-07-23 04:00:18 UTC; 50s ago
       Docs: man:pdns_server(1)
             man:pdns_control(1)
             https://doc.powerdns.com
   Main PID: 4968 (pdns_server)
      Tasks: 10 (limit: 2279)
     Memory: 6.7M
     CGroup: /system.slice/pdns.service
             mq4968 /usr/sbin/pdns_server --guardian=no --daemon=no --disable-syslog --log-timestamp=no --write-pid=no
```

## 正常性確認
[Power DNSのチュートリアル](https://doc.powerdns.com/authoritative/guides/basic-database.html) 通り、```example.com```をネタにレコードを追加

```sh
$ sudo pdnsutil create-zone example.com ns1.example.com
Creating empty zone 'example.com'
Also adding one NS record
$ sudo pdnsutil add-record example.com '' MX '25 mail.example.com'
New rrset:
example.com. 3005 IN MX 25 mail.example.com
$ sudo pdnsutil add-record example.com. www A 192.0.2.1
New rrset:
www.example.com. 3005 IN A 192.0.2.1
```

digコマンドで返ってくれば成功。

```sh
$ dig +short www.example.com @127.0.0.1
192.0.2.1
$ dig +short example.com MX @127.0.0.1
25 mail.example.com.
```

### DB側の確認（SQLiteの場合）
SQLite側でどのようなレコードで登録されたかを確認する。RECORDSテーブルに登録されていく様子が見て取れる。

```sql
$ sudo sqlite3 /var/lib/powerdns/pdns.sqlite3
SQLite version 3.31.1 2020-01-27 19:55:54
Enter ".help" for usage hints.
sqlite> 
sqlite> .schema records
CREATE TABLE records (
  id                    INTEGER PRIMARY KEY,
  domain_id             INTEGER DEFAULT NULL,
  name                  VARCHAR(255) DEFAULT NULL,
  type                  VARCHAR(10) DEFAULT NULL,
  content               VARCHAR(65535) DEFAULT NULL,
  ttl                   INTEGER DEFAULT NULL,
  prio                  INTEGER DEFAULT NULL,
  disabled              BOOLEAN DEFAULT 0,
  ordername             VARCHAR(255),
  auth                  BOOL DEFAULT 1,
  FOREIGN KEY(domain_id) REFERENCES domains(id) ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE INDEX rec_name_index ON records(name);
CREATE INDEX nametype_index ON records(name,type);
CREATE INDEX domain_id ON records(domain_id);
CREATE INDEX orderindex ON records(ordername);
sqlite>
sqlite>
sqlite>
sqlite> select * from records;
1|1|example.com|SOA|ns1.example.com hostmaster.example.com 1 10800 3600 604800 3600|3600|0|0||1
2|1|example.com|NS|ns1.example.com|3600|0|0||1
3|1|example.com|MX|mail.example.com|3600|25|0||1
4|1|www.example.com|A|192.0.2.1|3600|0|0||1
sqlite> .quit
```
***

## RestAPI
いろいろあるが、PowerDNS Adminを使うのが面倒なさそう。PowerDNS Admin は、PowerDNSをRestAPIでもって制御する。PowerDNS Adminは、PowerDNS本体と同じサーバで動作させる想定のため、`api` と `api-key`だけ変更すればひとまずは何とかなる。 `webserver-password`なんてのもあってパスワードも設定できる。ただ、いかなる理由かPowerDNS Admin 側ではAPI 設定でパスワードの入力項目を見つけられなかった。

| パラメータ | デフォルト値 | 設定変更後 | 備考 |
|:-:|:-:|:-:|:-:|
| api  | no（コメントアウト）| yes |  |
| api-key  | 空欄（コメントアウト）| 適当な値を設定 |  |
| webserver-address  | 127.0.0.1（コメントアウト）| - | |
| webserver-port  | 8081（コメントアウト） | - | |

```sh
#################################
# api   Enable/disable the REST API (including HTTP listener)
#
api=yes

#################################
# api-key       Static pre-shared authentication key for access to the REST API
#
api-key=<任意のパスワード>
```

変更後はPower DNS の再起動が必要。

```sh
$ sudo systemctl restart pdns.service
```

### 正常性確認
公式サイトのマニュアルをもと、実際にAPIを叩いてみる。

https://doc.powerdns.com/authoritative/http-api/index.html

```sh
$ curl -H 'X-API-Key: <任意のパスワード>' http://127.0.0.1:8081/api/v1/servers/localhost/zones | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   240  100   240    0     0  15000      0 --:--:-- --:--:-- --:--:-- 16000
[
  {
    "account": "",
    "dnssec": false,
    "edited_serial": 1,
    "id": "example.com.",
    "kind": "Native",
    "last_check": 0,
    "masters": [],
    "name": "example.com.",
    "notified_serial": 0,
    "serial": 1,
    "url": "/api/v1/servers/localhost/zones/example.com."
  }
]
```

Power DNS側の設定はここまで。Rest API を叩くPower DNS Admin側は別の記事。
この記事も長くなりそうなので、別エントリーにする。