Le DNS

Posted on Fri 12 March 2021 in Hosting

Pierre angulaire d’une bonne partie des systèmes sur internet, le DNS – pour Domain Name System, système de nom de domaine – permet d’associer un nom à une machine, avec plein de subtilité autour, mais je vais pas détailler.

Il y a principalement 2 types de serveur DNS : les serveurs faisant autorité et qui vont décrire une zone de nom, et les résolveurs qui vont chercher l’information sur les bons serveurs faisant autorité. Dans mon cas présent, ce qui m’intéresse, c’est un serveur DNS faisant autorité sur la zone yapbreak.fr.

Je ne vais pas chercher bien loin pour le logiciel à utiliser, Bind9 fait ça très bien et a la volonté affichée de suivre complètement les standards édictés par l’IETF, Internet Engineering Task Force. De ce point de vue là, il me convient parfaitement. Pour ce qui est de son installation sur la Debian, rien de plus simple, il est présent dans les dépôts et il y a moult tutoriel sur internet pour la configuration. Je vous laisse avec celui-là qui m’a bien servi surtout pour les exemples en guise de rappel de syntaxe :

https://www.linuxbabe.com/debian/authoritative-dns-server-debian-10-buster-bind9

Je ne me lancerai pas dans une énième explication de chacun des champs d’une zone DNS, l’internet fourmille de ce genre de ressources. Attachons nous par contre à la sécurité et aux outils de diagnostiques.

DNSSEC

DNSSEC – pour Domain Name System Security Extensions – est un protocole qui permet de signer cryptographiquement le contenu de chaque enregistrement d’une zone, les rendant inaltérables. Pour ce faire,il faut 2 paires de clés publique et privée : une pour la signature de la zone dans son entièreté, dite ZSK –Zone Signing Key – et une pour la signature de chacune des entrées de la zone, dite KSK – Key Signing Key.

# Assurons nous d’avoir les outils nécessaires à DNSSEC
apt install bind9utils

# Les paires de clés seront stockées dans /etc/bind/keys
mkdir -p /etc/bind/keys
cd /etc/bind/keys

# Génération de la paire ZSK
dnssec-keygen -a ECDSAP384SHA384 -n ZONE ${nom_de_la_zone}
# 2 fichiers sont générés, de la forme K{nom_de_la_zone}.+014+{keyId}.key et K{nom_de_la_zone}.+014+{keyId}.private
# je les renomme pour plus de simplicité en {nom_de_la_zone}.zsk.key et {nom_de_la_zone}.zsk.private
mv K*.key ${nom_de_la_zone}.zsk.key
mv K*.private ${nom_de_la_zone}.zsk.private

# Génération de la paire KSK
dnssec-keygen -f KSK -a ECDSAP384SHA384 -n ZONE ${nom_de_la_zone}
# 2 fichiers sont générés, de la même forme que précédemment, et comme tout à l’heure, je les renomme avec ksk dans le suffixe
mv K*.key ${nom_de_la_zone}.ksk.key
mv K*.private ${nom_de_la_zone}.ksk.private

On ajoute ensuite à la fin de la définition de la zone les liens vers ces nouvelles clés :

; Définition de la zone, fichier /etc/bind/db.{nom_de_la_zone}
...

; DNSSEC keys
$include /etc/bind/keys/{nom_de_la_zone}.zsk.key
$include /etc/bind/keys/{nom_de_la_zone}.ksk.key

Une fois que tout est prêt, nous passons à la signature de la zone « pour de vrai » avec la commande suivante :

dnssec-signzone -e 20210413211253 \
                -t -g \
                -k "/etc/bind/keys/${nom_de_la_zone}.ksk.key" \
                -o "${nom_de_la_zone}" \
                /etc/bind/db.${nom_de_la_zone} \
                /etc/bind/keys/${nom_de_la_zone}.zsk.key

Cette commande va donc signer la zone avec les clés de chiffrement, avec une validité allant jusqu’au 13 avril 2021 à 21h12 et 53 secondes (paramètre -e). La zone signée est alors disponible dans le fichier /etc/bind/db.{nom_de_la_zone}.signed qu’il faut référencer dans /etc/bind/named.conf.local en lieu et place de la zone non signée.

