Vérifier un dépôt restic par lecture, restauration et corruption

Vérifier un dépôt restic par lecture, restauration et corruption

Une sauvegarde peut être signalée comme réussie, puis se révéler illisible au moment de la restauration : les données stockées ont peut-être été corrompues après la fin de la sauvegarde. Compter les instantanés permet de vérifier qu’une tâche s’est exécutée, mais ne prouve pas que les paquets de données sont toujours intacts. L’administration du stockage exige trois preuves indépendantes : une structure de dépôt valide, la lecture de toutes les données et la conformité du contenu restauré à une référence.

Cet article utilise Debian 12, restic et Python 3 pour effectuer, dans un répertoire temporaire, des contrôles sur un dépôt sain puis un test de détection de corruption. Aucune donnée de production n’est lue, aucun disque n’est formaté et aucun dépôt de sauvegarde existant n’est modifié. L’exercice concerne les sauvegardes de fichiers sur serveur dédié ; pour une base de données en cours d’exécution, il faut d’abord produire une sauvegarde cohérente avec les mécanismes propres à la base, puis l’intégrer au processus de sauvegarde de fichiers.

1. Définir ce que chaque contrôle permet de prouver

restic organise le contenu des fichiers en paquets de données chiffrés et gère les instantanés, les index et leurs références. La commande check vérifie principalement la structure du dépôt ; check --read-data lit et vérifie en plus tous les paquets de données. Ces deux contrôles ne sont pas interchangeables, et aucun ne dispense d’un test de restauration.

La comparaison après restauration vérifie que l’instantané choisi permet de reconstituer les fichiers attendus dans un répertoire vide. Elle ne garantit pas l’intégrité de chaque paquet historique du dépôt. À l’inverse, une lecture complète réussie ne prouve ni que les bons répertoires ont été sauvegardés, ni que les règles d’exclusion ont épargné toutes les données nécessaires, ni que les données applicatives étaient cohérentes.

La mise en miroir maintient l’accès lors de certaines pannes matérielles, la sauvegarde conserve les versions antérieures et le contrôle d’intégrité détecte les anomalies ; aucun des trois ne remplace une restauration réelle.

Les serveurs dédiés AMD d’OnuCloud sont équipés de série de deux disques NVMe de 1 To, chacun en connexion directe, sans RAID matériel. Placer le répertoire source et le dépôt de sauvegarde sur deux disques distincts d’une même machine permet d’isoler certaines défaillances d’un disque, mais ne constitue pas une sauvegarde distante dans un domaine de défaillance indépendant. Le dépôt local ci-dessous sert uniquement à valider la procédure.

2. Créer un jeu d’essai isolé et reproductible

Installez d’abord les outils, puis exécutez les commandes de l’exercice dans une même session Bash afin de conserver les variables temporaires. L’installation nécessite des droits d’administration ; un compte ordinaire suffit pour l’exercice lui-même.

sudo apt-get update
sudo apt-get install restic python3

umask 077
LAB=$(mktemp -d /var/tmp/restic-lab.XXXXXXXX)
export LAB
export RESTIC_REPOSITORY="$LAB/repository"
export RESTIC_PASSWORD_FILE="$LAB/password"

mkdir -p "$LAB/source"
python3 - <<'PY'
import os
import secrets
from pathlib import Path

root = Path(os.environ["LAB"])
(root / "password").write_text(secrets.token_hex(32) + "\n")
(root / "source" / "record.txt").write_text(
    "backup verification\n", encoding="utf-8"
)
(root / "source" / "payload.bin").write_bytes(os.urandom(1024 * 1024))
PY

restic version
restic init
(
  cd "$LAB"
  restic backup source
)
restic snapshots

Le fichier aléatoire évite que l’ensemble du jeu d’essai soit comprimé en un volume minuscule et garantit la présence de contenu effectif dans le dépôt. Le fichier de mot de passe se trouve en dehors du répertoire du dépôt : une copie du dépôt n’emporte donc pas les éléments nécessaires à son déchiffrement.

Comme il n’existe ici qu’un seul instantané, les commandes suivantes peuvent utiliser latest. En production, consignez un ID d’instantané explicite : si une nouvelle sauvegarde se termine pendant le contrôle, la cible de restauration pourrait sinon changer. Ce mot de passe temporaire de laboratoire ne constitue pas une gestion pérenne des clés ; les éléments de déchiffrement d’un dépôt de production doivent être conservés séparément et rester récupérables.

3. Valider séparément la lecture complète et le contenu restauré

Exécutez d’abord le contrôle de structure, puis la lecture de tous les paquets. Ne redirigez pas directement la sortie vers un pipeline sans en gérer les codes de sortie : la réussite de la dernière commande pourrait masquer l’échec du contrôle.

restic check
restic check --read-data
restic restore latest --target "$LAB/restored"
diff -r -- "$LAB/source" "$LAB/restored/source"

Les quatre étapes doivent se terminer avec un code de sortie nul ; si les contenus sont identiques, diff n’affiche aucune différence. Le jeu d’essai ne contient que des fichiers ordinaires : une comparaison des contenus et des répertoires suffit donc ici. Pour une sauvegarde réelle, il faut aussi vérifier séparément les propriétaires, les permissions, les liens et les attributs étendus nécessaires aux applications.

