Post

⚙️🌐 Technitium DNS Server autoritatif et récursif

⚙️🌐 Technitium DNS Server autoritatif et récursif

Bloquer les publicités sur tout votre réseau, chiffrer vos requêtes DNS, héberger vos propres noms de domaine internes et même remplacer votre serveur DHCP
Technitium DNS Server tient sa promesse : un seul outil pour résoudre, bloquer, héberger ses zones et distribuer ses baux DHCP, là où d’autres solutions vous obligent à empiler plusieurs services. C’est vraiment une solution pertinente que vous pouvez utiliser comme alternative à AdGuard Home + Unbound ou Pi-Hole + Unbound, voire même les bloqueurs de publicités seuls.

Technitium DNS Server est un serveur DNS autoritatif et récursif à la fois, conçu pour le self-hosting et les réseaux d’entreprise.

  • Résoudre les noms de domaine pour tout votre réseau, soit par récursion native (en interrogeant directement les serveurs racines), soit en déléguant à un résolveur externe via différents protocoles (DNS classique, DNS-over-HTTPS, DNS-over-QUIC, etc.).
  • Bloquer les publicités et les domaines malveillants à l’échelle du réseau, à la manière de Pi-hole et AdGuard Home, grâce à des listes de blocage.
  • Héberger vos propres zones DNS (domaines internes), avec prise en charge de DNSSEC (signature et validation), des transferts de zone (AXFR/IXFR) et des mises à jour dynamiques (RFC 2136).
  • Chiffrer le trafic DNS via DNS-over-TLS (DoT), DNS-over-HTTPS (DoH) et DNS-over-QUIC (DoQ), aussi bien en entrée qu’en sortie (sauf en mode récursif pour l’externe).
  • Distribuer les adresses IP grâce à un serveur DHCP intégré
  • Synchroniser plusieurs instances via le clustering (apparu en version 14).

Côté projet : Technitium DNS Server est développé par Technitium (Shreyas Zare) et publié sous licence open source GNU GPLv3. Il est entièrement gratuit, sans édition payante.

Comparatif

Fonction Pi-hole + Unbound AdGuard Home + Unbound Technitium DNS Server
Blocage pub/malveillant Oui (Pi-hole) Oui (AdGuard Home) Oui (intégré)
Récursion native Via Unbound Via Unbound Intégrée
Serveur autoritatif (zones locales) Limité Limité Complet (DNSSEC, AXFR/IXFR)
Forwarders chiffrés DoH/DoT/DoQ Partiel DoH/DoT DoH/DoT/DoQ
Serveur DHCP Oui Oui Oui (intégré)
Mises à jour dynamiques (RFC 2136) Non Non Oui (avec TSIG)
Nombre de services à maintenir 2 2 1

Le principal argument de Technitium : une seule brique à installer, mettre à jour et superviser, là où les approches classiques en demandent deux.

Résumé:Technitium DNS Server est un serveur DNS open source (GPLv3) qui fonctionne à la fois en mode récursif (il résout lui-même depuis les serveurs racines) et autoritatif (il héberge vos zones). Il bloque les publicités au niveau DNS, prend en charge les protocoles chiffrés DoH, DoT et DoQ, signe et valide DNSSEC, embarque un serveur DHCP, et se pilote via une console web. Sur Linux, l’installation la plus pratique passe par Docker en mode réseau host.

Prérequis

  • Un serveur Linux (Debian ou Ubuntu) avec un accès sudo.
  • Docker et Docker Compose installés.
  • Une adresse IP fixe pour ce serveur. C’est cette adresse que vous distribuerez ensuite comme serveur DNS à vos clients : elle ne doit pas changer. Fixez-la via une réservation DHCP sur votre box/routeur, ou en IP statique sur l’hôte. Dans tout cet article, le serveur porte l’adresse 192.168.0.205.
  • Les ports 53 (UDP et TCP) et 5380 (TCP) disponibles sur l’hôte. Nous verrons que le port 53 est souvent déjà occupé sous Ubuntu.

Note : si votre serveur se trouve derrière un pare-feu maison (OPNsense, pfSense…), assurez-vous d’autoriser le DNS sortant en UDP et en TCP sur le port 53. La récursion native a besoin du TCP pour les réponses volumineuses (DNSSEC notamment). C’est une cause de panne fréquente, sur laquelle nous reviendrons dans la section dépannage.

Libérer le port 53

Technitium ne pourra pas démarrer tant que vous n-aurez pas libéré le port 53

Vérifier qui écoute sur le port 53 :

1
2
# Qui occupe le port 53 ?
sudo ss -ulpn | grep ':53'

unbound utilise le port 53

