Migration de TinyDNS vers PowerDNS

Tutoriel détaillant la migration de TinyDNS vers PowerDNS

Image d'entête " TinyDNS to PowerDNS "
Image d'entête " TinyDNS to PowerDNS "

Le pourquoi du comment

TL;DR : On a migré sur PowerDNS, c’est cool, ca tourne bien, c’est simple à mettre en place.
Moi même.

Récemment, j’ai eu le besoin pour un projet de réaliser une migration de TinyDNS vers une autre solution.

Plusieurs raisons à celà : Plateforme vieillissante, plus mises à jour, en retard techniquement ( Pas de support d’ IPv6, pas de support de DNSSEC.. ), bricolage avec des scripts maisons, RFC non respecté…

Plusieurs solutions s’offraient à nous. Du BIND, du PowerDNS, KNOT DNS… Finalement, PowerDNS a été retenu pour sa simplicité d’administration et son intégration possible avec nos outils interne ( Notamment PHPIPAM ). PowerDNS est également connu pour sa robustesse et sa capacité à gérer des milliers de zone et de requêtes / jour.

Il a également été retenu que le choix se porterait sur un PowerDNS avec un backend MySQL pour le stockage des zone. Cela nous permet une évolution / migration rapide vers un autre outil si le besoin s’en fait un jour ressentir. Ce choix est également motivé par l’utilisation de PHPIPAM comme interface pour PowerDNS. Il est également prévu de mettre en place des serveurs DNSDIST frontaux afin d’encaisser la charge, faire reverse proxy avec les DNS qui, eux, portent les zones. Ce choix permet d’isoler le WAN de la DMZ, où se trouvent les serveurs DNS et les bases de données.

Ce projet a été lancé pour 2 raisons, la mise en place de l’IPv6 ainsi qu’un crash survenu quelques mois auparavant ayant coupé nos 3 DNS durant plusieurs heures.

Sur ce projet, dés sa conception, celui-ci est prévu pour être intégralement résiliant, redondé, multisite et multiréseau.

Il faudra également penser à scripter la migration des zones ( Import ) et la modification chez les registres ( AFNIC + Gandi )

Installation de PowerDNS

Les service DNS étant des services critiques, sur des machines qui ne sont pas réinstallé régulièrement, le choix d’un OS avec un support a été fait. Nous sommes partis sur CentOS 8 Stream. Nous avons également fait le choix de partir sur les Repo de PowerDNS afin de suivre leurs évolutions dans le temp.

