Un serveur DNS-over-TLS ft. Docker, Traefik, Pi-hole, Unbound
Dans cet article nous allons voir comment créer son propre serveur DNS et comment communiquer avec celui-ci avec le protocole DNS-over-TLS. Je souhaitais également raccorder le tout à un Pi-hole permettant ainsi de bloquer les nuisances d'Internet...
Cet article a un intérêt purement démonstratif. Ce n'est pas parce que c'est faisable que vous devez le faire : utiliser un serveur DNS personnel vous rend responsable de sa sécurité, et peut vous rendre plus unique.
Préambule
Cet article n'a pas pour but de vous ré-expliquer ce qu'est un DNS (qu'est-ce que le DNS ?). Pour faire court, le DNS (Domain Name System) permet de se connecter à des machines sans utiliser leurs adresses IP directement. C'est un protocole aujourd'hui indispensable et donc critique en termes de sécurité.
Mais ce qui nous intéresse en particulier c'est effectivement le DNS-over-TLS, un protocole qui encapsule les requêtes DNS dans la couche TLS (Transport Layer Security). Vous utilisez TLS en ce moment-même, en vous connectant à mon blog avec le protocole HTTPS (HTTP + TLS). Imaginez donc la même chose, mais avec les DNS.
Aujourd'hui, on voit de moins de moins du HTTP non-sécurisé par TLS, et les navigateurs modernes commencent à marquer les sites sans HTTPS comme non-sûrs. La raison est que, sans TLS donc sans chiffrement, vos communications de votre ordinateur à la machine sont en clair et n'importe qui peut sur le chemin peut les intercepter (c'est ce qu'on appelle communément une man in the middle) voire les altérer (attaque DNS spoofing, un type de MITM).
À l'image de HTTPS, il en va de même pour le DNS : il serait bien temps de chiffrer une partie aussi sensible, non ?
Longtemps DNSCrypt (par Frank Denis & Yecheng Fu) a été une des seules solutions efficaces, mais des solutions ont été standardisées depuis, et commencent à être implémentées :
- DNS-over-TLS (DoT)
- DNS-over-HTTPS (DoH)
L'un et l'autre ont leurs avantages et inconvénients. L'avantage de DoH c'est qu'il utilise le port 443 comme HTTPS, donc il sera difficile de le filtrer contrairement au port 853 utilisé par DoT. DoT a également certains avantages techniques mais ce n'est pas le sujet de cet article.
Pour ma part, je préfère DoT car Android l'implémente nativement depuis Android Pie (9.0). C'est la feature Private DNS qui prime sur tout, même si vous avez un VPN.
Notes sur l'usage d'un VPN avec DoT (ou même DoH) :
- Idéalement, si vous utilisez un VPN de confiance qui fournit ses propres DNS sur le même serveur que le VPN, vous n'avez pas besoin de DoT car ce serait redondant (le chiffrement de vous jusqu'au VPN, incluant donc les requêtes DNS, a déjà lieu).
- Utiliser un serveur DNS custom avec un VPN peut aussi vous rendre plus unique ; mais vous pouvez utiliser ce DNS pour bloquer des domaines malicieux avec Pi-hole, ce qui est le but de l'article.
Il est aussi à noter que bien que DoT/DoH augmentent considérablement la sécurité de vos requêtes DNS, il y a encore des progrès à faire en matière de vie privée notamment avec Encrypted SNI.
Objectif
L'objectif du setup que je propose vous permettra :
- D'héberger votre propre serveur DNS récursif, avec Unbound. Un serveur DNS récursif remplace tout autre service DNS commercial en faisant le même travail : récupérer les domaines à partir des serveurs racine.
- De bloquer les nuisances courantes, avec le bien connu Pi-hole. Vous pouvez filtrer au niveau DNS les publicités, les trackers... Utile si vous voulez garder un Android rootless (préférable en sécurité).
- De chiffrer la communication entre le client (vous) et le serveur, avec Traefik et son routing TCP rendu possible depuis la v2. Traefik gère également la couche TLS et génère/renouvelle le certificat automatiquement avec Let's Encrypt.
Vous voyez, ce n'est pas si compliqué !
Motivation personnelle
Sachez d'abord qu'il existe déjà des services tels que AdGuard ou l'excellent NextDNS qui proposent du DNS-over-TLS/HTTPS en plus de bloquer des nuisances. NextDNS se rapproche d'ailleurs le plus de ce que vous obtiendrez à la fin de cet article, c'est-à-dire un Pi-hole dans le cloud.
Seulement, voilà :
- Vous devez leur faire confiance avec vos données de requêtes DNS.
- NextDNS est freemium, et limité à 300 000 requêtes/mois en gratuit.
- Tout est plus amusant quand on le fait soi-même...
Cela dit, en termes de fiabilité et de performances, AdGuard et NextDNS sont très solides et probablement resteront plus performants que votre DNS récursif personnel, pour la simple et bonne raison que des tas d'utilisateurs utilisent ces services ce qui aide à remplir leur cache ; tandis que votre petit DNS récursif devra souvent envoyer des requêtes aux serveurs DNS racines, qui sont parfois lents à répondre.
En termes de sécurité et de vie privée, au moins vous êtes sûrs que vous êtes le maître de vos données. Mais cela ne vous exempt pas de configurer rigoureusement votre serveur en matière de sécurité. Un serveur compromis est la pire intrusion possible en termes de vie privée, comparable au fait-même d'utiliser Facebook.
J'utilise ce setup depuis plus de deux semaines et j'ai "oublié" que j'utilisais mon propre serveur DNS : c'est un très bon signe !
Pré-requis
- Avoir installé Docker
- Avoir installé Compose
- Avoir configuré Traefik (un exemple)
- Avoir évidemment un nom de domaine
Routage TCP avec Traefik
Depuis sa version 2, Traefik supporte outre le routage classique HTTP/HTTPS deux nouveaux types de routage : UDP et TCP. DNS-over-TLS est un type de communication reposant sur TCP donc c'est ce dernier qui nous intéressera.
Il faut commencer d'abord par ouvrir le port 853 sur l'hôte et le mapper avec le conteneur Traefik. Dans un docker-compose, ça ressemble à ceci :
Désormais il va falloir modifier la configuration statique de Traefik pour rajouter un entrypoint
(point d'entrée) à l'image de ce que vous avez déjà pour HTTP/HTTPS, mais cette fois-ci pour DoT :
Boom, on redémarre Traefik et on constate dans la dashboard que c'est bien configuré comme il faut :
Fire up the containers!
Rien de bien compliqué, je vais vous donner les configurations que j'utilise. Mais je vous invite très fortement à vous renseigner sur chaque conteneur que vous lancez pour configurer par vous-même ou au moins, en connaissance de cause...
Pi-hole
Vous devez changer :
/mnt/docker
par l'endroit sur l'hôte où vous voulez monter.main_network
par le réseau que vous utilisez pour Traefik.- Les occurrences de
dns.domain.tld
par le domaine souhaité. - Les occurrences de
<IP DU CONTENEUR UNBOUND>
, cf. suite. - La variable d'environnement
WEBPASSWORD
. - Les labels Traefik selon votre configuration (changement de noms).
- Les middlewares Traefik que j'ai commentés car à adapter.
Pour ces derniers, je vous suggère en tous cas une authentification basique. Bien que l'accès administrateur soit verrouillé, ça évite que votre Pi-hole se retrouve listé dans shodan par exemple, et aussi que vos stats globales soient visibles par tout le monde.
Unbound
Vous devez changer :
/mnt/docker
par l'endroit sur l'hôte où vous voulez monter.<IP FIXE DU CONTENEUR>
par une IP fixe du subnet attribué àmain_network
(en cohérence avec précédemment).
Cette image d'Unbound est appréciée car elle ne tourne pas en root, est à jour, et fonctionne out-of-the-box comme DNS récursif.
En réalité, vous n'êtes pas obligé de monter ce volume, la configuration par défaut fonctionne. Mais j'ai apporté quelques modifications pour ma part :
Ces modifications permettent un gain de performance par le biais notamment d'un caching assez agressif (car oui, de base ça sera plus lent que les DNS récursifs de Cloudflare par exemple, et vous n'y pouvez rien).
J'ai apporté également quelques modifications relatives à la sécurité (dont DNSSEC). Encore une fois vous pouvez juste utiliser la configuration par défaut qui fonctionne, et bien sûr consulter la documentation officielle.
Lancement
À ce stade, vous avez simplement à faire docker-compose up -d
.
Considérations
Restreindre l'accès DNS-over-TLS
Oui, par défaut, n'importe qui avec votre domaine pourrait utiliser votre serveur DNS-over-TLS. Contrairement aux serveurs DNS classiques, les attaques par amplification ne devraient pas être un problème de toute façon. Et dans ce "tutoriel", nous avons exposé publiquement uniquement le port 853.
Toujours est-il que vous n'êtes pas forcément à l'aise à cette idée ! Malheureusement, Traefik ne propose pas des whitelists d'IP pour son mode de routage TCP (car le concept de middlewares ne s'applique vraiment qu'à son routage HTTP apparemment...).
- Une solution est de recourir à
iptables
, et c'est devenu plus simple avec Docker depuis le temps, mais j'en ferai un article à part. - Une autre solution est de se passer de Traefik et du DNS-over-TLS pour héberger un serveur WireGuard sur le même serveur que Pi-hole et Unbound. Radical (dépasse le cadre de cet article) mais ça marche aussi.
Au moins, je vous donne cette piste !
Pi-hole ne verra pas l'IP réelle
Pi-hole ne verra que l'IP de Traefik, car dans un routing TCP on ne peut pas vraiment faire usage de headers comme X-Forwarded-For
. Je suis actuellement à la recherche d'une solution à ce "problème", mais après je n'ai pas réellement besoin d'une gestion précise de mes clients donc ça ne me gêne pas plus que ça.
Utilisation & configuration
Accès à la Web UI Pi-hole
Votre interface Pi-hole sera disponible à l'adresse que vous avez configurée, dans mon exemple dns.domain.tld
.
Configurer Pi-hole
Une fois dans votre interface admin, vous n'avez pas vraiment autre chose à configurer que vos listes de blocage. Les DNS upstream sont forcés par les variables d'environnement DNS1
et DNS2
.
Concernant les listes de blocage, je vous conseille celles-ci en plus de celles activées par défaut :
Utiliser sur Android (9.0+)
Depuis Android Pie, vous pouvez utiliser DNS-over-TLS sans installer une application ou passer par une option VPN (iOS je te regarde !).
FR : Paramètres réseau > Avancé > DNS Privé
EN : Network & Internet > Advanced > Private DNS
Activez l'option et rentrez dans le champ dns.domain.tld
. Ça y est ! Si vous voyez "couldn't connect" à ce moment-là, quelque chose ne va logiquement pas ; autrement, on dirait bien que ça marche.
Utiliser sur macOS/Linux
Il est possible d'utiliser DNS-over-TLS avec stubby
. Je vous laisse vous renseigner dessus. Une fois stubby
configuré pour pointer sur dns.domain.tld
, changez vos DNS système sur 127.0.0.1
(localhost).
Utiliser sur Windows
Franchement je n'en ai aucune idée, you're on your own...
... vérifier que tout fonctionne ?
L'avantage du DNS c'est que vous verrez plus ou moins tout de suite si ça marche... ou pas. Premièrement, vous pouvez consulter l'activité DNS (blocages des nuisances y compris) dans votre Pi-hole, et également les statistiques de Unbound avec docker logs unbound
.
Outre dig
, vous pouvez vérifier que le DNS fonctionne avec ces services :
Conclusion
Si vous avez suivi cet article, félicitations, vous utilisez votre propre serveur DNS qui ne dépend que des serveurs racines et qui bloque les nuisances, et vous communiquez avec celui-ci de façon chiffrée.
Je pense avoir bien abordé le sujet, même s'il y a d'autres choses à dire évidemment.
Have fun & stay safe!