1
2
3
UNCONN 0      0      192.168.0.205:53         0.0.0.0:*    users:(("unbound",pid=977,fd=7))                         
UNCONN 0      0      192.168.0.205:53         0.0.0.0:*    users:(("unbound",pid=977,fd=5))                         
UNCONN 0      0      192.168.0.205:53         0.0.0.0:*    users:(("unbound",pid=977,fd=3))                         

Arrêter et désactiver Unbound

1
2
sudo systemctl stop unbound
sudo systemctl disable unbound

Installer Technitium DNS Server avec Docker

Nous allons déployer Technitium avec Docker, en mode réseau host. Vous connaissez mes habitudes, la stack sera placée dans un dossier dédié : /sharenfs/docker-app/technitium/, avec des bind mounts pour les données et les journaux, et les variables externalisées dans un fichier .env. Créer cette arborescence avec la commande mkdir :

1
2
mkdir -p /sharenfs/docker-app/technitium
mkdir -p /sharenfs/docker-app/technitium/{config,logs}

Structure

1
2
3
4
5
/sharenfs/docker-app/technitium/
├── docker-compose.yml
├── .env
├── config/            # Bind mount /etc/dns (configuration, zones, listes de blocage)
└── logs/              # Bind mount /var/log/technitium/dns (journaux)

Voici le fichier docker-compose.yml :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
services:
  technitium:
    container_name: technitium
    hostname: dns
    image: technitium/dns-server:latest
    # Mode host : indispensable pour voir les vraies IP des clients et utiliser le DHCP
    network_mode: "host"
    environment:
      - DNS_SERVER_DOMAIN=${DNS_SERVER_DOMAIN}
      - DNS_SERVER_ADMIN_PASSWORD=${DNS_SERVER_ADMIN_PASSWORD}
      - DNS_SERVER_WEB_SERVICE_LOCAL_ADDRESSES=${DNS_SERVER_WEB_SERVICE_LOCAL_ADDRESSES}
      - DNS_SERVER_ENABLE_BLOCKING=true
      - DNS_SERVER_LOG_USING_LOCAL_TIME=true
      - DNS_SERVER_LOG_FOLDER_PATH=/var/log/technitium/dns
      - TZ=Europe/Paris
    volumes:
      - ./config:/etc/dns
      - ./logs:/var/log/technitium/dns
    security_opt:
      - no-new-privileges:true
    restart: unless-stopped

Et le fichier .env à placer juste à côté :

1
2
3
4
5
6
7
8
# Nom interne par lequel le serveur s'identifie
DNS_SERVER_DOMAIN=dns.rnmkcy.eu

# Mot de passe du compte "admin" de la console web, appliqué au démarrage du conteneur.
DNS_SERVER_ADMIN_PASSWORD=VotreMotDePasseRobuste

# IP fixe du serveur : la console web (port 5380) n'écoutera QUE sur cette adresse
DNS_SERVER_WEB_SERVICE_LOCAL_ADDRESSES=192.168.0.205

Quelques explications sur les choix retenus :

  • no-new-privileges: true est compatible avec le port 53. Le conteneur démarre en root et peut donc se lier à ce port privilégié. L’option empêche seulement une élévation de privilèges ultérieure, sans gêner le service.
  • La console est associée à l’IP du LAN via DNS_SERVER_WEB_SERVICE_LOCAL_ADDRESSES. Comme nous n’exposons rien sur Internet, c’est le compromis simple et propre : vous administrez le serveur depuis votre réseau, sans que la console traîne sur d’autres interfaces. Sur un LAN de confiance, elle reste en HTTP : gardez-le en tête.
  • Bind mounts plutôt que volumes nommés : la configuration (./config) et les journaux (./logs) restent visibles sur l’hôte.
  • :latest ou version figée ? L’image :latest simplifie les mises à jour (que vous pouvez automatiser avec Watchtower ou What’s Up Docker). Si vous préférez la reproductibilité, figez une version majeure.

Pourquoi le mode host ?

Le mode host mérite une justification, car c’est un choix important. En partageant directement la pile réseau de l’hôte, Technitium voit les vraies adresses IP des clients, au lieu de ne voir que celle du bridge Docker. C’est indispensable pour :

  • Les statistiques par client dans le Dashboard,
  • Les règles de blocage et les ACL de récursion ciblées par adresse,
  • Le serveur DHCP, si vous l’activez plus tard (il a besoin d’être sur le réseau de diffusion).

C’est pour cette raison que, par rapport au modèle habituel, on ajoute network_mode: "host", on supprime tout le bloc ports: (inutile et ignoré en mode host) et on retire le sysctls présent dans le template (il ne doit pas rester en mode host, sous peine de modifier la plage de ports éphémères de l’hôte lui-même). C’est une problématique rencontrée avec tous les services comme celui-ci (évoquée dans mon article à propos d’AdGuard Home).

