8 juil. 2019

Bind : automatiser la mise à jour d'entrées DNS

Lire la suite...

J'ai eu récemment à configurer un accès vers une machine dont l'adresse IP n'est pas fixe (typiquement derrière une box ADSL dont l'abonnement ne propose pas d'IP fixe). J'avais déjà mis en place un accès similaire il y a quelques années, mais je n'en avais pas fait de billet, voici donc l'occasion.

Plantons un peu le décor

Je suis donc dans la situation suivante : la machine, sous NetBSD, dispose d'un accès Internet derrière une box ADSL fournissant une IPv4 dynamique. Je dispose d'un nom de domaine, d'un serveur DNS public, ainsi que d'un serveur web public. En dehors des éléments, je ne souhaite pas compter sur un service tiers supplémentaire. L'idée est donc la suivante : depuis la machine en question, réussir à obtenir son adresse IP publique de sortie, et aller la donner au serveur DNS pour qu'il mette à jour une entrée afin que la dite machine soit accessible (pour un accès SSH ou HTTPS par exemple).

Étape 1 : connaître son adresse IP publique

Pour cette première étape, j'ai choisi d'utiliser un serveur web existant, qui tourne sous Nginx. Celui-ci me permet d'afficher l'adresse IP du client, sans utiliser de script supplémentaire PHP, Python ou autre. J'ai ajouté la configuration suivante dans mon virtual host :

location /myip {
    default_type text/plain;
    return 200 "$remote_addr\n";
}

Une fois Nginx relancé, je peux lancer une requête via un navigateur, wget ou curl pour afficher mon adresse IP :

$ curl http://www.example.org/myip
109.XXX.YYY.ZZZ

Étape 2 : mettre à jour une entrée DNS sans les mains

Cette deuxième étape commence par la création, manuelle, d'une nouvelle entrée de type A dans la zone DNS. Je ne détaille cette création, elle est en théorie assez basique pour toute personne qui a déjà monté un serveur DNS. Par contre il va falloir mettre à jour régulièrement cet enregistrement. Pour ne pas avoir à le mettre à jour manuellement, j'ai utilisé nsupdate. Cet outil repose sur la RFC 2136, ce qui a l'avantage d'être ouvert et documenté, et de ne pas être une solution bricolée maison à base de sed dans le fichier de zone en direct.

Pour utiliser nsupdate, il faut commencer par créer une paire de clés TSIG sur le client, et ensuite autoriser la clé publique au niveau du serveur DNS. L'outil dnssec-keygen va nous aider pour la création de clés :

$ dnssec-keygen -a HMAC-SHA256 -b 256 -n HOST dynamic.example.org
Kdynamic.example.org.+163+16284

On notera que l'option -a permet de choisir l'algorithme cryptographique, -b la taille de clé, et l'option -n spécifie le type d'entrée à laquelle se destine cette paire de clés. 2 fichiers sont alors produits, dans notre exemples ils se nomment Kdynamic.example.org.+163+16284.key (la clé publique) et Kdynamic.example.org.+163+16284.private (la clé privée). La clé publique a cette tête :

$ cat Kdynamic.example.org.+163+16284.key 
dynamic.example.org. IN KEY 512 3 163 EmvYb14yJA+0qgRmqaMng02cQoCAbekP2ou9M1fNWX4=

Quant à la clé privée :

$ cat Kdynamic.example.org.+163+16284.private 
Private-key-format: v1.3
Algorithm: 163 (HMAC_SHA256)
Key: EmvYb14yJA+0qgRmqaMng02cQoCAbekP2ou9M1fNWX4=
Bits: AAA=
Created: 20181112210734
Publish: 20181112210734
Activate: 20181112210734

Note : je n'ai pas de problème à divulguer cette clé, car je l'ai volontairement générée à des fins d'exemple. Bien entendu, il ne fait pas divulguer sa clé privée ;)

Maintenant, autorisons notre clé publique au niveau du serveur DNS Bind. Cela se situe directement dans le fichier de configuration named.conf, et cela se passe en deux parties. La première consiste à déclarer la clé publique :

