Dagens episode av DNS-administrasjon tar for seg installasjon av PowerDNS Authoritative Name Server og PowerDNS-Admin på Ubuntu 20.04. PowerDNS er en DNS-server skrevet i C++ og GPL-lisensiert, og kjører på så å si alle Linuxvarianter og alle andre Unix-derivater. Nyeste versjon da denne artikkelen ble skrevet er versjon 4.1.x.

Installere PowerDNS på Ubuntu 20.04

I denne delen skal vi installere og sette opp:

  • MariaDB databaseserver.
  • PowerDNS-tjenesten

Steg 1: Installere og konfigurere MariaDB databaseserver

Vi må installere en databaseserver som vil bli brukt av PowerDNS for å lagre sonefiler. Merk at man også kan bruke tekstfiler på lik linje med BIND. 

For installasjon av MariaDB på Ubuntu Server:

sudo apt update
sudo apt install mariadb-server -y

Når databaseserveren er installert og startet, opprett PowerDNS-databasen og brukerkonto i MariaDB:

$ sudo mysql -u root -p
CREATE DATABASE powerdns;

Neste steg er å opprette powerdns databasebruker og tildele rettigheter:

GRANT ALL ON powerdns.* TO 'powerdns'@'localhost' IDENTIFIED BY 'Str0ngPasswOrd';

Flush privilegiene for å oppdatere brukerinnstillingene:

FLUSH PRIVILEGES;

Bytt til powerdns-databasen for å opprette tabeller:

USE powerdns;

Opprett de nødvendige tabellene:

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,
  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);

Sjekk at tabellene ble opprettet:

MariaDB [powerdns]> show tables;
+--------------------+
| Tables_in_powerdns |
+--------------------+
| comments           |
| cryptokeys         |
| domainmetadata     |
| domains            |
| records            |
| supermasters       |
| tsigkeys           |
+--------------------+
7 rows in set (0.000 sec)

Nå har vi en database og tomme tabeller, så PowerDNS burde klare å starte basert på dette.

Steg 2: Installere PowerDNS on Ubuntu 20.04

Ubuntu 20.04 kommer med systemd-resolve som må deaktiveres, siden det lytter på port 53 og dermed vil være i konflikt med PowerDNS.

Kjør følgende kommandoer for å deaktivere resolved-tjenesten:

sudo systemctl disable systemd-resolved
sudo systemctl stop systemd-resolved

Fjern også den symlinkede /etc/resolv.conf-filen:

$ ls -lh /etc/resolv.conf 
lrwxrwxrwx 1 root root 39 Jul 24 15:50 /etc/resolv.conf -> ../run/systemd/resolve/stub-resolv.conf
$ sudo rm /etc/resolv.conf

Opprett så en ny resolv.conf-fil:

echo "nameserver 1.1.1.1" | sudo tee /etc/resolv.conf

Man kan installere PowerDNS fra standard apt-repo eller fra PowerDNS' repo. For å installere fra apt-repo, kjør:

sudo apt update 
sudo apt install pdns-server pdns-backend-mysql

For å installere fra offisielt PowerDNS-repo for Ubuntu:

# Ubuntu 20.04
echo "deb [arch=amd64] http://repo.powerdns.com/ubuntu focal-auth-master main" | sudo tee /etc/apt/sources.list.d/pdns.list

# Ubuntu 18.04
echo "deb [arch=amd64] http://repo.powerdns.com/ubuntu bionic-auth-master main" | sudo tee /etc/apt/sources.list.d/pdns.list

Importer GPG-nøkkel:

curl https://repo.powerdns.com/CBC8B383-pub.asc | sudo apt-key add -

Oppdater pakkelisten og installer PowerDNS-pakken (pdns-server) og MySQL-backend (pdns-backend-mysql).

sudo apt update
sudo apt install pdns-server pdns-backend-mysql

Sett opp PowerDNS til å bruke MySQL-backend:

Her er min MySQL-config for PowerDNS:

$ sudo vim /etc/powerdns/pdns.d/pdns.local.gmysql.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=

Restart og aktiver (enable) pdns-tjenesten:

sudo systemctl restart pdns
sudo systemctl enable pdns

Nå kan du teste PowerDNS for å se at tjenesten er i gang:

