ajoute les sauvegardes chiffrées vers Dedibackup (rôle Ansible, timer quotidien, rotation)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
f5a5e8d8a9
commit
e879a214a9
9 changed files with 328 additions and 0 deletions
13
ansible/roles/sauvegardes/defaults/main.yml
Normal file
13
ansible/roles/sauvegardes/defaults/main.yml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
sauvegardes_retention_quotidiennes: 7
|
||||
sauvegardes_retention_hebdomadaires: 4
|
||||
# Jour de la semaine (1=lundi .. 7=dimanche, format `date +%u`) où la quotidienne
|
||||
# du jour est aussi conservée comme hebdomadaire.
|
||||
sauvegardes_jour_hebdomadaire: "7"
|
||||
sauvegardes_heure_timer: "03:15"
|
||||
sauvegardes_repertoires:
|
||||
- /etc
|
||||
- /home
|
||||
- /root
|
||||
sauvegardes_age_dir: /root/.age
|
||||
sauvegardes_age_cle: /root/.age/cle-sauvegardes.txt
|
||||
4
ansible/roles/sauvegardes/handlers/main.yml
Normal file
4
ansible/roles/sauvegardes/handlers/main.yml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
- name: recharger systemd
|
||||
ansible.builtin.systemd:
|
||||
daemon_reload: true
|
||||
70
ansible/roles/sauvegardes/tasks/main.yml
Normal file
70
ansible/roles/sauvegardes/tasks/main.yml
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
---
|
||||
- name: installer age et lftp
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- age
|
||||
- lftp
|
||||
state: present
|
||||
update_cache: true
|
||||
cache_valid_time: 3600
|
||||
|
||||
- name: créer le répertoire de la clé age
|
||||
ansible.builtin.file:
|
||||
path: "{{ sauvegardes_age_dir }}"
|
||||
state: directory
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0700"
|
||||
|
||||
- name: générer la paire de clés age (si absente)
|
||||
ansible.builtin.command:
|
||||
cmd: "age-keygen -o {{ sauvegardes_age_cle }}"
|
||||
creates: "{{ sauvegardes_age_cle }}"
|
||||
|
||||
- name: restreindre les permissions de la clé privée age
|
||||
ansible.builtin.file:
|
||||
path: "{{ sauvegardes_age_cle }}"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0600"
|
||||
|
||||
- name: lire la clé publique age (pour affichage, jamais la clé privée)
|
||||
ansible.builtin.command:
|
||||
cmd: "grep -oP '(?<=public key: )age1\\S+' {{ sauvegardes_age_cle }}"
|
||||
register: sauvegardes_age_pub
|
||||
changed_when: false
|
||||
|
||||
- name: déployer le script de sauvegarde
|
||||
ansible.builtin.template:
|
||||
src: sauvegarde-dedibackup.sh.j2
|
||||
dest: /usr/local/sbin/sauvegarde-dedibackup.sh
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0700"
|
||||
|
||||
- name: déployer le service systemd
|
||||
ansible.builtin.template:
|
||||
src: sauvegarde-dedibackup.service.j2
|
||||
dest: /etc/systemd/system/sauvegarde-dedibackup.service
|
||||
mode: "0644"
|
||||
notify: recharger systemd
|
||||
|
||||
- name: déployer le timer systemd
|
||||
ansible.builtin.template:
|
||||
src: sauvegarde-dedibackup.timer.j2
|
||||
dest: /etc/systemd/system/sauvegarde-dedibackup.timer
|
||||
mode: "0644"
|
||||
notify: recharger systemd
|
||||
|
||||
- name: appliquer les changements systemd
|
||||
ansible.builtin.meta: flush_handlers
|
||||
|
||||
- name: activer et démarrer le timer de sauvegarde
|
||||
ansible.builtin.systemd:
|
||||
name: sauvegarde-dedibackup.timer
|
||||
enabled: true
|
||||
state: started
|
||||
|
||||
- name: afficher la clé publique age (à connaître, jamais la privée)
|
||||
ansible.builtin.debug:
|
||||
msg: "Clé publique age du serveur : {{ sauvegardes_age_pub.stdout }}"
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
[Unit]
|
||||
Description=Sauvegarde quotidienne chiffrée vers Dedibackup
|
||||
# Géré par Ansible (rôle sauvegardes) — ne pas modifier à la main.
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/local/sbin/sauvegarde-dedibackup.sh
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
#!/bin/bash
|
||||
# Géré par Ansible (rôle sauvegardes) — ne pas modifier à la main.
|
||||
#
|
||||
# Archive {{ sauvegardes_repertoires | join(', ') }} en tar.zst, chiffre avec age
|
||||
# (clé publique du serveur — la clé privée ne quitte jamais le serveur, voir
|
||||
# {{ sauvegardes_age_cle }}), envoie vers Dedibackup en FTP, puis applique la
|
||||
# rotation ({{ sauvegardes_retention_quotidiennes }} quotidiennes,
|
||||
# {{ sauvegardes_retention_hebdomadaires }} hebdomadaires).
|
||||
set -euo pipefail
|
||||
|
||||
# Les identifiants ne sont jamais affichés ni journalisés : on désactive
|
||||
# l'option xtrace pour cette ligne précise, par précaution.
|
||||
set +x
|
||||
source /root/.dedibackup
|
||||
|
||||
AGE_KEY="{{ sauvegardes_age_cle }}"
|
||||
AGE_PUB=$(grep -oP '(?<=public key: )age1\S+' "$AGE_KEY")
|
||||
|
||||
DATE=$(date +%Y%m%d)
|
||||
DOW=$(date +%u)
|
||||
SEMAINE=$(date +%G-W%V)
|
||||
|
||||
WORKDIR=$(mktemp -d)
|
||||
trap 'rm -rf "$WORKDIR"' EXIT
|
||||
|
||||
ARCHIVE_QUOT="quotidienne-${DATE}.tar.zst.age"
|
||||
|
||||
tar --exclude="{{ sauvegardes_age_dir }}" --exclude='/root/.dedibackup' \
|
||||
-I zstd -cf - {{ sauvegardes_repertoires | join(' ') }} \
|
||||
| age -r "$AGE_PUB" -o "$WORKDIR/$ARCHIVE_QUOT"
|
||||
|
||||
lftp -u "$DEDIBACKUP_USER,$DEDIBACKUP_PASS" "$DEDIBACKUP_HOST" -e "
|
||||
set ftp:ssl-allow no
|
||||
put $WORKDIR/$ARCHIVE_QUOT
|
||||
quit
|
||||
"
|
||||
logger -t sauvegarde-dedibackup "Quotidienne envoyée : $ARCHIVE_QUOT"
|
||||
|
||||
if [ "$DOW" = "{{ sauvegardes_jour_hebdomadaire }}" ]; then
|
||||
ARCHIVE_HEBDO="hebdomadaire-${SEMAINE}.tar.zst.age"
|
||||
cp "$WORKDIR/$ARCHIVE_QUOT" "$WORKDIR/$ARCHIVE_HEBDO"
|
||||
lftp -u "$DEDIBACKUP_USER,$DEDIBACKUP_PASS" "$DEDIBACKUP_HOST" -e "
|
||||
set ftp:ssl-allow no
|
||||
put $WORKDIR/$ARCHIVE_HEBDO
|
||||
quit
|
||||
"
|
||||
logger -t sauvegarde-dedibackup "Hebdomadaire envoyée : $ARCHIVE_HEBDO"
|
||||
fi
|
||||
|
||||
# --- Rotation : on ne garde que les N plus récentes de chaque catégorie. ---
|
||||
rotation() {
|
||||
local motif="$1" garder="$2"
|
||||
local liste a_supprimer
|
||||
liste=$(lftp -u "$DEDIBACKUP_USER,$DEDIBACKUP_PASS" "$DEDIBACKUP_HOST" -e "
|
||||
set ftp:ssl-allow no
|
||||
cls -1 ${motif}
|
||||
quit
|
||||
" 2>/dev/null | sort)
|
||||
a_supprimer=$(echo "$liste" | head -n -"$garder")
|
||||
if [ -n "$a_supprimer" ]; then
|
||||
local commandes=""
|
||||
while IFS= read -r fichier; do
|
||||
[ -n "$fichier" ] && commandes+="rm $fichier;"
|
||||
done <<< "$a_supprimer"
|
||||
lftp -u "$DEDIBACKUP_USER,$DEDIBACKUP_PASS" "$DEDIBACKUP_HOST" -e "
|
||||
set ftp:ssl-allow no
|
||||
$commandes
|
||||
quit
|
||||
"
|
||||
logger -t sauvegarde-dedibackup "Rotation $motif : supprimé $(echo "$a_supprimer" | wc -l) fichier(s)."
|
||||
fi
|
||||
}
|
||||
|
||||
rotation "quotidienne-*.tar.zst.age" {{ sauvegardes_retention_quotidiennes }}
|
||||
rotation "hebdomadaire-*.tar.zst.age" {{ sauvegardes_retention_hebdomadaires }}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
[Unit]
|
||||
Description=Déclenche la sauvegarde quotidienne vers Dedibackup
|
||||
# Géré par Ansible (rôle sauvegardes) — ne pas modifier à la main.
|
||||
|
||||
[Timer]
|
||||
OnCalendar=*-*-* {{ sauvegardes_heure_timer }}:00
|
||||
Persistent=true
|
||||
RandomizedDelaySec=300
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
Loading…
Add table
Add a link
Reference in a new issue