Aller au contenu
Sauvegarder et restaurer un serveur

Sauvegarder et restaurer un serveur

À la fin, vous saurez

  • Dresser l'inventaire de ce qui doit être sauvegardé sur un serveur reconstructible, et justifier ce qui ne l'est pas
  • Exprimer un besoin de sauvegarde en perte de données maximale admissible (PDMA, RPO) et durée maximale d'interruption admissible (DMIA, RTO)
  • Distinguer sauvegarde, réplication et instantané, et appliquer la règle 3-2-1
  • Copier une arborescence avec rsync sans perdre de métadonnées, et produire des copies datées avec --link-dest
  • Initialiser un dépôt restic sur Object Storage Scaleway, sauvegarder des fichiers et un pg_dump, appliquer une politique de rétention et vérifier le dépôt
  • Protéger les sauvegardes contre leur destruction par des identifiants limités, le versionnage et le verrouillage d'objets
  • Restaurer un fichier, une arborescence puis un serveur complet, et mesurer la durée réelle de reprise

Prérequis

Testé avec borgbackup 1.2.8 (Ubuntu) / 1.4.0 (Debian) debian 13 postgresql-client 16 (Ubuntu) / 17 (Debian) restic 0.16.4 (Ubuntu) / 0.18.0 (Debian) rsync 3.2.7 (Ubuntu) / 3.5.0 (Debian) systemd 255 / 257 tar 1.35 ubuntu 24.04 , vérifié le 7 octobre 2026

Pourquoi

En reprenant sig-outils, vous trouvez dans la crontab de root une ligne laissée par Camille :

0 3 * * * tar czf /var/backups/sig.tar.gz /etc/signalements /srv/donnees/pieces-jointes

L'archive est écrasée chaque nuit, rangée sur le même disque que les données, non chiffrée, jamais ouverte, et la base de données n'y figure pas. Si le volume disparaît, l'archive disparaît avec lui. Un fichier supprimé lundi et réclamé mercredi n'existe plus nulle part. Un attaquant devenu root chiffre les données et l'archive dans la même minute.

Ce n'est pas une sauvegarde, c'est une copie qui rassure. Une sauvegarde se définit par ce qu'elle permet : revenir à un état antérieur connu, dans un délai connu, après un événement que l'on n'a pas choisi. Pour Signalements, ces événements vont de l'erreur humaine (un script de purge des pièces jointes qui purge trop) au bogue qui écrit des données fausses pendant trois jours, en passant par le sinistre chez l'hébergeur (l'incendie d'un centre de données strasbourgeois en mars 2021 a montré à beaucoup d'entreprises que leurs sauvegardes étaient dans le bâtiment voisin) et l'attaque : l'ANSSI note dans son guide Sauvegarde des systèmes d'information (ANSSI-BP-100) qu'il est fréquent qu'un attaquant tente de chiffrer ou d'effacer l'infrastructure de sauvegarde avant de demander une rançon.

Cette leçon conclut le cours parce qu'elle s'appuie sur les précédentes : disques, minuteurs, journaux, authentification, durcissement. Elle insiste sur un point plus que sur tous les autres : une sauvegarde dont la restauration n'a jamais été testée n'existe pas.

Les concepts

Que sauvegarder sur un serveur reconstructible ?

La leçon Prendre en charge un serveur a introduit la distinction entre animaux et bétail. Un serveur « bétail » se reconstruit depuis une image et cloud-init : on ne sauvegarde pas son système, on sauvegarde ce qui ne peut pas être recréé. L'ANSSI va plus loin (recommandation R27) : après un incident de sécurité, on réinstalle depuis des images officielles plutôt que de restaurer des systèmes qui peuvent contenir les implants de l'attaquant.

ÉlémentOùSauvegarde
Système/usr, /var/lib/dpkgnon : image Scaleway et cloud-init
Code de l'API/opt/signalementsnon : artefact de la CI (que la CI, elle, doit conserver)
Configuration/etc/signalements/oui, tant qu'elle ne vit pas dans un dépôt Git
Secrets/etc/signalements/secrets.envoui, chiffrés, ou dans le gestionnaire de secrets
Unités systemd, crontabs, scripts locaux/etc/systemd/system/, /var/spool/cron/, /usr/local/oui : c'est là que se cachent les modifications manuelles
Paquets installés à la mainapt-mark showmanualoui, comme liste
Pièces jointes (photos)/srv/donnees/pieces-jointes sur sig-outilsoui : avec la base, la donnée la plus précieuse
Base sig-dbPostgreSQL managésauvegardes managées et export logique
Journaux centralisés/srv/donnees/journaux/ (leçon 12)selon la politique de rétention

Pour sig-db, Scaleway active par défaut des sauvegardes automatiques : selon sa documentation, une par jour, conservées 7 jours, réglables. Elles restent chez le même fournisseur, dans le même compte, et ne se restaurent que vers une base Scaleway. On les complète par un export pg_dump rangé ailleurs, qui garantit aussi la réversibilité : pouvoir partir avec ses données.

PDMA et DMIA

Deux chiffres traduisent le besoin métier, que l'ANSSI nomme en français et les outils en anglais :

  • la perte de données maximale admissible (PDMA, RPO pour recovery point objective) : combien de temps de travail peut-on perdre ? Une sauvegarde par nuit, c'est jusqu'à 24 heures ;
  • la durée maximale d'interruption admissible (DMIA, RTO pour recovery time objective) : combien de temps le service peut-il rester arrêté pendant la restauration ?

