Votre sauvegarde ressuscite en silence les utilisateurs que vous avez supprimés
Toute sauvegarde incrémentale repose sur la même hypothèse silencieuse : pour sauvegarder ce qui a changé, il faut trouver les lignes qui ont changé. Sur un magasin clé-valeur comme Azure Table Storage ou DynamoDB, « ce qui a changé » signifie « les lignes dont l'horodatage de dernière modification est plus récent que mon dernier repère ». On parcourt la table, on prend tout ce qui est plus récent, on l'écrit. Rapide, pas cher, correct.
Correct pour les écritures. Maintenant, supprimez une ligne.
La ligne ne reçoit pas d'indicateur « supprimé ». Elle ne reçoit pas d'horodatage plus récent. Elle ne part pas dans une corbeille. Elle cesse simplement d'exister. Ces magasins n'ont ni marqueurs de suppression ni flux de changements pour les suppressions, donc une ligne supprimée ne laisse derrière elle exactement rien. Votre sauvegarde incrémentale, qui repère les changements en cherchant des horodatages plus récents, passe tout droit devant l'espace vide où la ligne se trouvait et ne trouve rien. Il n'y a rien à trouver. La suppression est invisible.
Ce qui veut dire que votre sauvegarde contient toujours la ligne. Et c'est là qu'une histoire de perte de données devient une histoire de sécurité.
Pensez à ce qu'une suppression signifie généralement dans un système d'authentification. Vous n'avez pas supprimé cet utilisateur pour le plaisir. Vous avez supprimé le compte d'un salarié qui partait. Vous avez retiré un compte dont le mot de passe est apparu dans un dump de fuite. Vous avez révoqué un octroi OAuth après la fuite d'un jeton. Vous avez retiré les accès d'un administrateur le jour de son départ. Chacune de ces actions est une décision de sécurité, et aucune ne survit à une sauvegarde qui ne voit pas les suppressions.
Alors vous restaurez. Peut-être après un vrai sinistre, peut-être juste vers un clone de staging. La sauvegarde fait exactement ce que vous lui avez demandé : elle remet chaque ligne qu'elle connaît. Le salarié parti est de nouveau un utilisateur. Le mot de passe compromis est de nouveau valide. L'octroi révoqué fonctionne de nouveau. L'administrateur écarté est de nouveau administrateur. Votre restauration n'a pas perdu de données. Elle a annulé vos décisions de sécurité, en silence, et vous a rendu un système qui a l'air sain et qui est discrètement compromis. Une sauvegarde qui oublie une suppression est pire que pas de sauvegarde du tout, parce que vous lui faites confiance.
La solution, c'est d'arrêter de traiter une suppression comme l'absence d'une ligne et de commencer à la traiter comme un événement. Les suppressions sont des données.
Nous donnons donc aux suppressions leur propre table. Chaque suppression du système passe par un ITombstoneWriter injecté qui enregistre un tombstone, une pierre tombale : la clé, et l'heure de la mort. Il n'existe aucun chemin de code qui supprime une ligne sans laisser de tombstone, parce que la suppression et le tombstone sont une seule opération. Une sauvegarde incrémentale devient alors deux parties capturées à un même repère : les upserts (les lignes à l'horodatage plus récent) et les tombstones (les suppressions depuis le dernier repère). La restauration rejoue les deux dans l'ordre chronologique, si bien qu'une suppression s'applique exactement comme une écriture, et qu'une clé supprimée puis recréée se résout à ce qui est arrivé en dernier. L'espace vide a enfin un enregistrement qui lui est attaché.
Voilà toute l'astuce, et elle est petite. La raison pour laquelle elle compte ne l'est pas.
Le schéma dépasse Table Storage et DynamoDB. Tout système qui modélise une suppression comme « la ligne n'est plus là » ne peut ni sauvegarder, ni répliquer, ni synchroniser les suppressions, parce qu'il n'y a rien à transporter. On le retrouve dans les replays d'événements naïfs qui ne rejouent que les créations et les mises à jour. On le retrouve dans les caches qui expirent mais ne s'invalident jamais. On le retrouve dans les réplicas de lecture qui dérivent parce que la suppression ne s'est jamais propagée. Et il est le plus dangereux exactement là où les suppressions sont votre moyen d'appliquer la sécurité, c'est-à-dire partout dans un système d'identité : révocation, offboarding, rotation, verrouillage. Si votre stratégie de durabilité ne suit que ce qui existe, elle préservera fidèlement ce que vous vous êtes donné du mal à faire disparaître.
Auditez donc vos propres sauvegardes avec une seule question : si je supprime un utilisateur maintenant, que je prends une sauvegarde et que je la restaure, cet utilisateur a-t-il disparu ? Si la réponse honnête est « je n'en suis pas sûr », votre sauvegarde est une machine à remonter le temps pointée dans le mauvais sens. Elle ne vous protège pas de vos erreurs. Elle les ressuscite : le mot de passe remplacé, le salarié parti, le jeton révoqué.
Les suppressions sont des données. Sauvegardez-les comme telles.
Si vous préférez que vos sauvegardes respectent une suppression sans avoir à le prouver vous-même, c'est à ça que sert une plateforme. Authagonal pose un tombstone sur chaque suppression, si bien qu'une restauration ne ramène jamais un identifiant révoqué.