Recette : valider — restauration de sauvegarde restic

Ajoute au make valider la preuve de RÉSILIENCE : pour chaque nœud client_backup,
restic restaure le dernier snapshot dans un dossier temporaire (lecture seule sur
le dépôt) et vérifie que des fichiers en sortent.

Éprouvé sur la flotte : 6 dépôts restaurables. La recette a débusqué un vrai trou
(collab-01/Nextcloud sans backup jobs -> service en échec, stockage fichier non
protégé) — corrigé côté instance.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Daniel Allaire 2026-07-07 03:40:37 -04:00
parent 3e7c85506c
commit 89d0e4e821
2 changed files with 40 additions and 2 deletions

View file

@ -8,8 +8,12 @@
lecture seule : **cibles Prometheus toutes UP** (API `/targets`) + **vhosts HTTPS exposés répondent**
(dérivés des `server_name` réels de l'edge, filtrés sur `domaine_interne` — générique) + **courriel
bout-en-bout** (envoi via le MTA → LDAP → LMTP → Maildir, remise vérifiée par `doveadm` sur le
compte `testmail`, message de test nettoyé). Éprouvé sur la flotte vivante sous pare-feu actif :
7 cibles UP, 8 vhosts OK, courriel remis. À venir : restauration de sauvegarde (restic).
compte `testmail`, message de test nettoyé) + **restauration de sauvegarde** (pour chaque nœud
`client_backup` : restic restaure le dernier snapshot dans un dossier temporaire — lecture seule
sur le dépôt — et vérifie que des fichiers en sortent). Éprouvé sur la flotte vivante sous pare-feu
actif : 7 cibles UP, 8 vhosts OK, courriel remis, 6 dépôts restaurables. **La recette a trouvé un
vrai trou** (collab-01/Nextcloud sans `client_backup_jobs` → service de sauvegarde en échec, fichiers
non protégés), corrigé côté instance.
- **Pare-feu nftables activé sur TOUTE la flotte (14 nœuds, activation prudente).** Les 14 hôtes
actifs tournent sous `policy drop` avec leur ruleset **résolu moindre-privilège** (flux est-ouest
déclarés autorisés par source, reste refusé). Vérifié en conditions réelles : flux déclarés OPEN

View file

@ -111,3 +111,37 @@
cmd: "doveadm expunge -u {{ recette_mail_dest }} mailbox INBOX subject {{ recette_mail_token }}"
changed_when: true
failed_when: false
- name: "Recette — Sauvegardes : le dernier snapshot restic se restaure"
hosts: client_backup
gather_facts: false
become: true
tasks:
- name: Restaurer le dernier snapshot dans un dossier temporaire (lecture seule sur le dépôt)
ansible.builtin.shell:
cmd: |
set -o pipefail
repo=$(grep -oP 'RESTIC_REPOSITORY="\K[^"]+' /usr/local/sbin/setops-sauvegarder.sh)
export RESTIC_REPOSITORY="$repo" RESTIC_PASSWORD_FILE=/etc/setops/restic.pass
n=$(restic snapshots 2>/dev/null | grep -cE '^[0-9a-f]{8} ' || echo 0)
if [ "$n" -lt 1 ]; then echo "snapshots=0 restored_files=0"; exit 0; fi
tmp=$(mktemp -d)
if restic restore latest --target "$tmp" >/dev/null 2>&1; then
f=$(find "$tmp" -type f | wc -l)
else
f=-1
fi
rm -rf "$tmp"
echo "snapshots=$n restored_files=$f"
executable: /bin/bash
register: recette_restore
changed_when: false
- name: "✔ Sauvegardes"
vars:
restaures: "{{ recette_restore.stdout | regex_search('restored_files=(-?\\d+)', '\\1') | first | int }}"
snaps: "{{ recette_restore.stdout | regex_search('snapshots=(\\d+)', '\\1') | first | int }}"
ansible.builtin.assert:
that: "restaures | int > 0"
success_msg: "OK — {{ snaps }} snapshot(s), restauration du dernier vérifiée ({{ restaures }} fichiers)."
fail_msg: "ÉCHEC — restauration KO (snapshots={{ snaps }}, fichiers restaurés={{ restaures }})."