久しぶりにPowerDNSをさわる

どーも、hondam です。

なんでこのネタにしたかっていうと(~~ネタを考える時間が1日しかなかったのでやっつけなんて言えない~~)、最近よく社内でBIND祭があるのと、過去(3年前)に自分が書いた「[[DNS] PowerDNSとAtomia DNSを使ってみる](http://qiita.com/hondam/items/65b29e069b9f0d5238a8)」という投稿が意外？と読まれているようなので、そういえばPowerDNSって最近どうしてるんだろう、息してるのかな？と思ったからです。

# :repeat:  PowerDNSおさらい
PowerDNSはGPLライセンスのC++で実装されたDNSサーバです。ほとんどのUNIXライクなOS上で動作します。PowerDNSはシンプルなBINDスタイルのゾーンファイルからRDBMSやロードバランシング／フェイルオーバーアルゴリズムまで多岐に渡る特徴があります。別プログラムとしてDNS recursorも含みます。

PowerDNSはオランダの企業PowerDNS.COM BVとオープンソースコミュニからの多くの貢献によって生み出されました。著名なデベロッパはBer Hubert氏です。

# :date:  2013年からのバージョンアップ
3年前に使ってたバージョンはAuthoritative Serverの3.2です。そこからのバージョンアップ履歴ですが、SAやCVEでのアップデートがBINDと比べると断然少ないですね。あまり使われてない？という見方もありますが...祭りは少ない。

* 4.0.1 2016年7月29日 CVE-2016-6172.
* 4.0.0 2016年7月11日 ... ALIASレコード対応
* 3.4.9 2016年5月17日
* 3.4.8 2016年2月3日 
* 3.4.7 2015年11月3日 Security Advisory 2015-03
* 3.4.6 2015年8月28日 Security Advisory 2015-02
* 3.4.5 2015年6月9日 Security Advisory 2015-01
* 3.4.4 2015年4月23日 Security Advisory 2015-01
* 3.4.3 2015年3月2日
* 3.4.2 2015年2月3日
* 3.4.1 2014年10月30日
* 3.4.0 2014年9月30日 ... REST API対応
* 3.3.1 2013年12月17日
* 3.3 2013年7月5日

# :pencil:  とりあえずインストール
インストールする環境は以下となります。たまには他のサービスを使ってみようかなということで某VPS(の月900円くらいの)にしました。

```
# cat /etc/redhat-release
CentOS Linux release 7.2.1511 (Core)

# cat /proc/version
Linux version 3.10.0-327.10.1.el7.x86_64 (builder@kbuilder.dev.centos.org) (gcc version 4.8.3 20140911 (Red Hat 4.8.3-9) (GCC) ) #1 SMP Tue Feb 16 17:03:50 UTC 2016
```

ではインストール。バックエンドDBはとりあえずMySQLでいきます。
PowerDNSの[インストールマニュアル](https://doc.powerdns.com/md/authoritative/installation/)は公式に用意されていますが、DBのインストール方法までは記載されていません。

```
# yum install mariadb mariadb-server

〜中略〜

インストール:
  mariadb.x86_64 1:5.5.50-1.el7_2
  mariadb-server.x86_64 1:5.5.50-1.el7_2

完了しました!
```

必要あれば `/etc/my.cnf` など修正してください。

```
# vi /etc/my.cnf
[mysqld]
character-set-server=utf8 # 追加するとか
```

systemctlでMySQLを有効にしておきます。

```
# systemctl list-unit-files --type=service | grep mariadb
mariadb.service                             disabled
# systemctl enable mariadb.service
# systemctl start mariadb.service

# ps xa | grep mysql
19272 ?        Ss     0:00 /bin/sh /usr/bin/mysqld_safe --basedir=/usr
19441 ?        Sl     0:00 /usr/libexec/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --log-error=/var/log/mariadb/mariadb.log --pid-file=/var/run/mariadb/mariadb.pid --socket=/var/lib/mysql/mysql.sock
```

インストールの仕上げに `mysql_secure_installation` を実行しておきます。
このコマンドはrootユーザのパスワード変更や、anonymousユーザーの削除などを行うものなので、特に実行しなくてもOKです。実行した場合は適宜設定してください。

```
# mysql_secure_installation
OTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB
      SERVERS IN PRODUCTION USE!  PLEASE READ EACH STEP CAREFULLY!

In order to log into MariaDB to secure it, we'll need the current
password for the root user.  If you've just installed MariaDB, and
you haven't set the root password yet, the password will be blank,
so you should just press enter here.

Enter current password for root (enter for none):

〜中略〜

All done!  If you've completed all of the above steps, your MariaDB
installation should now be secure.

Thanks for using MariaDB!
```

`mysql_secure_installation`でrootユーザのパスワードを変更したので、接続可能か確認します。

```
# mysql -u root -p
Enter password:
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 11
Server version: 5.5.50-MariaDB MariaDB Server

Copyright (c) 2000, 2016, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]>
```

OKですね。ではこの段階でPowerDNS用のデータベースとテーブルを作成しておきましょ。
まずはデータベースを作成します。ここでは `pdns` とします。

```
# mysql -u root -p  -e "CREATE DATABASE pdns CHARACTER SET utf8;"
```

次にPowerDNS用のテーブルを作成します。

```
# vi pdns_tables.sql
CREATE TABLE domains (
  id                    INT AUTO_INCREMENT,
  name                  VARCHAR(255) NOT NULL,
  master                VARCHAR(128) DEFAULT NULL,
  last_check            INT DEFAULT NULL,
  type                  VARCHAR(6) NOT NULL,
  notified_serial       INT DEFAULT NULL,
  account               VARCHAR(40) DEFAULT NULL,
  PRIMARY KEY (id)
) Engine=InnoDB;

CREATE UNIQUE INDEX name_index ON domains(name);


CREATE TABLE records (
  id                    INT AUTO_INCREMENT,
  domain_id             INT DEFAULT NULL,
  name                  VARCHAR(255) DEFAULT NULL,
  type                  VARCHAR(10) DEFAULT NULL,
  content               VARCHAR(64000) DEFAULT NULL,
  ttl                   INT DEFAULT NULL,
  prio                  INT DEFAULT NULL,
  change_date           INT DEFAULT NULL,
  disabled              TINYINT(1) DEFAULT 0,
  ordername             VARCHAR(255) BINARY DEFAULT NULL,
  auth                  TINYINT(1) DEFAULT 1,
  PRIMARY KEY (id)
) Engine=InnoDB;

CREATE INDEX nametype_index ON records(name,type);
CREATE INDEX domain_id ON records(domain_id);
CREATE INDEX recordorder ON records (domain_id, ordername);


CREATE TABLE supermasters (
  ip                    VARCHAR(64) NOT NULL,
  nameserver            VARCHAR(255) NOT NULL,
  account               VARCHAR(40) NOT NULL,
  PRIMARY KEY (ip, nameserver)
) Engine=InnoDB;


CREATE TABLE comments (
  id                    INT AUTO_INCREMENT,
  domain_id             INT NOT NULL,
  name                  VARCHAR(255) NOT NULL,
  type                  VARCHAR(10) NOT NULL,
  modified_at           INT NOT NULL,
  account               VARCHAR(40) NOT NULL,
  comment               VARCHAR(64000) NOT NULL,
  PRIMARY KEY (id)
) Engine=InnoDB;

CREATE INDEX comments_domain_id_idx ON comments (domain_id);
CREATE INDEX comments_name_type_idx ON comments (name, type);
CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);


CREATE TABLE domainmetadata (
  id                    INT AUTO_INCREMENT,
  domain_id             INT NOT NULL,
  kind                  VARCHAR(32),
  content               TEXT,
  PRIMARY KEY (id)
) Engine=InnoDB;

CREATE INDEX domainmetadata_idx ON domainmetadata (domain_id, kind);


CREATE TABLE cryptokeys (
  id                    INT AUTO_INCREMENT,
  domain_id             INT NOT NULL,
  flags                 INT NOT NULL,
  active                BOOL,
  content               TEXT,
  PRIMARY KEY(id)
) Engine=InnoDB;

CREATE INDEX domainidindex ON cryptokeys(domain_id);


CREATE TABLE tsigkeys (
  id                    INT AUTO_INCREMENT,
  name                  VARCHAR(255),
  algorithm             VARCHAR(50),
  secret                VARCHAR(255),
  PRIMARY KEY (id)
) Engine=InnoDB;

CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm);
```

先ほど作成した`pdns`データベースにインポートします。

```
# mysql -u root -p -D pdns < pdns_tables.sql
```

これでMySQLの準備はOKですね。
では次にPowerDNSをインストールします。

```
# yum info pdns
読み込んだプラグイン:fastestmirror, langpacks
Loading mirror speeds from cached hostfile
 * base: ftp.iij.ad.jp
 * epel: ftp.riken.jp
 * epel-debuginfo: ftp.riken.jp
 * epel-source: ftp.riken.jp
 * extras: ftp.iij.ad.jp
 * updates: ftp.iij.ad.jp
利用可能なパッケージ
名前                : pdns
アーキテクチャー    : x86_64
バージョン          : 3.4.10
リリース            : 1.el7
容量                : 2.1 M
リポジトリー        : epel/x86_64
要約                : A modern, advanced and high performance authoritative-only nameserver
URL                 : http://powerdns.com
ライセンス          : GPLv2
説明                : The PowerDNS Nameserver is a modern, advanced and high performance
                    : authoritative-only nameserver. It is written from scratch and conforms
                    : to all relevant DNS standards documents.
                    : Furthermore, PowerDNS interfaces with almost any database.
```

3年前のバージョンは3.2でしたが、3.4.10になっているようです。

```
# yum install pdns pdns-backend-mysql

〜中略〜

インストール:
  pdns.x86_64 0:3.4.10-1.el7
  pdns-backend-mysql.x86_64 0:3.4.10-1.el7

完了しました!
```

次に `pdns.conf` を修正します。
デフォルトではMySQLを使うようになっていません。

```
# egrep -v '^\s*(#|$)' /etc/pdns/pdns.conf
setuid=pdns
setgid=pdns
launch=bind
```

MySQLのユーザやパスワードは適宜変更してください。ここではrootで設定しています。

```
# vi /etc/pdns/pdns.conf
setuid=pdns
setgid=pdns
launch=gmysql
gmysql-host=127.0.0.1
gmysql-user=root
gmysql-dbname=pdns
gmysql-password=[設定したパスワード]
```

```
# systemctl list-unit-files --type=service | grep pdns
pdns.service                             disabled
# systemctl enable pdns.service
# systemctl start pdns.service
```

ちなみに `pdns.service` の中身はこんな感じですね。

```
# cat /etc/systemd/system/multi-user.target.wants/pdns.service
[Unit]
Description=PowerDNS Authoritative Server
Wants=network-online.target
After=network-online.target mariadb.service postgresql.service slapd.service

[Service]
Type=forking
ExecStart=/usr/sbin/pdns_server --daemon
ExecStop=/usr/bin/pdns_control quit
Restart=on-failure
RestartSec=2
PrivateTmp=true

[Install]
WantedBy=multi-user.target
```

ではPowerDNSを起動したところで、名前解決できるかどうか確認してみましょ。

```
# dig +short www.example.com @127.0.0.1
```

当然結果は何も返ってきませんね。
ではテストのゾーン情報を登録してみます。

```
# vi example.com.zone.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 ahu@ds9a.nl 1','SOA',86400,NULL);
INSERT INTO records (domain_id, name, content, type,ttl,prio) VALUES (1,'example.com','dns-us1.powerdns.net','NS',86400,NULL);
INSERT INTO records (domain_id, name, content, type,ttl,prio) VALUES (1,'example.com','dns-eu1.powerdns.net','NS',86400,NULL);
INSERT INTO records (domain_id, name, content, type,ttl,prio) VALUES (1,'www.example.com','192.0.2.10','A',120,NULL);
INSERT INTO records (domain_id, name, content, type,ttl,prio) VALUES (1,'mail.example.com','192.0.2.12','A',120,NULL);
INSERT INTO records (domain_id, name, content, type,ttl,prio) VALUES (1,'localhost.example.com','127.0.0.1','A',120,NULL);
INSERT INTO records (domain_id, name, content, type,ttl,prio) VALUES (1,'example.com','mail.example.com','MX',120,25);

# mysql -u root -p -D pdns < example.com.zone.sql
```

おもむろに再実行すると...

```
# dig +short www.example.com @127.0.0.1
192.0.2.10

# dig +short example.com MX @127.0.0.1
25 mail.example.com.
```

OKですね。これでひとまずMySQLを使ってPowerDNSが動く状況になりました。
3年前の記事ではここからAtomia DNSをインストールしましたが、はたして状況は変わってるでしょうか。

PowerDNS向けのツールは、PowerDNSのAPIを呼び出すものと、SQL実行するものがあります。
以下はその一覧です。GitHubのPowerDNSの[Wiki](https://github.com/PowerDNS/pdns/wiki/WebFrontends)に記載がありましたので載せておきます。
Atomia DNSも更新はあるようですね。

## PowerDNSのAPIを利用するタイプ

| 名称 | 使用言語 | 更新履歴 |
| ------- | -------- | -------|
| [nsedit](https://github.com/tuxis-ie/nsedit) | PHP/JS | Active |
| [PowerDNS-Admin](https://github.com/ngoduykhanh/PowerDNS-Admin) | Python/JS | Active |
| [PowerDNS-Shell-Wrapper](https://github.com/opensource-expert/powerdns-shell-wrapper)<br>(API based command-line tool) | Shell/Curl/JQ | Active |
| [pdnscontrol](https://github.com/PowerDNS/pdnscontrol) | Python/JS | Latest Commit 2016-03-30 |
| [yapdnsui](https://github.com/xbgmsharp/yapdnsui) | express.js | Latest Commit 2016-02-12 |
| [PoweREST](https://github.com/alexdo/powerest) | React.js | Latest Commit 2015-05-31 |
| [powr](https://github.com/porjo/powr) | AngularJS | Latest Commit 2015-02-15 |

## SQLを利用するタイプ

| 名称 | 使用言語 | 更新履歴 |
| ------- | -------- | -------|
| [django-powerdns-manager](http://pypi.python.org/pypi/django-powerdns-manager) | Django | Active, Work in progress |
| [DnsShop](https://github.com/tools4isp/dnsshop/) | PHP/JS | Active, code is since 2011 in production |
| [NicTool](http://www.nictool.com/) | Perl | Active |
| [PDNS Manager](https://pdnsmanager.lmitsystems.de/)| PHP | Active |
| [Poweradmin](https://github.com/poweradmin/poweradmin) | PHP | Active |
| [atomiadns](https://github.com/atomia/atomiadns/tree/develop/webapp) | JS | Active |
| [PowerDNS on Rails](http://kennethkalmer.github.com/powerdns-on-rails/) | Ruby on Rails | Last Commit 2015-09-30 |
| [pdns-gui](http://code.google.com/p/pdns-gui/) | PHP | Last Commit 2014-11-18, but apparently in active use |
| [freshdns](https://github.com/funzoneq/freshdns) | PHP, AJAX | Last Commit 2014-06-13 |
| [Powerdns Tango](https://github.com/averna-syd/PowerdnsTango) | Perl  | Last Commit 2014-05-21 |
| [JPower Admin](http://www.nicmus.com/community.html) | Java | Last Release 2014-02-12 |
| [pdnsui](https://github.com/leucos/pdnsui) | Ramaze | Last Commit 2014-01-09 |
| [ZoneAdmin](http://open.megabit.net/index.php?section=pro_home&project=ZoneAdmin) | PHP | Last Release 2013-10-07 |
| [GNUPanel](http://gnupanel.org/) | PHP | Last Release 2013-07-20 |
| [phpDNSAdmin](http://sourceforge.net/projects/phpdnsadmin/) | PHP | Last Release 2013-05-16 |
| [powerdns-webinterface](http://code.google.com/p/powerdns-webinterface/) | PHP | Last Commit 2013-05-14 |
| [PowerDNS Administration](http://sourceforge.net/projects/powerdnsadmin/) | PHP | Last Release 2013-03-22 |
| [DNS Master](http://sourceforge.net/projects/dmsmaster/) | PHP, jQuery | Released 2012-10-09 |
| [MoxieDNS](http://moxiefoxtrot.com/2009/01/07/powerdns-web-frontend/) | ??? | demo-url & project dead? (2012-05-15) |
| [GOsa²](https://oss.gonicus.de/labs/gosa) | PHP | Last Release 2012-05-09 |
| [PDNSOps](https://code.google.com/p/pdnsops/) | PHP | Last Commit 2012-02-12 |
| [pdns-ror-admin](http://code.google.com/p/pdns-ror-admin/) | Ruby on Rails | First/Last Commit in 2007-06-01 |
| [TUPA](http://tupa-dns.org/) | PHP, AJAX | Last Release 2006-03-16 |
| [djdns](http://code.google.com/p/djdns/) | Django | Last Commit in 2009 |
| [pdns-tools](http://code.google.com/p/pdns-tools/) | Python | Last Commit in 2009 |
| [pdnsfront](http://code.google.com/p/pdnsfront/) | PHP | Last Commit in 2008 |

色々ありますが、息してるのは少ないかな。Atomia DNSは無事なようです。

## PowerDNS-Admin
今回チョイスしたのは [PowerDNS-Admin](https://github.com/ngoduykhanh/PowerDNS-Admin) です。 
単純にGitHubのStarの数と見た目で選びました。

では動くかわかりませんが早速インストールしてみましょう。
`pdns.conf` に以下の設定を追加します。

```
# vi /etc/pdns/pdns.conf
experimental-json-interface=yes
experimental-api-key=[適宜keyを設定してください]
webserver=yes
```

この設定でPowerDNSのREST APIが有効になります。
ではAPIが有効か確認してみましょう。

```
# curl -s -H 'X-API-Key: experimental-api-keyの値' http://127.0.0.1:8081/servers/localhost/zones | jq "."
[
  {
    "id": "example.com.",
    "url": "/servers/localhost/zones/example.com.",
    "name": "example.com",
    "kind": "Native",
    "dnssec": false,
    "account": "",
    "masters": [],
    "serial": 1,
    "notified_serial": 0,
    "last_check": 0
  }
]
```

OKですね。
では次にPowerDNS-Admin用のデータベースを作成します。

```
# mysql -u root -p  -e "CREATE DATABASE powerdnsadmin CHARACTER SET utf8;"
# mysql -u root -p  -e "GRANT ALL PRIVILEGES ON powerdnsadmin.* TO powerdnsadmin@'%' IDENTIFIED BY '適宜設定してください';"
```

ではPowerDNS-Adminを起動します。
起動に伴い、必要なパッケージのインストールと、設定が必要なので行います。
環境によっては既にインストールされているものもあると思いますので、過不足あれば適宜インストールしてください。

PowerDNS-Admin は Pythonのマイクロフレームワーク[Flask](http://flask.pocoo.org/)を使用しています。

```
# python -V
Python 2.7.5
```

```
# yum install python-pip
# yum install mariadb-devel
# yum install gcc

# git clone https://github.com/ngoduykhanh/PowerDNS-Admin.git
# cd PowerDNS-Admin
```

mariadb-devel は MySQL-pythonで必要だったのでインストールしています。
gccはldap関連のモジュールをインストールするのに必要でした。(今回はLDAP認証使ってませんが)

```
# pip install --upgrade pip
# pip install virtualenv
# pip install MySQL-python
```

```
# virtualenv flask
# source ./flask/bin/activate
(flask)# pip install -r requirements.txt
(flask)# cp config_template.py config.py 

(flask)# vi config.py
# DATABASE CONFIG
SQLA_DB_USER = 'powerdnsadmin'
SQLA_DB_PASSWORD = '適宜設定してください'
SQLA_DB_HOST = '127.0.0.1'
SQLA_DB_NAME = 'powerdnsadmin'

# POWERDNS CONFIG
PDNS_STATS_URL = '適宜設定してください'
PDNS_API_KEY = '適宜設定してください'
PDNS_VERSION = '適宜設定してください'
```

config.pyのデフォルトポートが9393だったので、firewall-cmdで9393ポートを開けました。
最後に./run.pyすれば起動されます。

```
(flask)# ./create_db.py
(flask)# firewall-cmd --add-port=9393/tcp --zone=public
(flask)# ./run.py
```

| ログイン画面 |
|---|
| ![スクリーンショット 2016-11-30 15.54.57.png](https://qiita-image-store.s3.amazonaws.com/0/4305/32b5a9b6-c3cc-050b-2b4a-034a63654d6c.png) |

| ダッシュボード画面 |
|---|
| ![スクリーンショット 2016-11-30 15.53.01.png](https://qiita-image-store.s3.amazonaws.com/0/4305/c74785b4-0d00-c34e-29fd-21e5cc5e66a9.png) |

| レコード編集画面 |
|---|
| ![スクリーンショット 2016-11-30 16.17.19.png](https://qiita-image-store.s3.amazonaws.com/0/4305/be1b4cab-e62d-37c5-2fb2-8a5089641d37.png) |

ということで無事PowerDNS-Adminが起動できました。
最初にテストで登録したゾーン情報が閲覧・変更できますね。

まともに権威DNSとして利用するにはもっとちゃんとした設定やSlaveも必要ですが、簡単そうなのは伝わったかと思います。

# :notebook:  久しぶりにさわったPowerDNSまとめ
* 祭りは少ない(ただあまり使われてないという見方も)。BINDに疲れたら。
* PowerDNSのインストールは簡単(バックエンドをDBにすると多少運用が面倒)
* いつのまにかREST APIが使えるようになってたので夢は広がりそう
* Atomia DNS以外にイケてそうなUIの管理ツールも誕生してる

ということで12月1日担当の hondam でした。