Install Authoritative DNS

This recipe, which largely references existing documentation, guides you to the installation of a PowerDNS Authoritative DNS server and of its PowerDNS-admin GUI frontend. The PowerDNS server is backed by a MySQL/MariaDB database.

The recipe is intended for such cases where a minimal DNS service is needed. For this reason, the DNS server (as well as the backend MySQL/MariaDB database ) and its GUI will be installed on the same virtual machine.

Note

PowerDNS version 4.X will be installed, which acts as a pure DNS authoritative server. You may also consider installing a PowerDNS recursor, but this part is not covered here and is left as an exercise…

The recipe assumes CentOS operating system: for other operating systems, refer to the relevant official pages and change commands accordingly.

Note

Out of the many possible alternatives for the management GUI, I abandoned the glorious PowerAdmin (still available at https://www.poweradmin.org/), which served me so well until today, as it seems not to be maintained since a long time. On the other hand, PowerDNS-Admin seems to have a rather large and lively community behind. One benefit of this latter product is that it no longer requires direct access to the MySQL database, as it interacts via PowerDNS API.

Prerequisites

Configure firewall

In order to protect the virtual machine running the DNS server, you need to properly configure your firewall. If the virtual machine is created within an OpenStack tenant, I strongly advice to create a dedicated Security Group containing the following exceptions:

  • allow UDP access to port 53 (from the Universe, if this DNS is going to be authoritative)
  • allow TCP access to port 53 (from the Universe, if this DNS is going to be authoritative)
  • allow TCP access to port 8181 (PowerDNS webserver GUI) from trusted hosts/networks
  • allow TCP access to port 9191 (PowerDNS-Admin management GUI) from trusted hosts/networks
  • allow TCP access to port 22 (SSH) from trusted hosts/networks

Moreover, I also find it convenient to add ICMP access from 0.0.0.0.

MySQL server

Install the MariaDB server, configure it, update and reboot:

yum install epel-release
yum install mariadb-server
systemctl start mariadb
systemctl enable mariadb
systemctl status mariadb
mysql_secure_installation # initially, root password is blank, during the
                          # command execution you can set it to something sensible
yum update
reboot

Ansible

Install Ansible:

yum install epel-release
yum install ansible

Create Ansible user, with sudo privileges:

  • create a group for ansible, edit file /etc/group and add a line like:

    groupadd --gid 22222 ansible
    
  • create user ansible::

    useradd –create-home –gid 22222 –uid 22222 ansible

  • add user to sudoers, touch file /etc/sudoers.d/ansible with content:

    Defaults:ansible     !requiretty
    ansible ALL = (root) NOPASSWD:ALL
    

PowerDNS installation and setup

PowerDNS is managed via an Ansible role.

Since we assume the virtual machine belongs to an OpenStack tenant and has a floating IP, we are configuring our DNS server such that it listens on any interface.

  • create a working directory:

    mkdir /home/Ansible/PowerDNS
    
  • download from GitHub:

    cd /home/Ansible/PowerDNS
    ansible-galaxy --roles-path . install PowerDNS.pdns
    
  • create inventory file in Ansible working directory, with content:

    [mydns]
    localhost
    
    [mydns:vars]
    ansible_user=ansible
    
  • create manageDNS.yml in Ansible working directory, containing the configuration for your DNS server, read PowerDNS documentation for further information. For example, something like:

    - hosts: localhost
      roles:
        - { role: PowerDNS.pdns }
      vars:
        pdns_config:
          daemon: yes
          master: true
          slave: false
          # local-address: # leaving this commented, so DNS will bind to any interface
          disable-axfr: yes
          log-dns-details: on
          loglevel: 3
          slave-cycle-interval: 60
          api: yes
          api-key: superSecretString
          webserver: yes
          # webserver-address: # leaving this commented, so the webserver will listen on any interface
          webserver-password: dnspwd
          # configure next line as needed: add all networks authorized to make queries
          webserver-allow-from: 127.0.0.0/16,10.200.0.0/16,192.168.209.0/24,10.3.0.0/23,193.206.158.0/23
        pdns_backends:
          gmysql:
            host: 127.0.0.1
            port: 3306
            # user/password and PowerDNS database name to create
            user: powerdns
            password: someSafePwdForMyDNS
            dbname: pdns
        pdns_mysql_databases_credentials:
          gmysql:
          # set priv_user and priv_password to your MySQL credentials
            priv_user: root
            priv_password: whateverPwdYouConfiguredForMysqlRoot
            priv_host:
              - "%"
        pdns_install_repo: "{{ pdns_auth_powerdns_repo_41 }}"
    
  • run Ansible:

    cd /home/Ansible/PowerDNS
    ansible-playbook -b -v -i inventory.yml manageDNS.yml
    

PowerDNS-Admin installation and setup

Official documentation for PowerDNS-Admin is available here: lots of useful docs also available in the wiki.

Create the MySQL database as per official instructions for setting the powerdnsadmin database up.

Install PowerDNS-Admin as per official instructions for CentOS 7 or check the relevant page in the wiki for other operating systems.

Once you have PowerDNS-Admin up and running, follow instructions in the wiki to make it a service: I opted for Systemd, other configurations are possible. With respect to the instructions above, I made just coupld of changes:

  • created powerdnsadmin and its group with command:

    useradd --system --user-group powerdnsadmin
    
  • changed ownership of the PowerDNS-Admin directory:

    chown -R powerdnsadmin.powerdnsadmin /opt/web/powerdns-admin
    

For reference, I created file config.py by copying config_template.py and modifying:

BIND_ADDRESS = '0.0.0.0'
SQLA_DB_USER = '<choose_your_DB_username>'
SQLA_DB_PASSWORD = '<choose_a_decent_password>'
SQLA_DB_HOST = 'localhost'
PDNS_STATS_URL = 'http://127.0.0.1:8081/'
PDNS_API_KEY = '<whatever_is_set_in_pdns.conf_for_api-key>'