key "dynamic.example.org." {
        algorithm HMAC-SHA256;
        secret "EmvYb14yJA+0qgRmqaMng02cQoCAbekP2ou9M1fNWX4=";
};

Attention, il faut bien préciser le même algorithme que lors de la génération de clés.

La deuxième partie consiste à autoriser cette clé publique au niveau de la configuration de la zone DNS sur laquelle je souhaite agir :

zone "example.org" IN {
        type master;
        file "/var/named/master/example.org";
        allow-transfer {10.13.37.53; };
        allow-query { any; };
        update-policy {
                grant dynamic.anotherhomepage.org. name dynamic.anotherhomepage.org. A CNAME TXT;
                grant dynamic2.anotherhomepage.org. name dynamic2.anotherhomepage.org. A CNAME TXT;
        };
};

Il s'agit d'une déclaration relativement classique, mais on notera la présence d'une directive update-policy dans laquelle j'autorise ma clé (définie par le nom lors de la génération par dnssec-keygen) à modifier un enregistrement DNS (définie par name puis son nom) des types décrits après (ici, mon enregistrement peut être de type A, CNAME ou TXT). L'exemple ci-dessus propose même deux enregistrements modifiés par deux clés différentes.

On peut alors utiliser nsupdate. Créons un fichier qui va contenir les données à pousser vers le serveur DNS :

$ cat dnsupdate.txt
server ns0.example.org
zone example.org.
update delete dynamic.example.org.
update add dynamic.example.org. 180 A 10.13.37.92
show
send

Ensuite, lançons nsupdate :

nsupdate -k ./Kdynamic.example.org.+163+16284.private -v ./dnsupdate.txt

Si tout se passe bien, l'enregistrement DNS devrait être à jour. Pour se faciliter les tests, on peut, lors de la création de celui-ci, mettre une valeur volontairement erronée, et constater qu'une fois nsupdate lancé, la valeur est correcte.

Étape 3 : on secoue bien fort

Maintenant qu'on a tous les outils, il ne reste plus qu'à tout englober ensemble dans un script à glisser dans une tâche cron. Voici, dessous, le script que j'ai fait pour l'exemple. Bien entendu, il utilise la méthode "La Rache" et mériterait un peu plus de rigueur dans son développement. Mais c'est un début, fonctionnel et simple à comprendre.

#!/usr/pkg/bin/bash
set -x
curl_bin=$(which curl)
curl_opts="-s"
dig_bin=$(which dig)
nsupdate_bin=$(which nsupdate)
ip_check_service="http://www.example.org/myip"
keyfile="/home/nils/keys/Kdynamic.example.org.+163+16284.private"
current_ip=$(${curl_bin} ${curl_opts} ${ip_check_service})
current_reverse=$(${dig_bin} +short @ns1.fdn.org -x ${current_ip})
previous_cname=$(${dig_bin} +short @ns0.example.org dynamic.example.org)
dns_server=$(dig +short -t A ns0.example.org)

cat > /tmp/majdnscloud.txt << EOF
server ${dns_server}
zone example.org.
update delete dynamic.example.org.
update add dynamic.example.org. 180 CNAME ${current_reverse}
show
send
EOF

nsupdate -k ${keyfile} -v /tmp/majdnscloud.txt
rm -f /tmp/majdnscloud.txt

Autres possibilités ?

Il se peut qu'on ne dispose pas de ressource pour installer un serveur qui donnerait notre IP publique de sortie, il est alors possible d'utiliser un service tiers. J'en utilise occasionnellement deux : What's My IP et IP chicken.

Pour ce qui est de la mise à jour automatisée d'un enregistrement DNS, selon le registrar, il est possible que celui-ci le propose via une API, comme Gandi LiveDNS par exemple.

Vous avez aimé cet article ? Alors partagez-le sur les réseaux sociaux !

Crédit photo : Jake Givens - Busy freeway traffic at night.

2 mai 2011

Configuration d'une redondance DNS

Lire la suite...