Ils se négocient avec la mairie, pas dans l'équipe technique. L'ANSSI rappelle qu'une PDMA inférieure à 24 heures relève en général de la réplication plutôt que de la sauvegarde. On retient pour la suite : PDMA de 24 heures pour les fichiers (la base est couverte plus finement par les sauvegardes managées), DMIA de 4 heures pour l'API.

Sauvegarde, réplication, instantané

RéplicationInstantané (snapshot)Sauvegarde
Naturecopie tenue à jour en continuimage figée d'un volumecopie datée, conservée selon une rétention
Protège contrela panne d'une machine ou d'une zoneune erreur juste après l'instantanépresque tout, selon où elle est rangée
Ne protège pas contrel'erreur et le rançongiciel, répliqués aussitôtla perte du compte ou du fournisseurrien, si elle n'est pas testée
Chez Signalementssig-app-1 et sig-app-2avant une mise à jour majeure (leçon 4)restic vers Object Storage

Un instantané Scaleway se prend en quelques secondes et existe, d'après la documentation, comme une ressource indépendante du volume d'origine. Mais il reste dans le même compte et copie tout le volume, système compris : c'est un outil de retour arrière avant une opération risquée, pas une stratégie de sauvegarde.

La règle 3-2-1

Recommandée par l'ANSSI (R11) et qualifiée d'état de l'art par la CNIL dans son guide de la sécurité des données personnelles : 3 copies (la production et deux sauvegardes), sur 2 supports différents, dont 1 hors ligne ou au moins hors site. Dans le cloud, la traduction est imparfaite. Pour Signalements : la production sur le volume de sig-outils, une sauvegarde dans le bucket sig-sauvegardes en fr-par, et une troisième copie dans une autre organisation Scaleway ou chez un autre fournisseur, sur laquelle les identifiants de production n'ont aucun droit. Une variante répandue chez les éditeurs, 3-2-1-1-0, ajoute une copie immuable et zéro erreur à la vérification de restauration : ce dernier chiffre transforme l'intention en mesure.

Incrémental, déduplication, cohérence

Une sauvegarde complète copie tout ; une sauvegarde incrémentale (incremental) ne copie que ce qui a changé depuis la précédente, mais la restauration exige toute la chaîne, et un maillon corrompu rend la suite inutilisable. restic et BorgBackup remplacent ce schéma par la déduplication (deduplication, le fait de ne stocker qu'une fois un même morceau de données, où qu'il apparaisse). Chaque sauvegarde est logiquement complète et se restaure seule, mais seuls les morceaux nouveaux sont envoyés : les photos déjà présentes ne repartent jamais.

Reste la cohérence. Copier un fichier pendant son écriture donne un fichier à moitié ancien, à moitié nouveau. Pour des photos écrites une fois, le risque se limite au fichier en cours de dépôt. Pour une base de données, c'est rédhibitoire : on ne copie jamais les fichiers d'un PostgreSQL en marche. pg_dump exporte depuis une transaction et, selon sa documentation, produit une sauvegarde cohérente sans bloquer lecteurs ni écrivains.

En pratique

Les commandes s'exécutent sur sig-outils (Debian 13) sauf mention contraire. Les sorties sont reconstituées d'après la documentation des outils.

rsync : copier sans rien perdre

Pour rapatrier la configuration de sig-app-1 sur sig-outils :

$ sudo rsync -aHAX --numeric-ids --delete --rsync-path="sudo rsync" \
    sauvegarde@172.16.8.11:/etc/signalements/ /srv/copies/sig-app-1/etc-signalements/
  • -a : d'après la page de manuel, l'équivalent de -rlptgoD (récursif, liens symboliques, permissions, dates, groupe, propriétaire, fichiers spéciaux). Il ne comprend pas les liens physiques, les ACL ni les attributs étendus, d'où :
  • -H (liens physiques), -A (ACL POSIX), -X (attributs étendus, dont les capacités de fichiers) ;
  • --numeric-ids : garde les UID et GID par numéro au lieu de les traduire par nom ; le compte signalements n'a pas forcément le même numéro sur les deux machines ;
  • --delete : supprime dans la destination ce qui n'existe plus dans la source. Testez d'abord avec -n (--dry-run) et -i (--itemize-changes) ;
  • --rsync-path="sudo rsync" : le compte sauvegarde de sig-app-1 lit /etc/signalements grâce à une règle sudo limitée à rsync --server --sender ; le cours SSH montre comment restreindre la clé dans authorized_keys.

La barre oblique finale de la source change tout : /etc/signalements/ désigne le contenu du répertoire, /etc/signalements le répertoire lui-même, qui serait recréé sous la destination. La barre oblique de la destination, elle, est sans effet.

Note

Ce flux est initié par sig-outils, comme le recommande l'ANSSI (R8) : c'est le serveur de sauvegarde qui va chercher les données. Un sig-app-1 compromis n'a aucun accès aux copies.

Une copie miroir ne protège pas contre une suppression découverte trois jours plus tard. --link-dest produit des copies datées à faible coût :

#!/bin/bash
set -euo pipefail
base=/srv/copies/sig-app-1
jour=$(date -u +%F)
rsync -aHAX --numeric-ids --delete --rsync-path="sudo rsync" \
  --link-dest="$base/derniere" sauvegarde@172.16.8.11:/etc/ "$base/$jour/"
ln -sfn "$jour" "$base/derniere"

