DNS: faisez gaffe aux wildcard !
Encore un déterrage de brouillon, sur un problème qui doit être toujours d’actualité dans son concept. Un Problème surprenant (pour les pros du DNS peut-être pas), mais voilà, on a eu droit à un incident inattendu, que je voulais partager pour sa bizarrerie apparente. Parce que si j’ai trouvé la solution assez rapidement, il m’a fallu du temps pour comprendre, et je suis pas encore certain d’avoir tout intégré, même deux ans et demi après.
Pour fournir une résolution souple aux clients sur leur plateforme Kubernetes (parce que pourquoi pas), on leur a fourni un alias à configurer sur leur propre zone, histoire de ne pas avoir à dépendre d’eux pour d’éventuelles migrations/reconfigurations déménagements. Cet alias repose sur une fonctionnalité du DNS, les wildcard. Ça donne quelque chose dans ce genre-là :
#notredomaine.fr prd A 1.2.3.4 sta A 5.6.7.8 *.prd CNAME prd *.sta CNAME sta
On l’aura compris, « prd » c’est le cluster de prod, « sta » le cluster de staging. De leur côté, les clients déclarent l’alias dans leur propre zone :
www.domainX.com CNAME www.domainX.com.prd.notredomaine.fr
Dans une situation simple, classique, c’est l’alias *.prd
qui prend en charge et fournit la réponse aux clients qui cherchent à joindre un des domaines concernés par ce dispositif. Ah, et en passant, on ne peut pas appliquer un CNAME à l’apex (autrement appelé la racine) d’un domaine (RFC je sais plus, demandez à votre moteur de recherche). Et si vous vous demandez pourquoi un tel setup, c’est qu’on se sert aussi d’un tel « domaine technique » (comprendre un domaine différent de celui du vrai site et géré par nos soins) pour pouvoir tester le site dans différentes situations sans reposer sur le nom de domaine du client, notamment pendant certaines phases de validation, et pour pouvoir gérer ça au niveau des Ingress Rules.
Déplacement d’Ingress Controller, arrivent les problèmes
Eh oui, parce que la vie est ainsi faite, on nous demande de déployer un Ingress Controller particulier avec des paramètres bien précis, donc une nouvelle adresse IP, et de déplacer certains des sites derrière celui-ci. Je vais pas détailler la partie « kube » de ce dispositif, c’est assez trivial en principe (cherchez ingressClass si vraiment vous voyez toujours pas), mais voilà comment on prépare côté DNS :
prd-private A 4.3.2.1 *.prd-private CNAME prd-private
Et quand on doit bouger www.domain2.com
, avec notre dispositif, avec le Go du client, j’applique la modif côté cluster et je déplace de manière explicite côté DNS de mon côté:
www.domain2.com.prd CNAME prd-private
Et là, patatras. Quand un collègue est venu me voir au bout d’un quart d’heure, en me disant qu’un autre domaine sans rapport avec ma modification était tombé, et ayant l’historique prouvant que j’étais le dernier à avoir modifié notre zone notredomaine.fr
, il est clair que l’effet de bord n’avait pas été correctement anticipé. Mais quel effet me direz-vous, sachant qu’on avait testé en staging avant sans avoir détecté ce genre de comportement ?
Le premier indice, c’est que tous les domaines ne sont pas concernés. Sur les 4 alertes qui sont apparues, le point commun est que toutes les URLs ont des domaines en .com
. Le second, c’est que ma modif fonctionne pour mon propre domaine. Au bout de cinq minutes, je dis à Camille : « je suis pas sûr mais je tente un truc ». J’ai rajouté une ligne :
*.com.prd CNAME prd
Et ça répond à nouveau. J’ai eu du pif, mais j’avoue que sur le moment, c’est plus de l’instinct qu’autre chose, et j’aurais été bien en peine d’expliquer pourquoi, mais au niveau du comportement, on voit maintenant ce qui se passe. Je vais essayer de formuler du mieux possible ce que j’en ai compris.
Explication pas forcément claire
Pour rappel, dans le DNS les domaines fonctionnent par niveau, chaque niveau est séparé par un point. On parle souvent de « sous-domaine », mais c’est un abus de langage, en pratique, chaque niveau dispose des mêmes fonctionnalités et propriétés, ils héritent de certaines caractéristiques, le système étant hiérarchique (com, domain.com, www.domain.com, etc). Dans le cas qui nous occupe, tant qu’on avait qu’un seul wildcard pour tout ce qui concernait les niveaux au dessus de prd.mondomaine.fr
, le résolveur ne se posait pas trop de questions et répondait à tout. Mais quand j’ai déclaré www.domain2.com.prd
dans mondomaine.fr
, j’ai donc déclaré au moins une entrée sur .com.prd
. À partir de ce moment-là, cette déclaration explicite exclut toutes les autres réponses par le wildcard. La seule solution de contournement implique de déclarer un wilcard supplémentaire pour ce niveau spécifiquement afin de retrouver un comportement initial.
Pourquoi ce comportement ? Eh bien, comme je l’ai dit, les domaines sont gérés par niveau, et il faut savoir que chaque niveau peut être délégué / géré par un résolveur différent. Dès lors, déclarer une entrée spécifique pour un niveau implique que le résolveur arrête d’appliquer les propriétés des niveaux précédents aux niveaux suivants, ce que permet justement le wildcard. Et c’est logique, si un niveau contient des informations (ici au moins un CNAME), si jamais il est délégué, on n’est pas censé répondre à la place dudit délégué. Certes ici c’est le même, et donc il aurait pu continuer de répondre. Il faut se souvenir que le système de DNS remonte à 1983, et même s’il a été mis à jour à la marge, la majorité du fonctionnement intrinsèque n’a pas bougé, et cette gestion en niveaux en fait partie.
On évite les wildcard alors ?
Certains diront oui, mais dans le monde réel, parfois c’est plus pratique/évident de faire avec (tout le monde ne peut pas composer avec de la résolution dynamique comme le fait Kubernetes en interne). Ici, la solution la plus pratique aurait été de supprimer l’utilisation des .com/.fr/.it/.whatever des alias, et ne garder que le nom sans le TLD, ce qui aurait rendu chaque entrée plus unique et donc limité l’impact de l’exclusion du wildcard global du « calcul » de la réponse.
Dans certaines situations, déléguer le niveau de l’alias est une solution plus adaptée, notamment dans le cadre de l’usage certains outils comme les CDN Cloudflare ou Akamai, ainsi ils se chargent notamment de la mise à jour dynamique de la ou les adresses IP par lesquelles vous passez. Certains utilisent aussi du DNS « géographique », à savoir donner une réponse différente en fonction de là où vous vous trouvez sur le réseau (plus ou moins corrélé à votre emplacement physique), réponse qui doit pointer sur un serveur plus proche et donc plus « performant ». Bref, vous l’aurez compris, le wildcard dans le DNS n’est pas toujours la solution la plus adaptée, et ce problème rencontré en production est là pour le rappeler.
Ah, et pour ceux qui pensent qu’on aurait pu juste tout déclarer manuellement, quand on pense une plateforme pour de l’hébergement massif, semi-dynamique, et qu’on a pas les API / accès pour gérer la zone programmatiquement, et qu’on a passé les 50 sites, ben utilise les wildcards DNS « épicétou »