$ sudo apt install net-tools -y
$ sudo netstat -tap | grep pdns
tcp        0      0 0.0.0.0:domain          0.0.0.0:*               LISTEN      6211/pdns_server
tcp6       0      0 [::]:domain             [::]:*                  LISTEN      6211/pdns_server   

Sjekk at PowerDNS svarer korrekt:

$ dig @127.0.0.1

; <<>> DiG 9.16.1-Ubuntu <<>> @127.0.0.1
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: REFUSED, id: 14054
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;.              IN  NS

;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Wed Apr 28 11:04:57 UTC 2021
;; MSG SIZE  rcvd: 28

Installer PowerDNS-Admin på Ubuntu 20.04

PowerDNS-Admin er et PowerDNS web-interface med følgende avansert funksjonalitet:

  • Styring av mange domener
  • Domene-mal
  • Brukerhåndtering
  • Brukertilgangshåndtering basert på domene
  • Logging av brukeraktivitet
  • Lokal DB / LDAP / Active Directory-brukerautentisering
  • Støtter SAML-autentisering
  • Støtter Google OAuth-autentisering
  • Støtter Github OAuth-autentisering
  • Støtter to-faktor-autentisering (TOTP)
  • Dashboard og pdns-tjenestestatistikker
  • DynDNS 2 protokoll-støtte
  • Rediger IPv6 PTRs direkte ved hjelp av IPv6-adresser

Installer Python 3 dev-pakke:

sudo apt-get install python3-dev

Installer påkrevde pakker for å bygge python-biblioteker fra requirements.txt-fil

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

Installer Node.js

curl -sL https://deb.nodesource.com/setup_16.x | bash -
apt install -y nodejs

Installer yarn for å bygge asset-filer

curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt update -y
sudo apt install -y yarn

Checkout kildekode og opprett virtualenv:

git clone https://github.com/ngoduykhanh/PowerDNS-Admin.git /opt/web/powerdns-admin
cd /opt/web/powerdns-admin
virtualenv -p python3 flask

Output:

Already using interpreter /usr/bin/python3
Using base prefix '/usr'
New python executable in /opt/web/powerdns-admin/flask/bin/python3
Also creating executable in /opt/web/powerdns-admin/flask/bin/python
Installing setuptools, pkg_resources, pip, wheel...done.

Aktiver python3-miljøet og installer biblioteker:

source ./flask/bin/activate
pip install -r requirements.txt

Før vi kjører PowerDNS-Admin må vi sette opp database-forbindelsen:

vim ./powerdnsadmin/default_config.py

De følgende er påkrevd i oppsettet:

  • Databasetilkoblingsinformasjon
  • PNDS API service endpoint og  API key
  • Portnummer brukt
  • Biningsadresse

Kommenter ut SQLite SQLALCHEMY_DATABASE_URI-linjen og fjern kommenteringen fra MySQL-linjen:

### DATABASE CONFIG
SQLA_DB_USER = 'powerdns'
SQLA_DB_PASSWORD = 'Str0ngPasswOrd'
SQLA_DB_HOST = '127.0.0.1'
SQLA_DB_NAME = 'powerdns'
SQLALCHEMY_TRACK_MODIFICATIONS = True

### DATABASE - MySQL
SQLALCHEMY_DATABASE_URI = 'mysql://'+SQLA_DB_USER+':'+SQLA_DB_PASSWORD+'@'+SQLA_DB_HOST+'/'+SQLA_DB_NAME

Når oppsettet er ferdig, er det på tide å opprette database-schema ved å kjøre følgende kommandoer:

(flask) $ export FLASK_APP=powerdnsadmin/__init__.py
(flask)$ flask db upgrade
INFO  [alembic.runtime.migration] Context impl MySQLImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade  -> 787bdba9e147, Init DB
INFO  [alembic.runtime.migration] Running upgrade 787bdba9e147 -> 59729e468045, Add view column to setting table
INFO  [alembic.runtime.migration] Running upgrade 59729e468045 -> 1274ed462010, Change setting.value data type
INFO  [alembic.runtime.migration] Running upgrade 1274ed462010 -> 4a666113c7bb, Adding Operator Role
INFO  [alembic.runtime.migration] Running upgrade 4a666113c7bb -> 31a4ed468b18, Remove all setting in the DB
INFO  [alembic.runtime.migration] Running upgrade 31a4ed468b18 -> 654298797277, Upgrade DB Schema
INFO  [alembic.runtime.migration] Running upgrade 654298797277 -> 0fb6d23a4863, Remove user avatar
INFO  [alembic.runtime.migration] Running upgrade 0fb6d23a4863 -> 856bb94b7040, Add comment column in domain template record table
INFO  [alembic.runtime.migration] Running upgrade 856bb94b7040 -> b0fea72a3f20, Update domain serial columns type
INFO  [alembic.runtime.migration] Running upgrade b0fea72a3f20 -> 3f76448bb6de, Add user.confirmed column
INFO  [alembic.runtime.migration] Running upgrade 3f76448bb6de -> 0d3d93f1c2e0, Add domain_id to history table