À savoir : en mode host, le conteneur n’obtient pas d’adresse IP propre et ne demande aucun bail DHCP. Il utilise l’IP de l’hôte. « L’IP du conteneur », c’est donc tout simplement l’IP de votre machine Docker (pour ma part 192.168.0.205).

Déployer le conteneur

Il ne reste plus qu’à lancer la stack depuis le dossier du projet :

1
2
3
4
# dossier
cd /sharenfs/docker-app/technitium
# Démarrer le conteneur en arrière-plan
docker compose up -d
1
2
3
[+] up 13/13
 ✔ Image technitium/dns-server:latest Pulled                                                                                                                                                          4.3s
 ✔ Container technitium               Started                                                                                                                                                         0.5s

Vérifier qu’il tourne

1
docker compose ps
1
2
NAME         IMAGE                          COMMAND                  SERVICE      CREATED         STATUS         PORTS
technitium   technitium/dns-server:latest   "/usr/bin/dotnet /op…"   technitium   2 minutes ago   Up 2 minutes   

Suivre les journaux (Ctrl+C pour quitter)

1
docker compose logs -f
1
2
3
4
5
6
technitium  | Technitium DNS Server was started successfully.
technitium  | Using config folder: /etc/dns
technitium  | 
technitium  | Note: Open http://dns:5380/ in web browser to access web console.
technitium  | 
technitium  | Press [CTRL + C] to stop...

Vérifions que le service DNS écoute bien sur le port 53, sur toutes les interfaces :

1
2
3
# Le service DNS doit écouter en UDP et en TCP sur 0.0.0.0:53
sudo ss -ulnp 'sport = :53 '
sudo ss -tlnp 'sport = :53 '

Technitium est le processus dotnet qui écoute directement sur 0.0.0.0:53

Première connexion à la console d’administration

Rendez-vous sur http://192.168.0.205:5380 et connectez-vous avec l’utilisateur admin et le mot de passe défini dans votre .env. Le Dashboard s’affiche : il est vide pour l’instant, c’est normal, aucune requête n’a encore transité.

Avant d’aller plus loin, un réflexe de validation utile : ouvrez l’onglet DNS Client de la console et résolvez un domaine public (par exemple yannig.net). Cet outil interroge le serveur sans dépendre de la configuration réseau de votre poste. C’est le moyen le plus rapide de confirmer que la résolution fonctionne avant de toucher au reste.

Configurer la résolution DNS

Technitium peut résoudre les noms de deux façons, et c'est ce qui lui permet de remplacer le duo AdGuard Home + Unbound.

Récursion native ou forwarders chiffrés ?

Les deux modes protègent votre vie privée, mais pas contre le même observateur :

Critère Forwarders chiffrés (DoH/DoT) Récursion native
Trafic vers le serveur en amont Chiffré (HTTPS/TLS) En clair, sur le port 53 (car les serveurs racines ne sont pas compatibles DoH/DoT)
Visibilité par le FAI Aucune Possible (port 53 en clair)
Qui voit l’ensemble de vos requêtes Un résolveur (Cloudflare, Quad9…) Personne ne voit tout
Dépendance externe Forte (confiance déplacée vers le résolveur) Faible (serveurs racines)
Levier de confidentialité Chiffrement du canal QNAME minimization + DNSSEC
  • les forwarders chiffrés rendent vos requêtes invisibles pour votre FAI, mais un résolveur unique voit alors l’intégralité de votre historique DNS.
  • La récursion native, à l’inverse, fait qu’aucun acteur ne voit l’ensemble de vos requêtes (le serveur racine n’apprend que le TLD interrogé, le serveur du TLD que le domaine de second niveau, etc.), au prix d’un trafic non chiffré vers les serveurs faisant autorité.

Configurer la récursion native

En l’absence de forwarders, Technitium résout par lui-même depuis les serveurs racines mondiaux. Pour que ce mode soit actif, dans la section Settings > Recursion, vous devez passer l’accès sur Allow recursion only for private networks. C’est indispensable pour ne pas transformer votre serveur en résolveur ouvert exploitable depuis l’extérieur (même sur un LAN non exposé, c’est mieux en termes d’hygiène informatique).

Je vous encourage également à activer l’option QNAME minimization. C’est un plus pour la confidentialité du mécanisme de récursion. Technitium n’envoie alors à chaque serveur de la chaîne que le strict nécessaire à chaque fois, sans dévoiler l’adresse à résoudre en une seule fois. Qu’est-ce que la QNAME minimization ? Normalisée par la RFC 7816, c’est une technique qui consiste à n’envoyer à chaque serveur DNS que la partie du nom dont il a besoin pour répondre. Le serveur racine est interrogé pour « .fr », le serveur .fr pour « it-connect.fr », et seul le serveur faisant autorité reçoit le nom complet. Chaque acteur en apprend ainsi le moins possible sur votre navigation.