Pour assurer la chaîne de validation complète, il est nécessaire d’enregistrer les clés publiques sur le serveur de niveau supérieur. Ceci se fait généralement via l’interface de votre registrar. Chez OVH, il suffit de renseigner le formulaire avec les KeyId (ils sont rappelés en commentaire sur la première ligne des fichiers *.key), le bon flag (257 pour une clé KSK et 256 pour un clé ZSK), l’algorithme utilisé (dans mon cas, le 14 – ECDSAP384SHA384) et la clé publique en elle même :

DS Record OVH

L’automatisme

C’est bien beau toute ces commandes, mais si la génération de nouvelles clés et l’enregistrement DS n’est pas à refaire à chaque fois, il faut penser à re-signer la zone après chaque modification et assez régulièrement puisque la signature a une date d’expiration. Ajoutons à ça la mise à jour du numéro de série de la zone qui doit être strictement incrémentale… Ça fait un potentiel d’erreur assez élevé et donc, il y a forcément un script qui permet d’automatiser tout ça et d’éviter le plus possible les erreurs bêtes.

#!/usr/bin/env bash

if [ $# -ne 1 ]; then
    echo "Usage:"
    echo "$0 domain"
    exit 1
fi

domain="${1}"

zonefile="/etc/bind/db.${domain}"

if [ ! -f "${zonefile}" ]; then
    echo "Zone file ${zonefile} does not exists"
    exit 1
fi

update_zone() {
    local soa
    local old_serial
    local today
    local new_serial
    local index

    soa=$(grep "SOA" "$zonefile")
    old_serial=$(echo "$soa" | sed 's|^.*([ \t]*\([0-9][0-9]*\)[^0-9].*$|\1|g')
    today=$(date +"%Y%m%d")
    if echo "$old_serial" | grep "$today" > /dev/null; then
        index=$(echo "${old_serial}" | sed 's|^.*\([0-9][0-9]\)$|\1|g;s|^0||')
        index=$(( index + 1 ))
        new_serial="${today}$(printf "%02d" ${index})"
    else
        new_serial="${today}01"
    fi

    sed -i "s|${old_serial}|${new_serial}|" "${zonefile}"
}

update_zone

newdate=$(date -d "32 days" +"%Y%m%d%H%M%S")

if ! named-checkzone "${domain}" "${zonefile}"; then
    echo "Failed to validate zone file, abort."
    exit 1
fi

echo "Ready to sign zone valid until $newdate"
if [ ! -f "/etc/bind/keys/${domain}.zsk.key" ]; then
    echo "No ZSK key found. Abort."
    echo "You can generate one with:"
    echo "dnssec-keygen -a ECDSAP384SHA384 -n ZONE ${domain}"
    echo "and rename output to /etc/bind/keys/${domain}.zsk.{key,private}"
    exit 1
fi

if [ ! -f "/etc/bind/keys/${domain}.ksk.key" ]; then
    echo "No KSK key found. Abort."
    echo "You can generate one with:"
    echo "dnssec-keygen -f KSK -a ECDSAP384SHA384 -n ZONE ${domain}"
    echo "and rename output to /etc/bind/keys/${domain}.ksk.{key,private}"
    exit 1
fi

dnssec-signzone -e"${newdate}" \
                -t -g \
                -k "/etc/bind/keys/${domain}.ksk.key" \
                -o "${domain}" "${zonefile}" "/etc/bind/keys/${domain}.zsk.key"

echo "Restart bind9 service"
systemctl restart bind9.service

Pour que ce script fonctionne, il est nécessaire d’avoir le numéro de série sur la même ligne que SOA de cette façon :

@ IN SOA ns01.yapbreak.fr. admin.yapbreak.fr. (2021031216   ; serial

J’utilise la convention suivante pour les numéros de série afin d’assurer l’incrément : le numéro est composé de la date courante au format AAAAMMJJ, suivi de 2 chiffres d’index allant donc de 01 à 99. On peut donc modifier une zone au maximum 98 fois par jours, ce qui est déjà pas mal.

La zone est ensuite signée pour les 32 jours qui viennent.

Vérification

Pour vérifier que tout est bien en place, que tout est cohérent, voici deux outils bien pratique. Je les notes ici, comme ça, je n’ai pas à redemander à chaque fois à Stéphane Bortzmeyer :

  • ZoneMaster supporté par l’Afnic entre autre, et qui donne une bonne vue d’ensemble de tous les problèmes potentiels
  • DnsViz plus spécialisé dans les problèmes de DNSSEC.