2026-07-03 22:49:26 -04:00
|
|
|
---
|
|
|
|
|
# Sauvegarde applicative (logique) d'un nœud vers la cible restic hors-nœud.
|
|
|
|
|
# Chaque nœud déclare ses "jobs" ; restic chiffre côté client + applique la rétention.
|
|
|
|
|
client_backup_paquets:
|
|
|
|
|
- restic
|
restauration : la reconstruction remet l'etat de l'incarnation precedente
Chaque role proprietaire (AC, bases, annuaire, Nextcloud, rspamd/DKIM,
courriel, forge, web) remet son etat au moment ou il le creerait neuf,
depuis le dernier instantane anterieur a la naissance de la machine.
La sauvegarde refuse de deposer tant qu'un etat d'avant attend.
Outil de noeud setops-restaurer ; cibles sauvegarder-maintenant,
restauration-etat, restauration-renoncer ; test_restauration.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 02:39:22 -04:00
|
|
|
# `setops-restaurer` remet les repertoires par `rsync --delete` (absent du gabarit).
|
|
|
|
|
- rsync
|
2026-07-03 22:49:26 -04:00
|
|
|
|
|
|
|
|
# Cible (nœud serveur_backup) + transport SSH.
|
|
|
|
|
client_backup_cible: "backup-01.{{ domaine_interne }}"
|
|
|
|
|
client_backup_utilisateur_distant: "restic"
|
|
|
|
|
client_backup_ssh_key: "/etc/setops/backup_ed25519"
|
|
|
|
|
# Dépôt restic (un sous-dossier par nœud, relatif au home de l'utilisateur distant).
|
|
|
|
|
client_backup_repo: "sftp:{{ client_backup_utilisateur_distant }}@{{ client_backup_cible }}:{{ inventory_hostname }}"
|
|
|
|
|
client_backup_password: "{{ vault_restic_password | default('') }}"
|
|
|
|
|
client_backup_ssh_privkey: "{{ vault_backup_ssh_privkey | default('') }}"
|
|
|
|
|
|
|
|
|
|
# Dossier de préparation des dumps (pg_dump, slapcat, forgejo dump...).
|
|
|
|
|
client_backup_staging: "/var/backups/setops"
|
|
|
|
|
|
|
|
|
|
# Rétention (restic forget).
|
|
|
|
|
client_backup_retention: "--keep-daily 7 --keep-weekly 4 --keep-monthly 6"
|
2026-10-07 12:48:00 -04:00
|
|
|
# L'instantane d'avant rasage (`make sauvegarder-maintenant`) porte cette etiquette, et la
|
|
|
|
|
# retention la garde EN PLUS de la regle ci-dessus : jusqu'a la reconstruction suivante
|
|
|
|
|
# (decision de l'exploitant, 2026-10-07). Voir `templates/sauvegarder.sh.j2`.
|
|
|
|
|
client_backup_etiquette_avant_raser: "avant-raser"
|
2026-07-03 22:49:26 -04:00
|
|
|
|
|
|
|
|
# Planification (timer systemd).
|
|
|
|
|
client_backup_horaire: "*-*-* 02:30:00"
|
|
|
|
|
|
|
|
|
|
# Jobs déclaratifs. Chaque job :
|
|
|
|
|
# nom : identifiant
|
|
|
|
|
# commande : (optionnel) dump écrivant dans {{ staging }}/{{ nom }}
|
|
|
|
|
# chemins : liste de chemins à inclure dans le snapshot restic
|
sauvegarde : le catalogue derive du groupe, et P36 le prouve
Correction : l'entree precedente attribuait le defaut a la reconstruction
from-zero. C'est faux — le commit fondateur 7476a54 (2026-07-03) disait lui-meme
« Reste : jobs Tier 1 (pg_dump/slapcat/vmail/forgejo) ». Ils n'ont jamais ete
ecrits, et infra-pki-01 a ensuite perdu son integration client_backup.
Le role qui POSSEDE la donnee dit comment la sortir : client_backup_jobs est
l'intersection du catalogue et des group_names du noeud. Un tenant qui deplace un
service emporte sa sauvegarde avec lui. On sauvegarde l'etat NON REGENERABLE :
ni zones PowerDNS ni tableaux Grafana, ils se redeploient.
L'unite qui ment est RETIREE, pas rendue bloquante : refuser le deploiement aurait
casse infra-edge-01, infra-dns-01 et mon-01, qui ne detiennent legitimement rien.
Le defaut etait le timer qui echouait chaque nuit en donnant l'apparence d'une
sauvegarde.
P36 (D-75) lit les groupes detenteurs dans le catalogue : ajouter un role au
catalogue etend la preuve du meme geste. Elle a attrape infra-pki-01 — les cles
de l'AC — corrige au plan.
Mesure hors-noeud : collab-01 64,0 MiB/272, edge-mta-01 4,4 MiB/139,
data-sql-01 1,0 MiB (pg_dumpall complet), forge-01 26,4 KiB/68,
infra-pki-01 20,1 KiB/21, idm-01 2,3 KiB/5 (slapcat). 9 hotes, 9 success.
Reste : rien ne surveille l'unite — c'est ce silence qui a laisse le defaut
vivre un mois.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 20:50:46 -04:00
|
|
|
#
|
|
|
|
|
# CATALOGUE PAR GROUPE — c'est le rôle qui POSSEDE la donnée qui dit comment la sortir.
|
|
|
|
|
# On sauvegarde l'ETAT NON REGENERABLE, pas ce que le code reconstruit : ni les zones
|
|
|
|
|
# PowerDNS ni les tableaux de bord Grafana ne figurent ici, ils se redéploient.
|
|
|
|
|
#
|
|
|
|
|
# Les chemins reprennent les defauts du role proprietaire, mais NE PEUVENT PAS y faire
|
|
|
|
|
# reference : `make deployer` deroule un play par groupe, et les defaults de
|
|
|
|
|
# `serveur_forgejo` ne sont pas charges pendant le play de `client_backup`. D'ou la forme
|
|
|
|
|
# `var | default(litteral)` — la variable gagne si l'inventaire la definit, sinon le
|
|
|
|
|
# defaut du role proprietaire, recopie ici et a garder aligne avec lui.
|
|
|
|
|
client_backup_catalogue:
|
|
|
|
|
serveur_step_ca:
|
|
|
|
|
nom: step_ca
|
|
|
|
|
chemins:
|
|
|
|
|
- "{{ serveur_step_ca_steppath | default('/etc/step-ca') }}"
|
|
|
|
|
serveur_openldap:
|
|
|
|
|
nom: openldap
|
|
|
|
|
# slapcat lit la base a plat : pas d'authentification, coherent meme slapd arrete.
|
|
|
|
|
commande: >-
|
|
|
|
|
slapcat -b '{{ serveur_openldap_base_dn | default("dc=" + domaine_interne.split(".") | join(",dc=")) }}'
|
|
|
|
|
> {{ client_backup_staging }}/openldap/annuaire.ldif
|
|
|
|
|
chemins: ["{{ client_backup_staging }}/openldap"]
|
|
|
|
|
serveur_postgresql:
|
|
|
|
|
nom: postgresql
|
|
|
|
|
# pg_dumpall : TOUTES les bases + les roles et leurs mots de passe. Une base oubliee
|
|
|
|
|
# ici serait une base perdue — d'ou le dump global plutot qu'une liste a maintenir.
|
|
|
|
|
commande: >-
|
|
|
|
|
runuser -u postgres -- pg_dumpall --clean
|
|
|
|
|
> {{ client_backup_staging }}/postgresql/toutes-bases.sql
|
|
|
|
|
chemins: ["{{ client_backup_staging }}/postgresql"]
|
|
|
|
|
serveur_dovecot:
|
|
|
|
|
nom: courriel
|
|
|
|
|
chemins: ["{{ serveur_dovecot_vmail_base | default('/var/vmail') }}"]
|
|
|
|
|
serveur_forgejo:
|
|
|
|
|
nom: forgejo
|
|
|
|
|
chemins:
|
|
|
|
|
- "{{ serveur_forgejo_data | default('/var/lib/forgejo') }}"
|
|
|
|
|
- "{{ serveur_forgejo_config_dir | default('/etc/forgejo') }}"
|
|
|
|
|
serveur_nextcloud:
|
|
|
|
|
nom: nextcloud
|
|
|
|
|
chemins:
|
|
|
|
|
- "{{ serveur_nextcloud_data_dir | default('/var/www/nextcloud/data') }}"
|
|
|
|
|
- "{{ (serveur_nextcloud_racine | default('/var/www/nextcloud')) + '/config' }}"
|
|
|
|
|
serveur_rspamd:
|
|
|
|
|
# Le bayes APPRIS est de l'etat : reconstruire le noeud reinstalle rspamd, pas ce
|
|
|
|
|
# qu'il a appris. Les regles, elles, se redeploient et ne sont pas ici.
|
|
|
|
|
nom: rspamd
|
|
|
|
|
chemins: ["/var/lib/rspamd"]
|
2026-09-30 04:46:19 -04:00
|
|
|
# PAS DE `serveur_web_frontal` (retire le 2026-09-30) : le frontal RELAIE, il ne sert
|
|
|
|
|
# rien lui-meme — ses vhosts, son WAF et sa page 404 se redeploient depuis le depot.
|
|
|
|
|
# `/srv/web` venait de l'epoque ou il servait du statique ; ses instantanes etaient vides.
|
sauvegarde : le catalogue derive du groupe, et P36 le prouve
Correction : l'entree precedente attribuait le defaut a la reconstruction
from-zero. C'est faux — le commit fondateur 7476a54 (2026-07-03) disait lui-meme
« Reste : jobs Tier 1 (pg_dump/slapcat/vmail/forgejo) ». Ils n'ont jamais ete
ecrits, et infra-pki-01 a ensuite perdu son integration client_backup.
Le role qui POSSEDE la donnee dit comment la sortir : client_backup_jobs est
l'intersection du catalogue et des group_names du noeud. Un tenant qui deplace un
service emporte sa sauvegarde avec lui. On sauvegarde l'etat NON REGENERABLE :
ni zones PowerDNS ni tableaux Grafana, ils se redeploient.
L'unite qui ment est RETIREE, pas rendue bloquante : refuser le deploiement aurait
casse infra-edge-01, infra-dns-01 et mon-01, qui ne detiennent legitimement rien.
Le defaut etait le timer qui echouait chaque nuit en donnant l'apparence d'une
sauvegarde.
P36 (D-75) lit les groupes detenteurs dans le catalogue : ajouter un role au
catalogue etend la preuve du meme geste. Elle a attrape infra-pki-01 — les cles
de l'AC — corrige au plan.
Mesure hors-noeud : collab-01 64,0 MiB/272, edge-mta-01 4,4 MiB/139,
data-sql-01 1,0 MiB (pg_dumpall complet), forge-01 26,4 KiB/68,
infra-pki-01 20,1 KiB/21, idm-01 2,3 KiB/5 (slapcat). 9 hotes, 9 success.
Reste : rien ne surveille l'unite — c'est ce silence qui a laisse le defaut
vivre un mois.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 20:50:46 -04:00
|
|
|
serveur_web_dorsal:
|
|
|
|
|
nom: web_dorsal
|
|
|
|
|
chemins: ["{{ serveur_web_dorsal_racine | default('/srv/webapp') }}"]
|
|
|
|
|
|
|
|
|
|
# Jeux retenus pour CE noeud : intersection du catalogue et de ses groupes. Derive, donc
|
|
|
|
|
# un tenant qui deplace un service emporte sa sauvegarde avec lui, sans rien re-declarer.
|
|
|
|
|
client_backup_jobs: >-
|
|
|
|
|
{{ client_backup_catalogue | dict2items
|
|
|
|
|
| selectattr('key', 'in', group_names) | map(attribute='value') | list }}
|
supervision : c'est le DEPOT qui dit ou en sont les sauvegardes
Icinga ne surveillait rien : aucun objet Host ni Service de Set-OPS, seulement
la config Debian d'origine sur localhost.
Superviser setops-sauvegarde.service aurait reproduit le defaut du jour meme :
l'unite etait VERTE sur onze noeuds pendant qu'elle n'emportait rien. Le noeud
sait qu'il a LANCE sa sauvegarde, pas qu'elle est ARRIVEE. backup-01 evalue donc
ses depots et pousse un resultat passif par noeud vers l'API Icinga.
Trois criteres, parce qu'un seul suffit a mentir : l'instantane existe, il est
recent (26 h / 50 h), il contient au moins un fichier.
Le sens du flux est delibere : le depot parle a la supervision, jamais l'inverse
— compromettre mon-01 ne donne aucun acces aux sauvegardes.
Le ttl de 6 h fait la fraicheur : si le rapporteur se tait, Icinga perime les
services tout seul. C'est le silence qui a laisse le defaut vivre un mois.
Deux erreurs corrigees par la mesure :
- --data-urlencode refuse en Bad Request (l'API veut du JSON) ; le flux, le TLS
et l'auth marchaient, seule la charge etait perdue.
- le seuil « vide » en octets signalait a tort idm-01 (2363 o) : un export LDIF
d'un annuaire a un compte pese cela. « Vide » se mesure en FICHIERS. Et le
verdict est un AVERTISSEMENT : la machine ne distingue pas « les donnees ont
disparu » de « il n'y en a pas encore ».
Reserve assumee : curl -k — l'API presente le cert de sa propre AC, pas step-ca.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 21:39:05 -04:00
|
|
|
|
|
|
|
|
# La liste EN CLAIR des memes groupes vit dans `vars/main.yml` — sans Jinja, pour que la
|
|
|
|
|
# supervision et P36 puissent la lire par `include_vars` sans rendre ce catalogue.
|
2026-09-02 18:53:44 -04:00
|
|
|
|
|
|
|
|
# --- LE NOEUD VERIFIE SON PROPRE DEPOT ----------------------------------------
|
|
|
|
|
#
|
|
|
|
|
# POURQUOI ICI, ALORS QUE `serveur_backup` LE FAISAIT DEJA.
|
|
|
|
|
#
|
|
|
|
|
# Le depot etait le seul a voir ce qui etait REELLEMENT arrive : un noeud sait qu'il a
|
|
|
|
|
# lance sa sauvegarde, il ne sait pas qu'elle a abouti. C'etait juste tant que le depot
|
|
|
|
|
# appartenait au meme ecosysteme.
|
|
|
|
|
#
|
|
|
|
|
# Depuis que les ecosystemes deposent chez leur HEBERGEUR, ca ne l'est plus : le site
|
|
|
|
|
# heberge des octets chiffres par restic COTE CLIENT, avec un mot de passe qui ne quitte
|
|
|
|
|
# pas la voute du locataire. Il ne peut ni les lire, ni les ouvrir, ni dire s'ils valent
|
|
|
|
|
# quelque chose. C'est la propriete qui rend la mutualisation acceptable — et elle
|
|
|
|
|
# deplace la verification chez le seul qui detient la cle : le noeud lui-meme.
|
|
|
|
|
#
|
|
|
|
|
# Il verifie donc SON depot distant, pas le fait d'avoir lance sa sauvegarde. La nuance
|
|
|
|
|
# est tout : une unite systemd verte sur un depot vide est exactement ce qui a menti
|
|
|
|
|
# pendant un mois (2026-07-03 -> 2026-08-11).
|
|
|
|
|
client_backup_icinga_hote: "{{ (groups['serveur_icinga'] | default([]) | first) | default('') }}"
|
|
|
|
|
client_backup_icinga_utilisateur: "setops-depot"
|
|
|
|
|
client_backup_icinga_motdepasse: "{{ vault_icinga_api_depot | default('') }}"
|
|
|
|
|
client_backup_ca_verification: "/etc/setops/icinga-ca.crt"
|
2026-09-30 17:08:55 -04:00
|
|
|
# L'Icinga auquel ce noeud a deja rapporte (empreinte de son AC) — voir tasks/verifier.yml.
|
|
|
|
|
client_backup_marque_icinga: "/etc/setops/client_backup-icinga-entendu"
|
2026-09-02 18:53:44 -04:00
|
|
|
client_backup_icinga_ca_source: "/var/lib/icinga2/ca/ca.crt"
|
|
|
|
|
|
|
|
|
|
# `ttl` du resultat passif : au-dela, Icinga perime le service de lui-meme — c'est ce qui
|
|
|
|
|
# fait que le SILENCE alerte. Memes valeurs que cote depot : une verification toutes les
|
|
|
|
|
# 4 h, une execution peut etre manquee sans fausse alerte, deux ne le peuvent pas.
|
|
|
|
|
client_backup_verification_horaire: "*-*-* 01/4:00:00"
|
|
|
|
|
client_backup_ttl_icinga: 21600
|
|
|
|
|
client_backup_age_warn_h: 26
|
|
|
|
|
client_backup_age_crit_h: 50
|
2026-09-28 17:04:28 -04:00
|
|
|
|
|
|
|
|
# LE CONTROLE DE RESTAURATION (2026-09-28) — voir `templates/verifier-restauration.sh.j2`.
|
|
|
|
|
# Hebdomadaire : il relit une part du depot et restaure le dernier instantane pour de vrai.
|
|
|
|
|
client_backup_restauration_horaire: "Sun *-*-* 04:00:00"
|
|
|
|
|
client_backup_restauration_part: "10%"
|
|
|
|
|
# Huit jours : une semaine entre deux controles, plus une journee de marge. Au-dela sans
|
|
|
|
|
# nouvelle, Icinga passe le service au rouge (voir `serveur_icinga_fraicheur_restauration`).
|
|
|
|
|
client_backup_ttl_restauration: 691200
|
restauration : la reconstruction remet l'etat de l'incarnation precedente
Chaque role proprietaire (AC, bases, annuaire, Nextcloud, rspamd/DKIM,
courriel, forge, web) remet son etat au moment ou il le creerait neuf,
depuis le dernier instantane anterieur a la naissance de la machine.
La sauvegarde refuse de deposer tant qu'un etat d'avant attend.
Outil de noeud setops-restaurer ; cibles sauvegarder-maintenant,
restauration-etat, restauration-renoncer ; test_restauration.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 02:39:22 -04:00
|
|
|
|
2026-10-04 14:27:11 -04:00
|
|
|
# Combien de temps un script attend un depot verrouille par un autre (`restic --retry-lock`)
|
|
|
|
|
# avant d'echouer. Le plus long des occupants est le controle de restauration ; il relit
|
|
|
|
|
# 10 % du depot et le restaure entier.
|
|
|
|
|
client_backup_attente_verrou: "30m"
|
|
|
|
|
|
restauration : la reconstruction remet l'etat de l'incarnation precedente
Chaque role proprietaire (AC, bases, annuaire, Nextcloud, rspamd/DKIM,
courriel, forge, web) remet son etat au moment ou il le creerait neuf,
depuis le dernier instantane anterieur a la naissance de la machine.
La sauvegarde refuse de deposer tant qu'un etat d'avant attend.
Outil de noeud setops-restaurer ; cibles sauvegarder-maintenant,
restauration-etat, restauration-renoncer ; test_restauration.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 02:39:22 -04:00
|
|
|
# --- LA RESTAURATION DANS LA RECONSTRUCTION (2026-09-30) ----------------------------
|
|
|
|
|
#
|
|
|
|
|
# Jusqu'ici une reconstruction repartait d'un etat NEUF : les instantanes se restauraient
|
|
|
|
|
# pour PROUVER qu'ils s'ouvrent, jamais pour etre remis en service. Desormais chaque role
|
|
|
|
|
# proprietaire d'un etat inclut `tasks/restaurer.yml` au moment ou il le creerait neuf, et
|
|
|
|
|
# remet celui de l'incarnation precedente s'il existe. Voir `templates/restaurer.sh.j2`.
|
|
|
|
|
#
|
|
|
|
|
# `false` : ne jamais restaurer (chaque jeu est alors acte « desactive », et la
|
|
|
|
|
# sauvegarde ne s'en trouve pas bloquee).
|
|
|
|
|
client_backup_restauration_active: true
|
|
|
|
|
# Imposer un instantane (son `short_id`) au lieu du dernier anterieur a la naissance.
|
|
|
|
|
# Par hote, et le temps d'une passe : `-e client_backup_restauration_instantane=abcd1234`.
|
|
|
|
|
client_backup_restauration_instantane: ""
|
|
|
|
|
# Ou chaque jeu laisse la trace de ce qui lui est arrive (restaure, neuf, en_place...).
|
|
|
|
|
client_backup_restauration_marques: "/etc/setops/restauration"
|
|
|
|
|
# Ce qui etait en place avant d'etre ecrase. Hors des chemins sauvegardes : on ne veut
|
|
|
|
|
# pas deposer chez l'hebergeur l'etat qu'on vient justement de remplacer.
|
|
|
|
|
client_backup_restauration_mise_de_cote: "/var/backups/setops-avant-restauration"
|