使用 PowerDNS 构建权威 DNS 服务器

Posted by

on

前言

自从构建网络以来,为了图一时的方便,我一直在使用 Microsoft DNS Server 作为自己网域的权威 DNS 服务器。现在是时候抛弃专有软件,尝试一下朋友们都在用的 PowerDNS 了。

还有一件事就是,我打算对老核心网络节点(设在老家)去核心化,并把最重要的服务逐渐搬上云。

[alert]本文为操作笔记,并非教程。[/alert]

为什么

上云成本降低了,云端的稳定性相对比自有设备高很多,也不受浮动网络的影响。我于今年 7 月一下子购入了 5 年的 Aliyun 作为核心控制节点 —— 没错,核心业务都跑在一台机器上。

这时,有一个朋友(?)前来吐槽 —— “你为什么不用 Docker?” 或 “这样很容易发生单点故障!” 等等。

对于个人业务,在有限的资源环境下,现阶段我倾向于化繁为简。直接使用 systemd 来管理各业务,使用符号链接将配置文件集中管理,使用脚本记录部署过程以方便后续迁移。对于个人业务而言,这些足够了。相反使用 Docker 会消耗更多内存,对于区区 2 GB 内存的突发性能实例,实在是有点压力。最近看到群友相继入教 NixOS,我也略有兴趣,不过眼下咱还是继续留在 Debian 教派。

过程

现时我正在使用 Ubuntu 20.04 LTS。我选择使用 “PowerDNS Authoritative Server – master branch”。

1. 新建 “/etc/apt/sources.list.d/pdns.list”:

 deb [arch=amd64] http://repo.powerdns.com/ubuntu focal-auth-master main

2. 新建 “/etc/apt/preferences.d/pdns”:

Package: pdns-*
Pin: origin repo.powerdns.com
Pin-Priority: 600

3. 安装:

curl https://repo.powerdns.com/CBC8B383-pub.asc | sudo apt-key add - &&
sudo apt update &&
sudo apt install pdns-server

4. 使用 MySQL 作为后端,新增 “/etc/powerdns/pdns.d/mysql.conf”:

# MySQL Configuration
# Launch gmysql backend
launch+=gmysql
# gmysql parameters
gmysql-host=localhost
gmysql-port=3306
gmysql-dbname=powerdns
gmysql-user=powerdns
gmysql-password=Str0ngPasswOrd
gmysql-dnssec=yes
# gmysql-socket=

5. 初始化数据库内容,这里的 Schema 节选自文档 “Generic MySQL backend“,适配 4.3(或更高?)。内容来自 ( /usr/share/pdns-backend-mysql/schema/schema.mysql.sql) 注意不同版本的文件可能不同。也可以使用 mysql 直接导入:

 mysql -u pdnsadmin -p pdns < /usr/share/pdns-backend-mysql/schema/schema.mysql.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 UNSIGNED DEFAULT NULL,
account VARCHAR(40) CHARACTER SET 'utf8' DEFAULT NULL,
PRIMARY KEY (id)
) Engine=InnoDB CHARACTER SET 'latin1';

CREATE UNIQUE INDEX name_index ON domains(name);

CREATE TABLE records (
id BIGINT 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,
disabled TINYINT(1) DEFAULT 0,
ordername VARCHAR(255) BINARY DEFAULT NULL,
auth TINYINT(1) DEFAULT 1,
PRIMARY KEY (id)
) Engine=InnoDB CHARACTER SET 'latin1';

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

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

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) CHARACTER SET 'utf8' DEFAULT NULL,
comment TEXT CHARACTER SET 'utf8' NOT NULL,
PRIMARY KEY (id)
) Engine=InnoDB CHARACTER SET 'latin1';

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 CHARACTER SET 'latin1';

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,
published BOOL DEFAULT 1,
content TEXT,
PRIMARY KEY(id)
) Engine=InnoDB CHARACTER SET 'latin1';

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 CHARACTER SET 'latin1';

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

6. 安装 PowerDNS Admin 以简化管理。

git clone https://github.com/ngoduykhanh/PowerDNS-Admin.git /opt/web/powerdns-admin
sudo apt install python3.8-venv
sudo apt install -y libmysqlclient-dev libsasl2-dev libldap2-dev libssl-dev libxml2-dev libxslt1-dev libxmlsec1-dev libffi-dev pkg-config apt-transport-https virtualenv build-essential
cd powerdns-admin
python3 -mvenv ./venv
source ./venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt
npm install -g yarn
yarn install --pure-lockfile
export FLASK_APP=powerdnsadmin/__init__.py
flask assets build

7. 设置 PowerDNS 专用数据库及用户。更改 “./powerdnsadmin/default_config.py”。最后进行 DB 迁移。

flask db upgrade
deactivate

8. 设置 Gunicorn, systemd 服务及配置 Nginx 反向代理。

新建 “/etc/systemd/system/powerdns-admin.service”

[Unit]
Description=PowerDNS-Admin
Requires=powerdns-admin.socket
After=network.target