L’installation de CentOS n’est pas détaillé, de multiples articles existent sur ce sujet. La VM est hardené en suivant les recommande de CIS ( https://www.cisecurity.org/benchmark/centos\_linux )

Une fois installé, vous pouvez ajouter les repo de PowerDNS.

Attention !
2 choses à noter :
Le repo  » master branch  » correspond à la version développement de PowerDNS. Ne l’utilisez pas en production.
Les commandes ci dessous installent PowerDNS en version 4.8. Vérifiez si une nouvelle version n’est pas disponible sur le site de PowerDNS.

yum install epel-release &&
dnf install -y 'dnf-command(config-manager)' &&
dnf config-manager --set-enabled powertools &&
curl -o /etc/yum.repos.d/powerdns-auth-48.repo https://repo.powerdns.com/repo-files/el-auth-48.repo &&
yum install pdns

Configuration de PowerDNS

Installation de DNSDIST

Attention !
2 choses à noter :
Le repo  » master branch  » correspond à la version développement de DNSDist. Ne l’utilisez pas en production.
Les commandes ci dessous installent DNSDist en version 1.8. Vérifiez si une nouvelle version n’est pas disponible sur le site de PowerDNS.

yum install epel-release yum-plugin-priorities &&
curl -o /etc/yum.repos.d/powerdns-dnsdist-18.repo https://repo.powerdns.com/repo-files/el-dnsdist-18.repo &&
yum install dnsdist

Configuration de DNSDIST

La configuration de DNS Dist va définir le bakcend DNS à utiliser ainsi que les différent Health Check.

Il est indispensable de définir un premier port d’écoute via  « setLocal », puis ensuite d’ajouter d’autres ports ou interfaces d’écoute via un  » addLocal « . Ces information sont détaillés dans :

Il est ensuite nécessaire d’ajouter des ACL afin de permettre au clients d’interroger le DNS. Cela se fait via le paramètre  » AddACL « . Ces valeurs sont documentés ici :

DNS Dist n’étant qu’un  » proxy  » pour les requêtes DNS, il est indispensable de définir un backend qui va recevoir l’ensemble des requêtes. Dans notre cas, il s’agit de PowerDNS, mais il est possible d’intérroger n’importe quel outil DNS ( Bind, Unbound, DNSMasq… )
A travers ces backends, il est possible de définir plusieurs argumentes comme des Health Check, des poids, une limite de QPS ( Query per second ), TimeOut,…
DNS Dist propose de nombreuses options permettant une personnalisation assez poussée permettant de répondre à la majorité des besoins.

https://dnsdist.org/reference/config.html#newServer

Définir les ports d'écoutes IP v4 + IP v6

setLocal("0.0.0.0:53")
addLocal("[::]:53")

Autoriser toutes les IP à requetter le DNS IP v4 + IP v6

addACL("0.0.0.0/0")
addACL("::/0")

Définir les serveurs backends à requêter

newServer({address="IPBACKEND",name="HOSTNAME",mustResolve=true,checkName="Zone a vérifier"})
newServer({address="IPBACKEND",name="HOSTNAME",mustResolve=true,checkName="Zone a vérifier"})

Définir le cache

pc = newPacketCache(10000, {maxTTL=86400, minTTL=0, temporaryFailureTTL=60, staleTTL=60, dontAge=false})
getPool(""):setCache(pc)

Activer le serveur web pour le monitoring ( Prometheus )

webserver("127.0.0.1:8083")
setWebserverConfig({acl="127.0.0.1/32",password="My$up€rPa$$word"})
setVerboseHealthChecks(true)

Activation d’AXFR sur TinyDNS

Petite note : L’installation de TinyDNS peux varier en fonction de sa configuration.
Dans notre cas, la configuration se trouve dans le dossier /etc/axfrdns/

cd /etc/axfrdns/

Dans ce dossier, se trouve le fichier nommé  » tcp  »

cat tcp
# sample line:  1.2.3.4:allow,AXFR="heaven.af.mil/3.2.1.in-addr.arpa"
#:deny
:allow,AXFR=""

La configuration d’AXFR se fait dans ce fichier. Il est construit de cette manière :

IP à autoriser:action:AXFR=domaine1.fr/domaine2.fr

Dans notre cas, nous n’avons pas réussi à restreindre par IP, la configuration ne semble pas ajouter de filtre par IP.
Je vous recommande donc, soit de faire un DNS dédié à cet usage AXFR, soit depuis un firewall de filtrer les requêtes AXFR afin de filtrer en amont.

Pour appliquer vos modification, exécutez la commande suivante :

make
tcprules tcp.cdb tcp.tmp < tcp

Une fois fait, AXFR sera permis !

Validation du fonctionnement d’AXFR

Note : Dans cet exemple, nous allons utiliser le service zonetransfer.me pour tester.

Se connecter depuis le serveur disposant de l’IP autorisé et tester la commande suivante :

dig AXFR zonetransfer.me @IP_DU_DNS

Et voici le résultat attendu :

zonetransfer.me.	7200 IN	SOA nsztm1.digi.ninja. robin.digi.ninja. (
				2019100801 ; serial
				172800     ; refresh (2 days)
				900        ; retry (15 minutes)
				1209600    ; expire (2 weeks)
				3600       ; minimum (1 hour)
				)
zonetransfer.me.	300 IN HINFO "Casio fx-700G" "Windows XP"
zonetransfer.me.	301 IN TXT "google-site-verification=tyP28J7JAUHA9fw2sHXMgcCC0I6XBmmoVi04VlMewxA"
zonetransfer.me.	7200 IN	MX 0 ASPMX.L.GOOGLE.COM.
zonetransfer.me.	7200 IN	MX 10 ALT1.ASPMX.L.GOOGLE.COM.
zonetransfer.me.	7200 IN	MX 10 ALT2.ASPMX.L.GOOGLE.COM.
zonetransfer.me.	7200 IN	MX 20 ASPMX2.GOOGLEMAIL.COM.
zonetransfer.me.	7200 IN	MX 20 ASPMX3.GOOGLEMAIL.COM.
zonetransfer.me.	7200 IN	MX 20 ASPMX4.GOOGLEMAIL.COM.
zonetransfer.me.	7200 IN	MX 20 ASPMX5.GOOGLEMAIL.COM.
zonetransfer.me.	7200 IN	A 5.196.105.14
zonetransfer.me.	7200 IN	NS nsztm1.digi.ninja.
zonetransfer.me.	7200 IN	NS nsztm2.digi.ninja.
_acme-challenge.zonetransfer.me. 301 IN	TXT "6Oa05hbUJ9xSsvYy7pApQvwCUSSGgxvrbdizjePEsZI"
_sip._tcp.zonetransfer.me. 14000 IN SRV	0 0 5060 www.zonetransfer.me.
14.105.196.5.IN-ADDR.ARPA.zonetransfer.me. 7200	IN PTR www.zonetransfer.me.
asfdbauthdns.zonetransfer.me. 7900 IN AFSDB 1 asfdbbox.zonetransfer.me.
asfdbbox.zonetransfer.me. 7200 IN A 127.0.0.1
asfdbvolume.zonetransfer.me. 7800 IN AFSDB 1 asfdbbox.zonetransfer.me.
canberra-office.zonetransfer.me. 7200 IN A 202.14.81.230
cmdexec.zonetransfer.me. 300 IN	TXT "\; ls"
contact.zonetransfer.me. 2592000 IN TXT	"Remember to call or email Pippa on +44 123 4567890 or pippa@zonetransfer.me when making DNS changes"
dc-office.zonetransfer.me. 7200	IN A 143.228.181.132
deadbeef.zonetransfer.me. 7201 IN AAAA dead:beaf::
dr.zonetransfer.me.	300 IN LOC 53 20 56.558 N 1 38 33.526 W 0.00m 1m 10000m 10m
DZC.zonetransfer.me.	7200 IN	TXT "AbCdEfG"
email.zonetransfer.me.	2222 IN	NAPTR 1 1 "P" "E2U+email" "" email.zonetransfer.me.zonetransfer.me.
email.zonetransfer.me.	7200 IN	A 74.125.206.26
Hello.zonetransfer.me.	7200 IN	TXT "Hi to Josh and all his class"
home.zonetransfer.me.	7200 IN	A 127.0.0.1
Info.zonetransfer.me.	7200 IN	TXT "ZoneTransfer.me service provided by Robin Wood - robin@digi.ninja. See http://digi.ninja/projects/zonetransferme.php for more information."
internal.zonetransfer.me. 300 IN NS intns1.zonetransfer.me.
internal.zonetransfer.me. 300 IN NS intns2.zonetransfer.me.
intns1.zonetransfer.me.	300 IN A 81.4.108.41
intns2.zonetransfer.me.	300 IN A 167.88.42.94
office.zonetransfer.me.	7200 IN	A 4.23.39.254
ipv6actnow.org.zonetransfer.me.	7200 IN	AAAA 2001:67c:2e8:11::c100:1332
owa.zonetransfer.me.	7200 IN	A 207.46.197.32
robinwood.zonetransfer.me. 302 IN TXT "Robin Wood"
rp.zonetransfer.me.	321 IN RP robin.zonetransfer.me. robinwood.zonetransfer.me.
sip.zonetransfer.me.	3333 IN	NAPTR 2 3 "P" "E2U+sip" "!^.*$!sip:customer-service@zonetransfer.me!" .
sqli.zonetransfer.me.	300 IN TXT "' or 1=1 --"
sshock.zonetransfer.me.	7200 IN	TXT "() { :]}\; echo ShellShocked"
staging.zonetransfer.me. 7200 IN CNAME www.sydneyoperahouse.com.
alltcpportsopen.firewall.test.zonetransfer.me. 301 IN A	127.0.0.1
testing.zonetransfer.me. 301 IN	CNAME www.zonetransfer.me.
vpn.zonetransfer.me.	4000 IN	A 174.36.59.154
www.zonetransfer.me.	7200 IN	A 5.196.105.14
xss.zonetransfer.me.	300 IN TXT "'><script>alert('Boo')</script>"
zonetransfer.me.	7200 IN	SOA nsztm1.digi.ninja. robin.digi.ninja. (
				2019100801 ; serial
				172800     ; refresh (2 days)
				900        ; retry (15 minutes)
				1209600    ; expire (2 weeks)
				3600       ; minimum (1 hour)
				)

Import d’une zone grâce a PowerDNS + AXFR

Pour cet exemple, nous allons ajouter la zone en Slave dans IPAM. Nous allons également avoir besoin d’un autre serveur PowerDNS tampon en mode Slave qui permettra de récupérer la zone à travers AXFR.

https://doc.powerdns.com/authoritative/migration.html#using-axfr-to-a-slave-capable-backend

Activation de DNSSEC

TL;DR
https://www.cyres.fr/blog/qu-est-ce-que-dnssec/

Bilan

La migration de TinyDNS nous a permis de nombreuses améliorations, découvertes et modifications de nos zones.

L’aspect technique :

Nous avons pu faire évoluer une plateforme montée il y a plus d’une dizaine d’année, sans documentations d’exploitations, ne respectant pas certains standard ( développement personnalisés pour mettre des CNAME à l’apex de la zone via une conversion du CNAME en IP, support des DKIM / SRV records ). Nous avons également subi une interruption majeure de services il y a plusieurs mois suite à un SPOF non détecté, même AS sur plusieurs IP, manque de certains champs de plus en plus demandés ( CAA, AAAA), un support complet d’IP v6…

Cela nous a également permis de corriger de multiples entrées DNS ne respectant pas les standard et RFC.

Cette migration également été le point de départ d’une découverte, formation et apprentissage des prérequis et subtilités des DNS de manière poussée.

En un mot, Power DNS, c’est génial !