Une zone locale home.arpa signée avec DNSSEC


Pour s'auto-authentifier

Ce billet fait suite à une question posée sur le fédivers : comment profiter d'une zone home.arpa. à soi et d'enregistrements SSHFP pour faciliter la gestion de SSH sur le réseau local. Question non triviale car SSHFP nécessite DNSSEC. Voyons donc comment signer une zone locale. La technique va impliquer 2 outils supplémentaires en plus d'Unbound : NSD pour servir la zone locale et ldns pour gérer DNSSEC (génération de clés, signature de la zone). Pour ce billet, je ne rentrerai pas dans les détails de DNSSEC (ZSK, KSK, DS...), une connaissance préalable de la chose est donc préférable.

Fichier de zone

Donc, ce n'est plus Unbound qui va servir la zone locale, mais NSD, un vrai serveur faisant autorité. La première étape va donc être de nettoyer la configuration Unbound pour y enlever les paramètres local-zone, local-data,... (si présents) et installer NSD. On édite un fichier de configuration dans /etc/nsd/nsd.conf.d/

server:
			interface: 127.0.0.1:53530 # On n'écoute que localement et surtout pas sur le port 53
		zone:
			name: "home.arpa"
			zonefile: "/etc/nsd/nsd.conf.d/home.arpa.zone.signed"

Le fichier de zone n'existe pas encore, fabriquons le. Avant d'avoir un fichier de zone signé, il faut un fichier... sans signatures. Il devrait ressembler à quelque chose comme cela :

$TTL 86400
		$ORIGIN home.arpa.
		@       14400	IN	SOA	ns.home.arpa.	hostmaster.home.arpa. (
						1	; Serial
						4H	; refresh after 4 hour
						1H	; retry after 1 hour
						3W	; expire after 3 weeks
						1H)	; minimun TTL of 1 hour

		;IPv4
		router		IN	A	192.168.0.1
		cthulhu		IN	A	192.168.0.2
		eth.azathoth	IN 	A	192.168.0.3
		wifi.azathoth	IN 	A	192.168.0.4

		;IPv6
		router		IN	AAAA	2001:db8:1a1a:ca11::1
		cthulhu		IN	AAAA	2001:db8:1a1a:ca11:0f:c700:100:1926

		;Divers
		azathoth	IN	TXT	"Une adresse par interface"

Quelques remarques :

DNSSEC

C'est donc ldns qui va gérer la partie DNSSEC. C'est une boîte à outils très utile, notamment pour une gestion artisanale de ses zones signées (pour industrialiser, on utiliserait OpenDNSSEC). Sous Debian, il s'agit du paquet ldnsutils. On l'installe :

		# apt-get install ldns-utils

Les 2 outils qui nous intéressent sont ldns-keygen et ldns-signzone. Les noms ont l'avantage d'être explicites.

Génération des clés

Il faut générer une ZSK et une KSK. Commençons par la ZSK. Avant cela, il faut choisir un algorithme. ldns est dépendant d'OpenSSL de ce point de vue là. Pour connaître la liste supportée par ldns, on entre :

		# ldns-keygen -a list
		Possible algorithms:
		RSAMD5
		RSASHA1
		RSASHA1-NSEC3-SHA1
		RSASHA256
		RSASHA512
		ECDSAP256SHA256
		ECDSAP384SHA384
		ED25519
		ED448
		DSA
		DSA-NSEC3-SHA1
		hmac-md5.sig-alg.reg.int
		hmac-sha1
		hmac-sha256
		hmac-sha224
		hmac-sha384
		hmac-sha512

Pour ce billet, on prendra un algorithme répandu : ECDSAP256SHA256. Une précision importante : ldns n'a pas d'option pour indiquer le répertoire où écrire les clés générées, il le fait automatiquement dans le répertoire courant. Pensez à bien se positionner avant la génération. Cette étape génera jusqu'à 3 fichiers pour chaque clé :

Générons donc notre ZSK

		# ldns-keygen -a ECDSAP256SHA256 home.arpa
		Khome.arpa.+013+53551

Puis la KSK. Même commande, on ajoute uniquement le paramètre -k

		# ldns-keygen -k -a ECDSAP256SHA256 home.arpa
		Khome.arpa.+013+18062

On vérifie que l'on a tout :

		# ls Khome.arpa.+013+*
		Khome.arpa.+013+18062.ds  Khome.arpa.+013+18062.key  Khome.arpa.+013+18062.private  Khome.arpa.+013+53551.key  Khome.arpa.+013+53551.private

Nous avons donc une clé avec l'id 18062

		cat Khome.arpa.+013+18062.key
		home.arpa.	IN	DNSKEY  257 3 13 bOcYev/grRO3AOc/mtc+VJNIsfpzTP2da1LhUreOrMUViE1CGY0wye1WXsAAqHIWBD0z5EtZCKV6qS0Y8OOg2g== ;{id = 18062 (ksk), size = 256b}

On a le drapeau 257, c'est bien une KSK. Vérifions la clé avec l'id 53551

		# cat Khome.arpa.+013+53551.key
		home.arpa.	IN	DNSKEY  256 3 13 l+GT51VQ/PgJuJUXr3j6RkXqyDSCj1djhK+HOyoviKQnqmRi5Qs/6m71jsQ4lxj9caVXC0KlJB1OMove0keDkw== ;{id = 53551 (zsk), size = 256b}