Pour utiliser Technitium en tant que DNS récursif, vous devez veiller à ne pas déclarer de résolveur externe. Rendez-vous dans Settings > Proxy & Forwarders : laissez la liste des forwarders vide, puis enregistrez.

Bloquer les publicités et les domaines malveillants

C’est l’équivalent intégré de Pi-hole et AdGuard Home. Le blocage est déjà activé au niveau du conteneur (DNS_SERVER_ENABLE_BLOCKING=true dans notre Compose). Il reste à l’alimenter avec des listes et à choisir son comportement.

Dans Settings > Blocking, vérifiez tout de même que ce soit bien activé. Ajoutez des listes de blocage dans le champ Allow / Block List URLs. Une liste préconfigurée contient quelques références, dont les listes de Steven Black, mais vous pouvez aussi pointer vers d’autres listes (comme Red Flag Domains, par exemple).

1
2
https://raw.githubusercontent.com/StevenBlack/hosts/master/alternates/gambling/hosts
https://dl.red.flag.domains/adguard/red.flag.domains.txt

Réglez l’intervalle de mise à jour automatique des listes (Block List URL Update Interval) et choisissez le Blocking Type, c’est-à-dire la réponse renvoyée pour un domaine bloqué (voir ci-dessous). À côté des listes, Technitium propose une Blocked Zone (blocage manuel, domaine par domaine) et une Allowed Zone (liste blanche, prioritaire). Pratique pour débloquer un domaine victime d’un faux positif. Malgré la présence de listes, vous gardez la main pour gérer les exceptions.

Le Blocking Type détermine comment Technitium répond quand un domaine est bloqué. Deux approches principales, qui ne disent pas la même chose au client : retenu méthode NXDOMAIN. Pour valider le blocage, demandez un domaine connu pour être bloqué et observez la réponse (soit en mode Web ou en ligne de commande).

1
dig @192.168.0.205 doubleclick.net

C’est bien bloquée par Technitium :

Outil migration unbound technitium

Cloner outil

1
2
git clone https://github.com/danczar/unbound2technitium.git
cd ~/unbound2technitium/

Le(s) fichier(s) unbound à migrer: /etc/unbound/unbound.conf.d/local-unbound.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
server:
    # private-address définit les sous-réseaux de réseau privé sur votre infrastructure.
    # Seuls les noms ‘private-domain’ et ‘local-data’  sont autorisés à avoir ces adresses privées.
	private-address: 192.168.0.0/16
	private-address: 192.168.10.0/16
	private-address: fe80::/10
	private-address: 2a01:e0a:95a:e2f0::/64

    # Pour configurer un domaine local pour votre réseau, 
    # vous pouvez définir une zone locale dans Unbound. 
    # Cela vous permet d'accéder facilement aux applications 
    # auto-organisées sur votre réseau local.
    #
    local-zone: "home.arpa." transparent
    #local-zone: "home.arpa." static

    # IPv4 + PTR IPV4 + PTR IPV6(option)
    local-data: "cwwk.home.arpa.  86400 IN A 192.168.0.205"
    local-data-ptr: "192.168.0.205  86400 cwwk.home.arpa."
    local-data: "cwwk.home.arpa.  86400 IN AAAA 2a01:e0a:95a:e2f0:aab8:e0ff:fe04:ec45"
    local-data-ptr: "2a01:e0a:95a:e2f0:aab8:e0ff:fe04:ec45  86400 cwwk.home.arpa."

    local-data: "link.home.arpa.  86400 IN A 192.168.0.205"
    local-data-ptr: "192.168.0.205 86400 link.home.arpa."

    local-data: "lldap.home.arpa.  86400 IN A 192.168.0.205"
    local-data-ptr: "192.168.0.205 86400 lldap.home.arpa."

    local-data: "site.home.arpa.  86400 IN A 192.168.0.205"
    local-data-ptr: "192.168.0.205  86400 site.home.arpa."


    local-data: "pve.home.arpa.  86400 IN A 192.168.0.215"
    local-data-ptr: "192.168.0.215 86400 pve.home.arpa."
    local-data: "portainer.home.arpa.  86400 IN A 192.168.0.205"
    local-data-ptr: "192.168.0.205 86400 portainer.home.arpa."
    local-data: "ged.home.arpa.  86400 IN A 192.168.0.205"
    local-data-ptr: "192.168.0.205 86400 ged.home.arpa."

Test

1
2
3
python3 unbound_to_technitium.py \
    --unbound-conf /etc/unbound/unbound.conf.d/local-unbound.conf  \
    --dry-run

Migrer

