↓ До тексту
  1. Статті/

PowerDNS: свій авторитативний DNS на MariaDB з REST API

·6 хвилин
cat /etc/passwd
Автор
cat /etc/passwd
Технічний блог про Linux, DevOps та Open Source технології.
Зміст
Відмовостійкий DNS - частина серії статей.
Частина 1: ця стаття (ти тут)

PowerDNS - це авторитативний DNS-сервер, який зберігає зони не в текстових файлах, а в базі даних, і вміє керуватися через REST API. Це означає, що додати домен чи запис можна одним HTTP-запитом (або з вебпанелі), а дані переживуть що завгодно - бо лежать у MariaDB, а не в розкиданих db.*-файлах.

Це перша частина серії про відмовостійкий authoritative DNS. Тут ставимо базу: один сервер з MariaDB-бекендом і увімкненим API. Далі додамо реплікацію MariaDB між двома серверами, поставимо dnsdist спереду для балансування й захисту, і навчимося тримати удар, коли резолвери заливають нас запитами.

Що потрібно зробити?
#

Підняти PowerDNS на Debian, підключити бекенд MariaDB (а не BIND-файли), увімкнути REST API, створити першу зону - і показати, що записами можна керувати двома способами: класичним pdnsutil і через API одним curl. Усе налаштування записав наживо: кожен конфіг пишемо у vim на очах, щоб було видно не лише фінальний файл, а й що саме в ньому набирається.

З чим працюю?
#

1
2
root@ns1:~# cat /etc/os-release | grep PRETTY_NAME
PRETTY_NAME="Debian GNU/Linux 13 (trixie)"

Сервер - свіжа Debian 13 (trixie), усе від root. Але пакети беремо не з дистрибутива: там pdns-server версії 4.9, яка скоро отримає EOL. Натомість підключимо офіційне репо PowerDNS і поставимо 5.1 - поточну стабільну гілку. На один крок більше, зате сервер не застаріє за пів року.

У демо сервер має адресу 10.10.60.103 (приватна мережа стенду). На реальному VPS це буде публічний IP, але логіка й команди - ті самі.

Далі те саме, що в записі, тільки вже можна копіювати.

Репозиторій PowerDNS
#

Беремо ключ підпису й описуємо репо у форматі deb822. Гілка auth-51 - це PowerDNS Authoritative Server 5.1:

1
2
install -d -m 0755 /etc/apt/keyrings
curl -fsSL https://repo.powerdns.com/FD380FBB-pub.asc -o /etc/apt/keyrings/pdns-auth.asc

Файл /etc/apt/sources.list.d/pdns-auth.sources:

1
2
3
4
5
Types: deb
URIs: http://repo.powerdns.com/debian
Suites: trixie-auth-51
Components: main
Signed-By: /etc/apt/keyrings/pdns-auth.asc

І закріплюємо пріоритет за цим репо, щоб apt ніколи не підсунув старіший пакет із Debian - /etc/apt/preferences.d/pdns:

1
2
3
Package: *
Pin: origin repo.powerdns.com
Pin-Priority: 600

Встановлення
#

1
2
apt update
apt install -y pdns-server pdns-backend-mysql pdns-tools mariadb-server dnsutils jq
  • pdns-server - сам демон;
  • pdns-backend-mysql - бекенд для MySQL/MariaDB (пакет так і називається, gmysql);
  • mariadb-server - база, де житимуть зони;
  • dnsutils (для dig) і jq (щоб гарно дивитись відповіді API).

Перевіримо версію:

1
2
pdnsutil --version
# pdnsutil 5.1.4

MariaDB: база, користувач, схема
#

Створюємо базу pdns, окремого користувача й даємо йому права. На свіжій MariaDB root заходить через unix-сокет без пароля, тож mysql можна запускати одразу:

1
mysql -e "CREATE DATABASE pdns; CREATE USER 'pdns'@'localhost' IDENTIFIED BY 'надійний-пароль'; GRANT ALL ON pdns.* TO 'pdns'@'localhost';"

Замість надійний-пароль поставте свій - наприклад openssl rand -base64 18.

Бекенд pdns-backend-mysql постачає готову схему - просто вантажимо її в базу:

1
2
mysql pdns < /usr/share/pdns-backend-mysql/schema/schema.mysql.sql
mysql -e 'SHOW TABLES' pdns

З’являться таблиці domains, records, cryptokeys, domainmetadata та інші - це вся «файлова система» нашого DNS.

Конфіг pdns: бекенд gmysql
#

Debian кладе конфіги в /etc/powerdns/, а головний pdns.conf підтягує все з /etc/powerdns/pdns.d/. За замовчуванням там лежить bind.conf, який вмикає файловий BIND-бекенд - нам він не потрібен, прибираємо:

1
rm /etc/powerdns/pdns.d/bind.conf

Натомість створюємо /etc/powerdns/pdns.d/gmysql.conf:

1
2
3
4
5
6
launch=gmysql
gmysql-host=localhost
gmysql-dbname=pdns
gmysql-user=pdns
gmysql-password=надійний-пароль
gmysql-dnssec=yes

launch=gmysql каже серверу брати зони з MariaDB, а gmysql-dnssec=yes залишає можливість увімкнути DNSSEC пізніше.

API pdns
#

Тепер найцікавіше - вмикаємо REST API й вбудований вебсервер. Файл /etc/powerdns/pdns.d/api.conf:

