dns
PowerDNS
PowerDNS-Admin

久しぶりにPowerDNSをさわる

More than 1 year has passed since last update.

どーも、hondam です。

なんでこのネタにしたかっていうと(ネタを考える時間が1日しかなかったのでやっつけなんて言えない)、最近よく社内でBIND祭があるのと、過去(3年前)に自分が書いた「[DNS] PowerDNSとAtomia DNSを使ってみる」という投稿が意外?と読まれているようなので、そういえば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のインストールマニュアルは公式に用意されていますが、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に記載がありましたので載せておきます。

Atomia DNSも更新はあるようですね。


PowerDNSのAPIを利用するタイプ

名称
使用言語
更新履歴

nsedit
PHP/JS
Active

PowerDNS-Admin
Python/JS
Active

PowerDNS-Shell-Wrapper
(API based command-line tool)
Shell/Curl/JQ
Active

pdnscontrol
Python/JS
Latest Commit 2016-03-30

yapdnsui
express.js
Latest Commit 2016-02-12

PoweREST
React.js
Latest Commit 2015-05-31

powr
AngularJS
Latest Commit 2015-02-15


SQLを利用するタイプ

名称
使用言語
更新履歴

django-powerdns-manager
Django
Active, Work in progress

DnsShop
PHP/JS
Active, code is since 2011 in production

NicTool
Perl
Active

PDNS Manager
PHP
Active

Poweradmin
PHP
Active

atomiadns
JS
Active

PowerDNS on Rails
Ruby on Rails
Last Commit 2015-09-30

pdns-gui
PHP
Last Commit 2014-11-18, but apparently in active use

freshdns
PHP, AJAX
Last Commit 2014-06-13

Powerdns Tango
Perl
Last Commit 2014-05-21

JPower Admin
Java
Last Release 2014-02-12

pdnsui
Ramaze
Last Commit 2014-01-09

ZoneAdmin
PHP
Last Release 2013-10-07

GNUPanel
PHP
Last Release 2013-07-20

phpDNSAdmin
PHP
Last Release 2013-05-16

powerdns-webinterface
PHP
Last Commit 2013-05-14

PowerDNS Administration
PHP
Last Release 2013-03-22

DNS Master
PHP, jQuery
Released 2012-10-09

MoxieDNS
???
demo-url & project dead? (2012-05-15)

GOsa²
PHP
Last Release 2012-05-09

PDNSOps
PHP
Last Commit 2012-02-12

pdns-ror-admin
Ruby on Rails
First/Last Commit in 2007-06-01

TUPA
PHP, AJAX
Last Release 2006-03-16

djdns
Django
Last Commit in 2009

pdns-tools
Python
Last Commit in 2009

pdnsfront
PHP
Last Commit in 2008

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


PowerDNS-Admin

今回チョイスしたのは 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を使用しています。

# 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

ダッシュボード画面

スクリーンショット 2016-11-30 15.53.01.png

レコード編集画面

スクリーンショット 2016-11-30 16.17.19.png

ということで無事PowerDNS-Adminが起動できました。

最初にテストで登録したゾーン情報が閲覧・変更できますね。

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


:notebook: 久しぶりにさわったPowerDNSまとめ


  • 祭りは少ない(ただあまり使われてないという見方も)。BINDに疲れたら。

  • PowerDNSのインストールは簡単(バックエンドをDBにすると多少運用が面倒)

  • いつのまにかREST APIが使えるようになってたので夢は広がりそう

  • Atomia DNS以外にイケてそうなUIの管理ツールも誕生してる

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