Howto BIND
- Installation
- Configuration
- chroot
- Rotation des logs
- ACL
- DNS primaires et secondaires
- Mise à jour dynamique
- DNSSEC
- Reverse DNS
- Monitoring
- géolocalisation
- FAQ
- journal out of sync
- ran out of space
- received control channel command ‘stop’
- Zone replica avec Bind 9.9
- Vérifier la configuration
- Forcer un transfer sur le replica
- Pas d’IPv6 ou souci d’IPv6
- master “caché”
- refresh: timeout retrying without EDNS master
- délai de transfert de zones
- Mise a jour du serial
- Configuration update-policy
- Problèmes de rafraîchissement des DNS secondaires
- Erreurs “unable to find a DNSKEY”
- Documentation : https://www.isc.org/downloads/bind/doc/bind-9-10/
- DNS et BIND : http://www.zytrax.com/books/dns/
- Rôle Ansible : https://gitea.evolix.org/evolix/ansible-roles/src/branch/stable/bind
BIND (Berkeley Internet Name Daemon) est le serveur DNS historique écrit au début des années 1980, c’est encore le plus utilisé sur Internet. Il est développé par l’ISC qui développe aussi ISC DHCP. BIND peut être à la fois serveur récursif (résoudre n’importe quel enregistrement DNS pour certaines machines) ou serveur faisant autorité (renvoyer au monde entier les enregistrements DNS d’un nom de domaine spécifique).
Installation
# apt install bind9
$ /usr/sbin/named -V
BIND 9.18.19-1~deb12u1-Debian (Extended Support Version) <id:>
running on Linux x86_64 6.1.0-13-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.55-1 (2023-09-29)
built by make with '--build=x86_64-linux-gnu' '--prefix=/usr' '--includedir=${prefix}/include' '--mandir=${prefix}/share/man' '--infodir=${prefix}/share/info' '--sysconfdir=/etc' '--localstatedir=/var' '--disable-option-checking' '--disable-silent-rules' '--libdir=${prefix}/lib/x86_64-linux-gnu' '--runstatedir=/run' '--disable-maintainer-mode' '--disable-dependency-tracking' '--libdir=/usr/lib/x86_64-linux-gnu' '--sysconfdir=/etc/bind' '--with-python=python3' '--localstatedir=/' '--enable-threads' '--enable-largefile' '--with-libtool' '--enable-shared' '--disable-static' '--with-gost=no' '--with-openssl=/usr' '--with-gssapi=yes' '--with-libidn2' '--with-json-c' '--with-lmdb=/usr' '--with-gnu-ld' '--with-maxminddb' '--with-atf=no' '--enable-ipv6' '--enable-rrl' '--enable-filter-aaaa' '--disable-native-pkcs11' '--enable-dnstap' 'build_alias=x86_64-linux-gnu' 'CFLAGS=-g -O2 -ffile-prefix-map=/build/reproducible-path/bind9-9.18.19=. -fstack-protector-strong -Wformat -Werror=format-security -fno-strict-aliasing -fno-delete-null-pointer-checks -DNO_VERSION_DATE -DDIG_SIGCHASE' 'LDFLAGS=-Wl,-z,relro -Wl,-z,now' 'CPPFLAGS=-Wdate-time -D_FORTIFY_SOURCE=2'
compiled by GCC 12.2.0
compiled with OpenSSL version: OpenSSL 3.0.10 1 Aug 2023
linked to OpenSSL version: OpenSSL 3.0.11 19 Sep 2023
compiled with libuv version: 1.44.2
linked to libuv version: 1.44.2
compiled with libnghttp2 version: 1.52.0
linked to libnghttp2 version: 1.52.0
compiled with libxml2 version: 2.9.14
linked to libxml2 version: 20914
compiled with json-c version: 0.16
linked to json-c version: 0.16
compiled with zlib version: 1.2.13
linked to zlib version: 1.2.13
linked to maxminddb version: 1.7.1
compiled with protobuf-c version: 1.4.1
linked to protobuf-c version: 1.4.1
threads support is enabled
DNSSEC algorithms: RSASHA1 NSEC3RSASHA1 RSASHA256 RSASHA512 ECDSAP256SHA256 ECDSAP384SHA384 ED25519 ED448
DS algorithms: SHA-1 SHA-256 SHA-384
HMAC algorithms: HMAC-MD5 HMAC-SHA1 HMAC-SHA224 HMAC-SHA256 HMAC-SHA384 HMAC-SHA512
TKEY mode 2 support (Diffie-Hellman): yes
TKEY mode 3 support (GSS-API): yes
default paths:
named configuration: /etc/bind/named.conf
rndc configuration: /etc/bind/rndc.conf
DNSSEC root key: /etc/bind/bind.keys
nsupdate session key: //run/named/session.key
named PID file: //run/named/named.pid
named lock file: //run/named/named.lock
geoip-directory: /usr/share/GeoIP
Sous Debian 8, l’unité systemd ne gère pas
les options dans /etc/default/bind9
, il faut corriger
l’unité en copiant :
# cp -a /lib/systemd/system/bind9.service /etc/systemd/system/
et ajuster la section [Service] :
EnvironmentFile=-/etc/default/bind9
ExecStart=/usr/sbin/named -f $OPTIONS
puis :
# systemctl daemon-reload
Configuration
Les options de BIND sont dans /etc/default/named
(/etc/default/bind9
avant Bullseye).
Fichiers de configuration :
/etc/bind
├── bind.keys
├── db.0
├── db.127
├── db.255
├── db.empty
├── db.local
├── named.conf
├── named.conf.default-zones
├── named.conf.local
├── named.conf.options
├── rndc.key
└── zones.rfc1918
serveur DNS récursif
Lorsque BIND est utilisé en serveur DNS récursif pour une ou
plusieurs machines, on conseille d’activer la résolution DNS inverse
pour les zones RFC1918 dans le fichier
/etc/bind/named.conf.local
(c’est important car de nombreux
outils vérifient les reverses DNS) :
include "/etc/bind/zones.rfc1918";
Puis ajuster les options via
/etc/bind/named.conf.options
:
options {
directory "/var/cache/bind";
version "Bingo";
auth-nxdomain no;
listen-on-v6 { ::1; };
listen-on { 127.0.0.1; };
allow-recursion { ::1; 127.0.0.1; };
};
logging {
category default { default_file; };
channel default_file {
file "/var/log/bind.log";
severity info;
};
};
Note : dans l’exemple, BIND n’écoute que pour la machine locale. Si l’on veut l’interroger avec d’autres machines, on ajustera les options
listen-*
etallow-recursion
(on pourra notamment utiliser l’ACLlocalnets
serveur DNS faisant autorité
Lorsque BIND est utilisé en serveur DNS faisant autorité, on
conseille de le sécuriser en l’enfermant dans un
chroot (c’est notamment indispensable pour la configuration
ci-dessous qui va rotater /var/log/bind_queries.log
et qui
échouera donc si Bind n’est chrooté comme conseillé).
On va ensuite configurer via le fichier
/etc/bind/named.conf.options
:
acl "foo" {
::ffff:192.0.2.21; 192.0.2.21;
2001:db8::21;
};
options {
directory "/var/cache/bind";
version "Bingo";
auth-nxdomain no;
masterfile-format text;
statistics-file "/var/run/named.stats";
listen-on-v6 { any; };
listen-on { any; };
allow-query { localhost; };
allow-recursion { localhost; };
allow-transfer { localhost; };
};
logging {
category default { default_file; };
category queries { query_logging; };
channel default_file {
file "/var/log/bind.log";
severity info;
};
channel query_logging {
file "/var/log/bind_queries.log" versions 2 size 128M;
print-category yes;
print-severity yes;
print-time yes;
};
};
On peut ensuite ajouter ses domaines pour lesquels BIND fait autorité
dans le fichier /etc/bind/named.conf.local
, par exemple
pour example.com avec un serveur replica dans l’ACL
foo :
zone "example.com" {
type master;
file "/etc/bind/db.example.com";
allow-query { any; };
allow-transfer { "foo"; };
};
Puis enfin les fichiers de zone, exemple avec un
/etc/bind/db.example.com
simple :
$TTL 1800
@ IN SOA ns1.example.net. dnsmaster.example.com. (
2017072107 ; serial
2h ; rafraichissement replica->master
1h ; en cas d'echec du refraichissement, nouvel essai
5w ; expiration des enregistrements en cache par les serveurs replica
10m ) ; TTL negatif
A 192.0.2.80
NS ns1.example.net.
NS ns2.example.org.
MX 0 .
TXT "v=spf1 -all"
www CNAME @
ftp CNAME ftp.example.net.
Note : on s’assurera que les fichiers de zone sont lisibles par l’utilisateur bind en faisant
chown bind:bind /etc/bind/db.example.com
Options de configuration
allow-query
: spécifie les adresses autorisées à faire des requêtes DNS. Par défaut, toutes les adresses sont autoriséesallow-transfer
: spécifie les adresses des serveurs replica ou clefs TSIGs autorisées à faire des requêtes AXFR (transfert de zone). Par défaut, toutes les adresses sont autorisées, il est impératif de restreindre les autorisations.allow-recursion
: spécifie les adresses autorisées à faire des requêtes DNS récursives. À restreindre impérativement également.allow-update
: spécifie les adresses ou clefs TSIGs autorisées à mettre à jour dynamiquement des informations dans leur zone. Par défaut, aucune adresse n’est autorisée.update-policy
: spécifie finnement les droit de modification des entrées pour les adresses ou clefs TSIGs autorisées via une liste d’ACL, Attention : on ne peut pas définir à la foisallow-update
etupdate-policy
. voir Configuration update-policy
chroot
Pour enfermer BIND dans une prison chroot nous utilisons le script chroot-bind.sh :
# cd /root
# wget https://gitea.evolix.org/evolix/chroot-bind/raw/branch/master/chroot-bind.sh
# sh chroot-bind.sh
Puis ajoutez -t /var/chroot-bind
dans la variable
OPTIONS du fichier /etc/default/named
(/etc/default/bind9
avant Bullseye) :
RESOLVCONF=no
OPTIONS=" -u bind -t /var/chroot-bind"
AppArmor depuis Buster (Debian 10)
AppArmor protège par défaut les chemins utilisés par la version distribuée par Debian, il faut ajouter les chemins effectivement utilisés dans le chroot.
# cat /etc/apparmor.d/local/usr.sbin.named
/var/chroot-bind/ r,
/var/chroot-bind/** r,
/var/chroot-bind/etc/bind/** rw,
/var/chroot-bind/var/** rw,
/var/chroot-bind/dev/** rw,
/var/chroot-bind/run/** rw,
/var/chroot-bind/usr/** r,
Il faut relancer apparmor et bind9 après ces ajouts.
Sinon vous aurez des erreurs
open: /etc/bind/named.conf: permission denied
et
audit: type=1400 audit(1689581621.287:26): apparmor="DENIED" operation="open" profile="/usr/sbin/named" name="/var/chroot-bind/etc/bind/named.conf" pid=3205399 comm="named" requested_mask="r" denied_mask="r" fsuid=115 ouid=115
dans /var/log/syslog
.
bind mount à partir de Bookworm (Debian 12)
Depuis Bookworm, des points de montage sont nécessaires pour un fonctionnement normal de systemd et journald (sinon l’unité systemd ne renvoie jamais de signal après un redémarrage correct).
/etc/fstab
doit contenir les lignes suivantes.
/run/systemd/journal/socket /var/chroot-bind/run/systemd/journal/socket none bind 0 0
/run/systemd/journal/stdout /var/chroot-bind/run/systemd/journal/stdout none bind 0 0
/run/systemd/notify /var/chroot-bind/run/systemd/notify none bind 0 0
Puis les points de montages doivent être créés et montés.
# mkdir -p /var/chroot-bind/run/systemd/journal
# touch /var/chroot-bind/run/systemd/{journal/s{ocket,tdout},notify}
# chown -R bind: /var/chroot-bind/run/
# systemctl daemon-reload
# mount -a
Relancer bind
Vous devez alors relancer BIND :
# systemctl restart bind9
À chaque mise à jour du paquet bind9 ou de l’une de ses dépendances (libc6, libcap2, libssl, etc.) vous devrez relancer le script chroot-bind.sh et BIND ensuite.
Problèmes de permissions avec chroot
- Si erreur :
named: chroot(): Permission denied
, vérifier que/var/chroot-bind
est en750
. - Si
/var/log/bind_queries.log
n’existe pas, il faut créer le lien symbolique :ln -s /var/chroot-bind/var/log/bind_queries.log /var/log/bind_queries.log
Rotation des logs
On utilise logrotate pour la rotation des logs.
Voici le fichier /etc/logrotate.d/bind9
que l’on utilise
pour un serveur récursif :
/var/log/bind.log {
weekly
missingok
rotate 8
create 640 bind bind
sharedscripts
postrotate
rndc reload > /dev/null
endscript
}
Pour un serveur faisant autorité, on doit préciser le path des fichiers dans le chroot :
/var/chroot-bind/var/log/bind.log {
weekly
missingok
rotate 52
create 640 bind bind
sharedscripts
postrotate
rndc reload > /dev/null
endscript
}
Note : la rotation du fichier
/var/chroot-bind/var/log/bind_queries.log
est assurée par BIND sous réserve d’avoir bien précisé l’optionversions
dans les paramètres de logging
Il est aussi possible de faire la rotation du fichier de statistique
(/var/run/named.stats
ou
/var/chroot-bind/var/run/named.stats
avec chroot) avec
logrotate:
/var/run/named/named.stats
{
rotate 7
daily
missingok
notifempty
delaycompress
compress
su bind bind
}
La rotation du fichier de statistiques n’affecte ni Munin, ni BIND.
ACL
http://www.zytrax.com/books/dns/ch7/address_match_list.html
Au sein des différentes directives allow-*
on peut
utiliser des ACLs.
Par défaut, les ACLs suivantes sont prédéfinies :
none
: aucune adresse IPany
: toutes les adresses IPlocalhost
: toutes les adresses IP de la machine (127.0.0.1 mais aussi les adresses configurées sur les différentes interfaces réseau)localnets
: tous les sous-réseaux dans lesquels la machine possède une adresse IP
On peut également définir ses propres ACLs :
acl "bar" {
::ffff:192.0.2.21; 192.0.2.21;
::ffff:192.0.2.42; 192.0.2.42;
2001:db8::21; 2001:db8::42;
};
DNS primaires et secondaires
Il est possible de répliquer la configuration des zones DNS d’un serveur DNS primaire vers plusieurs secondaires.
Cela n’empêche pas les secondaires d’être primaires pour d’autres zones.
Si l’on reprend le cas de la zone suivante sur le primaire :
zone "example.com" {
type master;
file "/etc/bind/db.example.com";
allow-query { any; };
allow-transfer { <SLAVE1_IP>; <SLAVE2_IP>; ... | "<ACL1>"; "<ACL2>"; ... };
};
Sur le secondaire, on spécifiera l’adresse IP du primaire ainsi qu’un fichier pour sauvegarder la zone en local :
zone "example.com" {
type slave;
file "/etc/bind/bak.example.com";
allow-query { any; };
masters { <MASTER_IP>; };
};
Notes :
- Attention aux IPv4 / IPv6.
- Si on édite manuellement la configuration du master (plutôt que
d’utiliser le DNS dynamique avec
nsupdate
), il faut absolument mettrerequest-ixfr no;
dans la configuration de Bind sur les secondaires (dans les options générales, ou dans un blocserver
).- Pour en savoir plus, voir la documentation de Bind.
- Pour avoir le fichier de zone en clair sur le serveur secondaire (ce
qui est pratique notamment en cas d’incident avec le serveur primaire),
il faut s’assurer d’avoir l’option
masterfile-format text;
dans la configuration de Bind.
Debugger
Pour savoir si le primaire renvoie bien la zone DNS à jour, à partir
du serveur DNS secondaire, faire une requête de transfert de
zone incrémental avec dig
:
dns-secondaire$ dig -b <IP_OUT> <DOMAIN> IXFR=1 @<PRIMARY_DNS_IP>
Options :
-b <IP_OUT>
: si on a plusieurs IPs de sortie, force bind à faire sa requête à partir deIP_OUT
.IXFR=1
: récupère les changements de la zone depuis le serial 1.
Mise à jour dynamique
La mise à jour dynamique permet de mettre à jour une zone avec des
demandes de mise à jour Dynamic Updates
envoyés par le
réseau au server autoritaire pour ajouter ou supprimer des champs ( voir
RFC2136 )
- Il n’y a plus besoin de se connecter au serveur autoritaire pour changer le fichier de zone
- La syntaxe d’une demande est vérifiée avant d’être envoyé pour éviter d’ajouter des entrées incorrectes.
- Le SOA est incrémenté automatiquement.
- Dans une zone DNSSEC, le changement est immédiatement signé.
- On peut facilement scripter ces mises à jours ( certbot par exemple )
- Important : Les directives
$INCLUDE
et$GENERATE
d’un fichier de zone ne pourront plus être utilisé. Pour conserver cette fonctionnalité, on recommande d’activer la mise à jour uniquement sur des sous domaines/zone d’une zone qui utilise ces directives (ces sous-zones seront alors incluses).
Attention : lorsqu’on active le
dynamic-update
sur une zone, il devient difficile d’éditer le fichier de zone à la main, voir màj manuelle.
Activer la mise à jour dynamique sur une zone
Pour faire la mise à jour dynamique, Bind génère un fichier de
journal .jnl
binaire du même nom que la zone, contenant
l’historique des modifications apportées à la zone. L’historique est
Note : la synchronisation avec le fichier de zone n’est pas faite en temps réel, cela se fait toutes les 15 minutes en général, on peut forcer la synchronisation avec
$ rndc sync [nom_zone]
.
Pour éviter de donner à Bind le droit d’éditer tous les fichiers dans
/etc/bind
, il est préférable de placer les fichiers de
zones mise à jour dynamique dans un dossier séparer ou bind à l’accès en
écriture, par exemple :
Attention : la zone ne doit pas contenir de directives telles que
$INCLUDE
et$GENERATE
… celles-ci seront perdues à la synchronisation avec le fichier journal
On peut alors mettre en place le fichier de zone dans ce dossier…
# déplacer le fichier de zone avec les bon droits
$ mv /etc/bind/db.example.com /etc/bind/dynamic-zones/db.example.com
$ chown bind:bind /etc/bind/dynamic-zones/db.example.com
Puis activer la mise à jour dynamique dans sa configuration :
zone "example.com" in {
type master;
file "/etc/bind/dynamic-zones/db.example.com";
allow-update { key "custom-tsig"; localhost;};
allow-transfer { key "secondary-tsig"; 192.0.2.42; localhost; };
// update-policy {
// grant custom-tsig name _acme-challenge.example.com. txt;
// };
// serial-update-method ( date | increment | unixtime );
};
allow-update
permet d’autoriser la mise à jour de toute la zone avec des IPs ou clefs TSIGs tandis queupdate-policy
permet de contrôler finement quels champs peuvent être mis à jour, voir configuration update-policyallow-transfer
pour permettre de transférer la zone, utilisé pour que le client puisse aussi récupérer la zoneserial-update-method
permet de définir le mécanisme de mise à jour du serial SOA (incrément par défaut).
Voir mise en place d’une clef tsig si besoin
On peut ensuite tester le fonctionnement en jouant nsupdate ou nsvi pour ajouter ou supprimer une entrée.
Si le nsupdate fonctionne, on peut alors vérifier avec un dig normal
ou axfr ( par exemple dig -t axfr example.com @localhost
sur le server dns) ou encore mieux, en controlant le journal.
Attention, il faut que AppArmor autorise l’écriture dans
/etc/bind/**
ou /var/chroot-bind/etc/bind/**
(cf plus bas) sinon il y aura une erreur
create: permission denied
et
AVC apparmor="DENIED" operation="mknod"
.
client nsupdate
nsupdate est utilitaire en ligne de commande interactif fournit le
paquet de bind bind9-dnsutils
sur Debian.
Celui-ci permet d’envoyer des demandes de mise à jour à un serveur dns, avec ou sans TSIGs :
# nsupdate [-y [hmac:]keyname:secret]
$ nsupdate -y hmac-sha512:happydomain:"3JtiVQEBFXtQeU/3PorKpCV7jM1bZEEzkdD1zb9emvwaBZFSgYxOXV41OdSeeHb5dcud+SvNo47jEf5yRwfSkQ=="
> server <adresse_server> [port]
> zone example.com
> update add www.example.com. 172800 IN A 192.168.254.7
> send
>
Une réponse vide après send indique que la mise à jour à eu lieu. Sinon un code d’erreur sera affiché, par exemple
update failed: SERVFAIL
.
Le manuel contient plusieurs exemples.
nsdiff
Documentation : https://dotat.at/prog/nsdiff/
nsdiff est outil permettant de faciliter l’utilisation de nsupdate avec différents utilitaires:
- nsdiff : comme son nom l’indique, permet de voir la diff entre une
ancienne et une nouvelle vertsion de la zone, sa sortie peut directement
etre fournie à nsupdate :
nsdiff | nsupdate
- nspatch : joue
nsdiff | nsupdate
et n’affiche rien s’il n’y a pas d’erreur, utile dans un CRON - nsvi : fait un transfert de zone, ouvre la zone dans vi (ou un autre
editeur) et envoie les mise à jour avec
nsdiff | nsupdate
Remarque : les enregistrements dnssec sont retirés avant de passer la zone à l’éditeur et il n’y a pas besoin de s’occuper du SOA
Exemples d’utilisations (WIP) :
# editer une zone dynamique sur le serveur dns ... (avec localhost dans allow-update)
# nsvi example.com
# editer une zone dynamique avec la clef tsig associée
Contrôler le journal d’une zone
On peut vérifier le contenu du journal
# voir les changement dans le fichier de journal .jnl
$ named-journalprint [fichier_zone_jnl]
# si il y a des changement, on peut les synchroniser et vider le journal
$ rndc sync -clean example.com
Mise à jour manuelle de la zone
Il est possible de mettre à jour le fichier de zone directement, mais ce n’est pas recommandé, car on va devoir temporairement désactiver la mise à jour dynamique “freeze”.
Avant cela, il est préférable de vérifier l’état du journal et de la vider ( voir contrôler le journal )
# désactiver la mise à jour dynamique
$ rndc freeze [nom_zone]
# Modification manuelle de la zone avec vim ou autre
$ named-checkzone <nom_zone> <fichier_de_zone>
$ rndc unfreeze [nom_zone]
$ rndc reload [nom_zone]
Comme cela est compliqué et risqué, il est préférable d’utiliser un outil comme nsdiff avec nsvi qui va nous permettre d’éditer la zone comme si on l’édite à la main, mais va envoyer les changements par demande de mise à jour, voir nsdiff.
Mise en place de clefs TSIGs
On peut utiliser nsupdate, ou n’importe quel client, pour mettre à jour la zone en s’authentifiant avec une clef TSIG. Pour mettre celle-ci en place, il faut …
Générer une clef TSIG avec tsig-keygen si disponible ou avec dnssec-keygen sinon
Ajouter celle-ci à la configuration de bind…
$ vim /etc/bind/named.conf.tsigkeys
key "happydomain" {
algorithm HMAC-SHA512;
secret "3JtiVQEBFXtQeU/3PorKpCV7jM1bZEEzkdD1zb9emvwaBZFSgYxOXV41OdSeeHb5dcud+SvNo47jEf5yRwfSkQ==";
};
Ne pas oublier d’inclure named.conf.tsigkeys dans
/etc/bind/named.conf
On peut maintenant recharger la configuration et vérifier que notre clef est bien présente:
DNSSEC
Ajouter la gestion DNSSEC
Créer le répertoire /etc/bind/dnssec/db.$domain
(qui
servira aussi à conserver les clefs et fichiers de zones dynamiques) et
y déplacer le fichier de zone (un lien symbolique depuis son emplacement
précédent permet de continuer à pouvoir l’éditer comme avant). Prendre
garde à ce que tous les fichiers et répertoires appartiennent bien à
bind.
# sudo -u bind mkdir -p /etc/bind/dnssec/$domain
# mv /etc/bind/db.$domain /etc/bind/dnssec/$domain/
# ln -s dnssec/$domain/db.$domain /etc/bind/
Mettre en place une paire de clefs de zone (ZSK) et de signature (KSK)
# cd /etc/bind/dnssec/$domain
# sudo -u bind dnssec-keygen -a ECDSAP256SHA256 -n ZONE $domain
# sudo -u bind dnssec-keygen -a ECDSAP256SHA256 -n ZONE -f KSK $domain
Modifier le fichier de zone dans
/etc/bind/named.conf.local
pour ajouter les trois dernières
options suivantes (et modifier le chemin vers le fichier de zone).
zone "$domain" {
type master;
file "/etc/bind/dnssec/$domain/db.$domain";
allow-query { any; };
allow-transfer { "foo"; };
inline-signing yes;
auto-dnssec maintain;
key-directory "/etc/bind/dnssec/$domain";
};
Puis recharger la configuration de bind et la zone sera automatiquement signé.
# systemctl reload bind9
NSEC3 peut être ajouté à la zone signée.
# rndc signing -nsec3param 1 0 10 `cat /dev/urandom | tr -dc 'A-F0-9' | fold -w 8 | head -n 1` $domain
Modification de la zone
Attention le serial de la zone signée et du fichier original non signé peuvent différer (mise à jour dynamique).
Deux commandes pour savoir où en est le serial :
$ host -t soa $domain 127.0.0.1
# named-compilezone -j -i none -f raw -F text -o - $domain $domain.signed
Une fois le bon serial récupéré on peut modifier la zone en incrémentant le serial trouvé.
# Modifier le domaine example.org
domain=example.org
# Vérification du SOA pour le mettre à jour dans le fichier.
host -t soa $domain
# Arrêt (gel) de la mise à jour dynamique
rndc freeze $domain
# Mise à jour de la zone en pensant au SOA.
vim /etc/bind/db.$domain
# Vérification de la configuration.
named-checkzone $domain /etc/bind/db.$domain
named-checkconf
# Relance de la mise à jour dynamique
rndc thaw $domain
La zone sera automatiquement resigné.
Rotation de la ZSK
On génère une nouvelle clé comme vu plus haut.
Le temps d’inactivation de l’ancienne clé ainsi que la date de suppression doit être indiqué.
# La clé doit être retirée dans 2 jours
dnssec-settime -I +2d OLD_ZSK.key
# La clé doit être supprimée dans 6 jours
dnssec-settime -D +6d Kexample.tld.+008+25266.key
Bind fera tout seul la prébublication et le rollover.
Les 2 jours et les 6 jours sont à modifier en fonction du ttl de la zone, il faut à minima :
- 2 ttl avant que la OLD_ZSK soit inactivé ;
- durant ces 2 ttl, il y a 1 ttl où la OLD_ZSK est activée et la NEW_ZSK est publiée ;
- à la fin des 2 ttl la NEW_ZSK est activée et la OLD_ZSK peut être supprimée.
Reverse DNS
Un reverse DNS est un nom de domaine associé à une adresse IP. Le nom de cet enregistrement est PTR. Exemples :
$ dig -x 31.170.8.43
;; QUESTION SECTION:
;43.8.170.31.in-addr.arpa. IN PTR
;; ANSWER SECTION:
43.8.170.31.in-addr.arpa. 43200 IN PTR hosting.evolix.net.
$ dig -x 2a01:9500::3
;; QUESTION SECTION:
;3.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.5.9.1.0.a.2.ip6.arpa. IN PTR
;; ANSWER SECTION:
3.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.5.9.1.0.a.2.ip6.arpa. 43200 IN PTR forge.evolix.net.
Cela fonctionne avec un nom de domaine “virtuel” :
.in-addr.arpa
en IPv4 et .ip6.arpa
en IPv6
!
Il est important de configurer les reverses DNS, car ils sont souvent
vérifiés par les serveurs SMTP, et certains logiciels les vérifient
également (Postfix, MySQL, CUPS, SSH, etc.). Sur un réseau avec des
adresses privées, il également important de renvoyer au minimum une
réponse DNS NXDOMAIN ce qui peut être fait facilement grâce au
fichier /etc/bind/zones.rfc1918
.
À noter que les DNS de l’IANA répondent tout de même pour ces demandes… mais sans garantie de bon fonctionnement !
Monitoring
dnstop
L’outil dnstop permet de surveiller en direct l’activité DNS en analysant les paquets réseau qui circulent :
# apt install dnstop
# dnstop -l3 eth0
s - Sources list
d - Destinations list
t - Query types
o - Opcodes
r - Rcodes
1 - 1st level Query Names ! - with Sources
2 - 2nd level Query Names @ - with Sources
3 - 3rd level Query Names # - with Sources
4 - 4th level Query Names $ - with Sources
5 - 5th level Query Names % - with Sources
6 - 6th level Query Names ^ - with Sources
7 - 7th level Query Names & - with Sources
8 - 8th level Query Names * - with Sources
9 - 9th level Query Names ( - with Sources
^R - Reset counters
^X - Exit
Munin
Pour activer les plugins Munin pour BIND :
# cd /etc/munin/plugins
# ln -s /usr/share/munin/plugins/bind9_rndc
# ln -s /usr/share/munin/plugins/bind9
Le plugin bind9_rndc s’appuie sur le fichier
/var/run/named.stats
(option statistics-file de
BIND) et bind9 s’appuie un fichier de logs (channel
query_logging dans les logs BIND). Il donc s’assurer d’avoir
bien configuré ces deux fichiers puis on indique à Munin via
/etc/munin/plugin-conf.d/bind9
:
[bind*]
user root
env.logfile /var/chroot-bind/var/log/bind_queries.log
env.querystats /var/chroot-bind/var/run/named.stats
env.MUNIN_PLUGSTATE /var/lib/munin
timeout 120
Log2mail
Pour être alerté en cas de fichiers de zone incorrect, on peut rajouter ceci dans la conf de Log2mail :
file = /var/chroot-bind/var/log/bind.log
pattern = "not loaded due to errors"
mailto = alert@example.com
file = /var/log/syslog
pattern = "fatal error"
mailto = alert@example.com
pattern = "loading configuration: failure"
mailto = alert@example.com
géolocalisation
BIND peut répondre une réponse différente selon l’adresse IP qui l’interroge, on peut faire cela de deux façons :
- Depuis Buster (Debian 10) le patch geoip a été intégré a Bind. Le principe est de faire une recherche suivant un arbre binaire (binary search tree) sur la base de données de MaxMind. Cela n’impacte pas les temps de réponse mais nécessite de maintenir un Bind patché avant Buster ;
- en se basant sur le système de vue de Bind. Le principe est de récupérer les plages d’adresses par pays auprès de MaxMind et de générer des fichiers d’ACL à l’aide de ce script. Les performances sont en théorie moins bonnes (mais cette différence n’est pas vraiment constatée dans la pratique), mais l’installation est bien plus simple à maintenir.
À l’aide de vues
- On récupère le script GeoIP.py et on installe les dépendances nécessaires :
# apt install python-mpmath
- exécuter le script. Il générera un fichier
GeoIP.acl
, avec une ACL par pays :
$ ./GeoIP.py MaxMind
- Configurer Bind pour servir une zone différente en fonction des pays :
include "/etc/bind/GeoIP.acl";
view "europe" {
match-clients { FR; };
recursion no;
zone "example555.com" {
type master;
file "/etc/bind/db.example555-europe.db";
allow-query { any; };
};
};
view "north_america" {
match-clients { US; CA; MX; };
recursion no;
zone "example555.com" {
type master;
file "/etc/bind/db.example555-north-america.db";
allow-query { any; };
};
};
view "other" {
match-clients { any; };
recursion no;
zone "example555.com" {
type master;
file "/etc/bind/db.example555-other.db";
allow-query { any; };
};
};
Le script peut être mis en cron pour conserver des ACL à jour.
FAQ
journal out of sync
Si vous avez une erreur du type :
journal out of sync with zone
Lancer la commande :
# named -g
Voir http://www.thedumbterminal.co.uk/?action=showArticle&articleId=168
ran out of space
Si vous avez une erreur du type (par exemple pour des enregistrements TXT ou SPF) :
ran out of space
Vous devez spliter vos champs, voir http://www.jeoffrey54.com/article144/dns-sous-bind-ran-out-of-space
received control channel command ‘stop’
En lançant votre démon, celui-ci est stoppé immédiatement avec un simple message d’arrêt :
received control channel command 'stop'
…vérifiez si vous n’avez pas oublié l’option -f
tout en
utilisant systemd.
Zone replica avec Bind 9.9
À partir de Bind 9.9, le stockage des zones répliquées se fait en binaire. Avec une ancienne configuration vous aurez des erreurs :
zone example.com/IN: loading from master file /etc/bind/bak.example.com failed: not implemented
zone example.com/IN: unable to load from '/etc/bind/bak.example.com'; renaming file to '/etc/bind/db-5GoiCpdc' for failure analysis and retransferring.
Pour conserver l’ancien comportement il faut ajouter dans la configuration :
masterfile-format text;
Voir http://geekdom.wesmo.com/2014/06/05/bind9-dns-slave-file-format/
Vérifier la configuration
- Globalement :
# named-checkconf /etc/bind/named.conf
- Pour une zone en particulier :
# named-checkzone example.com /etc/bind/db.example.com
- Pour un reverse :
# named-checkzone $reversed_IP.in-addr.arpa. /etc/bind/db.reverse.ripe$subnet
Forcer un transfer sur le replica
Sur le replica :
# rndc reload example.com
zone refresh queued
Pas d’IPv6 ou souci d’IPv6
Si malheureusement vous n’avez pas d’IPv6 sur votre serveur ou alors si la qualité de votre connexion IPv6 est insuffisante, vous devez forcer Bind à ne pas écouter en IPv6 ainsi :
listen-on-v6 { none; };
Et via le fichier /etc/default/named
(/etc/default/bind9
avant Bullseye) vous allez le forcer à
n’effectuer des requêtes qu’en IPv4 :
OPTIONS="-u bind -4 -t /var/chroot-bind"
master “caché”
L’enregistrement SOA ns-hidden-master.example.com ...
doit bien pointer vers le master caché, dans ce cas
ns-hidden-master.example.com
sinon les NOTIFY ne
fonctionneront pas correctement.
refresh: timeout retrying without EDNS master
Cela signifie que les requêtes EDNS ne fonctionnent pas vers le
master, cela peut notamment être causé par un firewall qui tronque les
paquets EDNS qui sont volumineux. On peut notamment contourner cela en
désactivant EDNS vers le serveur concerné via
named.conf.options
:
options {
...
}
logging {
...
}
server 192.0.2.53 { edns no; };
délai de transfert de zones
Voir https://kb.isc.org/docs/aa-00726
Mise a jour du serial
Vous devez repérer un pattern unique sur la ligne du serial, par
exemple ; serial
On peut ainsi mettre à jour le serial d’une zone :
$ serial=$(date "+%Y%m%d%H")
$ sed -i "s/^\([ \t]*\)[0-9]\{10\}\([ \t]*; serial\)/\1$serial\2/" db.example.com
Si l’on doit automatiser, on utilisera les commandes suivantes pour prendre en compte plusieurs modifications le même jour :
zonefile=db.example.com
serial=$(grep -E '[ \t]*[0-9]{10}\s*; serial' $zonefile | sed "s/[ \t]*\([0-9]\{10\}\)[ \t]*; serial/\1/")
if [ `date "+%Y%m%d%H"` -gt $serial ]; then serial=$(date "+%Y%m%d%H"); else serial=$(( $serial + 1 )); fi
sed -i "s/^\([ \t]*\)[0-9]\{10\}\([ \t]*; serial\)/\1$serial\2/" $zonefile
Configuration update-policy
Dans update-policy
, les régles ACLs prennent la forme
( grant | deny ) identity ruletype name types
La première règle qui match un requête sera utilisé
identity
correspond à un fqdn ou le nom la clef TSIGname
le nom de l’entrée dans la zonetypes
le ou les types de l’entrée(s) dans la zoneruletype
est le type de règle utilisé, il en existe une vingtene de valeurs, les plus importantes sont (WIP)
Les ruletype
s pricipaux :
name
la règle match exactement avec le nom de l’entréename
subdomain
match avec tous le sous-domaine et le domaine de l’entréename
zonesub
match tous les sous-domaines de la zone contenant la configuration, il ne faut pas préciser d’entréename
wildcard
match toute les expansions wildcard valides de l’entréename
self
permet de faire correspondreidentity
directement avec le nom d’une entrée, il ne faut pas préciser d’entréename
ou sinon y mettre.
ou la même valeur queidentity
. On peut aussi mettre directement*
pouridentity
si le nom est bien le même que celui d’une entrée (cela permet de matcher automatiquement les clefs avec les noms d’entrées)selfsub
fonctionne comme self et permet de mettre à jour aussi les sous-domaine du nom d’une entréeselfwild
fonctionne comme self mais permet de mettre à jour uniquement les sous-domaine du nom d’une entrée- Liste complète: https://bind9.readthedocs.io/en/v9_18_2/reference.html#dynamic-update-policies
Problèmes de rafraîchissement des DNS secondaires
Si on modifie les zones du primaire à la main, les secondaires doivent désactiver les requêtes IXFR, en faveur de l’AXFR.
L’IXFR fonctionne bien seulement avec les mises-à-jour DNS dynamiques
(nsupdate
).
Erreurs “unable to find a DNSKEY”
Si vous obtenez des erreurs de ce type :
named[29200]: validating @0x555adbd13380: . DNSKEY: unable to find a DNSKEY which verifies the DNSKEY RRset and also matches a trusted key for '.'
named[29200]: validating @0x555adbd13380: . DNSKEY: please check the 'trusted-keys' for '.' in named.conf.
named[29200]: error (broken trust chain) resolving './NS/IN': 199.7.91.13#53
named[29200]: validating @0x555adc128030: . DNSKEY: unable to find a DNSKEY which verifies the DNSKEY RRset and also matches a trusted key for '.'
named[29200]: validating @0x555adc128030: . DNSKEY: please check the 'trusted-keys' for '.' in named.conf.
named[29200]: error (no valid KEY) resolving './DNSKEY/IN': 192.36.148.17#53
named[29200]: validating @0x555adc128030: . DNSKEY: unable to find a DNSKEY which verifies the DNSKEY RRset and also matches a trusted key for '.'
named[29200]: validating @0x555adc128030: . DNSKEY: please check the 'trusted-keys' for '.' in named.conf.
Cela peut empêcher Bind de fonctionner.
C’est relatif à DNSSEC, potentiellement vous devez mettre à jour des clés.
C’est déconseillé, mais une manière de contourner le problème est de
désactiver dnssec-validation auto;