Chaque fichier identique à celui de derniere devient un lien physique vers lui au lieu d'une copie. Chaque répertoire daté paraît complet, mais un fichier inchangé depuis un an n'occupe qu'un inode. La page de manuel précise qu'un chemin relatif donné à --link-dest est relatif au répertoire de destination (d'où le chemin absolu), et que les fichiers doivent être identiques dans tous les attributs préservés pour être liés. La technique convient à quelques machines et quelques gigaoctets sur un disque local ; elle ne chiffre rien et ne déduplique pas à l'intérieur des fichiers. Pour une archive ponctuelle avant une intervention, tar reste l'outil (leçon 4 de premiers pas), avec --acls --xattrs --numeric-owner pour ne pas perdre de métadonnées.

restic vers Object Storage Scaleway

restic est un binaire unique écrit en Go qui chiffre côté client, déduplique et écrit directement dans un stockage objet par l'API S3. Debian 13 fournit la version 0.18.0, Ubuntu 24.04 la version 0.16.4 : quelques options citées plus bas datent de la 0.17 et manquent donc sur sig-app-1 et sig-app-2.

Le bucket. Depuis le poste d'administration, avec l'AWS CLI et une clé d'administration qui ne réside sur aucun serveur :

$ aws s3api create-bucket --bucket sig-sauvegardes --object-lock-enabled-for-bucket \
    --endpoint-url https://s3.fr-par.scw.cloud --region fr-par

--object-lock-enabled-for-bucket active le verrouillage d'objets et le versionnage, expliqués dans la section Sécurité. https://s3.fr-par.scw.cloud est le point d'accès de la région Paris documenté par Scaleway. Créez ensuite dans Scaleway IAM une application sauvegarde-sig-outils et sa clé d'API, dont les droits sont détaillés plus bas.

Les secrets, dans un fichier lisible par root seul :

# /etc/restic/sig-outils.env  (root:root, mode 0600)
RESTIC_REPOSITORY=s3:https://s3.fr-par.scw.cloud/sig-sauvegardes/sig-outils
RESTIC_PASSWORD_FILE=/etc/restic/sig-outils.motdepasse
AWS_ACCESS_KEY_ID=SCWXXXXXXXXXXXXXXXXX
AWS_SECRET_ACCESS_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
AWS_DEFAULT_REGION=fr-par
  • RESTIC_REPOSITORY : s3: choisit le backend S3 (le type de stockage où écrit restic), suivi du point d'accès, du bucket et d'un sous-chemin. restic exige ce style « chemin ». Un sous-chemin par machine donne un dépôt par serveur, chacun avec son mot de passe.
  • RESTIC_PASSWORD_FILE : préférable à RESTIC_PASSWORD, qui exposerait le secret dans l'environnement de chaque processus enfant.
  • AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY : la clé de l'application Scaleway, sous les noms de variables d'AWS.
  • AWS_DEFAULT_REGION : restic suppose us-east-1 si elle manque.

Générez le mot de passe et copiez-le aussitôt dans le gestionnaire de secrets, puis initialisez le dépôt (set -a exporte les variables lues) :

$ sudo apt install restic
$ sudo install -d -m 0700 /etc/restic
$ sudo sh -c 'umask 077; openssl rand -base64 32 > /etc/restic/sig-outils.motdepasse'
$ sudo -i
# set -a; . /etc/restic/sig-outils.env; set +a
# restic init

La sortie ressemble à ceci :

created restic repository 3f9a1c2b7d at s3:https://s3.fr-par.scw.cloud/sig-sauvegardes/sig-outils

Please note that knowledge of your password is required to access
the repository. Losing your password means that your data is
irrecoverably lost.

Le dernier paragraphe est à prendre au pied de la lettre : sans le mot de passe, ni vous, ni Scaleway, ni les auteurs de restic ne liront une seule photo.

Sauvegarder les fichiers. Le périmètre tient dans un fichier /etc/restic/sig-outils.inclure (un chemin par ligne : /etc, /srv/donnees/pieces-jointes, /var/spool/cron, /usr/local, /srv/donnees/journaux, /root/paquets-manuels.txt) et les exclusions dans /etc/restic/sig-outils.exclure (/srv/donnees/pieces-jointes/tmp, *.swp) :

# apt-mark showmanual > /root/paquets-manuels.txt
# restic backup --files-from /etc/restic/sig-outils.inclure \
    --exclude-file /etc/restic/sig-outils.exclure \
    --exclude-caches --one-file-system --tag fichiers --verbose

--exclude-caches ignore les répertoires marqués par un fichier CACHEDIR.TAG ; --one-file-system empêche de descendre dans d'autres systèmes de fichiers montés sous les chemins listés ; --tag étiquette l'instantané pour filtrer et appliquer des rétentions distinctes. La sortie ressemble à ceci (format de la documentation, volumes illustratifs) :

repository 3f9a1c2b opened (version 2, compression level auto)
load index files
start scan on [/etc /srv/donnees/pieces-jointes /var/spool/cron /usr/local /srv/donnees/journaux /root/paquets-manuels.txt]
start backup on [/etc /srv/donnees/pieces-jointes /var/spool/cron /usr/local /srv/donnees/journaux /root/paquets-manuels.txt]
scan finished in 4.210s: 41873 files, 38.412 GiB

Files:       41873 new,     0 changed,     0 unmodified
Dirs:         2214 new,     0 changed,     0 unmodified
Added to the repository: 37.981 GiB (36.540 GiB stored)

processed 41873 files, 38.412 GiB in 21:14
snapshot 7c2e91ab saved

« Added » donne le volume après déduplication, « stored » après compression (les JPEG se compressent peu). La nuit suivante, presque tout sera unmodified.

Exporter sig-db. Dans la base, un rôle en lecture seule suffit : depuis PostgreSQL 14, le rôle prédéfini pg_read_all_data permet de lire toutes les tables sans aucun droit d'écriture.

CREATE ROLE sauvegarde LOGIN PASSWORD '...';
GRANT pg_read_all_data TO sauvegarde;

Son mot de passe va dans /root/.pgpass (mode 0600). Puis, avec restic 0.18 :

# restic backup --tag pg_dump --stdin-filename signalements.dump --stdin-from-command -- \
    pg_dump --host=172.16.8.30 --username=sauvegarde --no-password \
            --format=custom --no-owner --no-privileges signalements
  • --stdin-from-command (restic 0.17 et suivants) lance la commande placée après -- et sauvegarde sa sortie. Si elle échoue, aucun instantané n'est enregistré. L'ancienne forme pg_dump | restic backup --stdin enregistre un export tronqué sans broncher, sauf avec pipefail (leçon 6 de premiers pas).
  • --format=custom : archive compressée que pg_restore peut restaurer sélectivement ; --no-owner et --no-privileges omettent propriétaires et GRANT, ce qui simplifie une restauration chez un autre hébergeur ; --no-password fait échouer la commande plutôt que d'attendre une saisie.
  • 172.16.8.30 figure ici le point d'accès privé de sig-db.

Warning

pg_dump refuse d'exporter un serveur d'une version majeure plus récente que la sienne. Debian 13 fournit le client 17 : avant de passer sig-db en version 18, installez le client correspondant.

Lister, élaguer, vérifier.

# restic snapshots

La sortie ressemble à ceci :

ID        Time                 Host        Tags        Paths                 Size
----------------------------------------------------------------------------------
7c2e91ab  2026-10-06 01:42:10  sig-outils  fichiers    /etc                  38.412 GiB
                                                       /srv/donnees/pieces-jointes
                                                       ...
d41f0c33  2026-10-06 02:03:55  sig-outils  pg_dump     /signalements.dump    1.207 GiB
----------------------------------------------------------------------------------
2 snapshots

Sans politique de rétention, le dépôt grossit indéfiniment, et garder indéfiniment des données personnelles n'est pas permis. forget choisit les instantanés à retirer, --prune supprime les données devenues inutiles :

# restic forget --tag fichiers --keep-daily 14 --keep-weekly 8 --keep-monthly 6 --prune --dry-run

Un instantané par jour sur 14 jours, un par semaine sur 8 semaines, un par mois sur 6 mois. La documentation précise que les règles se combinent par OU : il suffit d'en satisfaire une pour être gardé. La politique s'applique par groupe « hôte et chemins » (--group-by host,paths par défaut). --dry-run affiche les décisions et leurs raisons ; retirez-le une fois vérifié.

restic check contrôle la structure du dépôt (index, arbres, références), sans relire les données, sauf avec --read-data (tout relire) ou --read-data-subset=5% (un échantillon aléatoire) ; la forme n/t relit la n-ième partie sur t, pour tout couvrir en t exécutions. La sortie se termine par no errors were found.

Automatiser avec un minuteur

On reprend la méthode de la leçon Planifier des tâches. Le script /usr/local/sbin/sauvegarde-sig-outils, avec set -euo pipefail, enchaîne apt-mark showmanual, les deux restic backup ci-dessus, deux restic forget (sans --prune), puis envoie un signal de vie à l'outil de supervision :

curl -fsS -m 10 --retry 3 "$URL_SIGNAL_DE_VIE" > /dev/null

prune et check, longs et qui prennent un verrou exclusif, passent dans un second minuteur hebdomadaire. Le service :

# /etc/systemd/system/sig-sauvegarde.service
[Unit]
Description=Sauvegarde restic de sig-outils
Wants=network-online.target
After=network-online.target
OnFailure=notifier-echec@%n.service

[Service]
Type=oneshot
EnvironmentFile=/etc/restic/sig-outils.env
Environment=RESTIC_CACHE_DIR=/var/cache/restic
CacheDirectory=restic
ExecStart=/usr/local/sbin/sauvegarde-sig-outils
Nice=10
IOSchedulingClass=idle
TimeoutStartSec=6h

CacheDirectory= fait créer /var/cache/restic, où RESTIC_CACHE_DIR place le cache local d'index de restic (sinon /root/.cache/restic, sur la partition racine). Nice= et IOSchedulingClass=idle laissent la priorité aux autres processus (leçon 11). Au-delà de TimeoutStartSec=, le service est tué et passe en échec : lancez la première sauvegarde complète à la main. Le minuteur :

# /etc/systemd/system/sig-sauvegarde.timer
[Timer]
OnCalendar=*-*-* 01:30:00 UTC
RandomizedDelaySec=20min
Persistent=true

[Install]
WantedBy=timers.target

OnFailure= signale l'échec, mais pas l'absence d'exécution (minuteur désactivé, machine éteinte). Le signal de vie couvre ce cas : la supervision l'attend chaque nuit et alerte s'il manque.

Restaurer un fichier

Mercredi, la mairie signale qu'une photo du signalement 18 342 a disparu depuis lundi. On la cherche, puis on la restaure à côté, jamais par-dessus la production :

# restic find --tag fichiers '18342-*.jpg'
# restic restore 5ab07e12 --target /root/restauration \
    --include /srv/donnees/pieces-jointes/2026/10/18342-1.jpg

5ab07e12 est l'instantané de lundi soir (latest désigne le plus récent) ; l'arborescence est recréée sous --target. Pour explorer avant de choisir, restic mount /mnt/restic présente le dépôt en lecture seule par FUSE : /mnt/restic/snapshots/ contient un répertoire par instantané, que l'on parcourt avec ls et diff ; Ctrl-C met fin au montage. Pour l'export de base, dump extrait un fichier vers la sortie standard, et pg_restore --list prouve au minimum qu'il est lisible :

# restic dump --tag pg_dump latest /signalements.dump > /root/signalements.dump
# pg_restore --list /root/signalements.dump | head

Restaurer un serveur : l'exercice sig-app-2

C'est l'étape qui distingue une sauvegarde d'une croyance. Une fois par trimestre, en heures ouvrées, on simule la perte de sig-app-2 et l'on chronomètre :

  1. Top départ. sig-app-2 sort du répartiteur de charge (leçon 4) ; on la garde de côté pour comparer.

  2. Instance Ubuntu 24.04 neuve en fr-par-2, sur pn-signalements, avec les données utilisateur cloud-init de référence.

  3. Installation de restic ; récupération dans le gestionnaire de secrets du fichier d'environnement et du mot de passe du dépôt de sig-app-2 ; restauration de paquets-manuels.txt et installation des paquets listés.

  4. Création du compte signalements avec son UID d'origine (voir Pièges courants), déploiement de l'artefact de la CI.

  5. Restauration de la configuration dans un répertoire de travail, relecture, puis mise en place :

    # restic restore latest --target /root/restauration \
        --include /etc/signalements --include /etc/systemd/system
    # diff -r /root/restauration/etc/signalements /etc/signalements
    
  6. systemctl enable --now signalements, appel du point de santé depuis sig-app-1, lecture du journal, signalement de test.

  7. Retour derrière le répartiteur. Fin du chronomètre.

L'écart est la DMIA réelle, à comparer aux 4 heures promises. On consigne tout ce qui a manqué (un paquet hors liste, un secret absent, une étape fausse) ; chaque manque corrige la sauvegarde ou le runbook (la procédure d'exploitation écrite), et l'exercice suivant le vérifie. La première fois, il manque presque toujours quelque chose : c'est pour cela qu'on le fait. Une fois par an, restaurez aussi le pg_dump dans une base vide, hors de Scaleway si possible, et comparez le nombre de lignes des tables principales : c'est la seule preuve de la réversibilité promise.

