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 :
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é vuods-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).