Kjør deretter db migrate:

(flask)$ flask db migrate -m "Init DB"
INFO  [alembic.runtime.migration] Context impl MySQLImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.autogenerate.compare] Detected removed index 'namealgoindex' on 'tsigkeys'
INFO  [alembic.autogenerate.compare] Detected removed table 'tsigkeys'
INFO  [alembic.autogenerate.compare] Detected removed index 'domainidindex' on 'cryptokeys'
INFO  [alembic.autogenerate.compare] Detected removed table 'cryptokeys'
INFO  [alembic.autogenerate.compare] Detected removed index 'nametype_index' on 'records'
INFO  [alembic.autogenerate.compare] Detected removed table 'records'
INFO  [alembic.autogenerate.compare] Detected removed index 'domainmetadata_idx' on 'domainmetadata'
INFO  [alembic.autogenerate.compare] Detected removed table 'domainmetadata'
INFO  [alembic.autogenerate.compare] Detected removed table 'supermasters'
INFO  [alembic.autogenerate.compare] Detected removed index 'comments_name_type_idx' on 'comments'
INFO  [alembic.autogenerate.compare] Detected removed index 'comments_order_idx' on 'comments'
INFO  [alembic.autogenerate.compare] Detected removed table 'comments'
INFO  [alembic.autogenerate.compare] Detected removed index 'name_index' on 'domains'
INFO  [alembic.autogenerate.compare] Detected removed table 'domains'
INFO  [alembic.autogenerate.compare] Detected added index 'ix_history_created_on' on '['created_on']'
Generating /opt/web/powerdns-admin/migrations/versions/b84731e09a35_init_db.py ...  done

Generer asset-filer med yarn:

(flask)$ yarn install --pure-lockfile
yarn install v1.22.5
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
Done in 14.84s.

(flask)$ flask assets build
Building bundle: generated/login.js
[INFO] Building bundle: generated/login.js
Building bundle: generated/login.css
[INFO] Building bundle: generated/login.css
Building bundle: generated/main.js
[INFO] Building bundle: generated/main.js
Building bundle: generated/main.css
[INFO] Building bundle: generated/main.css

Test at PowerDNS-Admin kjører som det skal:

(flask)$ ./run.py
[INFO] * Running on http://127.0.0.1:9191/ (Press CTRL+C to quit)
[INFO] * Restarting with stat
[WARNING] * Debugger is active!
[INFO] * Debugger PIN: 466-405-858

Sett opp systemd service og Nginx

Vi skal kontrollere PowerDNS-Admin med systemd.

Opprett en service unit-fil med følgende informasjon:

$ sudo vim /etc/systemd/system/powerdns-admin.service
[Unit]
Description=PowerDNS-Admin
Requires=powerdns-admin.socket
After=network.target

[Service]
PIDFile=/run/powerdns-admin/pid
User=pdns
Group=pdns
WorkingDirectory=/opt/web/powerdns-admin
ExecStart=/opt/web/powerdns-admin/flask/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

Opprett socket-fil

$ sudo vim /etc/systemd/system/powerdns-admin.socket
[Unit]
Description=PowerDNS-Admin socket

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

[Install]
WantedBy=sockets.target

Opprett environment-fil

$ sudo vim /etc/tmpfiles.d/powerdns-admin.conf
d /run/powerdns-admin 0755 pdns pdns -

Start PowerDNS-Admin-tjenesten på nytt og sett den opp til å starte sammen med systemet:

sudo systemctl daemon-reload
sudo systemctl restart powerdns-admin
sudo systemctl enable powerdns-admin

Sett tilgangsrettigheter for scriptene:

sudo chown -R pdns:pdns /run/powerdns-admin
sudo chown -R pdns:pdns /opt/web/powerdns-admin
sudo systemctl restart powerdns-admin

