Aller au contenu principal

Article

Ce qu’un état Terraform partagé coûte vraiment

Temps de lecture : 7 minutes

Une commande destinée à supprimer un enregistrement DNS a détruit l’infrastructure de production d’un éditeur SaaS, un vendredi après-midi. Trois personnes ont passé le week-end à la reconstruire.

Ce qui suit n’est pas le récit d’une erreur de manipulation. C’est l’analyse de ce qui a permis à une erreur de manipulation d’avoir cette portée.

Le système, tel qu’il était

Un état Terraform unique décrivait l’ensemble de l’infrastructure : les enregistrements DNS, les clusters Kubernetes, les interfaces applicatives, les images de conteneurs. Tout ce qui existait figurait dans un seul fichier, hébergé dans un compte de stockage partagé et manipulé depuis les postes de travail.

Cette configuration n’a rien d’exceptionnel. Elle est même la trajectoire par défaut : on commence par déclarer une ressource, puis une deuxième, et personne ne décide jamais explicitement de tout regrouper — c’est simplement ce qui arrive quand on ne décide rien.

Ce qui s’est passé

Une opération sur une ressource mineure. Une variable d’environnement absente au moment de l’exécution. La commande s’est appliquée à la totalité de l’état.

Le temps de comprendre ce qui se passait, la production n’existait plus.

La conclusion qu’il ne faut pas tirer

Il est tentant de s’arrêter à « il fallait faire attention ».

C’est la conclusion qui garantit que l’incident se reproduira, parce qu’elle ne change rien au système. Elle transforme une défaillance d’architecture en défaillance de vigilance, et la vigilance n’est pas une propriété qu’on peut exiger de façon fiable — surtout un vendredi à seize heures, dans une équipe de deux personnes qui ont passé la semaine à autre chose.

Un dispositif dans lequel une erreur d’inattention détruit la production est un dispositif défaillant. Cela reste vrai quelle que soit la personne qui commet l’erreur, et cela reste vrai les jours où personne ne la commet.

La cause racine

Un état unique signifie qu’il n’existe aucune limite au rayon de souffle.

Rayon de souffle d’une commandeAvec un état unique, une commande se propage à l’ensemble des ressources décrites : enregistrements DNS, clusters, applications, images. Avec des états découpés, une commande lancée dans le périmètre des enregistrements DNS n’atteint que cet état, les autres restent hors de portée.Un état uniqueÉtats découpéscommandeDNSclustersappsimagesun seul étatrayon de souffle : tout l’étatcommandeétat DNSétat clusterétat appsrayon de souffle : un étatHier : toute commande pouvait atteindre l’ensemble.Aujourd’hui : une commande s’arrête à son état.Rayon de souffle d’une commandeAvec un état unique, une commande se propage à l’ensemble des ressources décrites : enregistrements DNS, clusters, applications, images. Avec des états découpés, une commande lancée dans le périmètre des enregistrements DNS n’atteint que cet état, les autres restent hors de portée.Un état uniquecommandeDNSclustersappsimagesun seul étatrayon de souffle : tout l’étatÉtats découpéscommandeétat DNSétat clusterétat appsrayon de souffle : un étatHier : toute commande pouvait atteindre l’ensemble.Aujourd’hui : une commande s’arrête à son état.

C’est le point central, et il mérite d’être formulé précisément : dans cette configuration, toute commande — quelle que soit son intention, quelle que soit la ressource visée — s’exécute avec la capacité technique de détruire l’ensemble. L’écart entre « je supprime un enregistrement DNS » et « je détruis les clusters de production » n’est pas protégé par une barrière. Il est protégé par le fait que la commande est bien formée.

Trois autres manques ont amplifié l’incident.

Aucune séparation entre environnements. Rien ne distinguait techniquement ce qui pouvait être détruit sans conséquence de ce qui ne le pouvait pas.

Aucune relecture systématique du plan avant application. Terraform annonce ce qu’il s’apprête à faire ; encore faut-il que ce soit une étape obligatoire plutôt qu’une bonne habitude.