1
2
3
4
python3 unbound_to_technitium.py \
    --unbound-conf /etc/unbound/unbound.conf.d/local-unbound.conf  \
    --technitium-url http://192.168.0.205:5380 \
    --username admin --password mot_de_passe_technitium

Résultat

1
2
3
4
5
6
7
8
9
10
11
INFO     Parsing: /etc/unbound/unbound.conf.d/local-unbound.conf
INFO     Authenticated with Technitium successfully
INFO       Created zone: home.arpa (Primary)
INFO       Created zone: in-addr.arpa (Primary)
WARNING    Failed to add record 205.0.168.192.in-addr.arpa PTR: {'server': 'dns.rnmkcy.eu', 'status': 'error', 'errorMessage': 'Cannot add record: record already exists.'}
WARNING    Failed to add record 205.0.168.192.in-addr.arpa PTR: {'server': 'dns.rnmkcy.eu', 'status': 'error', 'errorMessage': 'Cannot add record: record already exists.'}
WARNING    Failed to add record 205.0.168.192.in-addr.arpa PTR: {'server': 'dns.rnmkcy.eu', 'status': 'error', 'errorMessage': 'Cannot add record: record already exists.'}
WARNING    Failed to add record 205.0.168.192.in-addr.arpa PTR: {'server': 'dns.rnmkcy.eu', 'status': 'error', 'errorMessage': 'Cannot add record: record already exists.'}
WARNING    Failed to add record 205.0.168.192.in-addr.arpa PTR: {'server': 'dns.rnmkcy.eu', 'status': 'error', 'errorMessage': 'Cannot add record: record already exists.'}
INFO       Created zone: ip6.arpa (Primary)
INFO       Settings updated

Créer des zones DNS locales

Au-delà de la résolution et du blocage, Technitium peut héberger vos propres zones : c’est son rôle autoritatif. Dans un homelab, cela permet de résoudre vos machines par un nom (dns.lab.it-connect.fr) plutôt que par leur IP.

Lorsque vous créez une zone (Zones > Add Zone), Technitium propose plusieurs types. Voici à quoi ils correspondent avec ce rapide rappel sur les zones DNS :

Type de zone Rôle Exemple d’usage
Primary Zone Version principale en lecture-écriture, faisant autorité Héberger votre domaine interne de homelab
Secondary Zone Copie en lecture seule synchronisée (AXFR/IXFR) Redondance / haute disponibilité d’une zone
Stub Zone Ne contient que les serveurs de noms (NS) d’un domaine Suivre un domaine délégué sans en copier le contenu
Conditional Forwarder Zone Force la résolution d’un domaine vers des forwarders donnés Renvoyer un domaine d’entreprise vers son DNS interne (zone Active Directory, par exemple).
Secondary Conditional Forwarder Zone Forwarder conditionnel répliqué depuis un primaire Diffuser une config de forwarding centralisée
Catalog Zone Liste de zones membres pour provisionnement automatique (RFC 9432) Gérer un parc de zones sur plusieurs serveurs
Secondary Catalog Zone Consommateur d’un catalogue, crée les zones automatiquement Le secondaire qui s’abonne au catalogue
Secondary ROOT Zone (RFC 8806) Copie locale de la zone racine Garder les requêtes racine en local (vie privée + perfs)

Pour un homelab, l’essentiel du besoin tient dans la Primary Zone. Créez-en une (par exemple lab.it-connect.fr), puis ajoutez vos enregistrements (type A, nom + adresse IP).

À quoi sert le « SOA Serial Date Scheme » ?

Lors de la création d’une zone, vous verrez l’option nommée “Use SOA Serial Date Scheme”, mais à quoi sert-elle ?

Chaque zone faisant autorité possède un enregistrement SOA contenant un numéro de série qui doit augmenter à chaque modification. C’est ce numéro que les serveurs secondaires comparent pour savoir si la zone a changé et déclencher un transfert. Cette option détermine comment il est généré :

  • Décochée (par défaut) : un simple compteur entier incrémenté de 1 à chaque changement.
  • Cochée : le format daté AAAAMMJJnn (par exemple 20270722 pour la première modification du 22 juillet 2026). C’est la convention recommandée par la RFC 1912, lisible d’un coup d’œil.

home.arpa

on peut faire quelques tests

1
dig cwwk.home.arpa

1
dig -x 192.168.0.205

On a dans les 2 exemples précédents, l’indication aa(Authoritative Answer) dans les réponses. Le résolveur fait donc autorité et nous a bien servi les enregistrements configurés.

1
dig SOA home.arpa

Configurer reverse proxy nginx