On a le drapeau 256, c'est bien une ZSK. Les indications en commentaires sont correctes, ldns a bien fait son travail.

Signature de la zone

Pour la signature, nous allons simplifier la procédure au maximum en ne s'occupant pas de NSEC (et NSEC3), ldns générant par défaut des enregistrement NSEC. Pour la durée de vie des signatures, 2 possibiltés :

On signe donc notre zone :

		# ldns-signzone -e $(($(date +%s) + 315365000)) -o home.arpa -f /etc/nsd/nsd.conf.d/home.arpa.zone.signed /etc/nsd/nsd.conf.d/home.arpa.zone Khome.arpa.+013+53551 Khome.arpa.+013+18062

S'il n'y a pas de messages d'erreurs, vérifions le fichier généré :

		# cat /etc/nsd/nsd.conf.d/home.arpa.zone.signed
		home.arpa.      14400   IN      SOA     ns.home.arpa. hostmaster.home.arpa. 1 14400 3600 1814400 3600
		home.arpa.      14400   IN      RRSIG   SOA 13 2 14400 20301112033940 20201114021620 53551 home.arpa. u7KPfzsPJXeal/24cdLbkCpCQzcb25Sn+Dch6yjIaKYv5M9/8b6pHR/XWVcvTUNVKL/P01FT1LtcrSEyTABKkw==
		home.arpa.      14400   IN      DNSKEY  256 3 13 l+GT51VQ/PgJuJUXr3j6RkXqyDSCj1djhK+HOyoviKQnqmRi5Qs/6m71jsQ4lxj9caVXC0KlJB1OMove0keDkw== ;{id = 53551 (zsk), size = 256b}
		home.arpa.      14400   IN      DNSKEY  257 3 13 bOcYev/grRO3AOc/mtc+VJNIsfpzTP2da1LhUreOrMUViE1CGY0wye1WXsAAqHIWBD0z5EtZCKV6qS0Y8OOg2g== ;{id = 18062 (ksk), size = 256b}
		home.arpa.      14400   IN      RRSIG   DNSKEY 13 2 14400 20301112033940 20201114021620 18062 home.arpa. 85j6NrPruCrPcytBe4ckfse9EnCfUfYeMjHQ69+chYtvk6J0wlmAF1SraSS/wgCWx2FciFhCMdzCYAjUr7kfjQ==
		home.arpa.      3600    IN      NSEC    azathoth.home.arpa. SOA RRSIG NSEC DNSKEY
		...

Tout semble bon. On peut relancer NSD.

		# systemctl restart nsd

Si dans le futur vous modifiez la zone :

		# nsd-control reload home.arpa

Configuration d'Unbound

Le plus dur est fait, reste à configurer le résolveur. Il y a 2 éléments à passer à Unbound :

Pour ce dernier paramètre, on récupère l'enregistrement DS précédemment généré

		# cat Khome.arpa.+013+18062.ds
		home.arpa.	IN	DS	18062 13 2 4eda0e1d8f64c986f3f1e5bb1f2ba834af9847955b0b1a8d5fc29c1e0cb9791a

On le copie, et on configure Unbound

server:
		...
			trust-anchor: "home.arpa.      IN      DS      18062 13 2 4eda0e1d8f64c986f3f1e5bb1f2ba834af9847955b0b1a8d5fc29c1e0cb9791a"

		stub-zone:
			name: "home.arpa."
			stub-addr: 127.0.0.1@53530

On le redémarre et on teste

		# dig cthulhu.home.arpa

		; <<>> DiG 9.16.6-Debian <<>> cthulhu.home.arpa
		;; global options: +cmd
		;; Got answer:
		;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 6043
		;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

		;; OPT PSEUDOSECTION:
		; EDNS: version: 0, flags:; udp: 1232
		;; QUESTION SECTION:
		;test.home.arpa.                        IN      A

		;; ANSWER SECTION:
		cthulhu.home.arpa.         86400   IN      A       192.168.0.2

		;; Query time: 0 msec
		;; SERVER: 127.0.0.1#53(127.0.0.1)
		;; WHEN: sam. nov. 14 03:31:05 CET 2020
		;; MSG SIZE  rcvd: 59

On a bien le bit AD (Authentificated Data), indiquant que la réponse est validée. Tout fonctionne bien donc. Une dernière chose : sur les systèmes récents, disposant de la libc6 2.31 (et supérieure), le système ne transmet plus automatiquement le bit AD aux applications qui en ont besoin (c'est a priori le cas de SSH lorsqu'on utilise SSHFP — à tester ceci dit, n'utilisant pas SSHFP — ou gnutls-cli lorsque l'on essaye d'utiliser DANE). Pour que les applications disposent de ce bit, il faut ajouter l'option suivante à votre resolv.conf :

options trust-ad

Ajoutons que ce nouveau comportement par défaut de libc6 est pensé pour les environnement où le résolveur n'est pas forcément fiable. S'il tourne localement, ce n'est normalement pas le cas (à moins de ne pas se faire confiance 🙂).