Aucune sauvegarde des charges applicatives sur Kubernetes. C’est le manque qui a coûté le plus de temps pendant le week-end. Reconstruire une infrastructure décrite en code est long mais mécanique. Reconstituer l’état applicatif qui vivait dedans, sans sauvegarde, l’est beaucoup moins.

Ce qui a été corrigé

La sauvegarde des clusters a été mise en place dans la foulée, avec Velero — ressources Kubernetes et volumes persistants. C’était le manque le plus coûteux et le plus rapide à combler.

Sauvegarde Velero et restauration testéeVelero sauvegarde les ressources Kubernetes et les volumes persistants du cluster vers un stockage objet. La restauration est rejouée dans un cluster de test : elle donne le temps réel de remise en service, l’ordre de reprise des services et la liste de ce qui ne revient pas tout seul.Cluster AKSressources Kubernetesvolumes persistantssauvegardeStockage objetsauvegardes VelerorestaurationCluster de testressources + volumes restaurésCe que le test donnetemps réel de remise en serviceordre de reprise des servicesce qui ne revient pas tout seulUne sauvegarde ne prouve rien.Une restauration testée, si.Sauvegarde Velero et restauration testéeVelero sauvegarde les ressources Kubernetes et les volumes persistants du cluster vers un stockage objet. La restauration est rejouée dans un cluster de test : elle donne le temps réel de remise en service, l’ordre de reprise des services et la liste de ce qui ne revient pas tout seul.Cluster AKSressources Kubernetesvolumes persistantssauvegardeStockage objetsauvegardes VelerorestaurationCluster de testressources + volumes restaurésCe que le test donnetemps réel de remise en serviceordre de reprise des servicesce qui ne revient pas tout seulUne sauvegarde ne prouve rien.Une restauration testée, si.

Mais une sauvegarde ne prouve rien tant qu’elle n’a pas été restaurée. Le dispositif a donc été éprouvé : ressources Kubernetes et volumes persistants restaurés depuis les sauvegardes Velero dans un cluster de test, jusqu’au redémarrage effectif des applications.

Ce test donne ce qu’aucun rapport au vert ne donne : le temps réel de remise en service, l’ordre dans lequel les services doivent revenir, et la liste de ce qui ne revient pas tout seul. Entre deux restaurations testées, une sauvegarde n’est pas une garantie, c’est une hypothèse.

Le découpage de l’état, lui, est une correction plus lourde : elle demande de reprendre l’organisation du code, pas d’ajouter un outil.

Ce que je fais différemment aujourd’hui

Sur l’infrastructure que je construis actuellement, quatre décisions découlent directement de cet incident.

L’état est découpé selon deux axes. Le cycle de vie d’abord : ce qui ne doit jamais être détruit vit dans un état séparé de ce qui a vocation à l’être. La fréquence de changement ensuite : les ressources qu’on modifie tous les jours ne partagent pas leur état avec celles qu’on ne touche jamais. Une commande lancée dans le périmètre des enregistrements DNS n’a plus la capacité technique d’atteindre le cluster.

L’identité d’exécution est dédiée et bornée. Terraform ne s’exécute pas sous mon compte, mais sous une identité qui ne porte que les permissions de ce qu’il gère — pas de droits sur la facturation, pas de droits d’administration des identités. Les journaux d’audit distinguent ce que j’ai fait de ce que l’outil a fait.

L’état est protégé contre sa propre destruction. Le stockage qui contient l’état vit dans un projet distinct de celui qu’il décrit, et porte une protection explicite contre la suppression. Le principe : un mécanisme de reprise ne doit pas vivre dans ce qu’il répare.

Aucun secret permanent. L’authentification passe par des jetons de courte durée dérivés d’une identité, plutôt que par une clé qui traîne sur un disque.

Ce que j’en retiens

Le rayon de souffle d’une commande est une décision d’architecture, prise longtemps avant l’incident et généralement sans qu’on s’en aperçoive. On ne décide pas de tout mettre dans le même état ; on omet de décider le contraire, ce qui revient au même le jour où ça compte.

Et une sauvegarde ne vaut que par sa dernière restauration réussie.

Retour aux articles