Configuring SSL for PowerDNS api

By default, the PowerDNS api comes with it’s own built in web server and API endpoint, which listens on port 8081. This is not a problem if you use it on your internal trusted network, or if you just need to get something up quickly and don’t care about security. But if you want to access the API for example over the internet, it’s a good idea to use a more secure solution.

This blog post will detail how to wrap your PowerDNS webserver/API with SSL using the Nginx web server as a reverse proxy.

This tutorial assumes some familiarity with Linux commands, a working PowerDNS server installation on a Linux Centos box.

Before you begin enable the PowerDNS API:

sudo vim /etc/pdns/pdns.conf
api=yes
api-key=changeme
webserver-address=127.0.0.1  #this is the default
webserver-address=0.0.0.0  #bind to all IP's
webserver-allow-from=127.0.0.1,::1  #this is the default

1) Install Nginx

First we are going to install Nginx, so login to your PowerDNS server and install Nginx. Then we check what version we just installed and third we are enabling the connection in SELINUX.

sudo yum install nginx -y
nginx -v
setsebool -P httpd_can_network_connect true

2) Install a SSL certificate

We are going to generate a self-signed certificate. Choose a common name for your certificate, we are going to use “ns01.dnssec-script.com” in this example.

cd /etc/nginx
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/cert.key -out /etc/nginx/cert.crt

3) Configure Nginx

Configure Nginx.

sudo vim /etc/nginx/conf.d/powerdns.conf
server {

    listen 443 default_server;

    ssl_certificate           /etc/nginx/cert.crt;
    ssl_certificate_key       /etc/nginx/cert.key;

    ssl on;
    ssl_session_cache  builtin:1000  shared:SSL:10m;
    ssl_protocols  TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
    ssl_prefer_server_ciphers on;

    access_log            /var/log/nginx/powerdns.access.log;

    location / {

      proxy_set_header        Host $host;
      proxy_set_header        X-Real-IP $remote_addr;
      proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header        X-Forwarded-Proto $scheme;

      proxy_pass          http://127.0.0.1:8081;
      proxy_read_timeout  90;

      proxy_redirect      http://127.0.0.1:8081 https://ns01.dnssec-script.com;
    }
  }

4) Enable & Start Nginx

Then we are going to enable and start the Nginx service.

sudo systemctl enable nginx
sudo systemctl start nginx
sudo systemctl status nginx

5) Open firewall

Open the firewall port 443 for API access using https://

sudo firewall-cmd --permanent --zone=public --add-service=https
sudo firewall-cmd --reload

Or open the firewall only for a specific IP-address:

sudo firewall-cmd --permanent --zone=public --add-rich-rule='
  rule family="ipv4"
  source address="1.2.3.4/32"
  port protocol="tcp" port="443" accept'
sudo firewall-cmd --reload

Now your PowerDNS API should be accessible and you could get all zones via this API endpoint: https://ns01.dnssec-script.com/api/v1/servers/localhost/zones

What’s next?

In this example we used a self-signed cert, we could use an official SSL certificate or better we could configure Let’s Encrypt to do it for us.