Partie A — Architecture : séparer interne et externe avec les views
A.1 Pourquoi séparer ?
Un serveur BIND en entreprise doit répondre à deux publics très différents :
| Public | Besoin | Comportement |
|---|---|---|
| Réseau interne | Résoudre les noms internes + Internet | Autoritaire + récursif |
| Internet | Résoudre uniquement vos domaines publics | Autoritaire uniquement — pas de récursion |
Sans séparation, votre serveur est un open resolver — il répond aux requêtes récursives de n'importe qui sur Internet. C'est un risque de sécurité majeur (amplification DDoS, exfiltration DNS) et une non-conformité ISO 27001.
A.2 Le concept de views dans BIND
Une view (ou « vue ») est un bloc de configuration dans BIND qui définit un comportement différent selon l'IP source du client. BIND évalue les views dans l'ordre et prend la première qui matche.
A.3 Structure des fichiers
Voici l'organisation cible des fichiers de configuration :
Arborescence/etc/bind/
├── named.conf # Point d'entrée (includes)
├── named.conf.options # ACL, options globales, logging
├── named.conf.view-internal # View interne : récursion + zones
├── named.conf.view-external # View externe : zones seulement
└── zones/
├── example.com.hosts # Fichier de zone (source unique)
├── example.fr.hosts
└── external/
├── example.com.hosts → ../example.com.hosts # Liens symboliques
└── example.fr.hosts → ../example.fr.hosts
external/ contient des liens symboliques vers les fichiers de zone. On édite un seul fichier, les deux views servent le même contenu. Si vous avez besoin de split-horizon (IPs différentes interne/externe), vous pouvez utiliser un fichier séparé pour la view external.
A.4 Le fichier named.conf principal
named.conf// named.conf — Point d'entrée avec views
// Options globales, ACL, logging
include "/etc/bind/named.conf.options";
// View interne : récursion + autoritaire (réseaux internes)
include "/etc/bind/named.conf.view-internal";
// View externe : autoritaire uniquement (Internet)
include "/etc/bind/named.conf.view-external";
A.5 Les ACL (listes de contrôle d'accès)
Définir les réseaux internes dans named.conf.options :
acl "internal-nets" {
127.0.0.0/8; // loopback
10.0.0.0/8; // RFC1918
172.16.0.0/12; // RFC1918
192.168.0.0/16; // RFC1918
// Ajoutez vos plages internes spécifiques
};
acl "secondary-ns" {
// IP de vos serveurs DNS secondaires
// Ajoutez les IPs de vos secondaires ici
};
A.6 Configuration de la view interne
named.conf.view-internalview "internal" {
match-clients { "internal-nets"; "secondary-ns"; };
recursion yes;
allow-query { any; };
allow-query-cache { "internal-nets"; };
// Zones racine et locales (indispensables pour la récursion)
zone "." { type hint; file "/usr/share/dns/root.hints"; };
zone "localhost" { type master; file "/etc/bind/db.local"; };
zone "127.in-addr.arpa" { type master; file "/etc/bind/db.127"; };
zone "0.in-addr.arpa" { type master; file "/etc/bind/db.0"; };
zone "255.in-addr.arpa" { type master; file "/etc/bind/db.255"; };
// Vos zones master
zone "example.com" {
type master;
file "example.com.hosts";
also-notify { /* IP secondaire */ };
allow-transfer { "secondary-ns"; };
};
};
A.7 Configuration de la view externe
named.conf.view-externalview "external" {
match-clients { any; }; // Tout ce qui n'est pas internal
recursion no; // ❌ Pas de récursion pour Internet
allow-query { any; };
allow-transfer { none; }; // ❌ Pas de transfert de zone
// Vos zones master (mêmes zones, fichier via lien symbolique)
zone "example.com" {
type master;
file "example.com.hosts"; // ou "external/example.com.hosts"
};
};
A.8 Créer les liens symboliques
Bash# Créer le répertoire external
mkdir -p /etc/bind/zones/external
# Créer un lien symbolique pour chaque zone
cd /etc/bind/zones
for f in *.hosts; do
[ ! -e "external/$f" ] && ln -s "/etc/bind/zones/$f" "external/$f"
done
A.9 Recharger une zone après modification
Avec les views, le rechargement change. Il faut préciser la view :
Bash# AVANT (ne fonctionne plus avec les views)
rndc reload example.com
# MAINTENANT — spécifier chaque view
rndc reload example.com IN internal
rndc reload example.com IN external
# Ou créer un script utilitaire :
cat > /usr/local/bin/dns-reload << 'EOF'
#!/bin/bash
ZONE="$1"
[ -z "$ZONE" ] && echo "Usage: dns-reload nom.de.zone" && exit 1
rndc reload "$ZONE" IN internal && echo "[internal] $ZONE rechargé"
rndc reload "$ZONE" IN external && echo "[external] $ZONE rechargé"
EOF
chmod +x /usr/local/bin/dns-reload
# Puis simplement : dns-reload example.com
'reload' failed: multiple — zone was found in multiple views. Le rndc reload sans nom de zone (reload global) fonctionne toujours.
Partie B — Sécuriser BIND
B.1 Masquer la version de BIND
Par défaut, dig @votreserveur version.bind chaos txt renvoie la version exacte de BIND. Un attaquant peut l'utiliser pour cibler des CVE spécifiques.
options {
version "none"; // Masque la version
hostname "none"; // Masque le hostname
};
B.2 Rate Limiting (RRL)
Protège contre les attaques d'amplification DNS :
named.conf.optionsoptions {
rate-limit {
responses-per-second 10;
window 5;
slip 2;
errors-per-second 5;
nxdomains-per-second 5;
};
};
B.3 Réponses minimales
named.conf.optionsoptions {
minimal-responses yes; // Réduit la taille des réponses (anti-amplification)
};
B.4 Restreindre les transferts de zone (AXFR)
named.conf.optionsoptions {
allow-transfer { none; }; // Par défaut : personne
};
// Dans chaque zone qui a un secondaire :
zone "example.com" {
allow-transfer { "secondary-ns"; };
};
B.5 Synthèse du bloc options sécurisé
named.conf.options — completoptions {
directory "/etc/bind";
listen-on { any; };
listen-on-v6 { any; };
// Sécurité
version "none";
hostname "none";
allow-transfer { none; };
minimal-responses yes;
// Récursion (désactivée globalement, activée dans la view internal)
recursion no;
// Rate limiting
rate-limit {
responses-per-second 10;
window 5;
slip 2;
errors-per-second 5;
nxdomains-per-second 5;
};
};
Partie C — Logs séparés par catégorie
C.1 Pourquoi séparer les logs ?
BIND mélange par défaut toutes les catégories dans syslog. Pour un audit de sécurité ou un dépannage, il faut pouvoir consulter indépendamment :
| Canal | Catégorie | Contenu |
|---|---|---|
security.log | security | Requêtes refusées, tentatives d'intrusion |
queries.log | queries | Toutes les requêtes DNS reçues |
bind.log | default | Fonctionnement général |
dnssec.log | dnssec | Signatures, validation, erreurs crypto |
xfer.log | xfer-in, xfer-out | Transferts de zone (AXFR/IXFR) |
C.2 Configuration complète du logging
named.conf.options — bloc logginglogging {
// Canal sécurité
channel security_info {
file "/var/log/named/security.log" versions 10 size 10m;
severity info;
print-category yes;
print-severity yes;
print-time yes;
};
// Canal requêtes
channel query_log {
file "/var/log/named/queries.log" versions 5 size 50m;
severity info;
print-category yes;
print-severity yes;
print-time yes;
};
// Canal général
channel bind_log {
file "/var/log/named/bind.log" versions 20 size 5m;
severity info;
print-category yes;
print-severity yes;
print-time yes;
};
// Canal DNSSEC
channel dnssec_log {
file "/var/log/named/dnssec.log" versions 10 size 5m;
severity debug 1;
print-category yes;
print-severity yes;
print-time yes;
};
// Canal transferts de zone
channel xfer_log {
file "/var/log/named/xfer.log" versions 10 size 5m;
severity info;
print-category yes;
print-severity yes;
print-time yes;
};
// Routage des catégories vers les canaux
category security { security_info; };
category queries { query_log; };
category default { bind_log; };
category dnssec { dnssec_log; };
category xfer-in { xfer_log; };
category xfer-out { xfer_log; };
// Réduire le bruit
category lame-servers { null; };
category delegation-only { null; };
};
C.3 Créer le répertoire et les permissions
Bash# Créer le répertoire de logs
mkdir -p /var/log/named
chown bind:bind /var/log/named
chmod 750 /var/log/named
# Vérifier la config
named-checkconf /etc/bind/named.conf
# Recharger
rndc reload
# Vérifier que les fichiers apparaissent
ls -la /var/log/named/
versions 10 size 5m signifie : conserver 10 fichiers rotés de 5 Mo max chacun. BIND gère sa propre rotation — pas besoin de configurer logrotate pour ces fichiers.
Partie D — DNSSEC : signer vos zones
D.1 Pourquoi DNSSEC ?
Sans DNSSEC, un attaquant peut falsifier les réponses DNS (DNS spoofing/poisoning) et rediriger vos utilisateurs vers un serveur malveillant. DNSSEC ajoute une signature cryptographique à chaque réponse, vérifiable par toute la chaîne de confiance (root → TLD → votre domaine).
inline-signing)D.2 Créer la politique DNSSEC
Depuis BIND 9.16+, la méthode recommandée est dnssec-policy (qui remplace auto-dnssec maintain). On utilise l'algorithme ECDSAP256SHA256 (algo 13) — moderne, performant, recommandé par l'ANSSI.
dnssec-policy "standard" {
keys {
// CSK = Combined Signing Key (KSK + ZSK en une seule clé)
csk key-directory lifetime unlimited algorithm ecdsap256sha256;
};
nsec3param iterations 0 optout no salt-length 0;
dnskey-ttl 3600;
publish-safety 1h;
retire-safety 1h;
zone-propagation-delay 300;
max-zone-ttl 86400;
parent-ds-ttl 3600;
parent-propagation-delay 1h;
};
lifetime unlimited signifie que la clé ne sera pas rotée automatiquement — un rollover manuel reste possible.
D.3 Activer DNSSEC sur une zone
Pour chaque zone, ajouter 3 lignes dans les deux views :
Dans chaque bloc zonezone "example.com" {
type master;
file "example.com.hosts"; // view internal
// file "external/example.com.hosts"; // view external
dnssec-policy "standard";
inline-signing yes;
key-directory "/etc/bind/keys";
};
Créer le répertoire de clés
Bashmkdir -p /etc/bind/keys
chown bind:bind /etc/bind/keys
chmod 750 /etc/bind/keys
# Valider et recharger
named-checkconf /etc/bind/named.conf
rndc reload
D.4 Vérifier la signature
Bash# Vérifier que les RRSIG apparaissent
dig @localhost +dnssec example.com SOA +short
# Attendu : le SOA + une ligne RRSIG
# Vérifier l'apparition du CDS (peut prendre ~25h)
dig @localhost example.com CDS +short
# Vérifier les clés générées
ls -la /etc/bind/keys/
D.5 Publier le DS chez le registrar
Une fois le CDS apparu, récupérez le DS et publiez-le chez votre registrar.
Récupérer le DS
Bash# Le CDS contient les informations du DS
dig @localhost example.com CDS +short
# Retourne : key-tag algo digest-type hash
# Ou récupérer le DNSKEY et calculer le DS
dig @localhost example.com DNSKEY +short
# Puis coller la DNSKEY dans l'interface registrar
Chez Gandi (exemple)
D.6 Valider la chaîne de confiance
Bash# Vérifier le DS chez le parent
dig DS example.com +short @8.8.8.8
# Vérifier la validation par un résolveur validant
dig +dnssec example.com SOA @1.1.1.1
# Le flag "ad" (Authenticated Data) doit être présent dans la réponse
# Analyse visuelle complète
# https://dnsviz.net/d/example.com/dnssec/
D.7 Automatiser DNSSEC sur toutes les zones
Pour déployer DNSSEC massivement (dizaines de zones), un script Python peut modifier les fichiers de configuration des views :
Bash# 1. Créer les liens symboliques manquants
cd /etc/bind/zones
for f in *.hosts; do
[ ! -e "external/$f" ] && ln -s "/etc/bind/zones/$f" "external/$f"
done
# 2. Ajouter dnssec-policy dans les views (si pas déjà présent)
# Vérifier manuellement ou avec un script qui parse les blocs zone
# et insère les 3 lignes après la ligne "file"
# 3. Valider TOUJOURS après modification
named-checkconf /etc/bind/named.conf && echo "CONFIG OK"
# 4. Recharger
rndc reload
rndc reload, BIND signe toutes les zones en arrière-plan. Pour surveiller la progression : tail -f /var/log/named/dnssec.log. Les clés apparaissent dans /etc/bind/keys/ au format Kdomaine.+013+XXXXX.key (013 = algo ECDSA).
Partie E — CAA : contrôler qui peut émettre vos certificats
E.1 Le problème
Sans enregistrement CAA, n'importe quelle autorité de certification (CA) peut émettre un certificat pour votre domaine. Un attaquant qui a compromis une CA peu scrupuleuse pourrait obtenir un certificat *.votredomaine.com parfaitement valide.
E.2 Le mécanisme CAA
L'enregistrement DNS CAA (RFC 8659) dit aux CA : « seules ces autorités ont le droit d'émettre des certificats pour ce domaine ». Toute CA conforme vérifie le CAA avant d'émettre.
E.3 Inventorier vos CA avant de configurer
letsencrypt.org alors qu'un sous-domaine utilise DigiCert.
Inventoriez d'abord les certificats émis pour votre domaine via Certificate Transparency :
Bash# Scanner les CA qui ont émis des certificats pour votre domaine
curl -s "https://crt.sh/?q=%.example.com&output=json" | \
python3 -c "
import json, sys
data = json.load(sys.stdin)
issuers = set()
for cert in data:
issuers.add(cert.get('issuer_name',''))
for i in sorted(issuers):
print(i)
"
E.4 Configurer les enregistrements CAA
Dans votre fichier de zone :
Zone file; CAA — Autorités de certification autorisées
@ IN CAA 0 issue "letsencrypt.org"
@ IN CAA 0 issue "digicert.com"
@ IN CAA 0 issue "sectigo.com"
@ IN CAA 0 iodef "mailto:securite@votredomaine.com"
| Tag | Signification |
|---|---|
issue | Autorise cette CA à émettre des certificats pour le domaine et ses sous-domaines |
issuewild | Autorise cette CA à émettre des certificats wildcard (*.domaine) |
iodef | Adresse email de notification si une CA refuse une émission à cause du CAA |
E.5 Héritage et sous-domaines
Les enregistrements CAA sont hérités vers le bas. Si example.com a un CAA issue "letsencrypt.org", alors mail.example.com hérite de cette restriction — sauf s'il a son propre CAA.
E.6 Vérifier le déploiement
Bash# Incrémenter le serial dans le fichier de zone
# Puis recharger
dns-reload example.com
# Vérifier
dig @localhost example.com CAA +short
# Attendu : 3 lignes issue + 1 ligne iodef
Partie F — Les pièges qu'on a évités pour vous
rndc reload example.com sans préciser la view échoue.
rndc reload example.com IN internal puis IN external. Ou utiliser le script dns-reload.
inline-signing, BIND utilise un fichier .signed et un journal .jnl en mémoire. L'ancien enregistrement persiste dans le cache signé.
rndc freeze example.com IN internal puis rndc thaw example.com IN internal. Si ça ne suffit pas, supprimer .signed et .jnl puis redémarrer BIND.
named-checkconf après modification. Le script doit détecter les zones déjà signées avant d'ajouter les directives.
dig NS example.com @8.8.8.8 vs dig NS example.com @votreNS.
esx-3.example.com, db-1.example.com) dans les SAN. Les logs Certificate Transparency sont publics et permanents.
named-checkconf /etc/bind/named.confVérifier une zone :
named-checkzone example.com /etc/bind/zones/example.com.hostsRecharger une zone :
dns-reload example.comRecharger tout :
rndc reloadTester DNSSEC :
dig +dnssec example.com SOA @1.1.1.1 (chercher le flag ad)Tester CAA :
dig example.com CAA +shortVisualiser DNSSEC :
https://dnsviz.net/d/example.com/dnssec/Logs DNSSEC :
tail -f /var/log/named/dnssec.logLogs sécurité :
tail -f /var/log/named/security.log