1
2
3
4
5
6
api=yes
api-key=ваш-довгий-секретний-ключ
webserver=yes
webserver-address=0.0.0.0
webserver-port=8081
webserver-allow-from=0.0.0.0/0

⚠️ webserver-allow-from=0.0.0.0/0 відкриває API з будь-якої адреси - так можна лише в ізольованій мережі стенду. На проді звужуйте до конкретних IP (наприклад 127.0.0.1 10.0.0.0/8), а api-key генеруйте довгим: openssl rand -base64 24.

Перезапускаємо й перевіряємо, що демон живий, а API відповідає:

1
2
3
4
5
systemctl restart pdns
systemctl is-active pdns

curl -s -H 'X-API-Key: ваш-довгий-секретний-ключ' \
  http://127.0.0.1:8081/api/v1/servers/localhost | jq '{version, daemon_type}'
1
2
3
4
{
  "version": "5.1.4",
  "daemon_type": "authoritative"
}

Перша зона
#

Створимо зону й додамо запис класичним інструментом pdnsutil:

1
2
pdnsutil create-zone example.com ns1.example.com
pdnsutil add-record example.com www.example.com A 203.0.113.20

Увага, зміна в 5.x: pdnsutil add-record тепер хоче повне ім’я (www.example.com), а не відносне www. Для кореня зони вказують саму назву зони (example.com). Старий запис через @ більше не приймається.

pdnsutil пише напряму в базу - повз кеш зон, який PowerDNS 5.x тримає в пам’яті. Тому щойно створену зону сервер не віддаватиме, доки не оновити кеш:

1
2
3
pdns_control rediscover
dig +short @127.0.0.1 www.example.com
# 203.0.113.20

Керування записами через API
#

А тепер - те саме, але через API, заради якого ми його й вмикали. Спершу подивимось список зон:

1
2
3
curl -s -H 'X-API-Key: ваш-довгий-секретний-ключ' \
  http://127.0.0.1:8081/api/v1/servers/localhost/zones | jq -r '.[].name'
# example.com.

Щоб додати запис, шлемо PATCH зі списком rrsets. Зручно покласти тіло в файл rrset.json:

1
2
{"rrsets":[{"name":"api.example.com.","type":"A","ttl":3600,"changetype":"REPLACE",
  "records":[{"content":"203.0.113.99","disabled":false}]}]}
1
2
3
4
curl -s -o /dev/null -w 'HTTP %{http_code}\n' -X PATCH \
  -H 'X-API-Key: ваш-довгий-секретний-ключ' -H 'Content-Type: application/json' \
  http://127.0.0.1:8081/api/v1/servers/localhost/zones/example.com. -d @rrset.json
# HTTP 204

Різниця з pdnsutil важлива: запис через API живий одразу, без rediscover - бо запит іде через сам демон, і той оновлює свій кеш сам. Серіал зони теж підбивається автоматично.

1
2
dig +short @127.0.0.1 api.example.com
# 203.0.113.99

Саме на цьому API тримаються вебпанелі (як PowerDNS-Admin) і автоматизація: видати домен клієнту чи оновити запис можна скриптом, не чіпаючи сервер руками.

Граблі
#

  • pdnsutil add-record вимагає FQDN. У 5.x відносні імена (www, @) відкидаються з Name ... is not part of zone. Пишіть повне ім’я, корінь зони - це сама назва зони.
  • pdnsutil не бачать без rediscover. PowerDNS 5.x кешує перелік зон; зміни через pdnsutil (він пише прямо в базу) не підхоплюються, доки не pdns_control rediscover або рестарт. Зміни через API цього не потребують.
  • pdns_control ping не існує - колишня звичка перевіряти так сервер дасть Unknown command: PING. Жива перевірка - systemctl is-active pdns або запит до /api/v1/servers/localhost.
  • Не відкривайте webserver-allow-from у світ. На стенді це зручно, на проді - діра: з API-ключем можна переписати будь-яку зону.

Що далі
#

Один сервер - це вже робочий DNS, але не відмовостійкий. У наступних частинах серії:

  • реплікація MariaDB master-slave між двома серверами - щоб дані жили на обох (і щоб показати, де в нас «публічна» мережа, а де окрема «приватна» для реплікації);
  • dnsdist спереду на кожній ноді - балансування, health-check і резервний бекенд;
  • тюнинг від флуду - обмеження запитів на один IP і динамічні блоки, коли резолвери починають нас заливати.

Підсумок
#

PowerDNS дає авторитативний DNS, який не живе в текстових файлах: зони - у MariaDB, керування - через REST API, DNSSEC - однією опцією. Ми поставили свіжу 5.1 з офіційного репо, підключили базу, увімкнули API й завели першу зону двома способами. Це фундамент, на якому далі збудуємо повноцінний відмовостійкий DNS.

Відмовостійкий DNS - частина серії статей.
Частина 1: ця стаття (ти тут)

Related

Базова безпека сервера - чеклист за один вечір

Свіжий сервер в інтернеті - уже мішень, боти стукають у SSH за кілька хвилин. Збираємо базовий чеклист, що закриває більшість: окремий користувач із sudo, ключі замість паролів, строга криптографія до нуля попереджень у ssh-audit, ufw і автооновлення. Це фінал серії «Захист сервера».