Chapitre 419 minIntermédiaire
Serveur DNS BIND 9 sous Debian 13 : zone primaire et secondaire
Par Josselyn C., prof de BTS SIO. Mis à jour le .
À la fin de ce chapitre, tu sauras
- installer BIND et configurer un serveur qui ne fait qu'autorité ;
- déclarer une zone primaire et écrire son fichier ;
- vérifier et recharger une zone avec named-checkzone et rndc ;
- monter un serveur secondaire avec des transferts signés par TSIG ;
- construire un split DNS avec les vues de BIND.
4 exercices corrigés
BIND 9 (Berkeley Internet Name Domain) est le serveur DNS libre le plus répandu sous Linux, maintenu par l'ISC ; il fait autorité pour des zones, résout pour des clients, ou les deux. Ce chapitre installe BIND 9.20 sur Debian 13 pour publier la zone publique sorbier.example depuis la DMZ, avec un serveur secondaire, des transferts signés et les commandes de contrôle. C'est l'alternative Linux au DNS de Windows Server, à connaître pour comparer les deux en épreuve.
Le projet : un serveur faisant autorité dans la DMZ
Jusqu'ici, la zone publique de Sorbier était gérée dans l'interface web de l'hébergeur. Antoine Mercier, le responsable informatique, veut la maîtriser lui-même : un serveur primaire ns1 dans la DMZ, et le serveur de l'hébergeur en secondaire. Si le site de Sorbier est coupé d'Internet, le secondaire continue de répondre pour la zone (et donc de publier le MX : les courriels attendent au lieu d'être rejetés).
| Élément | Valeur |
|---|---|
| Serveur | ns1, VM Debian 13 dans la DMZ (VLAN 60), 192.168.10.230/28, passerelle 192.168.10.238 |
| Publication | Le pare-feu redirige UDP et TCP 53 de 203.0.113.17 vers 192.168.10.230 |
| Rôle | Primaire de sorbier.example, sans récursion |
| Secondaire | dns2.hebergeur.example (198.51.100.53), qui copie la zone par transfert signé |
Installer BIND
sudo apt update
sudo apt install bind9 bind9-utils bind9-dnsutils
named -v # BIND 9.20.x (Debian 13 fournit la branche 9.20)
systemctl status named # le service s'appelle named, bind9 en est un alias
Le paquet crée l'utilisateur système bind, sous lequel le service tourne, et une configuration découpée en fichiers :
| Fichier ou dossier | Contenu |
|---|---|
/etc/bind/named.conf | Fichier principal : il inclut les trois suivants, rien d'autre |
/etc/bind/named.conf.options | Bloc options : écoute, récursion, sécurité |
/etc/bind/named.conf.local | Tes zones et tes clés |
/etc/bind/named.conf.default-zones | Zones fournies (racine, localhost, zones inverses locales) : n'y touche pas |
/var/lib/bind/ | Fichiers de zone que BIND doit pouvoir modifier : zones primaires signées, zones dynamiques |
/var/cache/bind/ | Dossier de travail : copies des zones secondaires, cache |
Les options : un serveur qui fait autorité, et rien d'autre
// /etc/bind/named.conf.options
options {
directory "/var/cache/bind";
listen-on { 127.0.0.1; 192.168.10.230; };
listen-on-v6 { none; };
// Serveur faisant autorité pour Internet : aucune récursion, pour personne
recursion no;
allow-query { any; };
// Par défaut, personne ne copie les zones ; chaque zone ouvre ce qu'il faut
allow-transfer { none; };
// Ne pas afficher la version exacte de BIND à qui la demande
version none;
};
| Directive | Rôle |
|---|---|
listen-on | Adresses sur lesquelles BIND écoute (port 53 par défaut) |
recursion no | Le serveur ne répond que pour ses zones. C'est la règle pour un serveur public : un serveur qui ferait aussi la récursion pour Internet serait un résolveur ouvert |
allow-query { any; } | Tout le monde peut interroger les zones publiques : c'est leur raison d'être |
allow-transfer { none; } | Interdit les transferts de zone, sauf exception par zone |
version none | Refuse de répondre à la question version.bind, qu'un attaquant pose pour chercher les failles connues de ta version |
Pour un résolveur interne sous BIND, ce serait l'inverse : recursion yes, et allow-recursion { 192.168.10.64/26; 192.168.10.128/27; 192.168.10.160/27; 192.168.10.208/28; 127.0.0.1; }; pour limiter la récursion aux réseaux internes. Liste les VLAN internes un par un : chez Sorbier, 192.168.10.0/24 contient aussi le VLAN des visiteurs (.0/26) et la DMZ (.224/28), qui n'ont pas à utiliser ce résolveur. La directive dnssec-validation auto; (valeur par défaut) fait valider DNSSEC par le résolveur.
Déclarer la zone primaire
// /etc/bind/named.conf.local
include "/etc/bind/transfert-sorbier.key";
zone "sorbier.example" {
type primary;
file "/var/lib/bind/db.sorbier.example";
allow-transfer { key "transfert-sorbier"; };
also-notify { 192.168.10.233; }; // le secondaire de la maquette, absent des NS
};
zone "230.10.168.192.in-addr.arpa" {
type primary;
file "/var/lib/bind/db.192.168.10.230";
};
La seconde zone est un détail utile : ns1 répond à la résolution inverse de sa propre adresse, ce que les outils de test apprécient. Elle ne sert qu'à l'intérieur ; la vraie zone inverse de 203.0.113.17 est chez le fournisseur d'accès (chapitre 2).
Les mots primary et secondary remplacent master et slave depuis BIND 9.16 ; les anciens mots sont encore acceptés, mais écris les nouveaux.
Le fichier de zone
; /var/lib/bind/db.sorbier.example
$TTL 3600
$ORIGIN sorbier.example.
@ IN SOA ns1.sorbier.example. hostmaster.sorbier.example. (
2026110301 ; serial AAAAMMJJnn
7200 ; refresh
3600 ; retry
1209600 ; expire
3600 ) ; TTL négatif
IN NS ns1.sorbier.example.
IN NS dns2.hebergeur.example.
IN MX 10 mail.sorbier.example.
IN A 203.0.113.17
IN TXT "v=spf1 mx -all"
IN CAA 0 issue "letsencrypt.org"
ns1 IN A 203.0.113.17
www IN A 203.0.113.17
suivi IN A 203.0.113.17
mail IN A 198.51.100.25
_dmarc IN TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc@sorbier.example"
; /var/lib/bind/db.192.168.10.230
$TTL 3600
@ IN SOA ns1.sorbier.example. hostmaster.sorbier.example. (
2026110301 7200 3600 1209600 3600 )
IN NS ns1.sorbier.example.
@ IN PTR ns1.sorbier.example.
Les fichiers doivent appartenir au groupe bind :
sudo chown root:bind /var/lib/bind/db.sorbier.example /var/lib/bind/db.192.168.10.230
sudo chmod 644 /var/lib/bind/db.sorbier.example /var/lib/bind/db.192.168.10.230
Vérifier avant de recharger
BIND fournit deux vérificateurs. Lance-les à chaque modification, avant tout rechargement : un serveur qui redémarre avec une erreur de syntaxe ne charge pas la zone, et tout le domaine devient introuvable.
# Syntaxe de toute la configuration (aucune sortie = aucune erreur)
sudo named-checkconf
# Contenu d'une zone
sudo named-checkzone sorbier.example /var/lib/bind/db.sorbier.example
# zone sorbier.example/IN: loaded serial 2026110301
# OK
# Recharger la configuration et toutes les zones, sans couper le service
sudo rndc reload
# Ou une seule zone, après modification de son fichier
sudo rndc reload sorbier.example
named-checkzone détecte les erreurs de syntaxe, un CNAME à côté d'autres données, un MX ou un NS qui pointe vers un nom sans adresse dans la zone, et il affiche le serial chargé : vérifie qu'il a bien augmenté.
Tester le serveur
# Depuis ns1 lui-même : la réponse doit porter le drapeau aa
dig @127.0.0.1 sorbier.example SOA +norec
dig @127.0.0.1 mail.sorbier.example A +short
# 198.51.100.25
# La récursion doit être refusée pour un nom extérieur
dig @127.0.0.1 www.service-public.fr
# status: REFUSED, et dig affiche « WARNING: recursion requested but not available »
# Un transfert sans la clé doit échouer
dig @127.0.0.1 sorbier.example AXFR
# ; Transfer failed.
Le drapeau +norec envoie une requête sans demande de récursion, comme le ferait un résolveur d'Internet : c'est la bonne façon de tester un serveur faisant autorité.
Transferts de zone sécurisés avec TSIG
TSIG (Transaction SIGnature, RFC 8945) signe chaque message entre deux serveurs avec une clé secrète partagée : le primaire n'envoie la zone qu'à qui présente la clé, et le secondaire vérifie que la zone vient bien du primaire. Générer la clé :
tsig-keygen -a hmac-sha256 transfert-sorbier | sudo tee /etc/bind/transfert-sorbier.key
sudo chown root:bind /etc/bind/transfert-sorbier.key
sudo chmod 640 /etc/bind/transfert-sorbier.key
Le fichier contient un bloc de cette forme, qui se transmet à l'hébergeur par un canal sûr (jamais par courriel en clair) :
key "transfert-sorbier" {
algorithm hmac-sha256;
secret "base64-de-32-octets-genere-par-tsig-keygen=";
};
Côté secondaire, ici une VM de ta maquette, 192.168.10.233, dans le même réseau que ns1 (l'hébergeur, lui, joint le primaire par l'adresse publique 203.0.113.17) :
// named.conf.local du secondaire
include "/etc/bind/transfert-sorbier.key";
server 192.168.10.230 {
keys { "transfert-sorbier"; };
};
zone "sorbier.example" {
type secondary;
file "/var/cache/bind/db.sorbier.example";
primaries { 192.168.10.230; };
};
Le bloc server dit au secondaire de signer avec la clé tous les messages vers le primaire. Le secondaire écrit sa copie dans /var/cache/bind/, où il a le droit d'écrire. Quand la zone change sur le primaire, BIND envoie un NOTIFY à tous les serveurs listés dans les NS de la zone (sauf lui-même) et aux adresses de also-notify : le secondaire demande aussitôt un transfert incrémental (IXFR). Le secondaire de la maquette n'est pas dans les NS publics de la zone : sans la ligne also-notify du primaire, il ne verrait les changements qu'à l'expiration du refresh du SOA.
Pour vérifier un transfert à la main, depuis le secondaire :
dig @192.168.10.230 sorbier.example AXFR -k /etc/bind/transfert-sorbier.key
sudo rndc zonestatus sorbier.example # serial chargé, prochain refresh, expiration
journalctl -u named --since "10 min ago" | grep -i transfer
Les vues : le split DNS dans un seul serveur
Une vue (view) est un jeu de zones servi à une liste de clients. Un même BIND peut ainsi répondre 192.168.10.225 aux réseaux internes et 203.0.113.17 à Internet pour suivi.sorbier.example. Chez Sorbier, le DNS interne est celui de l'annuaire, mais une PME sans Active Directory construit souvent son split DNS ainsi.
acl "reseaux-internes" { 192.168.10.64/26; 192.168.10.128/27; 192.168.10.160/27; 192.168.10.208/28; 127.0.0.1; };
view "interne" {
match-clients { "reseaux-internes"; };
recursion yes;
zone "sorbier.example" {
type primary;
file "/var/lib/bind/db.sorbier.example.interne";
};
include "/etc/bind/named.conf.default-zones";
};
view "externe" {
match-clients { any; };
recursion no;
zone "sorbier.example" {
type primary;
file "/var/lib/bind/db.sorbier.example";
allow-transfer { key "transfert-sorbier"; };
};
};
Trois règles : dès qu'une vue existe, toutes les zones doivent être dans une vue (retire l'include de named.conf.default-zones du fichier principal et place-le dans la vue interne) ; les vues sont lues dans l'ordre, la première dont match-clients correspond gagne ; et chaque vue a son propre fichier de zone, donc son propre serial à tenir.
BIND ou DNS de Windows Server ?
| Critère | DNS de Windows Server 2025 | BIND 9.20 sur Debian 13 |
|---|---|---|
| Stockage des zones | Dans l'annuaire (zones intégrées) ou en fichiers | Fichiers texte |
| Réplication | Par l'annuaire, multimaître | Primaire et secondaires, par transfert de zone (NOTIFY, IXFR, TSIG) |
| Mises à jour dynamiques | Sécurisées par Kerberos, natives pour les membres du domaine | Possibles, signées par TSIG |
| Administration | Console Gestionnaire DNS, PowerShell (DnsServer) | Fichiers, named-checkconf, rndc |
| DNSSEC | Oui (signature de zone, validation) | Oui, signature automatique avec dnssec-policy |
| Split DNS | Stratégies DNS et étendues de zone, ou zones ciblées | Vues |
| Usage type | DNS interne d'un domaine Active Directory | Serveur public faisant autorité, résolveur Linux, hébergeurs |
Le choix suit le rôle : l'annuaire impose le DNS de Windows pour la zone interne, et un serveur public en DMZ sur Linux limite la surface d'attaque (pas de compte du domaine sur une machine exposée).
Exercices
Exercice 1 sur 4 Lire une configuration Réussi À revoir
Voici l'extrait d'un named.conf.options trouvé sur un serveur public d'une autre entreprise :
options {
directory "/var/cache/bind";
recursion yes;
allow-query { any; };
allow-transfer { any; };
};
- Quels sont les deux problèmes de sécurité ?
- Quelles attaques rendent-ils possibles ?
- Corrige la configuration pour un serveur qui ne fait qu'autorité.
Voir la réponseMasquer la réponse de l'exercice 1
-
recursion yesavecallow-query { any; }: c'est un résolveur ouvert à tout Internet. Etallow-transfer { any; }laisse n'importe qui copier toutes les zones. -
Le résolveur ouvert sert de réflecteur pour des attaques par amplification (déni de service distribué contre une victime dont l'adresse est usurpée) et s'expose à l'empoisonnement de cache. Le transfert ouvert donne à un attaquant la liste complète des noms et adresses de la zone, utile pour préparer une attaque.
-
Correction :
options { directory "/var/cache/bind"; recursion no; allow-query { any; }; allow-transfer { none; }; };Puis, dans chaque zone,
allow-transfer { key "<clé TSIG>"; };pour le seul secondaire.
Tu avais trouvé ?
Exercice 2 sur 4 Ajouter un nom Réussi À revoir
Sorbier ouvre extranet.sorbier.example, publié sur 203.0.113.17 comme les autres sites.
- Écris la ligne à ajouter dans le fichier de zone, et la modification à faire dans le SOA (on est le 3 novembre 2026 et le serial actuel est
2026110301). - Donne, dans l'ordre, les commandes pour vérifier et appliquer la modification.
- Comment vérifies-tu que le secondaire a bien reçu la nouvelle version ?
Voir la réponseMasquer la réponse de l'exercice 2
-
extranet IN A 203.0.113.17(ouIN CNAME www.sorbier.example.), et le serial passe à2026110302. -
Les commandes :
sudo named-checkzone sorbier.example /var/lib/bind/db.sorbier.example sudo rndc reload sorbier.example dig @127.0.0.1 extranet.sorbier.example +norec +short -
Comparer le serial des deux serveurs :
dig @192.168.10.230 sorbier.example SOA +shortetdig @198.51.100.53 sorbier.example SOA +shortdoivent afficher2026110302. Sinon, lire les journaux du primaire (journalctl -u named) : NOTIFY envoyé ? transfert refusé ?
Tu avais trouvé ?
Exercice 3 sur 4 Le transfert qui échoue Réussi À revoir
Après la mise en place de TSIG, le secondaire ne se met plus à jour. Ses journaux contiennent : transfer of 'sorbier.example/IN' from 203.0.113.17#53: failed while receiving responses: REFUSED. Les journaux du primaire indiquent client @0x... 198.51.100.53#40211 (sorbier.example): zone transfer 'sorbier.example/AXFR/IN' denied.
- Qui refuse, et pourquoi ?
- Cite deux causes possibles côté secondaire.
- Quelle autre cause, liée au temps, produirait plutôt une erreur
BADTIME?
Voir la réponseMasquer la réponse de l'exercice 3
- C'est le primaire qui refuse : la requête de transfert ne présente pas une clé autorisée par
allow-transfer { key "transfert-sorbier"; };. - Le bloc
server 192.168.10.230 { keys { "transfert-sorbier"; }; };manque sur le secondaire (il demande le transfert sans signer), ou la clé n'a pas exactement le même nom, le même algorithme ou le même secret des deux côtés. - Un écart d'horloge de plus de 5 minutes entre les deux serveurs : la signature est jugée trop ancienne ou trop récente. La solution est NTP sur les deux serveurs.
Tu avais trouvé ?
Exercice 4 sur 4 Vue interne et vue externe Réussi À revoir
Une PME sans Active Directory a un seul serveur BIND, 192.168.50.2, pour ses postes (192.168.50.0/24) et pour Internet. Son site www.pme.example est sur 192.168.50.10, publié sur l'adresse publique 203.0.113.40.
- Pourquoi faut-il deux vues ?
- Quelle vue doit être écrite en premier, et pourquoi ?
- Quelle valeur de
recursiondans chaque vue ?
Voir la réponseMasquer la réponse de l'exercice 4
- Les postes internes doivent recevoir
192.168.50.10(pour éviter le NAT en épingle), Internet doit recevoir203.0.113.40. Un seul serveur, deux réponses : il faut deux vues, chacune avec son fichier de zone. - La vue interne d'abord, avec
match-clients { 192.168.50.0/24; 127.0.0.1; };. La vue externe amatch-clients { any; };, qui correspond à tout le monde : placée en premier, elle capterait aussi les postes internes. recursion yesdans la vue interne (les postes ont besoin de résoudre Internet),recursion nodans la vue externe (sinon le serveur devient un résolveur ouvert).
Tu avais trouvé ?