La restauration doit se faire dans un nouveau répertoire vide, sans écraser les fichiers source. Sinon, des fichiers déjà présents pourraient masquer des omissions de sauvegarde, et les données restaurées pourraient altérer un répertoire de production. Conservez ensuite l’ID de l’instantané, les versions des outils, les sorties des contrôles et le résultat de la comparaison. Une simple capture d’écran indiquant la réussite de la tâche ne permet pas de vérifier après coup ce qui a réellement été restauré.

Si check échoue, interrompez la suite de la validation normale et préservez l’état du dépôt. Si le contrôle de structure réussit mais que la lecture complète échoue, examinez en priorité la lecture des paquets et l’intégrité de leur contenu. Une liste d’instantanés apparemment normale ne justifie pas de continuer à utiliser le dépôt.

4. Corrompre uniquement une copie et vérifier son rejet

Le test négatif sert à prouver que la chaîne de contrôle détecte réellement un problème. Arrêtez d’abord toute écriture dans le dépôt d’essai, puis créez-en une copie indépendante. N’utilisez pas de copie par liens physiques : modifier la copie pourrait alors modifier aussi le dépôt d’origine. La commande suivante désactive explicitement la copie sur écriture ; le faible volume de l’exercice permet de bien distinguer les deux ensembles de données.

cp -a --reflink=never "$LAB/repository" "$LAB/damaged"

python3 - <<'PY'
import os
from pathlib import Path

data = Path(os.environ["LAB"]) / "damaged" / "data"
pack = next(p for p in sorted(data.rglob("*")) if p.is_file())
with pack.open("r+b") as f:
    f.seek(pack.stat().st_size // 2)
    pos = f.tell()
    original = f.read(1)
    if not original:
        raise RuntimeError("Empty data pack")
    f.seek(pos)
    f.write(bytes([original[0] ^ 1]))
print(pack.name)
PY

if restic -r "$LAB/damaged" check --read-data \
  >"$LAB/damaged-check.log" 2>&1; then
  printf '%s\n' 'UNEXPECTED_SUCCESS'
else
  printf '%s\n' 'EXPECTED_FAILURE'
fi
cat "$LAB/damaged-check.log"
restic check --read-data

Le contrôle de la copie doit se terminer avec un code de sortie non nul, et le journal doit signaler un paquet corrompu ; le contrôle du dépôt d’origine doit toujours réussir. Ne vous contentez pas du marqueur d’échec affiché par le script : vérifiez que l’échec provient bien de la corruption, et non d’un mot de passe incorrect, d’un mauvais chemin ou de permissions insuffisantes.

Cette étape prouve que la corruption est détectable, pas qu’elle est réparable. La modification d’un octet dans un paquet peut affecter un ou plusieurs objets. N’en déduisez pas une proportion de données touchées lors d’un incident de production et ne réutilisez pas cette copie comme destination de sauvegarde.

5. Définir les limites des contrôles en production à partir de l’exercice

Une lecture complète mobilise le débit des disques et, pour un dépôt distant, la bande passante réseau. Avant de lancer le contrôle, consignez la taille du dépôt, le périmètre à vérifier et la charge des services. Choisissez une période de faible charge et surveillez la latence des services. Un trafic illimité ne signifie ni un débit de transfert illimité, ni un contrôle d’intégrité sans coût en ressources.

Pour un dépôt volumineux, la lecture des paquets peut être répartie en plusieurs lots. Il faut toutefois consigner le périmètre couvert à chaque passage et s’assurer que toutes les données sont finalement lues. La réussite d’un échantillonnage ne permet pas de déclarer le dépôt entier valide. Évitez également toute exécution simultanée non planifiée avec des opérations de nettoyage, de réparation ou toute autre tâche modifiant le contenu du dépôt.

Si une corruption est détectée, suspendez d’abord les tâches qui modifient le dépôt, conservez les journaux et une copie, puis examinez le système de fichiers, les périphériques et la chaîne de transfert. N’exécutez pas immédiatement forget, prune ou une commande de réparation : cela pourrait réduire les éléments encore disponibles pour la récupération et l’analyse.

La validation finale doit réunir trois résultats : le dépôt sain est lisible dans son intégralité, l’instantané désigné peut être restauré avec un contenu conforme à la comparaison, et la copie corrompue est explicitement rejetée. Une fois les résultats conservés, les fichiers de l’exercice peuvent être supprimés après vérification manuelle des chemins. Le mot de passe, les journaux et les fichiers restaurés sont tous des éléments à traiter de manière contrôlée.

Questions fréquentes

Un contrôle restic check réussi a-t-il lu toutes les données ?

Non. Le contrôle simple vérifie surtout la structure et les références du dépôt. L’option --read-data lit et vérifie tous les paquets de données. Une restauration isolée avec comparaison reste nécessaire.

Faut-il nettoyer immédiatement un dépôt endommagé ?

Non. Suspendre les tâches qui modifient le dépôt, conserver les journaux et une copie, puis examiner le stockage et le transport. Ne pas lancer forget, prune ou une réparation sans préparation.

Serveur dédié AMD EPYC 7543P

À partir de $472/mois

Configurer un serveur dédié OnuCloud Consulter les tarifs des serveurs OnuCloud

Choisir la configuration du serveur selon la charge

Serveur dédié AMD EPYC 7543P : la redondance du stockage et la sauvegarde des données sont à prévoir par l’administrateur.