Sous le capot

Le dépôt restic

Un dépôt est un ensemble de fichiers immuables nommés par l'empreinte SHA-256 de leur contenu : config (paramètres), keys/ (un fichier par mot de passe), data/ (les packs qui contiennent les données), index/ (où trouver chaque morceau), snapshots/ (un petit fichier par instantané) et locks/ (verrous).

À la sauvegarde, chaque fichier est découpé en morceaux (blobs) par un découpage défini par le contenu : restic calcule une empreinte de Rabin sur une fenêtre glissante et coupe quand elle remplit une condition, ce qui donne, selon la documentation de conception, des morceaux de 512 Kio à 8 Mio, 1 Mio en moyenne. Insérer un octet au début d'un fichier ne déplace que les frontières voisines : les morceaux suivants gardent leur empreinte, là où un découpage en blocs fixes décalerait tout. Un morceau déjà présent dans l'index n'est pas renvoyé : c'est la déduplication. Les nouveaux sont compressés (zstd, format version 2), chiffrés en AES-256 en mode compteur, authentifiés par Poly1305-AES, puis groupés en packs. Les répertoires sont eux-mêmes des morceaux (trees) ; un instantané pointe vers l'arbre racine, et restaurer revient à le parcourir.

Le mot de passe passe par scrypt, une dérivation volontairement coûteuse, pour déchiffrer un fichier de keys/ qui contient la clé maîtresse. D'où la possibilité de plusieurs mots de passe (restic key add, list, remove). Mais retirer un mot de passe ne protège pas contre quelqu'un qui a déjà copié le fichier de clé : la clé maîtresse, elle, ne change pas.

