PowerDNS is a Dutch company (now part of Open-Xchange), which has developed three DNS software packages in the last twenty years: * PowerDNS Authoritative Server * PowerDNS Recursor * dnsdist (a load balancer)
Written in C++, the software is scalable and fast. The code runs on all Unix-type systems, and the latest versions are available in ready-to-use form for most Linux and BSD distributions; a macOS version is also available from Homebrew. All three packages are published as open-source software under the GPLv2 licence. The company generates its income from consultancy, support and customisation activities. The user therefore has all the benefits of the classic open-source business model: open software that you can use 'for free' if you have the time and expertise, an active community of users and developers, and a commercial service provider to fall back on if the need arises. Alternatively, there is the PowerDNS Platform, a software suite based on the three software products.
DNSSEC
It was the implementation of DNSSEC (from version 3.0) that opened the way for PowerDNS to make its big breakthrough: almost all major internet service providers that wanted to bulk-sign their domains did so using the Authoritative Server. DNSSEC validation wasn't added to Recursor until version 4.0. SIDN provided (financial) support to make that extension possible. One particularly interesting feature is the Lua engine incorporated into both the Authoritative Server and the Recursor. Lua is an easy-to-learn script language that makes internal data structures readily accessible to operators. The use of Lua is considered later. In this article, we look at the DNSSEC features of the Authoritative Server. It is the DNSSEC support features in particular that make PowerDNS attractive to many operators. We therefore take you through basic installation of the Authoritative Server on a system running CentOS/RHEL. The Bind connector is also considered. Configuration of the Recursor to work as a validating resolver is considered in a separate article.
Contents
Part I Installation and configuration
Part II Management
Part III DNSSEC-specific options and commands
Part I Installation and configuration
1.1 Ready-to-use packages
At the time of writing (autumn 2019), the current version of the PowerDNS Authoritative Server is 4.2.0. The software is available to download as a ready-to-use package from the repo site. Packages are available for all the most widely used Linux distributions (Debian, Raspbian, Ubuntu and CentOS/RHEL). DNSSEC is supported by the Authoritative Server from version 3.0. When support was introduced, the signing of domains on other authoritative servers (e.g. BIND named, possibly in combination with OpenDNSSEC) was quite cumbersome. By contrast, PowerDNS adopted a flick-the-switch approach from the start. Operators could therefore sign all their domains with a single command. The DNSSEC configuration, the re-signing of the DNS records and the key management were then all handled automatically by the server. Because PowerDNS saved operators the trouble of contending with the complexity of DNSSEC, it benefited from the growing demand for the security extension and soon accounted for a high proportion of signed domains. The discussion presented below is based on PowerDNS Authoritative Server version 4.1.13 on CentOS 7.6. The documentation for the Authoritative Server is available here.
1.2 Installation
Installation of the Authoritative Server begins with configuration of the EPEL and PowerDNS Authoritative Server repositories, plus installation of the yum-plugin-priorities package:
yum install epel-release yum-plugin-priorities && curl -o /etc/yum.repos.d/powerdns-auth-41.repo https://repo.powerdns.com/repo-files/centos-auth-41.repo
Followed by the pdns and pdns-tools packages:
yum install pdns pdns-tools
Although the PowerDNS software is also available directly from the EPEL repository for CentOS/RHEL, this article is based on the version from the powerdns-auth-41 repository. The latest versions of Fedora (29, 30 and 31, the last of which is still under development) are currently distributed with Authoritative Server versions 4.1.11 and 4.2.0 by means of updates. Alternatively, the packages can be downloaded directly from Kees Monshouwer's PDNS repository.
1.3 Backends
The Authoritative Server software includes numerous backends: connectors for various sources where the server can retrieve (and usually write) its zone information. The available backends, as well as the additional packages that you need to install for each, are listed in the table below.
Backend | Package |
---|---|
GeoIP (resolve to nearest host) | |
Lua (connector for the embedded Lua script language) | |
MyDNS (old, only for import) | |
Oracle pipe (connector for named pipes and IPC sockets) | |
remote (connector for pipes/sockets, HTTP and ZeroMQ) | |
SQLite 3 (embedded) | |
TinyDNS (djbdns; old, only for import) |
The Oracle backend is not supplied with CentOS/RHEL. To avoid rights violations, you need to compilere it yourself. However, the backend should no longer be used anyway, because the backends for Oracle, MyDNS and OpenDBX have been removed from the software from version 4.3. Most operators are likely to set up the Authoritative Server with a MySQL/MariaDB backend, though.
1.4 Modes of Operation
The Authoritative Server supports various Modes of Operation:
Native replication (default): no notifications or zone transfers are performed; all updates utilise the replication mechanisms of the supporting databases (as with the Infoblox appliances within a Grid). According to the makers of PowerDNS, the mechanism has been shown to work for MySQL/MariaDB and Oracle, even over poor intercontinental connections.
Master: notifications are sent out to slaves, which can then request zone updates.
Supermaster: when a server sends a notification, a receiving server responds by automatically configuring itself as a (super)slave for that particular domain.
Incoming zone transfers can be filtered using a Lua script for each zone, which is then run for each resource record.
For native replication (the default), therefore, you don't need to do anything except set up unidirectional database replication from master to slaves. Furthermore, all backends can subsequently be configured as read-only (except those connected to a user/management frontend; typically an administrative hidden master).
1.5 MariaDB
The set-up discussed in this article uses MariaDB, the successor to (fork) provided by MySQL following Sun's takeover by Oracle. Most readers will probably have similar set-ups. Many of the major operators that switched to the PowerDNS Authoritative Server did so because of the DNSSEC support. The basic installation is therefore described in full below.
Our first step is to install the MariaDB software and the MySQL/MariaDB backend:
yum install mariadb mariadb-server pdns-backend-mysql
Next, the MariaDB server is (permanently) enabled and started:
[root@localhost ~]# systemctl enable mariadb Created symlink from /etc/systemd/system/multi-user.target.wants/mariadb.service to /usr/lib/systemd/system/mariadb.service. [root@localhost ~]# systemctl start mariadb [root@localhost ~]# systemctl status mariadb ● mariadb.service - MariaDB database server Loaded: loaded (/usr/lib/systemd/system/mariadb.service; enabled; vendor preset: disabled) Active: active (running) since Mon 2019-02-04 15:31:09 CET; 1min 17s ago Main PID: 30431 (mysqld_safe) CGroup: /system.slice/mariadb.service ├─30431 /bin/sh /usr/bin/mysqld_safe --basedir=/usr └─30592 /usr/libexec/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --log... Feb 04 15:31:07 localhost.localdomain mariadb-prepare-db-dir[30215]: MySQL manual for more instructions. Feb 04 15:31:07 localhost.localdomain mariadb-prepare-db-dir[30215]: Please report any problems at http://mariadb.org/jira Feb 04 15:31:07 localhost.localdomain mariadb-prepare-db-dir[30215]: The latest information about MariaDB is available...g/. Feb 04 15:31:07 localhost.localdomain mariadb-prepare-db-dir[30215]: You can find additional information about the MyS...at: Feb 04 15:31:07 localhost.localdomain mariadb-prepare-db-dir[30215]: http://dev.mysql.com Feb 04 15:31:07 localhost.localdomain mariadb-prepare-db-dir[30215]: Consider joining MariaDB's strong and vibrant com...ty: Feb 04 15:31:07 localhost.localdomain mariadb-prepare-db-dir[30215]: https://mariadb.org/get-involved/ Feb 04 15:31:07 localhost.localdomain mysqld_safe[30431]: 190204 15:31:07 mysqld_safe Logging to '/var/log/mariadb/ma...og'. Feb 04 15:31:07 localhost.localdomain mysqld_safe[30431]: 190204 15:31:07 mysqld_safe Starting mysqld daemon with dat...ysql Feb 04 15:31:09 localhost.localdomain systemd[1]: Started MariaDB database server. Hint: Some lines were ellipsized, use -l to show in full.
Having done that, we can initialise a fresh installation of MariaDB as follows:
[root@localhost ~]# mysql_secure_installation NOTE: 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): OK, successfully used password, moving on... Setting the root password ensures that nobody can log into the MariaDB root user without the proper authorisation. Set root password? [Y/n] y New password: ************ Re-enter new password: ************ Password updated successfully! Reloading privilege tables.. ... Success! By default, a MariaDB installation has an anonymous user, allowing anyone to log into MariaDB without having to have a user account created for them. This is intended only for testing, and to make the installation go a bit smoother. You should remove them before moving into a production environment. Remove anonymous users? [Y/n] y ... Success! Normally, root should only be allowed to connect from 'localhost'. This ensures that someone cannot guess at the root password from the network. Disallow root login remotely? [Y/n] y ... Success! By default, MariaDB comes with a database named 'test' that anyone can access. This is also intended only for testing, and should be removed before moving into a production environment. Remove test database and access to it? [Y/n] y - Dropping test database... ... Success! - Removing privileges on test database... ... Success! Reloading the privilege tables will ensure that all changes made so far will take effect immediately. Reload privilege tables now? [Y/n] y ... Success! Cleaning up... All done! If you've completed all of the above steps, your MariaDB installation should now be secure. Thanks for using MariaDB!
1.6 Database user and definition
The following step involves using the MariaDB monitor to create a user account ('pdns') and the database itself (here also 'pdns') for the Authoritative Server:
[root@localhost ~]# mysql -u root -p Enter password: ************ Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 10 Server version: 5.5.60-MariaDB MariaDB Server Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MariaDB [(none)]> CREATE USER 'pdns'@'localhost' IDENTIFIED BY '************'; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> GRANT DELETE, INSERT, SELECT, UPDATE ON pdns.* TO 'pdns'@'localhost'; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> FLUSH PRIVILEGES; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> CREATE DATABASE pdns; Query OK, 1 row affected (0.00 sec) MariaDB [(none)]> USE pdns; Database changed MariaDB [pdns]>
The dedicated database tables for the Authoritative Server can then be created. For that, we have adopted the definitions published on the PowerDNS website [1]:
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) 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, 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 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, 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);
1.7 Configuration of the PowerDNS Authoritative Server
Having set up the MariaDB server and our 'pdns' database, we can move on to configuring the Authoritative Server itself. The first step is to add the following 'launch' command for the MySQL/MariaDB backend to the configuration file '/etc/pdns/pdns.conf':
launch=gmysql gmysql-host=127.0.0.1 gmysql-port=3306 gmysql-user=pdns gmysql-password=************ gmysql-dbname=pdns gmysql-dnssec=yes
Note the final statement, which enables DNSSEC support. Everything else (timing, re-signing, key management, etc) is then dealt with automatically. Our newly configured 'gmysql' backend will be loaded when the Authoritative Server is (re)started. Note that, midway through the configuration template, there is a stray 'launch=' statement. Therefore, if you get the response "Unable to launch, no backends configured for querying", it's a good idea to start by checking that your configuration file is clean. Other initial configuration options include the IP addresses that the Authoritative Server is to monitor for incoming DNS queries and the address that the server itself is to use to initiate outbound connections:
local-address
=192.0.2.3
local-ipv6
=2001:db8::2:3
query-local-address
=192.0.2.3
query-local-address6
=2001:db8::2:3
In addition, all Modes of Operation except for native mode (default) need to be explicitly enabled in the configuration file:
master=yes
of:
slave=yes
of: slave=yes, in combinatie met:
superslave=yes
1.8 Generic backends
From version 4.0.0, PowerDNS provides generic backends for MySQL/MariaDB, ODBC, Oracle, PostgreSQL and SQLite3. The generic backends contain general SQL commands, which you can easily modify using the configuration file. So, for example, you can tailor the backend database interface to your own set-up and database schema. The command for viewing all the SQL queries built into the generic MySQL/MariaDB backend is as follows:
pdns_server --no-config --launch=gmysql --config
The list of options is too long to reproduce in full. However, by way of example, here is the query used to add a new domain to the database:
################################# # gmysql-insert-zone-query # # gmysql-insert-zone-query=insert into domains # (type,name,master,account,last_check,notified_serial) # values(?,?,?,?,NULL,NULL)
Details of the generic interface are provided here. The linked page describes how to add records to the 'domain' and 'records' tables and how to compile the administrative 'supermasters' table for various server configurations (native/Slave/Superslave/Master). New slave domains are retrieved and activated within 60 seconds ('slave-cycle-interval'). Thereafter, the TTL of the SOA record determines the timing of the next check. On a Master server, the 'slave-cycle-interval' determines the timing of NOTIFY message transmission.
1.9 Starting the PowerDNS Authoritative Server
If we now start the Authoritative Server, it has to connect to the previously configured database via the 'gmysql' backend:
[root@localhost ~]# systemctl enable pdns.service Created symlink from /etc/systemd/system/multi-user.target.wants/pdns.service to /usr/lib/systemd/system/pdns.service. [root@localhost ~]# systemctl start pdns.service [root@localhost pdns]# systemctl status pdns.service ● pdns.service - PowerDNS Authoritative Server Loaded: loaded (/usr/lib/systemd/system/pdns.service; enabled; vendor preset: disabled) Active: active (running) since Fri 2019-08-16 17:07:06 CEST; 4s ago Docs: man:pdns_server(1) man:pdns_control(1) https://doc.powerdns.com Main PID: 3678 (pdns_server) Tasks: 8 CGroup: /system.slice/pdns.service └─3678 /usr/sbin/pdns_server --guardian=no --daemon=no --disable-syslog --log-timestamp=no --write-pid=no Aug 16 17:07:03 localhost.localdomain pdns_server[3678]: TCP server bound to 0.0.0.0:53 Aug 16 17:07:04 localhost.localdomain pdns_server[3678]: TCPv6 server bound to [::]:53 Aug 16 17:07:04 localhost.localdomain pdns_server[3678]: PowerDNS Authoritative Server 4.1.13 (C) 2001-2018 PowerDNS.COM BV Aug 16 17:07:04 localhost.localdomain pdns_server[3678]: Using 64-bits mode. Built using gcc 4.8.5 20150623 (Red Hat ...81d. Aug 16 17:07:04 localhost.localdomain pdns_server[3678]: PowerDNS comes with ABSOLUTELY NO WARRANTY. This is free sof...n 2. Aug 16 17:07:06 localhost.localdomain pdns_server[3678]: Polled security status of version 4.1.13 at startup, no know...: OK Aug 16 17:07:06 localhost.localdomain pdns_server[3678]: Creating backend connection for TCP Aug 16 17:07:06 localhost.localdomain systemd[1]: Started PowerDNS Authoritative Server. Aug 16 17:07:06 localhost.localdomain pdns_server[3678]: About to create 3 backend threads for UDP Aug 16 17:07:06 localhost.localdomain pdns_server[3678]: Done launching threads, ready to distribute questions Hint: Some lines were ellipsized, use -l to show in full.
As you will see from the following, the Authoritative Server then monitors UDP and TCP on all network interfaces for port number 53, using both IPv4 and IPv6:
[root@localhost ~]# netstat -lntup | grep pdns tcp 0 0 0.0.0.0:53 0.0.0.0:* LISTEN 3757/pdns_server tcp6 0 0 :::53 :::* LISTEN 3757/pdns_server udp 0 0 0.0.0.0:53 0.0.0.0:* 3757/pdns_server udp6 0 0 :::53 :::* 3757/pdns_server
Part II Management
2.1 Database interface
With the Authoritative Server, the database usually functions as an interface between the DNS server infrastructure and the administrative environment. Domains and associated records are created and modified in the database, then the information is automatically retrieved by the Authoritative Server for publication and, where relevant, distribution to slaves. Considering the complexity of the DNS, the database schema for the Authoritative Server (see above) is surprisingly simple. The 'records' table has two fields specifically for DNSSEC:
'auth': this field must be 1/true for all DNS records for which the zone in question is authoritative, except NS and glue records for delegated zones
'ordername': this field must be completed if NSEC/NSEC3 is used, with the value depending on the record type and the NSEC/NSEC3 mode used
However, we advise using the management port, the web interface or the web API, all of which are described below. That will be more straightforward, less error-sensitive and easier to maintain.
In the event of an inward zone transfer or use of the command 'pdnsutil rectify-zone', the two fields are automatically completed by the Authoritative Server. The default installation of PowerDNS uses NSEC. However, we recommend enabling NSEC3 by adding a NSEC3PARAM record, so as to protect against name walking:
pdnsutil set-nsec3 example.nl '1 0 1 -'
2.2 Management port
The Authoritative Server offers a management port on TCP port 53000 and on the Unix socket '/var/run/pdns.controlsocket'. The two interfaces offer exactly the same functionality for server-oriented management tasks (server configuration, statistics and the initiation of DNS transfers and notifications). In order to open the management port for localhost and local networks, you need to add the following statements to the configuration file:
tcp-control-address=127.0.0.1 tcp-control-port=53000 tcp-control-range=127.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fe80::/10 tcp-control-secret=************
The location of the Unix socket is configured as follows:
socket-dir=/var/run/
For direct access to the interface, you can use the command 'telnet localhost 53000'. After entering the password, you can only give a single command before the connection is broken. Normally, however, you will access the port using the 'pdns_control' command. The general syntax is as follows:
pdns_control <command> <arguments>
Visit the man page or use the command 'pdns_control --help'. Other commands are used to immediately forward the output received via the management port. See, for example, the command 'pdns_control help':
[root@localhost ~]# pdns_control help ccounts get cache statistics current-config retrieve the current configuration list-zones [master|slave|native] show list of zones notify <domain> queue a notification notify-host <domain> <host> notify host for specific domain purge [<record>] purge entries from packet cache qtypes get QType statistics quit quit daemon rediscover discover any new zones reload reload all zones remotes get top remotes respsizes get histogram of response sizes retrieve <domain> retrieve slave domain rping ping instance set <var> <value> set config variables show <statistic> show a specific statistic or * to get a list token-login <module> <slot> <pin> Login to a PKCS#11 token uptime get instance uptime version get instance version
For the avoidance of doubt, it is worth clarifying that the help is not obtained from the pdns_control program itself, but from a dump of the 'help' command sent via the control socket to the server. The same thing can be done remotely via the network interface, by entering the following command:
pdns_control --remote-address=192.0.2.3 --remote-port=53000 --secret=************ help
2.3 Web interface
In addition to the text-oriented management port described, the Authoritative Server features a built-in web server. The procedure for activating the web server and opening it for localhost and local networks (in our example, on port 8081) is as follows:
webserver=yes webserver-address=127.0.0.1 webserver-port=8081 webserver-allow-from=127.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fe80::/10 webserver-password=************ webserver-print-arguments=no webserver-loglevel=normal [vanaf versie 4.2.0]
As you'll see on your monitor (after opening port 8081 in your firewall), and as illustrated in the screenshot below, the web server provides only a port for (performance) monitoring of your server.
![](http://images.ctfassets.net/yj8364fopk6s/4o40F3U86vuxy04cHihHcu/59127180fac1cb2212ccabc1fb393fc1/PDNS-web-screenshot0.png?w=900&fl=progressive)
2.4 Web API
The Authoritative Server does, however, offer a fully featured interface in the form of a web API based on REST and JSON according to the OpenAPI Specification (Swagger). The interface uses the same web server as the web interface, but in addition to statistics it has functions for editing zone information, metadata and DNSSEC key material. The web API is enabled as follows:
In this article, it isn't practicable to illustrate how to program with the Authoritative Server's web API, but the availability of the web API can easily be tested like so:
curl -v -H 'X-API-Key: ************' http://127.0.0.1:8081/api/v1/servers/localhost [offerman@vegas DNSSEC2]$ curl -v -H 'X-API-Key: ************' http://192.0.2.3:8081/api/v1/servers/localhost * Trying 192.0.2.3... * TCP_NODELAY set * Connected to 192.0.2.3 (192.0.2.3) port 8081 (#0) > GET /api/v1/servers/localhost HTTP/1.1 > Host: 192.0.2.3:8081 > User-Agent: curl/7.53.1 > Accept: */* > X-API-Key: ************ > < HTTP/1.1 200 OK < Access-Control-Allow-Origin: * < Connection: close < Content-Length: 248 < Content-Security-Policy: default-src 'self'; style-src 'self' 'unsafe-inline' < Content-Type: application/json < Server: PowerDNS/4.1.13 < X-Content-Type-Options: nosniff < X-Frame-Options: deny < X-Permitted-Cross-Domain-Policies: none < X-Xss-Protection: 1; mode=block < * Closing connection 0
For a detailed description of the web API, refer to the PowerDNS documentation or the machine-readable Swagger interface specification here.
2.5 Bind backend
Before considering the Authoritative Server's the DNSSEC-specific functionality, it is useful to take a look at the Bind backend. After all, flick-the-switch DNSSEC support was the main reason why many operators migrated their DNS infrastructures to PowerDNS [1, 2]. The Bind backend allows you to load a (limited) 'named.conf' configuration file and associated zone files. Because data is retrieved from a static file set, rather than a dynamic database, the Authoritative Server can use the connector only to load zone information (read-only backend, except for slave zones). On the CentOS/RHEL platform, the Bind backend is a standard component of the Authoritative Server and does not therefore need to be installed separately. In the set-up described here, the connector is used in combination with the MySQL/MariaDB connector. The set-up is configured as follows:
launch=bind bind-config=/etc/pdns/named.conf bind-check-interval=600
That requires two simple configuration files 'named.conf' and 'db.example.nl' to be created and placed in the directory '/etc/pdns/'. The Bind backend supports only a handful of the normal options in 'named.conf':
options
directory
also-notify
zone
file
type
masters
also-notify
Here are the contents of the 'named.conf' file that we used to initiate the DNS server for our domain example.nl:
options { directory "/etc/pdns"; }; zone "example.nl" { type master; file "db.example.nl"; };
From the log file, we can then see that the relevant zone has been successfully loaded:
Sep 15 18:02:47 localhost pdns_server: [bindbackend] Parsing 1 domain(s), will report when done Sep 15 18:02:47 localhost pdns_server: [bindbackend] Done parsing domains, 0 rejected, 1 new, 0 removed
2.6 Combined backends
For more complex migrations, multiple backends can be combined by listing them in the 'launch' statement:
launch=gmysql,bind
When responding to incoming DNS queries, the Authoritative Server will then query the various backends in the order that they are listed. If you want to use multiple backends of the same type (typically multiple servers), you can name them separately:
launch=gmysql,gmysql:server2,bind
In the example, we are using both the primary MySQL/MariaDB server and a second database server. You then configure the second server by including the server name in the configuration options, as follows:
gmysql-server2-host=192.0.2.14 gmysql-server2-port=3306 gmysql-server2-user=pdns gmysql-server2-password=************ gmysql-server2-dbname=pdns gmysql-server2-dnssec=yes
It is important to note, however, that the Bind backend cannot be included in the 'launch' statement more than once. Any additional zone files therefore have to be added to the existing 'named.conf' configuration. The makers of PowerDNS advise against using combined backends unless you have a good reason for doing so. Their rationale is that multiple backend use is not a clearly defined option, so things may not work as expected following future updates.
2.7 More options for the Bind backend
Other Bind-specific options that can be included in the Authoritative Server configuration file:
bind-dnssec-db: A file for recording DNSSEC meta-information; required if the server in question functions as a slave for a zone that is already signed (elsewhere)
bind-check-interval: This option is used mainly when the information in the zone files is subject to frequent change; however, it also enables you to easily set up a combination with OpenDNSSEC, where zone files are automatically signed and recorded for automatic retrieval by the Authoritative Server
In addition, a hybrid Bind mode is available for Masters. In hybrid mode, the zone information is obtained from the Bind backend, but signing and key management are handled by the Authoritative Server. The DNSSEC-related records are saved in another backend, typically SQLite3 (embedded). The set-up therefore follows naturally from the combination of backends described above, where the various backends are queried in order when incoming queries are processed. As with combined backends, the makers of PowerDNS advise against using the hybrid mode unless you have a good reason for doing so.
2.8 Migration to PowerDNS
The PowerDNS documentation suggests various fairly straightforward ways of migrating old DNS information to the Authoritative Server:
By first creating all existing domains on the Authoritative Server as slaves, then switching them to master/native mode on the Authoritative Server following the zone transfer
By converting the zone files themselves to (generic) SQL using the 'zone2sql' tool
By using the 'pdnsutil load-zone' command to read the zone files directly
Another option is the 'pdnsutil b2b-migrate' command, which you can use to migrate a zone from one backend to another within the Authoritative Server itself. The command also enables you to use the Authoritative Server as a tool for performing a wide variety of backend/platform conversions on your zone files.
Deel III DNSSEC-specific options and commands
The third and final part of this article looks at the DNSSEC-specific options and commands not considered above.
3.1 Cryptographic algorithms
We'll start by going over the configuration options for the cryptographic algorithms:
default-ksk-algorithm=ecdsa256 The encryption algorithm used for the KSK pair when signing by means of a 'pdnsutil secure-zone' command or using the web API
default-ksk-size= The key length for the KSK pair (needed only if crypto-algorithms are used, for which the key length is not specified in the standard)
default-zsk-algorithm= As above, but for the ZSK pair
default-zsk-size= As above, but for the ZSK pair
PowerDNS provides a list of supported algorithms, but the actual availability of the listed algorithms depends on the options specified when compiling the software. A list can be retrieved using the 'pdnsutil list-algorithms' command:
[root@localhost ~]# pdnsutil list-algorithms DNSKEY algorithms supported by this installation of PowerDNS: 5 - RSASHA1 7 - RSASHA1-NSEC3-SHA1 8 - RSASHA256 10 - RSASHA512 13 - ECDSAP256SHA256 14 - ECDSAP384SHA384 15 - ED25519
Therefore, although the Authoritative Server supports various other cryptographic algorithms for DNSSEC [1, 2], we advise (continued) use of ECDSA256 [3, 4]. If you'd like to know more about the differences between the cryptographic algorithms, take a look at the dedicated section of our 'DNSSEC – FAQ' page.
3.2 Random generator
When deciding which cryptographic algorithm to use, it is important to bear in mind that DSA-based algorithms are particularly susceptible to the effects of a poorly initialised random generator. They are liable to provide insecure key pairs if the generator is not well initialised. For a production system, therefore, the following option should always be used.
entropy-source=/dev/random
Completely different random generators can be selected using the 'rng' option:
rng=openssl
For both security and scalability reasons, it is best to use a bump-in-the-wire architecture based on OpenDNSSEC and an HSM (Hardware Security Module) for a larger DNS infrastructure. The installation and configuration of OpenDNSSEC is considered in a separate article (in Dutch only). The Authoritative Server itself currently offers experimental support for PKCS#11.
3.3 More DNSSEC-specific options
The remaining DNSSEC-specific configuration options are as follows:
If this option is enabled, the DNSKEY-, CDS- and CDNSKEY records are also loaded from the zone information | |
The number of seconds that DNSSEC keys retrieved from the database are retained in the cache | |
Maximum number of NSEC3 iterations; nowadays you always set this to 0 | |
Maximum number of signatures that can be retained in the cache | |
Number of threads that the server can use for signing domains |
3.4 The 'pdnsutil' command
In this subsection, we consider the 'pdnsutil' command: the command that, as an operator, you are likely to make most use of for managing (signed) zones, whether directly (via the command line) or indirectly (in scripts). The 'pdnsutil' command acts on the database directly, implying that you can easily give commands for execution via the network. For command execution, the program uses the local PDNS configuration file. The 'pdnsutil' command used to be called 'pdnssec', which is reflected in the associated functionality. The DNSSEC-specific functions supported by the command are summarised below. In the following subsection, we'll illustrate the use of the various commands for signing the zone example.nl.
activate-zone-key < zone > < key-id > | Activate the < key-id > key for < zone > |
deactivate-zone-key < zone > < key -id> | Deactivate the < key-id > key for < zone > |
add-zone-key < zone > KSK/ZSK [active/inactive] < keybits > < algorithm > | Generate a new key pair for < zone > and use 'active' to sign the zone immediately |
create-bind-db < file > | Create the (embedded) DNSSEC database (SQLite3) for the hybrid Bind mode (Don not forget to specify this file with the bind-dnssec-db configuration option) |
disable-dnssec < zone > | Disable DNSSEC for < zone > |
export-zone-dnskey < zone > < key-id > | Export (dump) DNSKEY and DS records for key < key-id > in < zone > |
export-zone-ds < zone > | Export (dump) all KSK DS records in < zone > (After exporting the records, they can be uploaded to the operator of the parent domain for publication) |
export-zone-key < zone > < key-id > | Export (dump) all key information (including the private key) for < key-id > in < zone > |
generate-zone-key KSK/ZSK [algorithm] [keybits] | Generate (and dump) a new key pair (default cryptographic algorithm: ECDSA256) |
import-zone-key < zone > < file > KSK/ZSK | Import a key pair from < file > in < zone > |
list-keys [zone] | List all key pairs (for < zone >) |
rectify-zone < zone > | Recreate the auth and ordername database fields for < zone > |
rectify-all-zones | Recreate the 'auth' and 'ordername' database fields for all zones |
remove-zone-key < zone > < key-id > | Delete the key < key-id > from < zone > |
secure-zone < zone > | Sign < zone > (using the default settings) |
secure-all-zones [increase-serial] | Sign all zones (and increase the serial number) |
set-nsec3 < zone > ['< hash-algorithm > < flags > < iterations > < salt >'] [narrow] | Give the NSEC3 settings for < zone >; the parameter string contains the information to be included in the NSEC3PARAM record; the |
unset-nsec3 < zone > | Convert an NSEC3 setting for < zone > back to NSEC |
set-presigned < zone > | Use the provided in-zone) DNSSEC records for < zone > |
unset-presigned < zone > | Stop using the in-zone DNSSEC records for < zone > |
show-zone < zone > | Display all DNSSEC-related settings for < zone > |
set-publish-cds < zone > [digestalgos] | Publish the CDS records for < zone >; [digestalgos] contains a list of hash algorithms for (C)DS records (default: 2: SHA-256) |
unset-publish-cds < zone > | Deactivate publication of CDS records for < zone > |
set-publish-cdnskey < zone > | Publish the CDNSKEY records for < zone > |
unset-publish-cdnskey < zone > | Deactivate publication of CDNSKEY records for < zone > |
For information about the remaining functions of the 'pdnsutil' command, see the man man page.
3.5 Signing a zone
Having taken all the steps described to install, configure and get to know the PowerDNS Authoritative Server, we are ready to actually sign our zone example.nl. The following procedure assumes an installation as described above, where the zone is loaded using the Bind backend. Because the Bind backend is read-only, we'll create a hybrid Bind configuration, where the zone information is obtained from the Bind backend, but signing and key management are handled by the Authoritative Server. The signatures (RRSIG records) and the key material for the domain are stored in an (embedded) SQLite3 database. The first step is to create the database (if it doesn't already exist). We can then generate the KSK and ZSK pairs for signing the zone example.nl. The entire process is set out below, complete with a number of commands for displaying the current status.
[root@localhost ~]# pdnsutil create-bind-db /etc/pdns/bind-db.sqlite3 [root@localhost ~]# pdnsutil add-zone-key example.nl KSK inactive ecdsa256 Sep 19 17:50:40 [bindbackend] Done parsing domains, 0 rejected, 1 new, 0 removed Added a KSK with algorithm = 13, active=0 1 [root@localhost ~]# pdnsutil add-zone-key example.nl ZSK inactive ecdsa256 Sep 19 17:51:07 [bindbackend] Done parsing domains, 0 rejected, 1 new, 0 removed Added a ZSK with algorithm = 13, active=0 2 [root@localhost ~]# pdnsutil list-keys example.nl Sep 19 17:52:31 [bindbackend] Done parsing domains, 0 rejected, 1 new, 0 removed Zone Type Size Algorithm ID Location Keytag -------------------------------------------------------------------------- example.nl ZSK 256 ECDSAP256SHA256 2 cryptokeys 7300 example.nl KSK 256 ECDSAP256SHA256 1 cryptokeys 4293 [root@localhost ~]# pdnsutil set-nsec3 example.nl '1 0 0 -' NSEC3 set, please secure and rectify your zone. [root@localhost ~]# pdnsutil set-publish-cdnskey example.nl [root@localhost ~]# pdnsutil set-publish-cds example.nl [root@localhost ~]# pdnsutil activate-zone-key example.nl 1 [root@localhost ~]# pdnsutil activate-zone-key example.nl 2 [root@localhost ~]# pdnsutil check-zone example.nl Sep 19 17:53:14 [bindbackend] Done parsing domains, 0 rejected, 1 new, 0 removed Checked 19 records of 'example.nl', 0 errors, 0 warnings. [root@localhost ~]# pdnsutil show-zone example.nl Sep 19 18:01:16 [bindbackend] Done parsing domains, 0 rejected, 1 new, 0 removed This is a Master zone Last SOA serial number we notified: 0 != 2017101300 (serial in the database) Metadata items: NSEC3PARAM 1 0 0 - PUBLISH-CDNSKEY 1 PUBLISH-CDS 1,2 Zone has hashed NSEC3 semantics, configuration: 1 0 0 - keys: ID = 2 (ZSK), flags = 256, tag = 7300, algo = 13, bits = 256 Active ( ECDSAP256SHA256 ) ID = 1 (KSK), flags = 257, tag = 4293, algo = 13, bits = 256 Active ( ECDSAP256SHA256 ) KSK DNSKEY = example.nl. IN DNSKEY 257 3 13 y5JN0NxY8vYMyKDSR3D+6lJDJmQUAp1SsCRaMSOPSAMGvslhBOy4GXQxeMpxmhvM4aFdHAm09TtGwirSBS/ULw== ; ( ECDSAP256SHA256 ) DS = example.nl. IN DS 4293 13 1 78776d2a17958d3bac818b26172477119f4c2213 ; ( SHA1 digest ) DS = example.nl. IN DS 4293 13 2 a31facbfd1dff2003b91bb4348bd923dc9dabab3987b70371af1e6fc8eb7eda2 ; ( SHA256 digest ) DS = example.nl. IN DS 4293 13 4 3bd91b55b497a11a27efbb63bd97180b3946186257f6f02b3ce780d7c837fb419206ba70891c3fd45a4a3071f9e83172 ; ( SHA-384 digest ) [root@localhost ~]# pdnsutil export-zone-dnskey example.nl 1 example.nl IN DNSKEY 257 3 13 y5JN0NxY8vYMyKDSR3D+6lJDJmQUAp1SsCRaMSOPSAMGvslhBOy4GXQxeMpxmhvM4aFdHAm09TtGwirSBS/ULw== [root@localhost ~]# pdnsutil export-zone-ds example.nl Sep 19 18:07:06 [bindbackend] Done parsing domains, 0 rejected, 1 new, 0 removed example.nl. IN DS 4293 13 1 78776d2a17958d3bac818b26172477119f4c2213 ; ( SHA1 digest ) example.nl. IN DS 4293 13 2 a31facbfd1dff2003b91bb4348bd923dc9dabab3987b70371af1e6fc8eb7eda2 ; ( SHA256 digest ) example.nl. IN DS 4293 13 4 3bd91b55b497a11a27efbb63bd97180b3946186257f6f02b3ce780d7c837fb419206ba70891c3fd45a4a3071f9e83172 ; ( SHA-384 digest )
Exactly what key information is required to form a cryptographic link (in the chain of trust) with the parent domain depends on the registry. In our role as operator of the .nl top-level domain, we ask our registrars to provide DNSKEY records, not DS records. By generating DS records ourselves from the DNSKEY records provided, we can control which hash algorithm is used. If you go for a hybrid set-up like the one illustrated above, don't forget to add the location of the SQLite3 database to the Authoritative Server configuration:
bind-dnssec-db=/etc/pdns/bind-db.sqlite3
3.6 Signing everything at once
If you want to sign an existing zone in one go, on the basis of the defaults, you can do the whole job with just two commands:
pdnsutil secure-zone example.nl pdnsutil rectify-zone example.nl
It's also possible to do the same for all domains at once:
pdnsutil secure-all-zones pdnsutil rectify-all-zones
If you compare the simplicity of that procedure with the way DNSSEC is configured in other DNS server software, it's easy to see why the PowerDNS Authoritative Server has proved so popular with operators looking to introduce DNSSEC (where the .nl zone is concerned, often motivated by SIDN's incentive scheme for registrars).
3.7 Dynamic Lua records
Finally, it is worth taking a look at the Authoritative Server's built-in Lua engine. Lua has its design flaws, but as an embedded engine it is very useful for providing users with a run-time scripting portal within your software. It enables developers to quickly and easily add new interfaces to their C-code. Using the built-in Lua facility (from version 4.2), you can make DNS server responses dependent on current conditions. That's done by incorporating Lua-code strings in your DNS records, causing the server response to be determined dynamically when a query about a given record is received. By way of illustration, here is a simple example:
www IN LUA A "pickclosest({'192.0.2.14','198.51.100.14'})"
The effect of that code string is that the response includes details of the nearest server to the enquirer. To that end, the GeoIP backend is used to ascertain the smallest (physical) distance between the enquirer and a host. In order to use dynamic Lua records, you have to enable the relevant configuration option as follows:
enable-lua-records=yes
Lua records can be enabled for an individual zone like so:
ENABLE-LUA-RECORDS = 1
There's another setting, which causes the scripts to be assigned a shared context (per thread) for execution, rather than being handled separately. That option is activated as follows:
enable-lua-records=shared
Because the contents of the records are determined dynamically, Lua records cannot be combined with pre-signed zones. Consequently, the Authoritative Server signs DNS responses exclusively on-the-fly, implying that the private key has to be on the public servers as well. The intention is for the dynamic Lua records to be standardised, so that in due course this feature can also be implemented by other DNS server software. For more information about dynamic Lua records, use this link.
3.8 In conclusion
Because the PowerDNS Authoritative Server is quite extensive, it can take a while to get to know it. However, the software's architecture is well designed: the DNS server itself functions as a central hub, with a variety of ports arranged around it. Backend connectors provide interfaces with the supporting databases. Transfers to other Authoritative Servers are easily performed by means of database replication. As well as the direct database interface, there is a web interface and an API, plus a control socket with associated command-line tools. Standout features of the PowerDNS Authoritative Server include flick-the-switch support for DNSSEC (note that this article includes no information about timing, re-signing or key management), dynamic Lua records and the ability to convert zone information from one format to another by transferring it between the relevant backends. More information about the PowerDNS Authoritative Server is available here [1, 2, 3].