4 avril 2012
DNS dynamique sécurisé avec nsupdate et BIND9
Testé avec Bind 9.7.3 sous Debian Squeeze, poste moniteur sous Debian Squeeze
De nombreuses connexions internet ADSL ou satellite ne disposent pas d’une adresse IP publique fixe. Dès lors qu’on veut installer un serveur derrière ce type de liaison ou mettre en place un accès distant, on utilise généralement des services de DNS dynamique tels que Dyn ou no-ip. Ces services restent très limités dans leur version gratuite.
L’idée est donc de pouvoir s’en passer en utilisant notre propre serveur DNS pour tenir à jour un enregistrement DNS du type monip.mondomaine.com qui pointera sur l’adresse IP externe courante de la connexion. L’enregistrement DNS sera mis à jour de façon sécurisée par l’utilitaire DNS nsupdate.
Pré-requis
- Un serveur DNS Bind 9.2 ou plus récent connecté directement à internet. Ce serveur doit être maître pour la zone qui contiendra l’enregistrement DNS choisi :
Pour l’enregistrementmonip.onsenfout.com
le serveur doit être maître pour la zoneonsenfout.com
. - Une machine linux derrière la connexion à surveiller, ici j’utilise un serveur Debian Squeeze. Je l’appelle poste moniteur dans la suite de l’article.
Préparation du poste moniteur
installer les utilitaires DNS
aptitude install bind9utils dnsutils |
Générer la paire de clés TSIG
Il y a 2 méthodes pour sécuriser les mises à jours dynamiques du DNS : avec des clés TSIG ou avec des clés SIG(0). Les clés TSIG sont symétriques, la même clé est utilisée par le client et le serveur. A l’inverse, les clés SIG(0) sont asymétriques, ce qui est à priori plus sécurisé, mais la version actuelle de nsupdate dans Squeeze (dnsutils 1:9.7.3.dfsg-1~squeeze4
) plante avec les clés SIG(0). Je me suis donc rabattu sur TSIG en attendant que ça sèche.
La clé sera générée avec dnssec-keygen:
dnssec-keygen -a HMAC-MD5 -b 512 -n HOST monip.onsenfout.com |
On obtient deux fichiers :
Kmonip.onsenfout.com.+157+?????.private Kmonip.onsenfout.com.+157+?????.key |
Le contenu du fichier Kmonip.onsenfout.com.+157+13642.private est le suivant :
cat Kmonip.onsenfout.com.+157+13642.private Private-key-format: v1.3 Algorithm: 157 (HMAC_MD5) Key: BXLFFCyzbVK1OxTu+3HaJ2YytB64Rxplat738Zk3UFWDeLtkfUYIwgbX83LYR5W6z7fRgGBcwgVD191KtOErMQ== Bits: AAA= Created: 20120404104934 Publish: 20120404104934 Activate: 20120404104934 |
C’est le moment de copier la valeur de la clé (après Key: ) dans le presse-papiers, on en aura besoin pour configurer le serveur DNS.
Configuration du serveur DNS
créer un fichier /etc/bind/keys.conf et y ajouter la clé publique :
key monip.onsenfout.com { algorithm HMAC-MD5; secret "BXLFFCyzbVK1OxTu+3HaJ2YytB64Rxplat738Zk3UFWDeLtkfUYIwgbX83LYR5W6z7fRgGBcwgVD191KtOErMQ=="; }; |
Editer /etc/bind/named.conf.local et inclure le fichier de clé :
include "/etc/bind/keys.conf"; |
Côté serveur il ne reste plus qu’à définir les autorisations de mise à jour de la zone. L’instruction update-policy va nous permettre d’autoriser la clé monip.onsenfout.com
à modifier l’enregistrement DNS de type A monip.onsenfout.com
, et seulement celui là :
zone "onsenfout.com" in { type master; file "db.onsenfout.com"; update-policy { grant monip.onsenfout.com. name monip.onsenfout.com. A; }; |
On redémarre Bind :
/etc/init.d/bind9 restart |
Test de la mise à jour dynamique
Le serveur est prêt à recevoir des mises à jour dynamiques. Nous allons pouvoir vérifier que tout fonctionne en initialisant l’enregistrement DNS avec nsupdate
à partir du poste moniteur. La syntaxe de nsupdate est:
nsupdate -k <fichier clé privée> -v <fichier> |
-v
force l’utilisation de TCP au lieu d’UDP
fichier
contient le jeu d’instructions à envoyer au serveur, s’il est omis nsupdate passe en mode interactif.
C’est ce qu’on va faire pour initialiser l’enregistrement monip.onsenfout.com
avec l’adresse 0.0.0.0 et un TTL de 30. La commande show
affiche la requète de mise à jour, send
l’envoie au serveur :
nsupdate -k Kmonip.onsenfout.com.+157+13642.private -v > zone onsenfout.com > update add monip.onsenfout.com. 30 A 0.0.0.0 > show Outgoing update query: ;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id: 0 ;; flags:; ZONE: 0, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0 ;; ZONE SECTION: ;onsenfout.com. IN SOA ;; UPDATE SECTION: monip.onsenfout.com. 30 IN A 0.0.0.0 > send > quit |
On vérifie que tout s’est bien passé en regardant les logs de Bind et en faisant un dig sur le serveur DNS :
dig +nocmd monip.onsenfout.com +noall +answer monip.onsenfout.com. 30 IN A 0.0.0.0 |
Le fichier journal
Après la première mise à jour dynamique, on s’aperçoit qu’un nouveau fichier db.onsenfout.com.jnl
a été créé dans le répertoire des fichiers de zones, /var/cache/bind/
chez moi. On constate aussi que la commande dig retourne bien l’enregistrement demandé, mais que celui-ci n’apparaît pas dans le fichier de zone : lors des mises à jour dynamiques, Bind modifie la zone chargée en mémoire, et stocke l’information dans le fichier journal de la zone avec une extension .jnl
. C’est un point important à prendre en compte si on doit éditer manuellement une zone comportant des enregistrements dynamiques.
Dans ce cas il faut suspendre les mises à jour de la zone et forcer l’écriture du journal avec rndc freeze
:
rndc freeze onsenfout.com |
Editer la zone sans oublier d’incrémenter le numéro de série, rétablir les mises à jour et recharger la zone avec rndc thaw
:
rndc thaw onsenfout.com |
Le fichier journal n’est pas directement lisible mais l’utilitaire named-journalprint remédie au problème.
Un p’tit script pour finir
Maintenant que tout fonctionne il ne manque plus qu’un script placé en crontab sur le poste moniteur, toutes les minutes par exemple :
#!/bin/bash # Teste si l'ip publique a été modifiée et met à jour l'enregistrement DNS # Utilise la clé TSIG # François Grange 2012 # Inits ADMIN="xxxx@onsenfout.com" ZONE="onsenfout.com" RR="monip.$ZONE." TTL=30 LAST_IP="0.0.0.0" LAST_IP_FILE="/var/local/lastip" FLAG_ERR=0 ERR_FILE="/var/local/dyndns.err" KEY_FILE="/etc/bind/keys/Kmonip.onsenfout.com.+157+13642.private" TMP_FILE="/tmp/dyndns.tmp" CUR_IP=`wget -q -O - whatismyip.org` sortie() { # mail si erreur ou modification if [ $1 -eq 1 ]; then if [ ! -f $ERR_FILE ]; then touch $ERR_FILE cat $TMP_FILE | mail -s "Erreur de mise à jour de $RR" $ADMIN fi else cat $TMP_FILE | mail -s "Changement d'IP pour $RR" $ADMIN if [ -f $ERR_FILE ]; then rm -f $ERR_FILE fi fi exit } if [ "$CUR_IP" = "" ] || [ "$CUR_IP" = "unknown" ]; then echo "Impossible de récupérer l'IP actuelle - Abandon" > $TMP_FILE sortie 1 fi if [ -f $LAST_IP_FILE ]; then LAST_IP=`cat $LAST_IP_FILE` fi if [ ! "$LAST_IP" = "$CUR_IP" ]; then # L'adresse a changé echo "IP actuelle : $CUR_IP" > $TMP_FILE echo "IP précédente : $LAST_IP" >> $TMP_FILE ( echo "zone $ZONE" echo "update delete $RR A" echo "update add $RR $TTL A $CUR_IP" echo "send" ) | nsupdate -k $KEY_FILE -v if [ $? -ne 0 ]; then echo "Echec de la mise à jour de $RR" >> $TMP_FILE FLAG_ERR=1 else echo $CUR_IP > $LAST_IP_FILE fi sortie $FLAG_ERR fi |
Remarque : J’utilise dans le script le service web myip.dnsdynamic.com. Pour plus d’indépendance c’est très facile de se créer son propre service avec une page php d’une ligne :
<?php print $_SERVER['REMOTE_ADDR'] ?> |
Liens
Secure dynamic DNS howto
nsupdate: Painless Dynamic DNS
Mise en place d’un serveur DNS dynamique
Obtenir l’adresse IP publique en ligne de commande
[…] script provient de François Grange, je l’ai juste modifié un peu à ma sauce et l’ai commenté un peu plus, histoire que […]
@frank
Bonjour,
les serveurs DNS sont déclarés chez le registrar (OVH, Gandi et consorts) chez lequel tu as enregistré ton domaine.
Ça va sans dire mais c’est mieux en le disant, les serveurs DNS doivent avoir une IP fixe
Bonjour,
Mais le serveur DNS, comment est il connu du reste du monde internet ?
Je comprends pas ce point ? car lui aussi est sur ip dynamic ???
Cordialement
[…] Et j’ai trouvé également un moyen de mettre à jour l’IP de mon serveur @home sur mon serveur DNS sans avoir recours au… […]