Je suis dans la situation suivante : j'ai une machine exécutant entre autres un serveur DHCP et un serveur DNS, et je souhaite réinstaller cette machine. Problème, si je la réinstalle, le DHCP et le DNS seront indisponibles. Il me faut donc redonder ces deux services pour ne pas perturber les autres machines. Après la redondance DHCP, ce billet aborde la redondance DNS. Ce billet, comme le précédent, n'aborde pas la configuration complète d'un serveur DNS mais détaille les options de configurations liées à la redondance

Une redondance basique dans un LAN est très facile à mettre en œuvre car il n'y a pas besoin de modifier quoi que ce soit chez un registrar. Il faudra cependant ajouter l'adresse IP du second serveur DNS dans la configuration de toutes les machines ayant une adresse IP statique, car celles-ci ne récupèrent pas la liste des serveurs DNS via DHCP. Une redondance DNS se compose généralement d'au moins deux serveurs : un serveur maître et un ou plusieurs serveurs esclaves. Toutes nos futures modifications dans le DNS s'effectueront sur le serveur maître et seront répliquées automatiquement vers le serveur esclave. Dans notre cas, le serveur maître utilise NetBSD 4.0 et le serveur esclave utilise NetBSD 5.1; dans les deux cas, ISC Bind est utilisé dans sa version embarquée avec l'OS, et configuré dans un chroot.

Sur notre serveur maître, configurons nos zones dans le fichier /var/chroot/named/etc/named.conf :

zone "anotherhomepage.loc" IN {
        type master;
        file "anotherhomepage.loc";
        allow-update { none; };
        allow-query { any; };
        allow-transfer { 10.13.37.11; };
};

zone "37.13.10.in-addr.arpa" IN {
        type master;
        file "anotherhomepage.loc.reverse";
        allow-update { none; };
        allow-query { any; };
        allow-transfer { 10.13.37.11; };
};

Remarquons que nous autorisons le transfert vers 10.13.37.11 qui est le serveur esclave. Continuons dans le fichier de zone anotherhomepage.loc dont voici quelques extraits :

$TTL 86400
@       IN      SOA     ns0.anotherhomepage.loc. nils.anotherhomepage.loc. (
               2011042601 ; Serial
               8H   ; Refresh
               2H   ; Retry
               4W  ; Expire
               1D  ; Minimum TTL
)

; Name servers
anotherhomepage.loc.    IN      NS     ns0
anotherhomepage.loc.    IN      NS     ns1
; Mail servers
anotherhomepage.loc.    IN      MX      10      mail
; "A" entries
ns0                  IN      A       10.13.37.10
ns1                  IN      A       10.13.37.11
mail                 IN      A       10.13.37.12

Notre serveur esclave est donc renseigné pour le DNS, voyons voir dans le DNS inverse, fichier de zone anotherhomepage.loc.reverse :

$TTL 86400
@       IN      SOA     ns0.anotherhomepage.loc. nils.anotherhomepage.loc. (
               2011042601  ; Serial
               8H   ; Refresh
               2H   ; Retry
               4W  ; Expire
               1D  ; Minimum TTL
)
        IN      NS      ns0.anotherhomepage.loc.
        IN      NS      ns1.anotherhomepage.loc.
        IN      MX      10      mail.anotherhomepage.loc.
10      IN      PTR     ns0.anotherhomepage.loc.
11      IN      PTR     ns1.anotherhomepage.loc.
12      IN      PTR     mail.anotherhomepage.loc.

Occupons-nous à présent de notre serveur esclave. De ce côté, un seul fichier à modifier, /var/chroot/named/etc/named.conf, car les autres seront transférés par les mises à jour de zone :

zone "anotherhomepage.loc" IN {
        type slave;
        masters { 10.13.37.5; };
        file "anotherhomepage.loc";
        allow-update { 10.13.37.5; };
        allow-query { any; };
        allow-notify { 10.13.37.5; };
};

zone "37.13.10.in-addr.arpa" IN {
        type slave;
        masters { 10.13.37.10; };
        file "anotherhomepage.loc.reverse";
        allow-update { 10.13.37.10; };
        allow-query { any; };
        allow-notify { 10.13.37.10; };
};

Il ne reste maintenant qu'à vérifier notre configuration. Par défaut, les logs vont dans /var/log/messages. Vous pouvez définir un autre emplacement pour les logs, comme par exemple :

