From 89d0e4e8213efa22b1d4c0e2932390728bd0745f Mon Sep 17 00:00:00 2001 From: Daniel Allaire Date: Tue, 7 Jul 2026 03:40:37 -0400 Subject: [PATCH] =?UTF-8?q?Recette=20:=20valider=20=E2=80=94=20restauratio?= =?UTF-8?q?n=20de=20sauvegarde=20restic?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- CHANGELOG.md | 8 ++++++-- playbooks/valider.yml | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a8cf52..f82e39c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/playbooks/valider.yml b/playbooks/valider.yml index a5fe83a..6fbb163 100644 --- a/playbooks/valider.yml +++ b/playbooks/valider.yml @@ -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 }})."