Première rédaction de cet article le 28 octobre 2017
Le système DANE, normalisé dans le RFC 6698, permet de vérifier l'authenticité du certificat d'un serveur TLS, grâce à des enregistrements signés dans le DNS. Comme ces enregistrements doivent toujours être synchrones avec le certificat, il est prudent de les superviser.
DANE fonctionne en publiant dans le DNS un enregistrement qui résume le certificat utilisé par le serveur TLS. Les certificats changents (renouvellement, révocation) et l'enregistrement dans le DNS doit donc suivre ces changements. En outre, dans la plupart des organisations de taille moyenne ou grosse, ce n'est pas la même équipe qui gère le DNS et les serveurs TLS. Il y a donc un gros potentiel de mécommunication, et c'est pour cela que la supervision est cruciale.
J'utilise le logiciel Icinga pour cette
supervision, mais l'essentiel des techniques présentées ici
marcherait avec tous les logiciels compatibles avec
l'API des Monitoring
Plugins. Première étape, il nous faut un programme qui
teste l'état des enregistrements
DANE. Nous allons nous appuyer sur le
programme tlsa
, qui fait partie de hash-slinger. Cet ensemble de programme est dans un paquetage
Debian, donc l'installer est aussi simple que :
% aptitude install hash-slinger
Une fois qu'il est installé, testons-le avec un site Web qui a des enregistrements DANE :
% tlsa --verify dns.bortzmeyer.org SUCCESS (Usage 1 [PKIX-EE]): Certificate offered by the server matches the one mentioned in the TLSA record and chains to a valid CA certificate (204.62.14.153) SUCCESS (Usage 1 [PKIX-EE]): Certificate offered by the server matches the one mentioned in the TLSA record and chains to a valid CA certificate (2605:4500:2:245b::42)
(Il y a deux lignes car le nom dns.bortzmeyer.org
a deux adresses IP et,
potentiellement, il pourrait s'agir de serveurs
HTTP, voire de deux machines différentes.)
En prime, tlsa
définit évidemment le code de
retour :
% tlsa --verify dns.bortzmeyer.org ; echo $? ... 0
Si l'enregistrement TLSA a un problème, le code de retour est différent de zéro :
% tlsa --verify dougbarton.us ; echo $? FAIL: Certificate offered by the server does not match the TLSA record (208.79.90.218) FAIL: Certificate offered by the server does not match the TLSA record (2607:f2f8:ab14::2) 2
Rien de magique dans la commande tlsa
, on
aurait pu faire la vérification manuellement, par exemple pour
mercredifiction.bortzmeyer.org
:
% dig TLSA _443._tcp.mercredifiction.bortzmeyer.org ... ;; ANSWER SECTION: _443._tcp.mercredifiction.bortzmeyer.org. 86400 IN TLSA 1 1 1 ( 928DDE55DF4CD94CDCF998C55085FBB5228B561CC237 A122D950260029C5B8C9 ) _443._tcp.mercredifiction.bortzmeyer.org. 86400 IN RRSIG TLSA 8 5 86400 ( 20171113165155 20171025071419 50229 bortzmeyer.org. eRNZfL8ERWhs0SIGYHOIMh1l+tzFFfvDmV7XlPxd8BYa ...
Puis comparer avec ce que donne openssl
. Les commandes
exactes à utiliser dépendent évidemment de l'usage et du
sélecteur indiqués dans l'enregistrement TLSA, cf. RFC 6698. Par exemple, avec le sélecteur 0 (on
prend tout le certificat, pas juste la clé), on pourrait utiliser
openssl x509 -fingerprint
. Ici, avec le
sélecteur 1 (seulement la clé) :
% openssl s_client -servername mercredifiction.bortzmeyer.org -showcerts -connect mercredifiction.bortzmeyer.org:443 | \ openssl x509 -noout -pubkey | openssl pkey -outform der -pubin | openssl dgst -sha256 ... (stdin)= 928dde55df4cd94cdcf998c55085fbb5228b561cc237a122d950260029c5b8c9
On voit qu'on a le même condensat,
928dde55df4cd94cdcf998c55085fbb5228b561cc237a122d950260029c5b8c9
,
donc tout va bien.
(Ne pas oublier le SNI - RFC 6066, l'option
-servername
, sans laquelle vous risquez de
récupérer un mauvais certificat.)
Bien, on a désormais un moyen de tester qu'un serveur TLS a bien un certificat qui correspond à l'enregistrement DANE. Maintenant, il faut emballer tout ça dans un script qui est conforme à l'API des monitoring plugins. Le script (trivial), écrit en shell, est disponible ici. Testons-le :
% /usr/local/lib/nagios/plugins/check_dane_http -H www.afnic.fr ; echo $? OK - SUCCESS (Usage 3 [DANE-EE]): Certificate offered by the server matches the TLSA record (192.134.5.24) SUCCESS (Usage 3 [DANE-EE]): Certificate offered by the server matches the TLSA record (2001:67c:2218:30::24) 0 % /usr/local/lib/nagios/plugins/check_dane_http -H dougbarton.us ; echo $? DANE server 'dougbarton.us' has a problem: FAIL: Certificate offered by the server does not match the TLSA record (208.79.90.218) FAIL: Certificate offered by the server does not match the TLSA record (2607:f2f8:ab14::2) 2 % /usr/local/lib/nagios/plugins/check_dane_http -H ssi.gouv.fr ; echo $? DANE server 'ssi.gouv.fr' has a problem: Unable to resolve ssi.gouv.fr.: Unsuccessful DNS lookup or no data returned for rrtype TLSA (52). 2
Le premier domaine a un enregistrement TLSA et marche bien. Le second, comme vu plus haut, a un enregistrement TLSA mais incorrect. Le troisième n'a pas d'enregistrement TLSA.
On peut désormais configurer Icinga pour utiliser ce script :
object CheckCommand "dane_http" { command = [ PluginContribDir + "/check_dane_http" ] arguments = { "-H" = "$dane_domain$" } } ... apply Service for (dane_domain => config in host.vars.dane_domains) { import "generic-service" check_command = "dane_http" vars.dane_domain = dane_domain } ... vars.dane_domains["dns.bortzmeyer.org"] = true
(Bon, ça serait mieux si on pouvait spécifier indépendemment le nom à tester, l'adresse IP du serveur, et le nom qui va apparaitre dans l'interface Web d'Icinga. Mais j'étais paresseux et j'ai fait simple.)
Voilà, désormais Icinga surveille périodiquement l'enregistrement DANE et le certificat TLS et tout va bien :
S'il y a un problème, on sera averti et on verra le problème dans l'interface Web d'Icinga. Ici, par exemple, l'enregistrement TLSA était pour le certificat entier (sélecteur 0) et un renouvellement a changé le certificat (mais pas la clé). Le message d'Icinga indiquait :
CRITICAL since 00:59 Service: mercredifiction.bortzmeyer.org Plugin Output DANE server 'mercredifiction.bortzmeyer.org' has a problem: FAIL: Certificate offered by the server does not match the TLSA record (217.70.190.232) FAIL: Certificate offered by the server does not match the TLSA record (2001:4b98:dc0:41:216:3eff:fece:1902)
Cet incident a permis de tester que la supervision de DANE marchait
bien 😁. Mais il mérite davantage de discussion. Dans ce cas
précis, l'enregistrement TLSA commençait par « 1 0 1 ». Cela veut
dire « Usage 1, Sélecteur 0, Correspondance 0 » (voir les
explications dans le RFC 6698) ou bien, en
utilisant les mnémoniques du RFC 7218 (que
tlsa
affiche), « Usage PKIX-EE, Sélecteur Cert,
Correspondance SHA-256 ». Et en français ? L'usage PKIX-EE veut dire que
l'enregistrement TLSA doit désigner un certificat qui est à la fois
valide selon les règles PKIX (RFC 5280) traditionnelles et selon DANE,
avec le certificat du serveur, pas celui de
l'AC. Ensuite, le sélecteur Cert indique que
l'enregistrement TLSA doit être un condensat
du certificat entier. Or, le renouvellement d'un certificat change
les métadonnées (comme, évidemment, la date
d'expiration) et donc le condensat. Dans ces conditions, il vaut
mieux utiliser le sélecteur 1 (SPKI), où l'enregistrement TLSA va
désormais indiquer uniquement la clé, pas tout le certificat. C'est
également l'avis
de Let's Encrypt..
Voilà, maintenant que ça marche, prochaine étape : faire la même chose pour
SMTP (RFC 7672),
tlsa
sachant gérer le TLS lancé après la
connexion. Exemple :
% tlsa --verify --port 25 --starttls smtp mail.bortzmeyer.org SUCCESS (Usage 2 [DANE-TA]): A certificate in the certificate chain offered by the server (including the end-entity certificate) matches the TLSA record (217.70.190.232) SUCCESS (Usage 2 [DANE-TA]): A certificate in the certificate chain offered by the server (including the end-entity certificate) matches the TLSA record (2001:4b98:dc0:41:216:3eff:fece:1902)
Autres solutions possibles pour tester DANE :
openssl
seul, avec
ses options -dane_tlsa_domain
et
-dane_tlsa_rrdata
: ainsi, openssl
s_client -dane_tlsa_domain mercredifiction.bortzmeyer.org
-dane_tlsa_rrdata "$(dig +short +nodnssec TLSA
_443._tcp.mercredifiction.bortzmeyer.org)" -connect
mercredifiction.bortzmeyer.org:443
vous affichera un
succès (DANE TLSA 1 1 1 ...c237a122d950260029c5b8c9
matched EE certificate at depth 0
) et le test sur un
domaine à problème (openssl s_client -dane_tlsa_domain
dougbarton.us -dane_tlsa_rrdata "$(dig +short +nodnssec TLSA
_443._tcp.dougbarton.us)" -connect dougbarton.us:443
)
donnera Verification error: No matching DANE TLSA
records
.Version PDF de cette page (mais vous pouvez aussi imprimer depuis votre navigateur, il y a une feuille de style prévue pour cela)
Source XML de cette page (cette page est distribuée sous les termes de la licence GFDL)