Créer le fichier de configutation /etc/nginx/conf.d/dns.rnmkcy.eu.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;
    server_name dns.rnmkcy.eu;

    include /etc/nginx/conf.d/ssl-modern.inc;

    access_log /var/log/nginx/dns-access.log;
    error_log /var/log/nginx/dns-error.log;

    # DoH endpoint
    location = /dns-query {
        proxy_pass http://192.168.0.205:8053/dns-query;
        proxy_http_version 1.1;
        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_set_header X-Forwarded-Proto $scheme;
    }

    # Technitium Web UI (everything else)
    location / {
        proxy_pass http://192.168.0.205:5380;
        proxy_http_version 1.1;
        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_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Vérifier et recharger nginx

1
2
sudo nginx -t
sudo systemctl reload nginx

Modifier le paramétrage Technitium: Settings -> Web Service
HTTPS Options: ✔️Enable HTTPS
Save Settings

Lien https://dns.rnmkcy.eu

Configuration SSO pour Technitium avec Authelia OIDC

Dans cet article de blog, nous allons configurer Authelia comme fournisseur OIDC et l’utiliser pour activer l’authentification unique (SSO) dans Technitium

Etapes

  • LLDAP: Créer un utilisateur techtinium
  • Authelia:
    • Vérifier que le fournisseur OIDC est actif
    • Création client OIDC techtinium
  • Techtinium:
    • Activer SSO
    • Connexion via SSO

LLDAP - Authelia

Pour que Techtinium puisse fonctionner avec Authelia, il faut créer un utilisateur avec LLDAP qui est la base utlisée par Authelia

Ouvrir LLDAP (accès local): https://lldap.home.arpa/

  • ajouter un utilisateur nommé techtinium et son mot de passe
  • Créer le groupe authelia (si inexistant), ajouter l’utilisateur techtinium à ce groupe

Se connecter avec utilisateur nommé techtinium et son mot de passe sur https://auth.rnmkcy.eu/ Suivre la procédure pour créer une authentification à 2 facteurs TOTP

1 - Nous avons créer dans LLDAP un utilisateur techtinium qui appartient au groupe authelia 2 - Connexion avec utilisateur techtinium sur authelia https://auth.rnmkcy.eu pour ajouter une connexion via TOTP

Authelia fournisseur OIDC

Authelia - Création secret client

Authelia nous demande de définir un secret client sécurisé.

Vous pouvez en générer un via la commande suivante :

1
authelia crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986

La commande précédente renvoie 2 lignes

1
2
Random Password: -G3xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Digest: $pbkdf2-sha512xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

⚠️ Veuillez noter le mot de passe en clair (Random Password) ainsi que le hachage $pbkdf2 (Digest) du mot de passe pour une utilisation ultérieure.

Côté Technitium - Activer SSO

Administration → Sessions → Single Sign-On

  • Adresse de métadonnées: https://auth.rnmkcy.eu/.well-known/openid-configuration
  • Client ID / Secret: Authelia (Random Password)
  • Autoriser L’inscription : Allow New User Sign Up
  • Enregistrer Config

L’URI de redirect/callback est https://dns.rnmkcy.eu/sso/callback

Côté Authelia - Création client OIDC

Mettez ce qui suit à la fin de votre configuration Authelia /etc/authelia/configuration.yml :

1
2
3
4
5
6
7
8
identity_providers:
  oidc:
    [...]
    clients:
      - client_id: immich
        [...]
      - client_id: technitium

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    clients:
      - client_id: technitium
        client_name: technitium OIDC
        client_secret: '$pbkdf2-sha512$310000$IxPfnOlpxWpaikXDw.qTSg$1d6xUB2YxVzwg.d7rNF.JhESblbfSgM.nuQJWrZgyj21IGKC7LCDHtMnuLvzNmuGy9Hr3INsL02tCbqXCwHOgQ'
        public: false
        authorization_policy: 'two_factor'
        redirect_uris:
          - 'https://dns.rnmkcy.eu/sso/callback'
        scopes:
          - 'openid'
          - 'profile'
          - 'email'
        userinfo_signed_response_alg: 'none'
        token_endpoint_auth_method: 'client_secret_post'

Après avoir ajusté la configuration d’Authelia, vérifiez et redémarrez-le pour appliquer la nouvelle configuration. Inspectez activement les journaux des conteneurs pour détecter d’éventuels problèmes.

1
2
3
4
5
# en mode su
# vérification
authelia validate-config --config /etc/authelia/configuration.yml
# relancer
systemctl restart authelia

Technitium via SSO

Ouvrir le lien https://dns.rnmkcy.eu

Mise à jour dynamique des enregistrements avec une clé TSIG

Voici un usage plus avancé, qui illustre encore un peu plus l’intérêt de Technitium, qui est bien plus qu’un bloqueur de pub : les mises à jour dynamiques des enregistrements. Au lieu d’ajouter manuellement chaque enregistrement dans la console, une machine s’enregistre elle-même à son déploiement, via une mise à jour dynamique (RFC 2136) authentifiée par une clé TSIG.

Qu’est-ce que TSIG ? TSIG (Transaction SIGnature, RFC 8945) authentifie les échanges DNS à l’aide d’une clé secrète partagée et d’un HMAC. Une fois en place, TSIG signe le message (authenticité + intégrité), il ne le chiffre pas. C’est un mécanisme d’authentification, pas de confidentialité.

La configuration se fait en deux temps côté Technitium :

Tout d’abord, créez la clé TSIG via le menu Settings > TSIG. Créez une clé (nom ddns-deploy, algorithme HMAC-SHA256, Shared Secret laissé vide pour génération automatique). Notez le secret généré.

Puis, vous devez autoriser les mises à jour sur la zone en allant dans : Zones > Votre zone > Options > Zone Options > onglet Dynamic Updates (RFC 2136). Ici, choisissez Allow, puis ajoutez une politique de sécurité : la clé dynamicupdate créée précédemment, le domaine couvert (*.home.arpa - n’oubliez pas l’astérisque) et les types autorisés (A, AAAA). La clé ne pourra rien toucher d’autre : on applique ici le principe du moindre privilège.

Attention, ne choisissez pas le mode Allow sans définir une stratégie de sécurité avec une clé TSIG. Sinon, n’importe qui peut venir pousser des mises à jour dans votre zone DNS…

Côté machine déployée, vous pouvez utiliser différentes méthodes pour inscrire la machine dans le DNS : Terraform, Ansible, Cloud-init… Et même un simple script Bash pour tester. Voici un script d’exemple (et qui peut être embarqué dans un autre outil) :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
HOSTNAME="srv-passbolt"
ZONE="home.arpa"
DNS="192.168.0.205"                                 # le serveur Technitium
IP="$(hostname -I | awk '{print $1}')"     # IP primaire de la machine

# -k : fichier de clé (secret hors de la ligne de commande, voir plus bas)
nsupdate -k /etc/ddns-deploy.key <<EOF
server ${DNS}
zone ${ZONE}
#update delete ${HOSTNAME}.${ZONE}. A
update add ${HOSTNAME}.${ZONE}. 300 A ${IPV4}
update add ${HOSTNAME}.${ZONE}. 300 AAAA ${IPV6}
send
EOF

Pour que cela fonctionne, vous devez installer ce paquet :

1
sudo apt install dnsutils

Le fichier ~/.ddns-deploy.key au format BIND, à protéger en chmod 600, contient la clé au format BASE64

1
2
3
4
key "dynamicupdate" {
    algorithm hmac-sha256;
    secret "MTIzNDU2YXplcnR5MTIzNDU2";
};

On exécute le script Bash, et cela a pour effet d’inscrire la machine dans le DNS.

Côté sécurité, trois réflexes :

  • Limitez le périmètre des permissions pour les mises à jour dynamiques,
  • Créez une clé par usage et par zones (pour pouvoir en révoquer une sans tout casser),
  • Veillez à la protection du secret (fichier en 600, à minima).

Dépannage quand la résolution DNS ne fonctionne pas

Cette dernière partie de ce guide sera dédiée au dépannage. Nous appliquerons la règle suivante : diagnostiquer du serveur vers le client, en entonnoir. Tant qu’on n’a pas confirmé que Technitium répond en local, inutile de chercher côté poste de travail.

1. Le port 53 est-il en écoute ?

1
2
3
4
5
6
7
8
9
sudo ss -ulnp 'sport = :53'

# Attendu : 0.0.0.0:53 ... dotnet

State           Recv-Q           Send-Q                      Local Address:Port                     Peer Address:Port          Process
UNCONN          0                0                               127.0.0.1:53                            0.0.0.0:*              users:(("dotnet",pid=2627,fd=290))
UNCONN          0                0                          192.168.0.205:53                            0.0.0.0:*              users:(("dotnet",pid=2627,fd=256))
UNCONN          0                0                                 0.0.0.0:53                            0.0.0.0:*              users:(("dotnet",pid=2627,fd=242))
UNCONN          0                0                                    [::]:53                               [::]:*              users:(("dotnet",pid=2627,fd=244))

2. Technitium répond-il en local ?

1
dig @127.0.0.1 it-connect.fr +short

S’il répond en local mais pas depuis un autre poste, le problème est sur le chemin réseau (pare-feu, sous-réseau), pas sur Technitium.

3. L’hôte peut-il joindre un serveur racine en UDP et en TCP ?

1
2
3
4
5
# Interroger directement une racine par son IP (a.root-servers.net), en UDP
dig @198.41.0.4 fr NS +norecurse +timeout=3

# Puis en TCP
dig @198.41.0.4 fr NS +norecurse +tcp +timeout=3

Ce double test est important. Un pare-feu qui n’autorise que l’UDP/53 laissera passer les requêtes simples, mais fera échouer certaines requêtes où le TCP/53 est utilisé.

4. Le pare-feu côté client (le faux négatif nslookup)

Sous Windows, nslookup tente d’abord une résolution inverse (PTR) sur l’IP du serveur pour afficher son nom. Sans zone inverse, vous obtenez un message d’erreur… alors que la résolution directe fonctionne. Préférez PowerShell :

1
2
3
4
5
# Résolution directe, sans le bruit du reverse lookup
Resolve-DnsName -Name it-connect.fr -Server 192.168.0.205

# Joignabilité du port 53/TCP (pour écarter un blocage réseau)
Test-NetConnection 192.168.0.205 -Port 53

Technitium API

Créer un token

Depuis l’interface Web

1.Se connecter à la console Web Technitium en admin.

  1. Crée de préférence un utilisateur dédié à la synchronisation, dns-sync
  2. Donnez-lui uniquement les droits nécessaires sur la zone DNS :

    • View pour lire les enregistrements ;
    • Modify pour les créer ou modifier ;
    • Delete pour supprimer les anciennes adresses.
  3. Se connecter avec l’utilisateur. dns-sync
  4. Clique sur son nom, en haut à droite.
  5. Choisis Create API Token.
  6. Saisis le mot de passe du compte.
  7. Donne un nom au token, par exemple defined-networking-sync.
  8. Clique sur Create.
  9. Copie immédiatement le token et conserve-le dans un gestionnaire de secrets.

Le token n’est généralement affiché qu’une seule fois. La création depuis le menu utilisateur est également documentée par plusieurs intégrations Technitium.[poshac][homarr]

Export URL + Token

1
2
export TECHNITIUM_URL="https://dns.rnmkcy.eu"
export TECHNITIUM_TOKEN="le_token_copié"

Puis l’appel API doit transmettre le token ainsi :

1
2
3
4
headers: {
  Authorization: `Bearer ${TECHNITIUM_TOKEN}`,
  Accept: "application/json",
}

Technitium utilise également un endpoint de connexion /api/user/login qui retourne un token de session, mais ce token est soumis à la durée de session. Pour un script automatisé, préfère un API token permanent ou dédié plutôt qu’un token de session.[docs]

Tester le token

Teste le token avec une requête sans modification :

1
2
3
curl -i \
  -H "Authorization: Bearer ${TECHNITIUM_TOKEN}" \
  "${TECHNITIUM_URL}/api/user/whoami"

Ou teste directement la lecture de la zone :

1
2
3
4
curl -G \
  -H "Authorization: Bearer ${TECHNITIUM_TOKEN}" \
  --data-urlencode "zone=homr.arpa" \
  "${TECHNITIUM_URL}/api/zones/records/list"

Évite d’utiliser le compte admin dans le script de production : un utilisateur dns-sync limité à la zone concernée est plus sûr.### Obtenez des informations de session

Lister les sous-domaines home.arpa

1
2
3
4
curl -sS -G \
  -H "Authorization: Bearer ${TECHNITIUM_TOKEN}" \
  --data-urlencode "zone=home.arpa" \
  "${TECHNITIUM_URL}/api/zones/export"

Réponse

1
2
3
4
5
6
7
8
9
10
11
$ORIGIN home.arpa.
@                     900       IN  SOA           dns.rnmkcy.eu. hostadmin 9 900 300 604800 900
@                     14400     IN  NS            dns.rnmkcy.eu.
cwwk                  86400     IN  AAAA          2a01:e0a:95a:e2f0:aab8:e0ff:fe04:ec45
cwwk                  86400     IN  A             192.168.0.205
ged                   86400     IN  A             192.168.0.205
link                  86400     IN  A             192.168.0.205
lldap                 86400     IN  A             192.168.0.205
portainer             86400     IN  A             192.168.0.205
pve                   86400     IN  A             192.168.0.215
site                  86400     IN  A             192.168.0.205

Lister les noms DNS de la zone

1
2
3
4
5
6
7
8
9
10
curl -sS -G \
  -H "Authorization: Bearer ${TECHNITIUM_TOKEN}" \
  --data-urlencode "zone=home.arpa" \
  "${TECHNITIUM_URL}/api/zones/export" |
  awk '
    /^[[:space:]]*;/ { next }
    NF >= 2 { print $1 }
  ' |
  sed 's/\.$//' |
  sort -u

Réponse

1
2
3
4
5
6
7
8
9
@
$ORIGIN
cwwk
ged
link
lldap
portainer
pve
site
Cet article est sous licence CC BY 4.0 par l'auteur.