DNSSEC


Signature de zone sous FreeBSD

DNSSEC

Un mien ami écrit le même article que moi (en réalité c’est moi l’odieux copieur). Il utilise un système Linux (Debian 10 Buster). Je vais donc m’attarder sur les différences et particularités de FreeBSD (peu nombreuses il est vrai).

Autre différence, s’il parle de la zone qu’il gère, je serais plus générique en utilisant la zone exemple.com et les adresses IP destinées aux documentations (RFC 5737 et RFC 2606.

Nous allons donc voir comment signer une zone DNS avec DNSSEC, car gérer son DNS faisant autorité c’est rigolo mais y ajouter DNSSEC ça l’est aussi.

DNSSEC est le protocole qui permet de sécuriser les données du DNS en signant les enregistrements d’une zone DNS.

Mini-introduction à DNSSEC

Le but de DNSSEC est que l’utilisateur final (ou plutôt son résolveur) puisse établir une chaîne de confiance entre la racine (en qui le résolveur à déjà confiance car il en connait les clés au démarrage) et le DNS faisant autorité lui donnant la réponse à sa requête.

En théorie le fonctionnement est le suivant :

  • chaque zone signe ses enregistrements de zone avec une clé ;
  • la zone parent possède un enregistrement de zone qui contient le hash de la clé dont la zone enfant se sert pour signer ;
  • il est de mise d’avoir confiance dans les clés de la racine, on peut vérifier toute la chaîne jusqu’aux enregistrements signés par la clé finale.

Par exemple pour example.com :

  • on a confiance dans les clés A de la racine et celle-ci signe ses enregistrements avec.
  • on interroge la racine qui nous dit d’aller interroger les DNS de com.
    • La racine à aussi un enregistrement qui indique que com signe avec une clé B
  • on interroge com qui nous dit d’aller interroger les DNS de example.com.
    • com à aussi un enregistrement qui indique que example.com signe avec une clé C.
  • on interroge example.com qui nous donne notre réponse en signant avec sa clé C

Au final on a donc la racine qui signe ses réponses avec la clé A, com qui signe ses réponses avec la clé B et example.com qui signe ses réponses avec la clé C. On a de base confiance en A, A à confiance en B et B à confiance en C : Ainsi on fait confiance aux réponses de example.com via toute la chaîne.

Cet exemple sert juste d’explication et est une simplification Dans la dure réalité, chaque zone n’a pas qu’une clé mais plusieurs et seulement deux clés actives en même temps : les KSK (Key Signing Keys) et les ZSK (Zone Signing Key).

Les KSK sont comme les clés A, B et C de notre exemple sauf qu’au lieu de signer directement les enregistrements DNS de la zone elles vont signer des ZSK qui elles vont signer les enregistrements de la zone.

La chaîne de confiance suit toujours le même principe sauf qu’il y a plus d’éléments. À noter que les hash de la clé fille dans la zone parent sont appelés DS (Delegation Signer).

Pour prendre un exemple concret :

/assets/images/dnssec/dnssec-lithiofr.png

Schema DNSSEC de lihio.fr

Dans ce schéma qui représente le chaîne DNSSEC jusqu’à lithio.fr1 :

  • On a confiance dans la clé qui à l’id 20326 de la racine.
  • On interroge la racine qui nous dit d’aller interroger les DNS de com.
    • La racine a bien la clé 20326 qui signe la clé 22545
    • La racine à aussi un enregistrement DS signé par 22545 qui indique que com signe avec la clé 35095
  • On interroge com qui nous dit d’aller interroger les DNS de example.com.
    • com a bien la clé 35095 qui signe la clé 28756
    • com à aussi un enregistrement DS signé par 28756 qui indique que example.com signe avec la clé 65035.
  • On interroge lithio.fr
    • lithio.fr a bien la clé 65035 qui signe la clé 6378
    • lithio.fr nous donne la réponse à notre requête en signant cette réponse avec la clé 6378

Ainsi en ayant confiance uniquement en une clé de la racine on peut vérifier les réponses de toute la chaîne.

Pour commencer

Dans cet article nous allons nous intéresser uniquement à la dernière partie (avec example.com). Notre but va être de générer une KSK, de transmettre le DS à la zone parent pour que celle-ci puisse dire que l’on signe avec cette KSK, d’utiliser la KSK pour signer des ZSK qui vont elles-mêmes signer les enregistrements DNS de notre zone.

Nou allons partir du principe que vous gérez déjà votre propre DNS faisant autorité avec Bind ou NSD par exemple.

La zone de départ (non signée) est déjà servie par BIND, dans une jail (FreeBSD 12.1-RELEASE-p1). Nous allons juste ajouter le gestion de DNSSEC

Nous allons donc devoir :

  • installer les programmes utiles ;
  • configurer le HSM (Notre stockage de clés) ;
  • configurer OpenDNSSEC ;
  • ajouter notre zone à OpenDNSSEC ;
  • publier notre zone ;
  • transmettre le DS à la zone parent ;
  • signer notre zone.

Installation des paquets

  Si vous utilisez une poudriere, pensez à compiler les paquets nécessaires.

On installe OpenDNSSEC et SoftHSM2 :

pkg install opendnssec softhsm2

Et on indique que l’on veux que opendnssec soit lancé au démarrage de la machine :

sysrc opendnssec_enable="yes"

OpenDNSSEC est le logiciel qui va s’occuper de la signature de la zone, la génération et la rotation des clés en suivant une politique que nous lui indiquerons.

SoftHSM2 est un HSM logiciel. (Nous n’avons pas de HSM matériel), un HSM est utilisé pour stocker des clés cryptographiques.

Configuration du HSM

On crée un slot HSM sur le slot 0 avec l’étiquette (TokenLabel) OpenDNSSEC, il nous demande un code pin administrateur et utilisateur.

  Noter ce code pin dans votre gestionnaire de mot de passe

# softhsm2-util --init-token --slot 0 --label "OpenDNSSEC"
=== SO PIN (4-255 characters) ===
Please enter SO PIN: ****
Please reenter SO PIN: ****
=== User PIN (4-255 characters) ===
Please enter user PIN: ****
Please reenter user PIN: ****
The token has been initialized and is reassigned to slot 364027858

On peut vérifier les informations avec la commande suivante :

# softhsm2-util --show-slots
Available slots:
Slot 364027858
    Slot info:
        Description:      SoftHSM slot ID 0x15b29fd2
        Manufacturer ID:  SoftHSM project
        Hardware version: 2.4
        Firmware version: 2.4
        Token present:    yes
    Token info:
        Manufacturer ID:  SoftHSM project
        Model:            SoftHSM v2
        Hardware version: 2.4
        Firmware version: 2.4
        Serial number:    6b9fa0e695b29fd2
        Initialized:      yes
        User PIN init.:   yes
        Label:            OpenDNSSEC

On constate également qu’il n’y a pour le moment aucune clé générée :

# ods-hsmutil list

Listing keys in all repositories.
0 keys found.

Repository            ID                                Type
----------            --

Configuration d’OpenDNSSEC

OpenDNSSEC contient 2 outils principaux qui nous intéressent : l’enforcer et le signer.

L’enforcer s’occupe de faire appliquer les politiques et le signer et bien signe.

Configuration générale

En éditant /usr/local/etc/opendnssec/conf.xml.

On modifie le bloc du HSM pour indiquer à OpenDNSSEC où sont stockées nos clés :

<Repository name="SoftHSM">
    <Module>/usr/local/lib/softhsm/libsofthsm2.so</Module>
    <TokenLabel>OpenDNSSEC</TokenLabel>
    <PIN>03032020</PIN>
    <SkipPublicKey/>
</Repository>

On ne touche pas à la configuration Common qui est bien comme elle est.

Les clés (surtout les ZSK) sont régulièrement changées, le logiciel en génèrent donc à l’avance pour assurer le remplacement de manière fluide. On va modifier la configuration de l’enforcer, pour générer nos clés 1 jour en avance.

<Enforcer>
<!--
<Privileges>
   <User>opendnssec</User>
   <Group>opendnssec</Group>
</Privileges>
-->
<!-- NOTE: Enforcer worker threads are not used; this option is ignored -->
    <WorkerThreads>8</WorkerThreads>

    <!-- <PidFile>/usr/local/var/run/opendnssec/enforcerd.pid</PidFile> -->
    <Datastore><SQLite>/usr/local/var/opendnssec/kasp.db</SQLite></Datastore>
    <!--Interval>PT900S</Interval-->
    <!-- <ManualKeyGeneration/> -->
    <!-- <RolloverNotification>P14D</RolloverNotification> -->
    <AutomaticKeyGenerationPeriod>P6D</AutomaticKeyGenerationPeriod>
    <!-- <DelegationSignerSubmitCommand>/usr/local/sbin/simple-dnskey-mailer.sh</DelegationSignerSubmitCommand> -->
</Enforcer>

On va modifier la configuration du signer pour indiquer – une fois la zone signée – à BIND de recharger la zone.

<Signer>
    <Privileges>
        <User>opendnssec</User>
        <Group>opendnssec</Group>
    </Privileges>


    <!-- <PidFile>/usr/local/var/run/opendnssec/signerd.pid</PidFile> -->
    <!-- <SocketFile>/usr/local/var/run/opendnssec/engine.sock</SocketFile> -->
    <WorkingDirectory>/usr/local/var/opendnssec/tmp</WorkingDirectory>
    <WorkerThreads>8</WorkerThreads>
    <SignerThreads>4</SignerThreads>


    <Listener>
        <Interface><Port>53</Port></Interface>
    </Listener>


    <!-- the <NotifyCommmand> will expand the following variables:

     %zone      the name of the zone that was signed
     %zonefile  the filename of the signed zone
        -->

    <NotifyCommand>/usr/local/bin/my_nameserver_reload_command</NotifyCommand>

    <NotifyCommand>/usr/local/sbin/rndc reload %zone</NotifyCommand>
</Signer>

Configuration Kasp

KASP pour “Key And Signature Policy” est la configuration qui contient les politiques génération et renouvellement des clés. Le mieux pour bien en comprendre le fonctionnement est d’en lire la documentation.

On va modifier /usr/local/etc/opendnssec/kasp.xml.

Nous devons ici éditer la configuration que nous allons utiliser, il y en a de base 2 :

  • default ;
  • lab.

Dans le cadre de ce test je vais utiliser lab mais en production il est préférable d’en utiliser d’autres, si par exemple vous souhaitez signer un domaine dont la zone parente est fr l’AFNIC à mis à disposition un document sur le sujet.

On voit également que l’on peut indiquer les algorithmes utilisés pour générer les clés, par défaut c’est le 8 (RSA-SHA256) qui est utilisé. Pour savoir quoi mettre la section 3.1 du RFC 8624 est bien utile en nous donnant un tableau qui contient les algorithmes que l’on doit, ne doit pas, ou devrait employer. Je vais utiliser ici le 13 (ECDSAP256SHA256) et indique que le renouvellement de la KSK est manuel (car il faudra l’envoyer à la zone parent à la main) :

<Keys>
    <!-- Parameters for both KSK and ZSK -->
    <TTL>PT300S</TTL>
    <RetireSafety>PT360S</RetireSafety>
    <PublishSafety>PT360S</PublishSafety>
    <!-- <ShareKeys/> -->
    <Purge>P14D</Purge>

    <!-- Parameters for KSK only -->
    <KSK>
        <Algorithm length="512">13</Algorithm>
        <Lifetime>P1Y</Lifetime><!-- Inactive -->
        <Repository>SoftHSM</Repository>
        <ManualRollover/>
    </KSK>

    <!-- Parameters for ZSK only -->
    <ZSK>
        <Algorithm length="512">13</Algorithm>
        <Lifetime>PT25H</Lifetime>
        <Repository>SoftHSM</Repository>
    </ZSK>
</Keys>

On vérifie que notre configuration soit correcte :

# ods-kaspcheck

On initialise la base de données de l’enforcer avec la commande :

# ods-enforcer-db-setup

On supprime le fichier /usr/local/etc/opendnssec/prevent-startup qui empêche le lancement d’OpenDNSSEC tant que celui-ci n’est pas configuré et on lance l’enforcer et le signer DNSSEC avec une seule commande :

# service opendnssec start

On importe nos politiques :

# ods-enforcer policy import

Normalement tout est prêt pour commencer à gérer nos zones.

Ajout de la zone à signer

OpenDNSSEC prévoit de mettre les fichiers de zones dans /var/opendnssec/unsigned/*et de voir le résultat signé dans /var/opendnssec/signed/.

  Cela n’est pas une obligation.

Bind utilise le répertoire /usr/local/etc/namedb/working pour les fichiers de zones, c’est ici que nous allons aussi mettre les fichiers de zones signées pour en faciliter la gestion.

Le fichier de zone signé se verra ajouté l’extension .signed.

On ajoute notre zone à l’enforcer :

# ods-enforcer zone add --zone dnssec.example.com --policy lab --input /usr/local/etc/namedb/working/dnssec.example.com --output /usr/local/namedb/working/dnssec.example.com.signed

Après chaque ajout de zone on joue la commande d’export afin de tenir le fichier zonelist.xml à jour :

# ods-enforcer zonelist export

Notre zone est normalement immédiatement signée et on peut vérifier ça dans les logs et dans le fichier de sortie.

On peut voir les clés dans notre HSM :

# ods-hsmutil list

Listing keys in all repositories.
9 keys found.

Repository            ID                                Type
----------            --                                ----
SoftHSM               1aa9234b8deeb67654e0a54073f1810f  ECDSA/256
SoftHSM               4fc296406405101f2ff07d5b57dbc3f9  ECDSA/256
SoftHSM               15be78d2934f0fffdbb56cf7be69e50a  ECDSA/256
SoftHSM               8b03481c104686d88c7e59d09043e776  ECDSA/256
SoftHSM               b53d288301fcaf678bffb152cf13ff80  ECDSA/256
SoftHSM               a755e62000e11e194c7d93a3b2c09395  ECDSA/256
SoftHSM               3f81735b5e1913ccfd0c15adafae47d9  ECDSA/256
SoftHSM               45a1dddc8e01d69c62de4a956efbd419  ECDSA/256
SoftHSM               2747f82955fea88a4495b94fc4f001be  ECDSA/256

À présent il faut indiquer à notre logiciel de DNS faisant autorité sur la zone d’utiliser ce nouveau fichier contenant les signatures DNSSEC.

Autrement dit, dans le fichier /usr/local/etc/namedb/named.conf.local on change file "/usr/local/etc/namedb/working/db.example.com"; par file "/usr/local/etc/namedb/working/db.example.com.signed";

On vérifie ensuite que les enregistrements RRSIG soient bien présent avec dig :

$ dig +dnssec dnssec.example.com

; <<>> DiG 9.11.5-P4-5.1-Debian <<>> +dnssec dnssec.example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 15101
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;dnssec.example.com.      IN  A

;; ANSWER SECTION:
dnssec.example.com.   56  IN  A   203.0.113.23
dnssec.example.com.   56  IN  RRSIG   A 13 3 60 20200102143140 20200102123044 
17006 dnssec.example.com. CNz7ipxye839NwTm2C3xXpCisJaSWBpfgCe1ZMCakmZc0NZ+rODXPWi/ Z1E25CkuKEa86Rg/NGl3tcU56K2o0A==

On note qu’il n’y a pas le flag ad, indiquant que le résolveur n’a pas validé avec DNSSEC, c’est normal.

Publier l’enregistrement DS

On vérifie l’état de notre zone :

$ ods-enforcer key list --verbose --all --zone dnssec.example.com
Keys:
Zone:                           Keytype: State:    Date of next transition: Size: Algorithm: CKA_ID:                          Repository: KeyTag:
dnssec.example.com                KSK      publish   2020-01-02 14:40:44      512   13         2747f82955fea88a4495b94fc4f001be SoftHSM     54859
dnssec.example.com                ZSK      ready     2020-01-02 14:40:44      512   13         1aa9234b8deeb67654e0a54073f1810f SoftHSM     17006

La KSK est en état publish, on attend qu’elle passe en état ready (On voit qu’elle attend qu’on lui indique que le DS est bien visible) :

# ods-enforcer key list --verbose --all --zone dnssec.example.com
Keys:
Zone:                           Keytype: State:    Date of next transition: Size: Algorithm: CKA_ID:                          Repository: KeyTag:
dnssec.example.com                KSK      ready     waiting for ds-seen      512   13         2747f82955fea88a4495b94fc4f001be SoftHSM     54859
dnssec.example.com                ZSK      active    2020-01-02 18:30:44      512   13         1aa9234b8deeb67654e0a54073f1810f SoftHSM     17006

On exporte alors son DS :

# ods-enforcer key export --zone dnssec.example.com --ds
;ready KSK DS record (SHA256):
dnssec.example.com.   3600    IN  DS  54859 13 2 b0f3c176f7f8d5a8712f87582b462d4e7f7450da7a8f24e2f2bb71c0fc212356

On le transmet à la zone parent. Dans mon cas je l’ajoute à la zone example.com mais sinon il faut en général le transmettre via votre bureau d’enregistrement qui doit avoir un formulaire pour cela.

Une fois le temps de juvénisation passé on indique à l’enforcer que l’enregistrement DS à étéi ¨vu¨ et que l’on peut signer avec, en précisant la KSK en question (son keytag) :

# ods-enforcer key ds-seen --zone dnssec.example.com --keytag 54859
1 KSK matches found.
1 KSKs changed.

On constate que notre KSK est à présent active :

# ods-enforcer key list -v --all --zone dnssec.example.com
Keys:
Zone:                           Keytype: State:    Date of next transition: Size: Algorithm: CKA_ID:                          Repository: KeyTag:
dnssec.example.com                KSK      active    2020-01-02 18:30:44      512   13         2747f82955fea88a4495b94fc4f001be SoftHSM     54859
dnssec.example.com                ZSK      active    2020-01-02 18:30:44      512   13         1aa9234b8deeb67654e0a54073f1810f SoftHSM     17006

On vérifie avec dig, normalement notre zone est à présent signée et le flag ad présent :

$ dig +dnssec dnssec.example.com

; <<>> DiG 9.11.5-P4-5.1-Debian <<>> +dnssec dnssec.example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 3212
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;dnssec.example.com.      IN  A

;; ANSWER SECTION:
dnssec.example.com.   60  IN  A   203.0.113.23
dnssec.example.com.   60  IN  RRSIG   A 13 3 60 20200102143140 20200102123044 17006 dnssec.example.com. CNz7ipxye839NwTm2C3xXpCisJaSWBpfgCe1ZMCakmZc0NZ+rODXPWi/ Z1E25CkuKEa86Rg/NGl3tcU56K2o0A==

Ajouter une nouvelle zone à signer

Si votre serveur DNS doit gérer une nouvelle zone à gérer via DNSSEC et bien, la plus grosse partie du travail est fait.

Il suffit :

  • faire le fichier de zone%nbsp;;
  • ajouter la zone au signer :
# ods-enforcer zone add --zone dnssec.example.net --policy lab --input /usr/local/etc/namedb/working/dnssec.example.net --output /usr/local/namedb/working/dnssec.example.net.signed
  • modifier le fichier de gestion de bind pour utiliser le fichier .signed ;
  • signer la zone avec ods-sign ;
  • export la nouvelle zone dans le fichier zonelist : ods-enforcer zonelist export
  • attendre et publier le DS record ;
  • indiquer que le DS a été vu ods-enforcer key ds-seen --zone dnssec.example.net --keytag 12345 ;
  • relancer bind ;
  • faire les vérifications d’usage avec dig.

Supprimer une zone

Pour supprimer une zone de la gestion de DNSSEC, il suffit de :

  • prévenir l’enforcer ods-enfocer delete <zone> ;
  • relancer bind ;
  • modifier le fichier de gestion de zone de BIND.

Monitoring

Il convient bien sûr de surveiller nos signatures DNSSEC afin de voir si un souci arrive, pour cela on peut consulter la section 3.5 du document de l’AFNIC.

Stéphane Bortzmeyer a également fait un article sur le sujet avec Icinga.

Il existe d’autres solutions mais ce n’est pas l’objet de cet article.

Conclusion

Une fois la mise en place, assez longue et fastidieuse, faite, le reste de la gestion est simple. Il faut simplement acquérir de nouveaux réflexes pour modifier une zone et la recharger.

L’outil dnsviz est utile pour vérifier la chaine de signature.

Une fois la zone signée, on peut avoir une confiance raisonnable envers les informations qui s’y trouvent, à condition toutefois d’utiliser un resolveur validant.

Il faut penser à sauvegarder les configurations et les clefs de softhsm2.

Remerciements

Merci à Stéphane Bortzmeyer2 et à Codimp qui m’a aider à comprendre, qui est à l’origne de ce billet (lisez le [sien] (https://toutetrien.lithio.fr/article/signer-sa-zone-dns-avec-opendnssec) et tous ceux et celles qui font tourner l’Internet Libre et Ouvert (bisous fdn).


  1. Je parle ici de la zone lithio.fr parce que j’ai la flemme de refaire le schema avec exemple.com ↩︎

  2. Il faut toujours remecier Stéphane Bortzmeyer, si tu ne sais pas pourquoi, lui le sais et inversement, ↩︎

powered by FreeBSD