Documentation Index
Fetch the complete documentation index at: https://snakysec.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Runbook 02 — Restauration Vault depuis snapshot raft
1. Quand activer ce runbook
| Scénario | Activer ? |
|---|
| Vault sealed automatiquement après reboot, refus d’unseal avec shares connues | OUI (corruption raft) |
Volume vault-data corrompu ou supprimé | OUI |
Vault répond Internal error: storage backend corrupt | OUI |
| Vault opérationnel mais les secrets sont incorrects | NON (rotation des secrets, pas restore) |
| Plateforme exposée publiquement et Vault ne démarre pas | OUI (priorité absolue, app ne peut pas démarrer sans Vault) |
2. Objectifs
- RPO atteint : 24 heures (snapshots quotidiens 04:00 UTC)
- RTO cible : 1 heure
- WRT cible : 30 minutes (vérification que app + worker peuvent lire Vault)
3. Prérequis CRITIQUES
- Accès SSH au VPS OVH avec utilisateur
mssp
- 3 shares Shamir au minimum (threshold) :
- Cas normal : DR Owner détient 3 shares (S1 YubiKey + S2 KeePass + S3 papier coffre domicile) → suffisant
- Cas dégradé : si l’une des 3 est inaccessible, récupérer 1 share de l’enveloppe trustee notaire (cf. 01-keyholders.md)
- Restic password disponible (KeePass + papier coffre + enveloppe trustee). Sans cette passphrase, le snapshot S3 est inutilisable.
- DR S3 access keys OVH ou Scaleway (au moins l’un des deux)
- Container
mssp-vault arrêté (pas de Vault qui tente de servir pendant le restore)
4. Communication client
Identique au runbook 01 §4. Vault HS = plateforme entièrement HS (login, audits,
rapports, tout). Notification immédiate.
5. Procédure de restauration
5.1 Sauvegarde de l’état actuel (si données partiellement présentes)
Même si le volume semble corrompu, on conserve avant tout effacement :
ssh mssp@vps.snakysec.com
sudo tar czf /opt/mssp/snapshots/vault-pre-restore-$(date +%Y%m%dT%H%M%SZ).tar.gz \
-C /opt/mssp/data vault
5.2 Stop de toute la stack
L’application tente de lire Vault au démarrage — si on restaure Vault avec
l’app vivante, on risque des reads sur Vault à moitié déverrouillé.
cd /opt/mssp/app/platform
make prod-down
5.3 Récupération du snapshot le plus récent
Le snapshot est dans le repo restic OVH au chemin vault/. La passphrase
restic est requise. On utilise un container temporaire dr-runner.
# Démarrer Vault d'abord (pour que le container temporaire puisse contacter
# le service avant restore — Vault recevra le snapshot via API).
# NON. Vault ne doit PAS être démarré avant restore. Le restore se fait via
# `vault operator raft snapshot restore` qui REMPLACE le storage avant unseal.
# On lance un container restic standalone pour télécharger le snapshot
docker run --rm -it \
--network platform_mssp-net \
-v platform_dr-runtime:/dr-runtime \
-v platform_mssp-approle-dr:/vault/approle-dr:ro \
-v $(pwd)/../../scripts/dr:/dr:ro \
-e VAULT_ADDR=http://mssp-vault:8200 \
-e VAULT_DR_APPROLE_FILE=/vault/approle-dr/dr.env \
registry.gitlab.com/snakysec/mssp-snakysec-multi-tenants/dr-runner:latest \
/dr/restore/vault-restore.sh --download-only
Le script vault-restore.sh --download-only télécharge le snapshot le plus
récent dans /dr-runtime/tmp/vault-snapshot-latest.snap.
Si OVH inaccessible, ajouter --repo=scaleway :
... vault-restore.sh --download-only --repo=scaleway
5.4 Démarrage Vault avec storage VIDE (mode init)
Pour appliquer un snapshot raft, Vault doit être initialisé. Si le storage
existant est corrompu, on le vide et on ré-initialise.
# Vider le volume vault-data
docker run --rm \
-v platform_vault-data:/data \
alpine sh -c "rm -rf /data/* /data/.[!.]* 2>/dev/null || true"
# Démarrer Vault (en mode prod, pas dev)
make vault-up
sleep 5
# Vault sera "Not initialized". Ré-initialiser avec 5/3 keyholders existants
# n'est PAS possible directement (init génère NOUVELLES shares). Il faut un
# init initial + apply snapshot avant unseal.
# Étape 1 : init temporaire avec 1 share (juste pour pouvoir poster le snapshot)
docker exec mssp-vault vault operator init -key-shares=1 -key-threshold=1 \
> /tmp/vault-temp-init.json
TEMP_ROOT_TOKEN=$(grep "Initial Root Token" /tmp/vault-temp-init.json | awk '{print $NF}')
TEMP_UNSEAL_KEY=$(grep "Unseal Key 1" /tmp/vault-temp-init.json | awk '{print $NF}')
# Étape 2 : unseal temporaire
docker exec mssp-vault vault operator unseal "${TEMP_UNSEAL_KEY}"
5.5 Apply du snapshot
docker cp /dr-runtime/tmp/vault-snapshot-latest.snap mssp-vault:/tmp/snap.snap
docker exec -e VAULT_TOKEN="${TEMP_ROOT_TOKEN}" mssp-vault \
vault operator raft snapshot restore -force /tmp/snap.snap
# À ce stade, Vault redevient "sealed" car les keys du snapshot précédent
# ne correspondent pas au TEMP_UNSEAL_KEY.
# Cleanup snapshot file (contient TOUS les secrets en clair)
docker exec mssp-vault shred -u /tmp/snap.snap
5.6 Unseal avec les 3 shares Shamir originales
Maintenant Vault attend les shares qui étaient actives au moment du snapshot.
# Saisir les 3 shares interactivement (NE PAS les loguer)
docker exec -it mssp-vault vault operator unseal
# Prompt 1 : entrer share 1 (depuis YubiKey décodée)
docker exec -it mssp-vault vault operator unseal
# Prompt 2 : entrer share 2 (depuis KeePass)
docker exec -it mssp-vault vault operator unseal
# Prompt 3 : entrer share 3 (depuis papier coffre domicile)
# Vérifier sealed=false
docker exec mssp-vault vault status
# attendu : Sealed: false
Si l’une des 3 shares ne fonctionne pas, DO NOT PANIC — récupérer
l’enveloppe trustee chez le notaire (cf. 01-keyholders.md §4)
et utiliser une share de cette enveloppe.
5.7 Re-provisioning AppRoles (si invalides après restore)
Les AppRoles mssp-app, mssp-worker, mssp-dr peuvent avoir des secret-ids
expirées si le snapshot date de >TTL. Re-générer si nécessaire :
docker exec mssp-vault vault login "${OLD_ROOT_TOKEN_FROM_SNAPSHOT}"
# Régénérer secret-id pour mssp-app
NEW_SECRET_ID=$(docker exec mssp-vault \
vault write -force -format=json auth/approle/role/mssp-app/secret-id | \
jq -r .data.secret_id)
# Mettre à jour le shared volume
docker run --rm \
-v platform_mssp-approle:/vault/approle \
alpine sh -c "echo 'VAULT_ROLE_ID=...' > /vault/approle/app.env && \
echo 'VAULT_SECRET_ID=${NEW_SECRET_ID}' >> /vault/approle/app.env"
# Idem pour mssp-worker et mssp-dr
6. Validation post-restore
6.1 Sanity check Vault
docker exec mssp-vault vault status
# Sealed: false, Initialized: true
docker exec -e VAULT_TOKEN="${ROOT_TOKEN}" mssp-vault \
vault kv list mssp/
# attendu : platform, clients, dr
6.2 Smoke check secrets accessibles
docker exec -e VAULT_TOKEN="${ROOT_TOKEN}" mssp-vault \
vault kv get -field=auth_secret mssp/platform | wc -c
# attendu : >32 (auth secret est >32 chars)
docker exec -e VAULT_TOKEN="${ROOT_TOKEN}" mssp-vault \
vault kv get -field=encryption_key mssp/platform | wc -c
# attendu : >32
6.3 Démarrage application
make prod
sleep 30 # laisse les containers démarrer + AppRole login
curl -sI https://snakysec.com/api/health
# attendu : HTTP/2 200
Si l’app ne démarre pas, lire les logs make app-logs — les erreurs Vault
les plus communes sont :
403 Forbidden : AppRole secret-id expirée → re-provisionner (§5.7)
connection refused : Vault sealed → re-unseal
permission denied on path : policies AppRole modifiées dans le snapshot → re-créer
6.4 Smoke functional
Login plateforme + vérifier qu’on accède au dashboard. Si OK, restore validé.
7. Communication post-incident
Identique runbook 01 §8.
Mention spécifique sur la fenêtre RPO 24h : si le snapshot date de plus
de 12h, certains secrets clients récents (rotation cert, nouveau client
ajouté) peuvent manquer. Lister ces clients dans le post-incident report et
re-saisir les credentials manuellement après confirmation client.
8. Erreurs courantes et solutions
| Erreur | Cause | Solution |
|---|
Error checking seal status: connection refused | Vault container pas démarré | make vault-up puis re-test |
Error: read-only mode active | Snapshot apply en cours | Attendre quelques secondes |
mismatch: persisted leader != my-leader | Snapshot d’une autre instance Vault | Vérifier qu’on apply le bon snapshot |
| Unseal échoue avec “invalid share” | Share corrompue ou erreur de saisie | Réessayer avec une autre des 3 shares Nicolas, ou récupérer enveloppe trustee |
| Application start fails 403 sur Vault | AppRole secret-id expirée post-restore | Re-provisionner secret-ids (§5.7) |
| Snapshot file corrompu (restic restore failed) | Bucket OVH compromis | Switch vers Scaleway : vault-restore.sh --repo=scaleway |
9. Validation du runbook
Testé annuellement (Q2) avec restore réel sur env pré-prod. Résultats dans
docs/dr/test-results/.
| Version | Date | Auteur |
|---|
| 1.0 | 2026-04-26 | Nicolas Schiffgens |