Aller au contenu

Sauvegarde, restauration & rétention

Une propriété gouverne tout ce qui suit : l’intégrité voyage avec les données, pas avec la sauvegarde. Chaque enregistrement est chaîné par hachage et signé à l’origine, chaque point de contrôle est signé et revérifié au chargement, et un store dont le disque a été édité refuse de s’ouvrir plutôt que de servir une histoire réécrite. Une sauvegarde protège donc la disponibilité et la confidentialité. Corollaire : une copie restaurée se prouve elle-même ou refuse de se charger, si bien que chaque restauration se termine par un verdict vérifiable par machine.

ArtefactÉcrit parContenu
Répertoire du WALpasserelleun <chain>.jsonl par chaîne d’audit (transport HTTP : un par session)
Store du ledgerledgerpar chaîne : <chain>.checkpoints.jsonl, <chain>.anchors.jsonl ; pour tout le store : keys.json
Packs de preuvesobsign-ledger exportpreuve autonome — l’artefact de rétention
Matériel de confianceopstrusted-keys.json, le bundle de déploiement signé — à traiter comme de la configuration
Clé de scellementHSMpas à vous de la copier en fichier : la cérémonie de sauvegarde du fournisseur s’applique. La perdre arrête les nouveaux scellements ; elle n’invalide rien de déjà scellé. Un remplacement prend un nouveau key_id

Tout ce qui figure dans les trois premières lignes est du JSONL ou du JSON, en ajout seul. C’est délibéré, et cela rend la sauvegarde ennuyeuse : les fichiers ne font que grandir, une dernière ligne déchirée est tolérée et rognée par le processus propriétaire, et keys.json est remplacé atomiquement. Les copies à chaud sont sûres au niveau du fichier.

L’ordre de copie compte. Les fichiers du store se référencent mutuellement, et Store::open refuse un store dont les références pendent. Copiez dans l’ordre des références, et le store avant le WAL (la couverture scellée ne doit jamais dépasser la fin du journal) :

Fenêtre de terminal
# Hot backup, safe while gateway and ledger run.
rsync -a store/*.anchors.jsonl backup/store/ 2>/dev/null || true
rsync -a store/*.checkpoints.jsonl backup/store/
rsync -a store/keys.json backup/store/
rsync -a wal/ backup/wal/

Un instantané de système de fichiers atomique unique (LVM, ZFS, EBS) des deux répertoires est équivalent et plus simple.

Fréquence. Votre intervalle de sauvegarde est votre RPO pour la piste d’audit. Le WAL est en ajout seul et persisté par fsync à chaque enregistrement, ce qui rend la réplication continue peu coûteuse ; au minimum, sauvegardez à l’intervalle de scellement.

Vérifiez chaque sauvegarde. Une sauvegarde que personne n’a ouverte est un espoir :

Fenêtre de terminal
for f in backup/wal/*.jsonl; do
chain=$(basename "$f" .jsonl)
obsign-ledger export --wal backup/wal --store backup/store \
--chain-id "$chain" --out "/tmp/$chain.pack.json" \
--deployment-bundle deployment-bundle.json
obsign verify --strict --trusted-keys trusted-keys.json \
"/tmp/$chain.pack.json" || echo "BACKUP BAD: $chain"
done

Code de sortie 0, ou la sauvegarde n’en est pas une. Chiffrez ensuite et appliquez le 3-2-1 : les copies ne portent aucun matériel de clé, mais elles portent qui a fait quoi.

Règles de base : restaurez le WAL et le store depuis le même jeu de sauvegarde. Un WAL plus récent avec un store plus ancien convient (la queue non scellée sera scellée au passage suivant) ; un WAL plus ancien avec un store plus récent donne TruncatedLog.

  • Hôte de la passerelle perdu — restaurez le WAL sur un volume qui honore fsync, redémarrez. La passerelle rejoue le journal, vérifie la signature d’origine de chaque enregistrement et reprend là où la copie s’arrête. Un ForeignRecord à la reprise signifie soit une falsification, soit une clé de rotation manquante dans le bundle de déploiement : rien n’est rogné ni adopté ; un humain décide. Les actes accomplis après la dernière sauvegarde sont absents. Dites-le dans le compte rendu d’incident : une lacune documentée est défendable, une chaîne discrètement raccourcie ne l’est pas.
  • Hôte du ledger perdu — restaurez le store et exécutez une passe de scellement. Un Store::open réussi est le contrôle d’intégrité. Un DivergedLog signifie que le WAL et le store ne s’accordent pas sur l’histoire scellée : l’un des deux n’est pas l’original, et les ancres arbitrent : un jeton RFC 3161 fixe ce que le point de contrôle disait, et quand.
  • Les deux hôtes perdus — les packs de preuves archivés sont autonomes et se vérifient hors ligne sans aucun service : l’histoire n’est pas perdue, elle est déjà sous sa forme de long terme. L’exploitation reprend sur de nouvelles chaînes. Ne reconstruisez pas de fichiers WAL depuis les packs. Les packs sont la preuve qui fait foi ; le travail nouveau obtient des chaînes nouvelles.
  • Clé de scellement perdue — rien de déjà scellé n’est affecté. Provisionnez une nouvelle clé, scellez sous un nouveau key_id. L’ancien identifiant reste lié à l’ancienne clé pour toujours ; c’est cette liaison qui garde les anciens scellés vérifiables.

L’artefact de rétention est le pack de preuves : un seul fichier JSON, vérifiable hors ligne aussi longtemps que vous saurez exécuter sha256 et Ed25519. Par chaîne, le cycle de vie est le suivant : fermer, sceller, ancrer, exporter (auto-vérification), vérifier indépendamment avec les clés hors bande, archiver (le pack et son sha256 dans un stockage immuable, par exemple S3 Object Lock, en deux emplacements), et seulement ensuite élaguer les fichiers de travail de la chaîne. L’élagage supprime les fichiers de chaînes entières, jamais des lignes à l’intérieur d’un fichier : un fichier raccourci est indiscernable d’une falsification, et l’outillage le traitera comme telle.

Chaque trimestre, et après chaque restauration :

Fenêtre de terminal
fail=0
for pack in archive/*/*/*.pack.json; do
sha256sum -c "$pack.sha256" || fail=1
obsign verify --strict --trusted-keys trusted-keys.json "$pack"
[ $? -eq 0 ] || { echo "FAIL: $pack"; fail=1; }
done
exit $fail

Traitez toute sortie non nulle comme un échec, y compris 3 : dans une tâche planifiée, le code 3 signifie que le fichier de clés de confiance n’est pas parvenu au vérificateur, pas que la vérification est passée.

Deux points de long terme : le trusted-keys.json utilisé pour la revérification doit être la copie hors bande sous votre contrôle, et il doit s’accumuler, jamais se réduire. Une clé retirée des nouveaux déploiements vérifie encore deux ans d’anciens scellés. Et archivez la chaîne de certificats de la TSA aux côtés des packs : prouver qui a émis un horodatage la deuxième année exige les certificats de l’émetteur, et la TSA aura fait sa rotation d’ici là.

Une fois par an, faites un exercice de restauration : restaurez un jeu de sauvegarde tiré au hasard sur un hôte de test et exécutez la boucle ci-dessus. Le code de sortie de l’exercice est la seule preuve que ce runbook fonctionne.