logging {
        channel simple_log {
                file "/var/log/named/bind.log" ;
                severity info;
                print-time yes;
                print-severity yes;
                print-category yes;
        };
        category default{
                simple_log;
        };
        category queries{
                simple_log;
        };
};

Cet exemple est à insérer dans votre named.conf. Incrémentons les numéros de série, effectuons une relance de bind sur le serveur esclave puis le serveur maître :

root@ns0:/var/chroot/named/var# /etc/rc.d/named reload
Reloading named config files.

Regardons le résultat sur le serveur esclave pour la relance du serveur maître :

root@ns1:/var/chroot/named/etc# tail -f /var/chroot/named/var/log/named/bind.log
26-Apr-2011 19:14:10.864 notify: info: client 10.13.37.5#64893: received notify for zone '37.13.10.in-addr.arpa'
26-Apr-2011 19:14:10.923 general: info: zone 37.13.10.in-addr.arpa/IN: Transfer started.
26-Apr-2011 19:14:10.924 xfer-in: info: transfer of '37.13.10.in-addr.arpa/IN' from 10.13.37.5#53: connected using 10.13.37.60#65525
26-Apr-2011 19:14:11.335 general: info: zone 37.13.10.in-addr.arpa/IN: transferred serial 2011042601
26-Apr-2011 19:14:11.336 xfer-in: info: transfer of '37.13.10.in-addr.arpa/IN' from 10.13.37.5#53: Transfer completed: 1 messages, 258 records, 8672 bytes, 0.411 secs (21099 bytes/sec)
27-Apr-2011 19:14:11.337 notify: info: zone 37.13.10.in-addr.arpa/IN: sending notifies (serial 2011042601)
26-Apr-2011 19:14:11.383 notify: info: client 10.13.37.5#64893: received notify for zone 'anotherhomepage.loc'
26-Apr-2011 19:14:11.388 general: info: zone anotherhomepage.loc/IN: Transfer started.
26-Apr-2011 19:14:11.390 xfer-in: info: transfer of 'anotherhomepage.loc/IN' from 10.13.37.5#53: connected using 10.13.37.60#65524
26-Apr-2011 19:14:11.654 general: info: zone anotherhomepage.loc/IN: transferred serial 2011042601
26-Apr-2011 19:14:11.654 xfer-in: info: transfer of 'anotherhomepage.loc/IN' from 10.13.37.5#53: Transfer completed: 1 messages, 268 records, 8464 bytes, 0.263 secs (32182 bytes/sec)
26-Apr-2011 19:14:11.657 notify: info: zone anotherhomepage.loc/IN: sending notifies (serial 2011042601)

Houra ! Les transferts ont eu lieu ! Maintenant, il reste à modifier dans notre serveur DHCP les adresses IP des serveurs DNS. Dans le cas d'ISC DHCP :

option domain-name-servers 10.13.37.10, 10.13.37.11;

Notez que ce billet permet une redondance assez basique, et loin d'être totalement sécurisée : quelqu'un d'assez malin peut, en utilisant une attaque de type Man-in-the-middle peut appliquer des modifications au serveur esclave. Pour les personnes qui aimeraient corriger ce défaut, il faut se tourner vers DNSSEC.

12 mai 2008

Session de débug DNS

pour un site ami

Lire la suite...

J'ai eu à donner un petit coup de main pour le serveur DNS de QuebecOS, j'en profite donc pour ajouter quelques petites choses qui m'ont aidées à faire du débug de configuration DNS utilisant Bind:

logging {
        channel default_debug {
                file "data/named.run";
                severity dynamic;
        };

dans le fichier named.conf est assez pratique lorsqu'on veut voir si le serveur se lance correctement.

Sinon un site assez sympa pour voir si la configuration est correcte, IntoDNS : on donne son nom de domaine et il regarde ce que rend le serveur à ses requêtes; presque tout y passe, on peut même y lire si notre configuration respecte les bonnes pratiques. A garder sous la main en plus des bons vieux nslookup et dig.

Propulsé par Dotclear