forget ne supprime que des fichiers de snapshots/. prune parcourt ensuite les arbres restants, supprime les packs devenus inutiles et réécrit ceux qui le sont en partie : c'est long, et cela prend un verrou exclusif, alors que backup prend un verrou partagé. Un verrou non rafraîchi depuis 30 minutes est considéré comme périmé.

rsync et les liens physiques

Avec --link-dest, un fichier identique n'est pas transféré : rsync appelle link(), qui ajoute un nom pointant vers le même inode et incrémente son compteur de liens. Le contenu n'est libéré que lorsque ce compteur retombe à zéro. Corollaire : tous les répertoires datés partagent les mêmes octets. Un bloc corrompu touche toutes les copies qui le référencent ; ce sont des copies datées, pas indépendantes.

Le versionnage côté S3

Dans un bucket versionné, écrire sur une clé existante crée une nouvelle version, et une suppression simple pose un marqueur de suppression qui masque l'objet sans rien détruire. Seule une suppression qui désigne une version précise efface des données. La table d'équivalence de Scaleway le traduit en permissions : DeleteObject correspond à s3:DeleteObject, mais avec un versionId, à s3:DeleteObjectVersion. restic a besoin de la première, jamais de la seconde : c'est la base de la protection décrite plus bas.

Pièges courants

La barre oblique qui vide la destination. rsync -a --delete /srv/donnees/pieces-jointes/ /srv/copie/ rend /srv/copie/ identique au contenu source et efface tout le reste. Toujours -n -i d'abord.

« some files vanished ». rsync se termine par le code 24 et un message de la forme :

file has vanished: "/srv/donnees/pieces-jointes/tmp/upload-8f3a.part"
rsync warning: some files vanished before they could be transferred (code 24) at main.c(...) [generator=3.5.0]

La page de manuel définit 24 comme un transfert partiel dû à des fichiers disparus : normal pour des fichiers temporaires, à exclure ou à tolérer dans le script. Le code 23 (transfert partiel dû à une erreur) mérite une enquête.

Le mauvais UID après restauration. restic, comme rsync --numeric-ids et tar --numeric-owner, restaure les propriétaires par numéro. Si signalements avait l'UID 998 et reçoit 997 sur l'instance neuve, parce qu'un paquet a créé un compte système avant lui, le service échoue sur Permission denied. Fixez l'UID à la construction (useradd --system --uid 998, ou un fichier sysusers.d explicite) ou corrigez par chown.

Le mot de passe perdu. Fatal: wrong password or no key found, avec le code de sortie 12 depuis restic 0.17.1. Si la copie du gestionnaire de secrets existe, c'est réglé. Sinon, le dépôt est perdu : il n'existe aucune récupération, par conception.

Le dépôt verrouillé. Une sauvegarde tuée laisse un verrou ; une opération exclusive suivante échoue avec un message qui ressemble à ceci :

unable to create lock in backend: repository is already locked exclusively by PID 2318 on sig-outils by root (UID 0, GID 0)
lock was created at 2026-10-06 01:31:12 (5h12m3s ago)
storage ID 6c1e2f0a
the `unlock` command can be used to remove stale locks

Vérifiez qu'aucun restic ne tourne (pgrep -a restic, systemctl status sig-sauvegarde), puis restic unlock, qui ne retire que les verrous périmés. Depuis 0.17, ce cas renvoie le code 11.

Le code 3. backup renvoie 3 quand l'instantané est créé mais que des fichiers n'ont pas pu être lus. Avec set -e, le minuteur passe en échec : c'est voulu, un instantané incomplet doit être examiné (journalctl -u sig-sauvegarde).

Le client PostgreSQL trop ancien.

pg_dump: error: aborting because of server version mismatch
pg_dump: detail: server version: 18.0; pg_dump version: 17.6

sig-db a été mis à jour avant sig-outils : installez un client de même version majeure ou plus récente.

Les options absentes d'Ubuntu 24.04. restic 0.16.4 ne connaît ni --stdin-from-command, ni restore --overwrite, ni restore --delete, apparus en 0.17.0 selon le journal des modifications : unknown flag: --stdin-from-command. Faites les exports de base depuis sig-outils.

La politique de bucket qui vous enferme dehors. Chez Scaleway, dès qu'une politique de bucket existe, seules les actions qu'elle autorise sont permises, y compris pour vous. Incluez toujours un principal d'administration.

Sécurité

Une sauvegarde est une copie de tout

Le dépôt de sig-outils contient toutes les photos, les secrets de l'API et l'export complet de la base : adresses électroniques, positions, descriptions. L'ANSSI demande (R29) que la protection des sauvegardes soit alignée sur celle de la production, et considère l'opérateur de sauvegarde comme un administrateur à hauts privilèges. Le chiffrement côté client signifie que Scaleway ne stocke que des octets illisibles ; il concentre toute la sensibilité sur le mot de passe du dépôt :

  • un mot de passe aléatoire par dépôt, donc par machine ;
  • une copie dans le gestionnaire de secrets et une copie hors ligne (enveloppe scellée dans un coffre), car un gestionnaire hébergé dans le système détruit ne sert à rien (ANSSI R26 et R30) ;
  • au moins deux personnes capables d'y accéder : un départ sans transmission, comme celui de Camille, peut rendre toutes les sauvegardes illisibles ;
  • un essai de la copie hors ligne à chaque exercice de restauration.

Des identifiants qui ne peuvent pas détruire

Un rançongiciel root sur sig-outils lit /etc/restic/sig-outils.env. Que peut faire cette clé ? restic doit lister, lire, écrire et supprimer (ses verrous, les packs élagués) ; le forum du projet confirme qu'il ne fonctionne pas avec une clé en écriture seule et ne gère pas lui-même le verrouillage d'objets. La parade combine trois mécanismes :

  1. Le versionnage, avec une clé qui a s3:DeleteObject mais pas s3:DeleteObjectVersion ni le droit de modifier le bucket : un restic forget --prune malveillant ne pose que des marqueurs, les anciennes versions restent.
  2. Une règle de cycle de vie NoncurrentVersionExpiration, prise en charge par Scaleway, qui supprime les versions non courantes après, par exemple, 30 jours. Ce délai est votre fenêtre de détection.
  3. Le verrouillage d'objets (Object Lock, modèle WORM, write once, read many) : une rétention par défaut interdit de supprimer une version avant son terme. En mode governance, un utilisateur disposant des permissions adéquates peut lever la protection ; en mode compliance, personne, pas même le propriétaire de l'organisation. Scaleway avertit qu'une fois activé, le verrouillage ne peut plus être désactivé sur le bucket.

La politique de bucket correspondante :

{
  "Version": "2023-04-17",
  "Id": "sig-sauvegardes",
  "Statement": [
    {
      "Sid": "Administration",
      "Effect": "Allow",
      "Principal": {"SCW": "application_id:<ID_APPLICATION_ADMIN>"},
      "Action": "s3:*",
      "Resource": ["sig-sauvegardes", "sig-sauvegardes/*"]
    },
    {
      "Sid": "ResticSigOutils",
      "Effect": "Allow",
      "Principal": {"SCW": "application_id:<ID_APPLICATION_SIG_OUTILS>"},
      "Action": ["s3:ListBucket", "s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
      "Resource": ["sig-sauvegardes", "sig-sauvegardes/sig-outils/*"]
    }
  ]
}

La clé de sig-outils n'écrit que sous son préfixe ; elle peut lister les noms des autres dépôts, mais ni les lire ni les déchiffrer. La clé d'administration ne réside sur aucun serveur.

Important

La rétention protège chaque version pendant N jours à partir de son écriture. Un pack écrit il y a un an et toujours utilisé n'est plus couvert : c'est l'absence de s3:DeleteObjectVersion qui le protège. Aucun des trois mécanismes ne suffit seul.

Une copie hors du compte

Si l'organisation Scaleway elle-même est compromise, tout le bucket est menacé. La troisième copie vit dans une autre organisation ou chez un autre fournisseur, alimentée par restic copy --from-repo (en initialisant la cible avec restic init --from-repo ... --copy-chunker-params pour conserver la déduplication), depuis une machine de cette seconde organisation qui ne détient qu'une clé en lecture seule (ObjectStorageReadOnly) sur la première.

Restaurer sans réintroduire l'attaquant

Les sauvegardes peuvent contenir les implants d'un attaquant : une crontab ajoutée, une clé dans authorized_keys, un script dans /usr/local/bin. L'ANSSI (R27) recommande de reconstruire depuis des images officielles, de restaurer de façon granulaire et de contrôler les configurations avant de redémarrer les applications, à partir d'un instantané antérieur à la compromission, ce qui suppose une rétention assez longue. Restaurer /etc entier à l'aveugle peut réimplanter la porte dérobée.

Données personnelles et RGPD

Les sauvegardes sont un traitement soumis au RGPD comme la production :

  • conservation : six mois de copies mensuelles signifient qu'un signalement supprimé survit six mois dans les sauvegardes ; la durée doit figurer, justifiée, au registre des traitements ;
  • localisation : bucket en fr-par, troisième copie dans l'Union européenne ; l'ANSSI recommande de chiffrer par un moyen propre avant l'envoi, ce que fait restic ;
  • effacement : le rapport du Comité européen de la protection des données sur le droit à l'effacement (février 2026) admet qu'il n'est pas toujours souhaitable de modifier les sauvegardes, à condition de tracer les demandes d'effacement et de les réappliquer sur tout système restauré, et relève que beaucoup de responsables n'ont aucune procédure. Pour Signalements : une liste des effacements conservée hors de la base, et une étape « rejouer les effacements » dans le runbook.

En production

Surveiller l'âge, pas seulement l'échec. L'indicateur utile est l'âge du dernier instantané réussi, par machine et par étiquette, avec une alerte au-delà de 26 heures. Ajoutez une alerte sur un volume ajouté anormal : une nuit à 30 Go au lieu de 300 Mo peut trahir un chiffrement massif, chaque fichier chiffré devenant un fichier nouveau (l'ANSSI, R21, demande ce type de contrôle). Les journaux de restic partent vers sig-outils comme les autres (leçon 12).

Un dépôt par niveau de sensibilité. Un dépôt commun déduplique mieux, mais une machine compromise lit alors celles des autres ; l'ANSSI (R4) recommande de séparer selon la sensibilité. Un dépôt, un mot de passe et une identité IAM par machine est ici le bon compromis : la configuration des serveurs d'application ne pèse que quelques mégaoctets.

Pousser ou tirer. Avec restic vers S3, chaque machine pousse et détient une clé d'écriture ; l'ANSSI préfère que le serveur de sauvegarde tire (R8). BorgBackup, l'alternative principale, sauvegarde par SSH vers un serveur qui exécute borg serve ; son option --append-only, imposée côté serveur dans authorized_keys, interdit au client toute suppression, mais Borg 1.x n'écrit pas directement dans un stockage S3 : il faut administrer ce serveur. restic offre un équivalent avec rest-server --append-only. Le choix revient à ce que vous préférez opérer : un bucket bien configuré ou un serveur de plus.

Les coûts. Le stockage objet facture le volume, versions non courantes comprises ; versionnage et verrouillage l'augmentent, check --read-data relit tout. La classe Glacier de Scaleway, moins chère, exige une restauration préalable avant lecture : bonne pour une copie d'archive, pas pour le dépôt courant que backup relit à chaque exécution.

Documenter et répéter. La procédure de restauration est écrite, exécutable par quelqu'un qui ne l'a pas rédigée, et rangée hors du système qu'elle restaure (ANSSI R22 et R26) : ordre de restauration (réseau et DNS, puis base, puis serveurs d'application), emplacement des mots de passe, commandes exactes. Si la DMIA mesurée dépasse la DMIA promise, on restaure par priorités (les pièces jointes récentes d'abord), on muscle l'instance de restauration, ou l'on réplique la partie critique. Le cours Sauvegarde et reprise d'activité élargit ces questions à tout un système d'information.

Exercices

1. Classer (niveau 100). Faut-il sauvegarder, sur sig-app-1 : /usr/bin/python3, /etc/signalements/secrets.env, /opt/signalements/, /etc/systemd/system/signalements.service.d/override.conf, /var/lib/apt/lists/ ?

Solution

python3 : non, paquet de la distribution. secrets.env : oui, chiffré (restic le fait), idéalement aussi dans le gestionnaire de secrets. /opt/signalements/ : non, artefact de la CI, qui doit conserver les versions déployées. override.conf : oui, c'est l'archétype de la modification manuelle non documentée. /var/lib/apt/lists/ : non, index retéléchargés par apt update.

2. La barre oblique (niveau 100). Qu'obtient-on dans /srv/copie/ avec rsync -a /etc/signalements /srv/copie/, puis avec rsync -a /etc/signalements/ /srv/copie/ ? Laquelle devient dangereuse avec --delete ?

Solution

Sans barre oblique : /srv/copie/signalements/config.toml. Avec : /srv/copie/config.toml. La seconde, avec --delete, rend /srv/copie/ identique au contenu de /etc/signalements/ et supprime tout ce qui s'y trouvait d'autre. Testez avec -n -i.

3. Une rétention (niveau 200). La mairie veut pouvoir revenir sur chaque jour des deux dernières semaines, chaque semaine des deux derniers mois et chaque mois de l'année écoulée ; le registre des traitements déclare six mois de conservation pour les pièces jointes supprimées. Écrivez la commande et nommez le conflit.

Solution

restic forget --tag fichiers --keep-daily 14 --keep-weekly 8 --keep-monthly 12 --prune, d'abord avec --dry-run. Avec douze mensuelles, une pièce jointe supprimée survit jusqu'à un an dans les sauvegardes, plus le délai NoncurrentVersionExpiration du bucket : au-delà des six mois déclarés. Il faut ramener --keep-monthly à 6 ou faire évoluer et justifier le registre avec le délégué à la protection des données. Ce n'est pas une décision technique à prendre seul.

4. Une nuit sans signal (niveau 200). Le signal de vie de sig-outils n'est pas arrivé, mais aucune notification OnFailure= n'a été reçue. Votre démarche ?

Solution
  1. systemctl list-timers sig-sauvegarde.timer et systemctl is-enabled sig-sauvegarde.timer : le minuteur est-il actif, quand a-t-il tourné ?
  2. systemctl status sig-sauvegarde.service : encore activating ? La sauvegarde tourne toujours, d'où l'absence d'échec.
  3. journalctl -u sig-sauvegarde.service --since yesterday : dernière étape ou erreur de restic.
  4. journalctl --list-boots : un redémarrage dans la nuit ? Persistent=true rattrape l'exécution au démarrage suivant. (Sur Debian 13, last n'est plus fourni par défaut.)
  5. Service réussi mais signal absent : c'est le curl final qui a échoué (variable manquante, filtrage en sortie, leçon 8).

restic snapshots --latest 1 confirme la date du dernier instantané réellement présent.

5. L'audit (niveau 300). « Un attaquant root sur sig-outils à 10 h, détecté 45 jours plus tard, peut-il vous empêcher de restaurer les pièces jointes ? » Configuration : versionnage, clé sans s3:DeleteObjectVersion, versions non courantes supprimées après 30 jours, rétention governance de 30 jours. Répondez et proposez des améliorations.

Solution

Oui. Un restic forget --keep-last 1 --prune à 10 h rend les anciennes versions non courantes ; la règle de cycle de vie les supprime 30 jours plus tard, avant la détection. Il peut aussi chiffrer les pièces jointes en production : les sauvegardes suivantes contiennent des fichiers chiffrés pendant que les instantanés sains sortent de la rétention. La rétention de 30 jours expire elle aussi avant la détection.

Améliorations : porter NoncurrentDays et la rétention au-delà du délai réaliste de détection (90 jours par exemple), en conciliant coût et RGPD ; exécuter forget et prune depuis une machine d'administration distincte, la clé de sig-outils ne gardant s3:DeleteObject que sur le préfixe locks/ ; surveiller les instantanés disparus et le volume ajouté pour raccourcir la détection ; tenir la copie hors compte en mode compliance, alimentée par une clé en lecture seule.

Récapitulatif

  • On sauvegarde ce qui ne se reconstruit pas : données, configuration, secrets, modifications manuelles. Le système se reconstruit depuis une image, et après un incident il doit l'être.
  • PDMA (RPO) et DMIA (RTO) se négocient avec le métier et dictent l'architecture.
  • Réplication, instantané et sauvegarde sont trois choses distinctes. Règle 3-2-1, et le 0 de 3-2-1-1-0 : zéro erreur à la restauration.
  • rsync -aHAX --numeric-ids copie sans perdre de métadonnées ; gare à la barre oblique et à --delete ; --link-dest donne des copies datées par liens physiques.
  • restic chiffre côté client, déduplique par découpage défini par le contenu et écrit dans Object Storage : init, backup, snapshots, forget --prune, check, restore, mount, dump. Mot de passe perdu, dépôt perdu.
  • Une base se sauvegarde par pg_dump, jamais par copie de fichiers ; --stdin-from-command refuse un export en échec.
  • Contre la destruction : clé sans s3:DeleteObjectVersion, versionnage, cycle de vie, verrouillage d'objets, copie hors compte.
  • Minuteur avec OnFailure= et signal de vie ; surveiller l'âge du dernier instantané.
  • Tester la restauration, du fichier au serveur complet, chronomètre en main.
  • RGPD : rétention cohérente avec le registre, données dans l'UE, effacements rejoués après restauration.

Pour aller plus loin

  • Le guide de l'ANSSI Sauvegarde des systèmes d'information : les fondamentaux (ANSSI-BP-100) : ses 32 recommandations font une excellente grille d'audit.
  • La documentation de restic (format du dépôt, suppression d'instantanés) et celle de BorgBackup pour comparer les modèles.
  • La fiche 17 du guide de la sécurité des données personnelles de la CNIL, et le rapport 2026 du Comité européen de la protection des données sur le droit à l'effacement.
  • La documentation de Scaleway sur le verrouillage d'objets et les règles de cycle de vie, à relire avant d'activer quoi que ce soit d'irréversible.
  • Le cours Sauvegarde et reprise d'activité, pour passer d'un serveur à un système d'information entier.
  • Pour valider le cours : le quiz et le lab, où vous reprenez en main les trois serveurs de Signalements jusqu'à l'exercice de restauration.
+20 XP Carte du ciel →Mon cosmonaute →

Sources