[Service]
PIDFile=/run/powerdns-admin/pid
User=www-data
Group=www-data
WorkingDirectory=/iedon/powerdns-admin
ExecStart=/iedon/powerdns-admin/venv/bin/gunicorn --pid /run/powerdns-admin/pid --bind unix:/run/powerdns-admin/socket 'powerdnsadmin:create_app()'
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target

新建 “/etc/systemd/system/powerdns-admin.socket”

[Unit]
Description=PowerDNS-Admin socket

[Socket]
ListenStream=/run/powerdns-admin/socket

[Install]
WantedBy=sockets.target

新建 “/etc/tmpfiles.d/powerdns-admin.conf”,设置相应目录权限,启动并设置相关服务自启。

d /run/powerdns-admin 0755 www-data www-data -
sudo mkdir /run/powerdns-admin/
sudo chown -R www-data: /run/powerdns-admin/
sudo chown -R www-data:www-data /iedon/powerdns-admin/powerdnsadmin/static
sudo systemctl daemon-reload
sudo systemctl start powerdns-admin.socket
sudo systemctl enable powerdns-admin.socket
sudo systemctl enable powerdns-admin.service

Nginx 反向代理关键配置段:

location / {
    proxy_pass http://unix:/run/powerdns-admin/socket;
}

9. 在 PowerDNS Admin 中创建新用户(第一个用户将作为管理用户),并进行后续设置。最终我们可以得到类似于下图的效果:

PowerDNS Admin

10. 在搬运旧配置并适当更新后,我重启了 3 个 anycast 节点(BIND, 它们通过 AXFR 与主 DNS Server 联系以获得区域拷贝),在观察到区域传递正常后,我终于得以为老 DNS Server 按下停止的红色按钮:

stop old ms dns

验证

使用 Dig 来验证配置是否正确。我们通过查询全网递归服务器来检视结果是否符合预期。

dig @172.23.0.53 lg.iedon.xxxx

; <<>> DiG 9.16.1-Ubuntu <<>> @172.23.0.53 lg.iedon.xxxx
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10964
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;lg.iedon.xxxx.                 IN      A

;; ANSWER SECTION:
lg.iedon.xxxx.          475     IN      CNAME   anycast-services.iedon.xxxx.
anycast-services.iedon.xxxx. 475 IN     A       172.23.91.1

;; Query time: 240 msec
;; SERVER: 172.23.0.53#53(172.23.0.53)
;; WHEN: Fri Nov 26 20:39:46 UTC 2021
;; MSG SIZE  rcvd: 99

很好,我们再来看看反向解析(PTR):

dig -x 172.23.91.121 @172.23.0.53

; <<>> DiG 9.16.1-Ubuntu <<>> -x 172.23.91.xxx @172.23.0.53
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 57412
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;xxx.91.23.172.in-addr.arpa.    IN      PTR

;; ANSWER SECTION:
xxx.91.23.172.in-addr.arpa. 900 IN      CNAME   xxx.0/25.91.23.172.in-addr.arpa.
xxx.0/25.91.23.172.in-addr.arpa. 396 IN PTR     50me.xx-xxx-xxx1.bkb.iedon.xxxx.

;; Query time: 456 msec
;; SERVER: 172.23.0.53#53(172.23.0.53)
;; WHEN: Fri Nov 26 20:41:45 UTC 2021
;; MSG SIZE  rcvd: 123

非常棒。

参考

1. How to Install PowerDNS Server and PowerDNS Admin on Ubuntu 20.04, https://www.howtoforge.com/how-to-install-powerdns-admin-on-ubuntu-20-04/

2. Generic MySQL backend, PowerDNS Document, https://doc.powerdns.com/authoritative/backends/generic-mysql.html

3. PowerDNS-Admin Project, GitHub, https://github.com/ngoduykhanh/PowerDNS-Admin


12 responses to “使用 PowerDNS 构建权威 DNS 服务器”

  1. 不明觉历呀。😜

    1. “网络过家家游戏” 哈哈 😂

  2. 搞DNS服务不是要备案嘛?

    1. 这是内网使用的 DNS 服务器。外网不开放任何服务。你可以看到本文中的数据均是内部地址。
      另外,权威 DNS 一般不提供公众日常使用的递归查询服务(DNS 服务分为权威服务器和递归服务器)。即使不小心开放于公网,也仅能查询到该服务器具有权威的数据。

  3. 很强,收藏备用~

  4. 真技术牛!学习(观摩)了

    1. 还是要不断学习的( :dinosaur-sweat:

  5. 试试 CoreDNS?୧(๑•̀⌄•́๑)૭

    1. 只在 K8S 里面听过 CoreDNS 大名,实际还没折腾过。
      不过我目测两者的侧重应该不同吧。PowerDNS 可能更适合停靠/托管/对外提供解析。CoreDNS 更注重/被用于为内网/基础设施提供高质量的解析。不知我的理解对不对。

      1. 我也没用过,应该就是你说的这样。😂

  6. 请问有搭配递归服务器一并使用吗

    1. 没有哦。这里只构建对本地域具有权威的权威服务器。对于递归服务器,我使用的是传统的 bind 9 而不是 PowerDNS。

Leave a Reply

Your email address will not be published. Required fields are marked *