Sjekk at status er "running state":

$ systemctl status powerdns-admin
● powerdns-admin.service - PowerDNS-Admin
     Loaded: loaded (/etc/systemd/system/powerdns-admin.service; enabled; vendor preset: enabled)
     Active: active (running) since Wed 2021-04-28 12:51:22 UTC; 9s ago
TriggeredBy: ● powerdns-admin.socket
   Main PID: 19574 (gunicorn)
      Tasks: 2 (limit: 4683)
     Memory: 63.3M
     CGroup: /system.slice/powerdns-admin.service
             ├─19574 /opt/web/powerdns-admin/flask/bin/python /opt/web/powerdns-admin/flask/bin/gunicorn --pid /run/powerdns-admin/pid --bind unix:/run/powerdns->
             └─19582 /opt/web/powerdns-admin/flask/bin/python /opt/web/powerdns-admin/flask/bin/gunicorn --pid /run/powerdns-admin/pid --bind unix:/run/powerdns->

Apr 28 12:51:22 ubuntu systemd[1]: Started PowerDNS-Admin.
Apr 28 12:51:22 ubuntu gunicorn[19574]: [2021-04-28 12:51:22 +0000] [19574] [INFO] Starting gunicorn 20.0.4
Apr 28 12:51:22 ubuntu gunicorn[19574]: [2021-04-28 12:51:22 +0000] [19574] [INFO] Listening at: unix:/run/powerdns-admin/socket (19574)
Apr 28 12:51:22 ubuntu gunicorn[19574]: [2021-04-28 12:51:22 +0000] [19574] [INFO] Using worker: sync
Apr 28 12:51:22 ubuntu gunicorn[19582]: [2021-04-28 12:51:22 +0000] [19582] [INFO] Booting worker with pid: 19582

Installere og sette opp Nginx for PowerDNS-Admin

Installer Nginx:

sudo apt install nginx

Sett opp Nginx:

sudo vim /etc/nginx/conf.d/powerdns-admin.conf

Lim inn følgende innhold i filen. Endre domenenavnene til dine egne:

server {
  listen *:80;
  server_name               powerdns-admin.example.com www.powerdns-admin.example.com;

  index                     index.html index.htm index.php;
  root                      /opt/web/powerdns-admin;
  access_log                /var/log/nginx/powerdns-admin.local.access.log combined;
  error_log                 /var/log/nginx/powerdns-admin.local.error.log;

  client_max_body_size              10m;
  client_body_buffer_size           128k;
  proxy_redirect                    off;
  proxy_connect_timeout             90;
  proxy_send_timeout                90;
  proxy_read_timeout                90;
  proxy_buffers                     32 4k;
  proxy_buffer_size                 8k;
  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_headers_hash_bucket_size    64;

  location ~ ^/static/  {
    include  /etc/nginx/mime.types;
    root /opt/web/powerdns-admin/powerdnsadmin;

    location ~*  \.(jpg|jpeg|png|gif)$ {
      expires 365d;
    }

    location ~* ^.+.(css|js)$ {
      expires 7d;
    }
  }

  location / {
    proxy_pass            http://unix:/run/powerdns-admin/socket;
    proxy_read_timeout    120;
    proxy_connect_timeout 120;
    proxy_redirect        off;
  }
}

Test Nginx syntax og start deretter Nginx:

$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

$ sudo systemctl restart nginx

Besøk PowerDNS-Admin web interface.

http://powerdns-admin.example.com/

Klikk “Create an account”-knappen og opprett en bruker. Den første brukeren som opprettes blir automatisk tildelt Administrator-rollen.

Når du logger inn med brukeren du nettopp opprettet, skal du se et grensesnitt som under:

Sette opp PowerDNS API

Rediger PowerDNS-configfilen og aktiver det innebygde APIet:

$ sudo vim /etc/powerdns/pdns.conf
# Sett opp som under
webserver-port=8081
api=yes
api-key=f5ee4390-6542-48c9-a2a0-e5d0bd399490 #Du kan opprette din egen api key på https://codepen.io/corenominal/pen/rxOmMJ

Start pdns-tjenesten på nytt:

sudo systemctl restart powerdns-admin

Oppgi PowerDNS API-forbindelse før PowerDNS-Admin kan be om PowerDNS-data. Dette gjøres under  Settings > PDNS

Referanser: