Module 4 — Backups, monitoring, incident response

Stratégie 3-2-1, snapshots, dumps DB chiffrés, monitoring uptime, post-mortem structuré, RTO/RPO.

💾 Stratégie 3-2-1

Règle classique du backup :

Pourquoi cette redondance ?

ScénarioProtection
Suppression accidentelleCopie 2 (ou 3) sur autre support
Corruption disqueCopie sur autre support (pas le même disque)
Ransomware qui chiffre tout en ligneCopie offsite déconnectée du réseau
Incendie / vol bureauCopie offsite (cloud distant)
Account cloud compromisCopie sur support local

Exemple concret pour Ezway

⏱️ RTO et RPO — chiffrer vos objectifs

MétriqueDéfinitionQuestion
RTO (Recovery Time Objective)Temps maximum acceptable pour récupérer le service après incident"Combien de temps puis-je rester offline ?"
RPO (Recovery Point Objective)Perte de données maximum acceptable"Combien de temps de travail puis-je perdre ?"

Exemples par criticité

ServiceRTORPOImplication
Site vitrine24h1 semaineBackup hebdo OK, restauration manuelle OK
n8n workflows4h1 jourSnapshot quotidien + procédure de restauration documentée
Odoo prod2h1hBackup DB toutes les heures + restauration scriptée
Plateforme e-commerce (revenue)15 min5 minRéplication temps réel, basculement automatique

Plus le RTO/RPO est court, plus c'est cher. Le bon RTO/RPO est celui qui balance le coût de l'outage vs le coût de la solution.

🔐 Backup PostgreSQL chiffré offsite

Pattern type pour backup d'une base Postgres vers stockage objet distant, chiffré côté client.

#!/bin/bash
# /usr/local/bin/backup-postgres.sh
# À planifier dans cron : 0 2 * * * /usr/local/bin/backup-postgres.sh

set -euo pipefail

# Configuration
DB_NAME="odoo_prod"
BACKUP_DIR="/var/backups/postgres"
S3_BUCKET="s3://ezway-backups/postgres"
GPG_RECIPIENT="backups@ezway-technology.com"
DATE=$(date +%Y-%m-%d_%H-%M)
TMPFILE="${BACKUP_DIR}/${DB_NAME}_${DATE}.sql.gz.gpg"

mkdir -p "$BACKUP_DIR"

# 1. Dump + compression + chiffrement en pipeline (pas de fichier intermédiaire en clair)
pg_dump "$DB_NAME" \
  | gzip -9 \
  | gpg --encrypt --trust-model always --recipient "$GPG_RECIPIENT" \
  > "$TMPFILE"

# 2. Upload S3 (Backblaze B2 utilise la même API)
aws s3 cp "$TMPFILE" "${S3_BUCKET}/${DB_NAME}_${DATE}.sql.gz.gpg" \
  --endpoint-url https://s3.eu-west-1.amazonaws.com

# 3. Nettoyer local (garder 3 jours)
find "$BACKUP_DIR" -name "*.sql.gz.gpg" -mtime +3 -delete

# 4. Vérification (taille non nulle, exit code OK)
if [ ! -s "$TMPFILE" ]; then
  echo "ERREUR: backup vide" | mail -s "Backup KO $(hostname)" alerts@ezway-technology.com
  exit 1
fi

echo "Backup OK : $TMPFILE"
Chiffrer AVANT d'envoyer

Si vous chiffrez côté serveur du cloud (SSE-S3), le fournisseur a vos données en clair en transit + un instant en mémoire. Préférez le chiffrement côté client (GPG) — le fournisseur ne voit que des bytes opaques.

Conséquence : conservez précieusement la clé GPG ailleurs (USB chiffrée, coffre physique). Sinon vos backups sont des bytes inutiles.

🧪 Tester la restauration

Un backup non testé n'existe pas. Beaucoup d'organisations découvrent au moment fatidique que :

Procédure de test trimestrielle

# 1. Provisionner un VPS de test (5€ prorata)
# 2. Télécharger le backup le plus récent
aws s3 cp s3://ezway-backups/postgres/odoo_prod_LATEST.sql.gz.gpg .

# 3. Déchiffrer + décompresser
gpg --decrypt odoo_prod_LATEST.sql.gz.gpg | gunzip > odoo_prod_restore.sql

# 4. Restaurer dans une base vierge
createdb odoo_restore_test
psql odoo_restore_test < odoo_prod_restore.sql

# 5. Vérifier
psql odoo_restore_test -c "SELECT COUNT(*) FROM res_partner;"
# Doit retourner un chiffre cohérent avec la prod

# 6. Lancer l'app sur la DB de test, vérifier que ça boot
# 7. Destruction du VPS de test

Critères de succès

Documentez chaque test dans un fichier backup-tests.md versionné en git — preuve d'audit + détection des dégradations.

📡 Monitoring uptime — Uptime Kuma

Uptime Kuma est l'outil open-source de référence pour monitorer ses services. Auto-hébergeable, UI propre, alertes via tous les canaux (email, Slack, Telegram, Discord, webhook).

Installation

# Via Docker
docker run -d --restart=always \
  -p 3001:3001 \
  -v uptime-kuma:/app/data \
  --name uptime-kuma \
  louislam/uptime-kuma:1

# Ouvrir http://<votre-vps>:3001 et créer le compte admin

Monitors à configurer dès le début

Status page publique

Uptime Kuma génère une status page publique (`/status/...`) — utile pour la transparence avec vos utilisateurs/clients. Pattern : status.votre-domaine.com.

🚨 Incident response — la procédure

Quand un incident se produit (piratage, fuite de données, ransomware, downtime majeur), le réflexe est crucial. Voici le runbook à imprimer (oui, sur papier, accessible même si tout est down).

Phase 1 — Détection & confirmation (10 min max)

  1. Confirmer l'incident est réel (pas un faux positif)
  2. Évaluer la sévérité : critique / haute / moyenne / basse
  3. Identifier les systèmes touchés
  4. Démarrer un canal Slack/Discord dédié, désigner un Incident Commander
  5. Démarrer un doc de timeline (Google Doc partagé) — TOUS les actes y sont loggés en temps réel

Phase 2 — Confinement (1h max)

  1. Isoler les systèmes compromis (couper réseau, mettre offline)
  2. Préserver les preuves : faire un dump complet du système compromis AVANT toute modification
  3. Révoquer tous les tokens / sessions du périmètre suspecté
  4. Bloquer les IPs/comptes attaquants identifiés
  5. Communiquer aux personnes concernées (équipe, clients impactés) avec ce que vous savez

Phase 3 — Éradication & restauration

  1. Identifier la cause racine (CVE exploitée ? credentials leak ? phishing ?)
  2. Patcher la vulnérabilité avant remise en service
  3. Restaurer depuis backup propre (vérifier date de compromission < date du backup)
  4. Rotater TOUS les secrets exposés (mots de passe, tokens, clés)
  5. Tests fonctionnels avant remise en ligne

Phase 4 — Notification réglementaire

Phase 5 — Post-mortem (sous 7 jours)

Document structuré, blameless (pas de culpabilisation individuelle) :

# Post-mortem — Incident YYYY-MM-DD — [Titre court]

## Résumé
[2-3 lignes : quoi, quand, impact]

## Timeline
| Heure | Action | Qui |
|---|---|---|
| 14:23 | Alerte Uptime Kuma : site down | Auto |
| 14:25 | Investigation démarrée | François |
| 14:40 | Identification : WP piraté via plugin obsolète | François |
| 14:45 | Site mis offline | François |
| 15:30 | Restauration backup propre démarrée | Webmaster |
...

## Cause racine (5 whys)
- Pourquoi le site a été piraté ? → Plugin WP obsolète
- Pourquoi le plugin était obsolète ? → Pas de mise à jour auto
- Pourquoi pas de MAJ auto ? → Crainte de breaking changes
- Pourquoi pas de staging ? → Pas prioritisé budget
- Pourquoi pas prioritisé ? → Risque pas évalué

## Impact
- Site offline 4h
- 2 clients ont contacté pour s'inquiéter
- Aucune donnée personnelle exfiltrée (vérifié logs)

## Ce qui a bien marché
- Détection auto via Uptime Kuma (5 min)
- Backup propre disponible (J-1)
- Communication client claire

## Ce qui a mal marché
- 30 min perdues à chercher l'origine (logs pas centralisés)
- Procédure de restauration pas documentée → improvisation

## Actions correctives
| Action | Owner | Deadline |
|---|---|---|
| Activer MAJ auto WP + plugins | François | 2026-05-25 |
| Mettre en place staging WP | Webmaster | 2026-06-15 |
| Documenter procédure restauration | François | 2026-05-30 |
| Centraliser logs (Loki) | François | 2026-07-01 |

🧠 Cas réel — piratage WordPress Ezway

Cas vécu sur un site WP de l'écosystème Ezway (cf. mémoire). Leçons apprises :

  1. Plugin obsolète était l'entrée — d'où l'importance des MAJ auto en module 5
  2. L'attaquant a persisté via les Application Passwords WP — il revenait via API même après changement du mdp admin. Solution : purger les Application Passwords (table wp_usermeta) + désactiver via mu-plugin
  3. Le compte admin était partagé entre nous et le webmaster — impossible de savoir qui avait fait quoi en premier. Solution : comptes nominatifs depuis (cf. module 3)
  4. Détection tardive — pas de monitoring sur ce site. Solution : Uptime Kuma + keyword check pour détecter les modifs de homepage
  5. Backup datait de 3 semaines — perte de 3 semaines de contenu (article, commandes). Solution : backup quotidien + test trimestriel
Chaque incident est un cours gratuit

Un incident bien post-mortem-é coûte 2-3 jours mais vous économise les 5 suivants. C'est de loin le meilleur formateur en sécurité opérationnelle.

🔗 Ressources

📋 Quiz de validation

← Module 3 — Secrets Module 5 — Sécu app & RGPD →