Merge pull request 'fix : changelog plus readme a jour' (#16) from fix/correctif into develop
Reviewed-on: #16
This commit was merged in pull request #16.
This commit is contained in:
@@ -34,3 +34,22 @@ REMOTE_DIR=
|
|||||||
|
|
||||||
# Chemin vers la clé privée SSH utilisée pour la connexion
|
# Chemin vers la clé privée SSH utilisée pour la connexion
|
||||||
SSH_KEY=
|
SSH_KEY=
|
||||||
|
|
||||||
|
# Port SSH du serveur distant
|
||||||
|
BACKUP_REMOTE_SSH_PORT=22
|
||||||
|
|
||||||
|
# Timeout SSH en secondes
|
||||||
|
SSH_CONNECT_TIMEOUT=10
|
||||||
|
|
||||||
|
# Validation stricte des clés hôtes SSH (yes/no)
|
||||||
|
BACKUP_KNOWN_HOSTS_STRICT=yes
|
||||||
|
|
||||||
|
# Fichier known_hosts utilisé par ssh/scp
|
||||||
|
BACKUP_KNOWN_HOSTS_FILE=/root/.ssh/known_hosts
|
||||||
|
|
||||||
|
#############################################
|
||||||
|
# ROTATION DES BACKUPS
|
||||||
|
#############################################
|
||||||
|
|
||||||
|
# Nombre de jours de conservation des sauvegardes
|
||||||
|
# BACKUP_RETENTION_DAYS=10
|
||||||
|
|||||||
@@ -28,12 +28,13 @@ Avant de mettre en place le script, vérifier que les éléments suivants sont d
|
|||||||
- `ssh`
|
- `ssh`
|
||||||
- `curl`
|
- `curl`
|
||||||
- `cron`
|
- `cron`
|
||||||
|
- `jq`
|
||||||
|
|
||||||
Installation sur Debian / Ubuntu :
|
Installation sur Debian / Ubuntu :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install -y tar openssh-client curl cron
|
sudo apt install -y tar openssh-client curl cron jq
|
||||||
````
|
````
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -43,13 +44,13 @@ sudo apt install -y tar openssh-client curl cron
|
|||||||
Le script est situé dans :
|
Le script est situé dans :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
/home/matt/vaultwarden/Malio-ops/BackupVaultWarden/
|
/home/<USER>/Malio-ops/BackupVaultWarden/
|
||||||
```
|
```
|
||||||
|
|
||||||
Structure recommandée :
|
Structure recommandée :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
/home/matt/vaultwarden/Malio-ops/BackupVaultWarden/
|
/home/<USER>/Malio-ops/BackupVaultWarden/
|
||||||
├── backup-vaultwarden.sh
|
├── backup-vaultwarden.sh
|
||||||
├── .env
|
├── .env
|
||||||
└── README.md
|
└── README.md
|
||||||
@@ -65,24 +66,36 @@ Elles doivent être placées dans un fichier `.env`.
|
|||||||
## Exemple de fichier `.env`
|
## Exemple de fichier `.env`
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
WEBHOOK_URL=https://discord.com/api/webhooks/...
|
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/...
|
||||||
REMOTE_USER=<USER>
|
REMOTE_USER=<USER>
|
||||||
REMOTE_HOST=<IP_SERVEUR>
|
REMOTE_HOST=<IP_SERVEUR>
|
||||||
SSH_KEY=/home/matt/.ssh/id_ed25519_vaultwarden_backup
|
SSH_KEY=/home/<USER>/.ssh/id_ed25519_backup
|
||||||
DATA_DIR=/opt/vaultwarden/data
|
DATA_DIR=/opt/vaultwarden/data
|
||||||
|
LOCAL_BACKUP=/var/backups/vaultwarden
|
||||||
REMOTE_DIR=/home/backup/backups/vaultwarden
|
REMOTE_DIR=/home/backup/backups/vaultwarden
|
||||||
|
# BACKUP_REMOTE_SSH_PORT=22
|
||||||
|
# SSH_CONNECT_TIMEOUT=10
|
||||||
|
# BACKUP_KNOWN_HOSTS_STRICT=yes
|
||||||
|
# BACKUP_KNOWN_HOSTS_FILE=/root/.ssh/known_hosts
|
||||||
|
# BACKUP_RETENTION_DAYS=10
|
||||||
```
|
```
|
||||||
|
|
||||||
## Description des variables
|
## Description des variables
|
||||||
|
|
||||||
| Variable | Description |
|
| Variable | Description |
|
||||||
| ----------- | ------------------------------------------------------ |
|
| --------------------- | -------------------------------------------------------------------- |
|
||||||
| WEBHOOK_URL | Webhook Discord pour les notifications |
|
| DISCORD_WEBHOOK_URL | Webhook Discord pour les notifications |
|
||||||
| REMOTE_USER | Utilisateur du serveur distant |
|
| REMOTE_USER | Utilisateur du serveur distant |
|
||||||
| REMOTE_HOST | Adresse IP ou DNS du serveur de sauvegarde |
|
| REMOTE_HOST | Adresse IP ou DNS du serveur de sauvegarde |
|
||||||
| SSH_KEY | Chemin vers la clé SSH utilisée pour le transfert |
|
| SSH_KEY | Chemin vers la clé SSH utilisée pour le transfert |
|
||||||
| DATA_DIR | Dossier `data` de Vaultwarden |
|
| DATA_DIR | Dossier `data` de Vaultwarden |
|
||||||
| REMOTE_DIR | Dossier de stockage des backups sur le serveur distant |
|
| LOCAL_BACKUP | Dossier local où stocker temporairement l'archive |
|
||||||
|
| REMOTE_DIR | Dossier de stockage des backups sur le serveur distant |
|
||||||
|
| BACKUP_REMOTE_SSH_PORT | Port SSH du serveur distant, optionnel, défaut `22` |
|
||||||
|
| SSH_CONNECT_TIMEOUT | Timeout SSH en secondes, optionnel, défaut `10` |
|
||||||
|
| BACKUP_KNOWN_HOSTS_STRICT | Validation stricte des hôtes SSH (`yes`/`no`) |
|
||||||
|
| BACKUP_KNOWN_HOSTS_FILE | Fichier `known_hosts` utilisé par `ssh`/`scp` |
|
||||||
|
| BACKUP_RETENTION_DAYS | Nombre de jours de conservation distante, optionnel, défaut `10` |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -121,13 +134,13 @@ Le transfert des sauvegardes utilise une **clé SSH** afin de permettre une conn
|
|||||||
Sur la machine exécutant les scripts :
|
Sur la machine exécutant les scripts :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_bitwarden
|
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_backup
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 2. Copie de la clé vers le serveur distant
|
#### 2. Copie de la clé vers le serveur distant
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ssh-copy-id -i ~/.ssh/id_ed25519_bitwarden.pub <USER>@<IP_SERVEUR>
|
ssh-copy-id -i ~/.ssh/id_ed25519_backup.pub <USER>@<IP_SERVEUR>
|
||||||
```
|
```
|
||||||
|
|
||||||
Cette commande ajoute la clé dans :
|
Cette commande ajoute la clé dans :
|
||||||
@@ -141,20 +154,20 @@ sur la machine IA.
|
|||||||
#### 3. Vérification de la connexion
|
#### 3. Vérification de la connexion
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ssh -i ~/.ssh/id_ed25519_bitwarden backup@192.168.0.179
|
ssh -i ~/.ssh/id_ed25519_backup -o StrictHostKeyChecking=yes <USER>@<IP_SERVEUR>
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 4. Vérification des fichiers de clé
|
#### 4. Vérification des fichiers de clé
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ls ~/.ssh/id_ed25519_bitwarden*
|
ls ~/.ssh/id_ed25519_backup*
|
||||||
```
|
```
|
||||||
|
|
||||||
Fichiers attendus :
|
Fichiers attendus :
|
||||||
|
|
||||||
```
|
```
|
||||||
~/.ssh/id_ed25519_bitwarden
|
~/.ssh/id_ed25519_backup
|
||||||
~/.ssh/id_ed25519_bitwarden.pub
|
~/.ssh/id_ed25519_backup.pub
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 5. Permissions SSH
|
#### 5. Permissions SSH
|
||||||
@@ -163,8 +176,8 @@ Machine locale :
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
chmod 700 ~/.ssh
|
chmod 700 ~/.ssh
|
||||||
chmod 600 ~/.ssh/id_ed25519_bitwarden
|
chmod 600 ~/.ssh/id_ed25519_backup
|
||||||
chmod 644 ~/.ssh/id_ed25519_bitwarden.pub
|
chmod 644 ~/.ssh/id_ed25519_backup.pub
|
||||||
```
|
```
|
||||||
|
|
||||||
Machine distante :
|
Machine distante :
|
||||||
@@ -174,10 +187,19 @@ chmod 700 ~/.ssh
|
|||||||
chmod 600 ~/.ssh/authorized_keys
|
chmod 600 ~/.ssh/authorized_keys
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 6. Déclaration dans `.env`
|
#### 6. Provisionnement de `known_hosts`
|
||||||
|
|
||||||
|
Le script est prévu pour fonctionner avec validation stricte des hôtes SSH.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
SSH_KEY=/home/matt/.ssh/id_ed25519_bitwarden
|
ssh-keyscan -H <IP_SERVEUR> >> ~/.ssh/known_hosts
|
||||||
|
chmod 600 ~/.ssh/known_hosts
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 7. Déclaration dans `.env`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
SSH_KEY=/home/<USER>/.ssh/id_ed25519_backup
|
||||||
```
|
```
|
||||||
|
|
||||||
Cette clé sera utilisée automatiquement par les scripts (`scp` / `ssh`) pour transférer les sauvegardes.
|
Cette clé sera utilisée automatiquement par les scripts (`scp` / `ssh`) pour transférer les sauvegardes.
|
||||||
@@ -188,7 +210,7 @@ Cette clé sera utilisée automatiquement par les scripts (`scp` / `ssh`) pour t
|
|||||||
Le script crée une archive compressée du dossier `data` :
|
Le script crée une archive compressée du dossier `data` :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
tar -czf "$LOCAL_BACKUP" -C "$(dirname "$DATA_DIR")" "$(basename "$DATA_DIR")"
|
tar -czf "$LOCAL_BACKUP_FILE" -C "$(dirname "$DATA_DIR")" "$(basename "$DATA_DIR")"
|
||||||
```
|
```
|
||||||
|
|
||||||
Cela permet d’obtenir une sauvegarde portable et compressée.
|
Cela permet d’obtenir une sauvegarde portable et compressée.
|
||||||
@@ -200,7 +222,7 @@ Cela permet d’obtenir une sauvegarde portable et compressée.
|
|||||||
Une fois l’archive créée :
|
Une fois l’archive créée :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
scp "${SSH_OPTS[@]}" "$LOCAL_BACKUP" "$REMOTE_USER@$REMOTE_HOST:$REMOTE_DIR/"
|
scp "${SCP_OPTS[@]}" "$LOCAL_BACKUP_FILE" "$REMOTE_USER@$REMOTE_HOST:$REMOTE_DIR/"
|
||||||
```
|
```
|
||||||
|
|
||||||
Le fichier est envoyé vers le serveur de sauvegarde via SCP.
|
Le fichier est envoyé vers le serveur de sauvegarde via SCP.
|
||||||
@@ -209,23 +231,22 @@ Le fichier est envoyé vers le serveur de sauvegarde via SCP.
|
|||||||
|
|
||||||
# 9. Notification Discord
|
# 9. Notification Discord
|
||||||
|
|
||||||
Le script envoie une notification Discord pour informer de l’état de la sauvegarde.
|
Le script envoie une notification Discord pour informer de l'etat de la sauvegarde.
|
||||||
|
|
||||||
Construction du message :
|
Construction du message :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
local msg="**@here Backup Vaultwarden $color**\n"
|
msg="**${ping}Backup Vaultwarden ${icon}**\n"
|
||||||
msg+="Backup: ${BACKUP_NAME}\n"
|
msg+="Backup: ${BACKUP_NAME}\n"
|
||||||
msg+="Data transfer: $dumps_display\n"
|
msg+="Data transfer: ${status_line}\n"
|
||||||
[[ -n "$details" ]] && msg+="Details: $details"
|
[[ -n "$details" ]] && msg+="Détails: ${details}"
|
||||||
```
|
```
|
||||||
|
|
||||||
Envoi du message :
|
Envoi du message :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -fsS -H "Content-Type: application/json" \
|
payload="$(jq -n --arg content "$msg" '{content: $content}')"
|
||||||
-d "{\"content\":\"$msg\"}" \
|
curl -fsS -H "Content-Type: application/json" -d "$payload" "$DISCORD_WEBHOOK_URL"
|
||||||
"$WEBHOOK_URL"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Le message indique :
|
Le message indique :
|
||||||
@@ -237,7 +258,27 @@ Le message indique :
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# 10. Planification avec cron
|
# 10. Rotation distante des sauvegardes
|
||||||
|
|
||||||
|
Le script supprime les archives distantes plus anciennes que la durée de retention configurée.
|
||||||
|
|
||||||
|
Configuration dans `.env` :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# BACKUP_RETENTION_DAYS=10
|
||||||
|
```
|
||||||
|
|
||||||
|
Commande utilisée :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find "$REMOTE_DIR" -type f -name 'vaultwarden-backup-*.tar.gz' -mtime +$RETENTION_DAYS -delete
|
||||||
|
```
|
||||||
|
|
||||||
|
Si la variable n'est pas définie, le script utilise `10` jours par défaut.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 11. Planification avec cron
|
||||||
|
|
||||||
Le script est exécuté automatiquement tous les jours à 19h.
|
Le script est exécuté automatiquement tous les jours à 19h.
|
||||||
|
|
||||||
@@ -250,7 +291,7 @@ crontab -e
|
|||||||
Ajouter :
|
Ajouter :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
0 19 * * * /home/matt/vaultwarden/Malio-ops/BackupVaultWarden/backup-vaultwarden.sh >> /var/log/vaultwarden_backup.log 2>&1
|
0 19 * * * /home/<USER>/Malio-ops/BackupVaultWarden/backup-vaultwarden.sh >> /var/log/vaultwarden_backup.log 2>&1
|
||||||
```
|
```
|
||||||
|
|
||||||
Signification :
|
Signification :
|
||||||
@@ -267,29 +308,29 @@ Le script s’exécute donc **tous les jours à 19h00**.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# 11. Nettoyage
|
# 12. Nettoyage
|
||||||
|
|
||||||
Une fois la sauvegarde transférée :
|
Une fois la sauvegarde transférée :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
rm -f "$LOCAL_BACKUP"
|
rm -f "$LOCAL_BACKUP_FILE"
|
||||||
```
|
```
|
||||||
|
|
||||||
Cela évite de remplir le disque de la machine Vaultwarden.
|
Cela évite de remplir le disque de la machine Vaultwarden.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# 12. Test manuel
|
# 13. Test manuel
|
||||||
|
|
||||||
Avant de mettre le script en cron, tester :
|
Avant de mettre le script en cron, tester :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bash /home/matt/vaultwarden/Malio-ops/BackupVaultWarden/backup-vaultwarden.sh
|
bash /home/<USER>/Malio-ops/BackupVaultWarden/backup-vaultwarden.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# 13. Vérification des logs
|
# 14. Vérification des logs
|
||||||
|
|
||||||
Logs :
|
Logs :
|
||||||
|
|
||||||
@@ -299,7 +340,7 @@ cat /var/log/vaultwarden_backup.log
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# 14. Résumé
|
# 15. Résumé
|
||||||
|
|
||||||
Le script automatise :
|
Le script automatise :
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
umask 077
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Chemins fixes du script
|
# Chemins fixes du script
|
||||||
@@ -27,6 +28,7 @@ log() {
|
|||||||
# Chargement du .env
|
# Chargement du .env
|
||||||
#######################################
|
#######################################
|
||||||
set -a
|
set -a
|
||||||
|
# shellcheck disable=SC1090
|
||||||
source "$ENV_FILE"
|
source "$ENV_FILE"
|
||||||
set +a
|
set +a
|
||||||
|
|
||||||
@@ -40,6 +42,10 @@ set +a
|
|||||||
: "${REMOTE_HOST:?Variable REMOTE_HOST manquante dans .env}"
|
: "${REMOTE_HOST:?Variable REMOTE_HOST manquante dans .env}"
|
||||||
: "${REMOTE_DIR:?Variable REMOTE_DIR manquante dans .env}"
|
: "${REMOTE_DIR:?Variable REMOTE_DIR manquante dans .env}"
|
||||||
: "${SSH_KEY:?Variable SSH_KEY manquante dans .env}"
|
: "${SSH_KEY:?Variable SSH_KEY manquante dans .env}"
|
||||||
|
: "${BACKUP_REMOTE_SSH_PORT:=22}"
|
||||||
|
: "${SSH_CONNECT_TIMEOUT:=10}"
|
||||||
|
: "${BACKUP_KNOWN_HOSTS_STRICT:=yes}"
|
||||||
|
: "${BACKUP_KNOWN_HOSTS_FILE:=${HOME}/.ssh/known_hosts}"
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Variables backup
|
# Variables backup
|
||||||
@@ -50,7 +56,53 @@ BACKUP_NAME="${BACKUP_PREFIX}-${DATE}.tar.gz"
|
|||||||
LOCAL_BACKUP_FILE="${LOCAL_BACKUP}/${BACKUP_NAME}"
|
LOCAL_BACKUP_FILE="${LOCAL_BACKUP}/${BACKUP_NAME}"
|
||||||
RETENTION_DAYS="${BACKUP_RETENTION_DAYS:-10}"
|
RETENTION_DAYS="${BACKUP_RETENTION_DAYS:-10}"
|
||||||
|
|
||||||
SSH_OPTS=(-i "$SSH_KEY" -o IdentitiesOnly=yes -o BatchMode=yes -o ConnectTimeout=10)
|
[[ "$BACKUP_REMOTE_SSH_PORT" =~ ^[0-9]+$ ]] || {
|
||||||
|
echo "ERROR: Variable BACKUP_REMOTE_SSH_PORT invalide dans .env" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ "$SSH_CONNECT_TIMEOUT" =~ ^[0-9]+$ ]] || {
|
||||||
|
echo "ERROR: Variable SSH_CONNECT_TIMEOUT invalide dans .env" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ "$RETENTION_DAYS" =~ ^[0-9]+$ ]] || {
|
||||||
|
echo "ERROR: Variable BACKUP_RETENTION_DAYS invalide dans .env" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${BACKUP_KNOWN_HOSTS_STRICT,,}" in
|
||||||
|
yes|y|oui|o|true|1) BACKUP_KNOWN_HOSTS_STRICT="yes" ;;
|
||||||
|
no|n|non|false|0) BACKUP_KNOWN_HOSTS_STRICT="no" ;;
|
||||||
|
*)
|
||||||
|
echo "ERROR: Variable BACKUP_KNOWN_HOSTS_STRICT invalide dans .env" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
mkdir -p "$(dirname "$BACKUP_KNOWN_HOSTS_FILE")"
|
||||||
|
chmod 700 "$(dirname "$BACKUP_KNOWN_HOSTS_FILE")" || true
|
||||||
|
touch "$BACKUP_KNOWN_HOSTS_FILE"
|
||||||
|
chmod 600 "$BACKUP_KNOWN_HOSTS_FILE" || true
|
||||||
|
|
||||||
|
SSH_OPTS=(
|
||||||
|
-i "$SSH_KEY"
|
||||||
|
-p "$BACKUP_REMOTE_SSH_PORT"
|
||||||
|
-o IdentitiesOnly=yes
|
||||||
|
-o BatchMode=yes
|
||||||
|
-o ConnectTimeout="$SSH_CONNECT_TIMEOUT"
|
||||||
|
-o StrictHostKeyChecking="$BACKUP_KNOWN_HOSTS_STRICT"
|
||||||
|
-o UserKnownHostsFile="$BACKUP_KNOWN_HOSTS_FILE"
|
||||||
|
)
|
||||||
|
SCP_OPTS=(
|
||||||
|
-i "$SSH_KEY"
|
||||||
|
-P "$BACKUP_REMOTE_SSH_PORT"
|
||||||
|
-o IdentitiesOnly=yes
|
||||||
|
-o BatchMode=yes
|
||||||
|
-o ConnectTimeout="$SSH_CONNECT_TIMEOUT"
|
||||||
|
-o StrictHostKeyChecking="$BACKUP_KNOWN_HOSTS_STRICT"
|
||||||
|
-o UserKnownHostsFile="$BACKUP_KNOWN_HOSTS_FILE"
|
||||||
|
)
|
||||||
|
|
||||||
mkdir -p "$LOCAL_BACKUP"
|
mkdir -p "$LOCAL_BACKUP"
|
||||||
|
|
||||||
@@ -95,11 +147,22 @@ fail() {
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
require_cmd() {
|
||||||
|
command -v "$1" >/dev/null 2>&1 || fail "commande requise absente : $1"
|
||||||
|
}
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Vérifications préalables
|
# Vérifications préalables
|
||||||
#######################################
|
#######################################
|
||||||
[[ -d "$DATA_DIR" ]] || fail "Le dossier source n'existe pas : $DATA_DIR"
|
[[ -d "$DATA_DIR" ]] || fail "Le dossier source n'existe pas : $DATA_DIR"
|
||||||
[[ -f "$SSH_KEY" ]] || fail "La clé SSH est introuvable : $SSH_KEY"
|
[[ -f "$SSH_KEY" ]] || fail "La clé SSH est introuvable : $SSH_KEY"
|
||||||
|
[[ -r "$SSH_KEY" ]] || fail "La clé SSH est non lisible : $SSH_KEY"
|
||||||
|
[[ ! -L "$SSH_KEY" ]] || fail "La clé SSH ne doit pas être un lien symbolique : $SSH_KEY"
|
||||||
|
chmod 600 "$SSH_KEY" || true
|
||||||
|
|
||||||
|
for cmd in tar ssh scp jq curl find; do
|
||||||
|
require_cmd "$cmd"
|
||||||
|
done
|
||||||
|
|
||||||
log "Début du backup Vaultwarden"
|
log "Début du backup Vaultwarden"
|
||||||
log "Source : $DATA_DIR"
|
log "Source : $DATA_DIR"
|
||||||
@@ -123,7 +186,7 @@ ssh "${SSH_OPTS[@]}" "$REMOTE_USER@$REMOTE_HOST" "mkdir -p '$REMOTE_DIR'" \
|
|||||||
#######################################
|
#######################################
|
||||||
# Envoi du backup
|
# Envoi du backup
|
||||||
#######################################
|
#######################################
|
||||||
scp "${SSH_OPTS[@]}" "$LOCAL_BACKUP_FILE" "$REMOTE_USER@$REMOTE_HOST:$REMOTE_DIR/" \
|
scp "${SCP_OPTS[@]}" "$LOCAL_BACKUP_FILE" "$REMOTE_USER@$REMOTE_HOST:$REMOTE_DIR/" \
|
||||||
|| fail "Erreur lors de l'envoi du backup vers $REMOTE_HOST"
|
|| fail "Erreur lors de l'envoi du backup vers $REMOTE_HOST"
|
||||||
|
|
||||||
log "Backup envoyé sur $REMOTE_HOST:$REMOTE_DIR"
|
log "Backup envoyé sur $REMOTE_HOST:$REMOTE_DIR"
|
||||||
|
|||||||
56
CHANGELOG.md
56
CHANGELOG.md
@@ -1,45 +1,29 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
Liste des évolutions du projet Scripts Serveur
|
Ce projet suit le format [Keep a Changelog](https://keepachangelog.com/fr/1.1.0/)
|
||||||
|
et applique le versionnement semantique.
|
||||||
|
|
||||||
## [1.0.0]
|
## [Unreleased]
|
||||||
### Parameters
|
|
||||||
Ajouter dans le fichier /RecetteScripts/.env
|
|
||||||
SSH_TIMEOUT
|
|
||||||
BACKUP_LOG_DIR
|
|
||||||
APP_LOG_DIR
|
|
||||||
DISCORD_WEBHOOK_URL
|
|
||||||
DISCORD_PING
|
|
||||||
CHECK_CONNECT_TIMEOUT
|
|
||||||
CHECK_MAX_TIME
|
|
||||||
APP_URLS
|
|
||||||
|
|
||||||
Ajouter dans le fichier /CheckStorage/.env
|
## [1.0.0] - 2026-03-18
|
||||||
WEBHOOK_URL
|
|
||||||
|
|
||||||
Ajouter dans le fichier /BackupVaultWarden/.env
|
|
||||||
DATA_DIR
|
|
||||||
LOCAL_BACKUP
|
|
||||||
REMOTE_USER
|
|
||||||
REMOTE_HOST
|
|
||||||
REMOTE_DIR
|
|
||||||
SSH_KEY
|
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
* [#361] Script dump BDD
|
- Ajout des scripts legacy de sauvegarde PostgreSQL, de verification de statut applicatif et de supervision du stockage.
|
||||||
* [#367] Avoir une notification discord quand les backup sont faites
|
- Ajout du script de sauvegarde Vaultwarden.
|
||||||
* [#368] Script pour check que les applis ne sont pas hors-ligne
|
- Ajout des scripts de reconstruction de bases PostgreSQL dans `RebuildBdd/`.
|
||||||
* first push
|
- Ajout du bootstrap cible, du precheck et de l'orchestration de reconstruction.
|
||||||
* Reorganisation des fichiers et dossiers
|
- Ajout du support d'utilisation via une interface web avec sorties JSON.
|
||||||
* [#372] Script de check si la machine a le stockage plein
|
- Ajout des fichiers d'exemple de configuration pour les scripts et les cibles.
|
||||||
* [#378] Script Backup BDD Vaultwarden
|
|
||||||
* [#381] Variabiliser tous les scripts
|
|
||||||
* [#384] Fix Correctif
|
|
||||||
* [#390] Rotation des scripts
|
|
||||||
* [#392] Scripts de reconstruction des bases de données
|
|
||||||
* [#427] Correctifs
|
|
||||||
* [#433] Ajout du dossier RebuildBdd et creation de la theorique du script de rebuild de base de données
|
|
||||||
* [#002-19] correctif generaliser sur l'application suite aux nombreuses modifications et ajout de script
|
|
||||||
### Changed
|
### Changed
|
||||||
|
- Reorganisation des fichiers et des dossiers du projet.
|
||||||
|
- Variabilisation des scripts via des fichiers `.env`.
|
||||||
|
- Ajout de la rotation des sauvegardes.
|
||||||
|
- Harmonisation progressive de la documentation et des exemples de configuration.
|
||||||
|
- Ajout du bit executable sur les scripts qui doivent etre lancables directement.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
- Correctifs multiples sur les scripts legacy et sur le flux `RebuildBdd`.
|
||||||
|
- Corrections de chemins de configuration et de telechargement des dumps.
|
||||||
|
- Corrections de messages Discord, de revue de code et d'orthographe dans la documentation.
|
||||||
|
- Correctifs sur la preparation PostgreSQL, `scp`, `sudoers` et le reperage des environnements cibles.
|
||||||
|
|||||||
@@ -4,3 +4,9 @@
|
|||||||
|
|
||||||
# Webhook Discord pour notifications
|
# Webhook Discord pour notifications
|
||||||
DISCORD_WEBHOOK_URL=
|
DISCORD_WEBHOOK_URL=
|
||||||
|
|
||||||
|
# Mention Discord en cas d'alerte
|
||||||
|
DISCORD_PING=@here
|
||||||
|
|
||||||
|
# Seuil d'alerte en pourcentage d'utilisation
|
||||||
|
STORAGE_ALERT_LIMIT=70
|
||||||
|
|||||||
@@ -1,65 +1,51 @@
|
|||||||
# Scripts de vérification de l'espace de stockage
|
# CheckStorage
|
||||||
|
|
||||||
Ce projet contient des scripts pour vérifier l'espace de stockage
|
Script de vérification de l’espace disque sur Ubuntu Server, avec notification Discord optionnelle.
|
||||||
|
|
||||||
## Préambule
|
## Fonctionnement
|
||||||
Ce script est conçu pour vérifier l'espace de stockage disponible sur un serveur et envoyer une alerte
|
|
||||||
La vérification de l'espace de stockage ce fait sur la partition racine.
|
|
||||||
La limite d'alerte est fixée à 70% d'utilisation, mais vous pouvez ajuster cette valeur dans le script selon vos besoins.
|
|
||||||
|
|
||||||
## Installation du script
|
Le script :
|
||||||
|
|
||||||
1. Clonez le dépôt GitHub :
|
1. charge `.env`
|
||||||
```bash
|
2. lit l’utilisation de la partition `/`
|
||||||
git clone https://gitea.malio.fr/MALIO-DEV/Scripts-Serveur.git
|
3. compare le taux d’occupation au seuil configuré
|
||||||
```
|
4. envoie une alerte Discord si le seuil est dépassé
|
||||||
|
|
||||||
2. Accédez au répertoire du projet :
|
## Pré-requis
|
||||||
3. ```bash
|
|
||||||
cd Scripts-Serveur/CheckStorage
|
|
||||||
```
|
|
||||||
### Génération de la clé SSH
|
|
||||||
|
|
||||||
Sur la machine exécutant les scripts :
|
Installation recommandée sur Ubuntu Server :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ssh-keygen -t ed25519 -f ~/.ssh/check_storage_key
|
sudo apt update
|
||||||
|
sudo apt install -y coreutils gawk jq curl
|
||||||
```
|
```
|
||||||
Copier la clé sur le serveur distant :
|
|
||||||
|
`jq` et `curl` ne sont nécessaires que si `DISCORD_WEBHOOK_URL` est renseigné.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ssh-copy-id -i ~/.ssh/check_storage_key.pub user@serveur
|
cp .env.exemple .env
|
||||||
|
chmod 600 .env
|
||||||
```
|
```
|
||||||
Tester la connexion sans mot de passe :
|
|
||||||
|
Variables disponibles :
|
||||||
|
|
||||||
|
- `DISCORD_WEBHOOK_URL` : webhook Discord, optionnel
|
||||||
|
- `DISCORD_PING` : mention en cas d’alerte, optionnel, défaut `@here`
|
||||||
|
- `STORAGE_ALERT_LIMIT` : seuil d’alerte en pourcentage, défaut `70`
|
||||||
|
|
||||||
|
## Utilisation
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ssh -i ~/.ssh/check_storage_key <USER>@<HOST>
|
chmod 700 check-storage.sh
|
||||||
|
./check-storage.sh
|
||||||
```
|
```
|
||||||
## Utilisation du script
|
|
||||||
0. Copiez le fichier d'environnement exemple et modifiez les variables selon votre configuration :
|
|
||||||
```bash
|
|
||||||
cp .env.example .env
|
|
||||||
nano .env
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Donnez les permissions d'exécution au script :
|
## Cron
|
||||||
```bash
|
|
||||||
chmod +x check-storage.sh
|
|
||||||
```
|
|
||||||
2. Exécutez le script pour vérifier l'espace de stockage :
|
|
||||||
```bash
|
|
||||||
./check-storage.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
## Initialisé un cron pour exécuter le script régulièrement
|
Exemple quotidien à `07:50` :
|
||||||
1. Ouvrez le crontab pour l'édition :
|
|
||||||
```bash
|
|
||||||
crontab -e
|
|
||||||
```
|
|
||||||
2. Ajoutez la ligne suivante pour exécuter le script tous les jours à 7h50 du matin :
|
|
||||||
```bash
|
|
||||||
50 7 * * * /chemin/vers/le/script/check-storage.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
## Avertissement
|
```bash
|
||||||
Assurez-vous de remplacer `/chemin/vers/le/script/check-storage.sh` par le chemin réel où se trouve le script sur votre système.
|
50 7 * * * /chemin/vers/CheckStorage/check-storage.sh
|
||||||
|
```
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
umask 077
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# CHARGEMENT DU .env
|
# CHARGEMENT DU .env
|
||||||
@@ -22,8 +23,34 @@ set +a
|
|||||||
# CONFIGURATION
|
# CONFIGURATION
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
|
require_cmd() {
|
||||||
|
command -v "$1" >/dev/null 2>&1 || {
|
||||||
|
echo "ERROR: commande requise absente : $1" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Limite maximale d'utilisation du disque en pourcentage
|
# Limite maximale d'utilisation du disque en pourcentage
|
||||||
limit=70
|
limit="${STORAGE_ALERT_LIMIT:-70}"
|
||||||
|
DISCORD_PING="${DISCORD_PING:-@here}"
|
||||||
|
|
||||||
|
[[ "$limit" =~ ^[0-9]+$ ]] || {
|
||||||
|
echo "ERROR: STORAGE_ALERT_LIMIT invalide" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
(( limit >= 1 && limit <= 99 )) || {
|
||||||
|
echo "ERROR: STORAGE_ALERT_LIMIT doit être compris entre 1 et 99" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
require_cmd df
|
||||||
|
require_cmd awk
|
||||||
|
|
||||||
|
if [[ -n "${DISCORD_WEBHOOK_URL:-}" ]]; then
|
||||||
|
require_cmd jq
|
||||||
|
require_cmd curl
|
||||||
|
fi
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# RÉCUPÉRATION DES INFORMATIONS DISQUE
|
# RÉCUPÉRATION DES INFORMATIONS DISQUE
|
||||||
@@ -48,15 +75,17 @@ avail_gb=$(awk -v b="$avail_bytes" 'BEGIN {printf "%.2f", b/1024/1024/1024}')
|
|||||||
|
|
||||||
if [ "$usage" -ge "$limit" ]; then
|
if [ "$usage" -ge "$limit" ]; then
|
||||||
|
|
||||||
msgLimit="@here\n**CHECK STOCKAGE :red_circle:**\nLimite autorisé : ${limit}%\nUtilisation actuelle: ${usage}%\nEspace restant: ${free}%\nUtilise / total: ${used_gb} GB / ${total_gb} GB\nDisponible: ${avail_gb} GB\nHeure: $(date)"
|
msgLimit="${DISCORD_PING}\n**CHECK STOCKAGE :red_circle:**\nLimite autorisée : ${limit}%\nUtilisation actuelle : ${usage}%\nEspace restant : ${free}%\nUtilisé / total : ${used_gb} GB / ${total_gb} GB\nDisponible : ${avail_gb} GB\nHeure : $(date)"
|
||||||
|
|
||||||
payload="$(jq -n --arg content "$msgLimit" '{content: $content}')"
|
if [[ -n "${DISCORD_WEBHOOK_URL:-}" ]]; then
|
||||||
|
payload="$(jq -n --arg content "$msgLimit" '{content: $content}')"
|
||||||
|
|
||||||
curl -X POST \
|
curl -fsS \
|
||||||
-H "Accept: application/json" \
|
-H "Accept: application/json" \
|
||||||
-H "Content-Type: application/json; charset=utf-8" \
|
-H "Content-Type: application/json; charset=utf-8" \
|
||||||
-d "$payload" \
|
-d "$payload" \
|
||||||
"$DISCORD_WEBHOOK_URL"
|
"$DISCORD_WEBHOOK_URL" >/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
22
README.md
22
README.md
@@ -1,8 +1,3 @@
|
|||||||
Voici une version **corrigée, structurée et professionnalisée**, adaptée à votre contexte actuel (scripts rebuild + infra + exploitation).
|
|
||||||
Format directement exploitable pour README.md / BookStack.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# MALIO-OPS
|
# MALIO-OPS
|
||||||
|
|
||||||
Ce dépôt centralise l’ensemble des **scripts d’exploitation, de maintenance et d’automatisation** utilisés dans l’infrastructure MALIO.
|
Ce dépôt centralise l’ensemble des **scripts d’exploitation, de maintenance et d’automatisation** utilisés dans l’infrastructure MALIO.
|
||||||
@@ -150,6 +145,16 @@ cp global.env.exemple global.env
|
|||||||
* Validation des paramètres en entrée (scripts rebuild)
|
* Validation des paramètres en entrée (scripts rebuild)
|
||||||
* Isolation des environnements (cibles distinctes)
|
* Isolation des environnements (cibles distinctes)
|
||||||
* Logs sans données sensibles
|
* Logs sans données sensibles
|
||||||
|
* Validation stricte des hôtes SSH recommandée et utilisée par défaut sur les scripts durcis
|
||||||
|
* Permissions restrictives recommandées sur les `.env`, clés privées et `known_hosts`
|
||||||
|
|
||||||
|
## Déploiement Ubuntu Server
|
||||||
|
|
||||||
|
Le dépôt est maintenant pensé prioritairement pour des cibles **Ubuntu Server** :
|
||||||
|
|
||||||
|
* bootstrap `RebuildBdd` basé sur `apt`, `systemctl` et `sudo -n`
|
||||||
|
* clients SSH en mode batch avec `StrictHostKeyChecking=yes` quand le mode strict est actif
|
||||||
|
* exemples `.env` mis à jour pour expliciter les ports SSH, `known_hosts` et les timeouts
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -180,10 +185,3 @@ cp global.env.exemple global.env
|
|||||||
* `RecetteScripts` = **legacy en cours de migration**
|
* `RecetteScripts` = **legacy en cours de migration**
|
||||||
* Objectif : convergence vers une **chaîne unique, robuste et automatisable (web/API)**
|
* Objectif : convergence vers une **chaîne unique, robuste et automatisable (web/API)**
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Si vous le souhaitez, je peux :
|
|
||||||
|
|
||||||
* restructurer votre README `RebuildBdd` pour qu’il soit au même niveau
|
|
||||||
* ajouter un schéma d’architecture (flux SSH / dump / restore)
|
|
||||||
* ou intégrer directement votre workflow réel (IA machine + backup server + cible) dans la doc
|
|
||||||
|
|||||||
@@ -70,6 +70,8 @@ print_stdout() {
|
|||||||
[[ "$JSON_ONLY" == "yes" ]] || echo "$*"
|
[[ "$JSON_ONLY" == "yes" ]] || echo "$*"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG_FILE=/dev/stderr
|
||||||
|
|
||||||
log() {
|
log() {
|
||||||
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] $*"
|
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] $*"
|
||||||
echo "$msg" >>"$LOG_FILE"
|
echo "$msg" >>"$LOG_FILE"
|
||||||
@@ -114,13 +116,16 @@ require_env_vars() {
|
|||||||
|
|
||||||
validate_env_values() {
|
validate_env_values() {
|
||||||
[[ "$PGPORT" =~ ^[0-9]+$ ]] || fail "PGPORT invalide"
|
[[ "$PGPORT" =~ ^[0-9]+$ ]] || fail "PGPORT invalide"
|
||||||
|
[[ "$ENV_NAME" =~ ^[a-zA-Z0-9_-]+$ ]] || fail "ENV_NAME invalide"
|
||||||
[[ -n "$DBS" ]] || fail "DBS vide"
|
[[ -n "$DBS" ]] || fail "DBS vide"
|
||||||
[[ "$PGUSER" =~ ^[a-zA-Z0-9_][a-zA-Z0-9_-]*$ ]] || fail "PGUSER invalide"
|
[[ "$PGUSER" =~ ^[a-zA-Z0-9_][a-zA-Z0-9_-]*$ ]] || fail "PGUSER invalide"
|
||||||
[[ -n "$BACKUP_REMOTE_HOST" ]] || fail "BACKUP_REMOTE_HOST vide"
|
[[ -n "$BACKUP_REMOTE_HOST" ]] || fail "BACKUP_REMOTE_HOST vide"
|
||||||
[[ -n "$BACKUP_REMOTE_USER" ]] || fail "BACKUP_REMOTE_USER vide"
|
[[ -n "$BACKUP_REMOTE_USER" ]] || fail "BACKUP_REMOTE_USER vide"
|
||||||
[[ -n "$BACKUP_REMOTE_DIR" ]] || fail "BACKUP_REMOTE_DIR vide"
|
[[ -n "$BACKUP_REMOTE_DIR" ]] || fail "BACKUP_REMOTE_DIR vide"
|
||||||
BACKUP_REMOTE_SSH_PORT="${BACKUP_REMOTE_SSH_PORT:-22}"
|
BACKUP_REMOTE_SSH_PORT="${BACKUP_REMOTE_SSH_PORT:-22}"
|
||||||
|
BACKUP_KNOWN_HOSTS_STRICT="${BACKUP_KNOWN_HOSTS_STRICT:-yes}"
|
||||||
[[ "$BACKUP_REMOTE_SSH_PORT" =~ ^[0-9]+$ ]] || fail "BACKUP_REMOTE_SSH_PORT invalide"
|
[[ "$BACKUP_REMOTE_SSH_PORT" =~ ^[0-9]+$ ]] || fail "BACKUP_REMOTE_SSH_PORT invalide"
|
||||||
|
to_bool_yes_no "$BACKUP_KNOWN_HOSTS_STRICT" >/dev/null || fail "BACKUP_KNOWN_HOSTS_STRICT invalide"
|
||||||
}
|
}
|
||||||
|
|
||||||
prepare_log_file() {
|
prepare_log_file() {
|
||||||
@@ -193,7 +198,11 @@ prepare_known_hosts() {
|
|||||||
chmod 644 "$known_hosts" || fail "impossible de chmod 644 sur known_hosts"
|
chmod 644 "$known_hosts" || fail "impossible de chmod 644 sur known_hosts"
|
||||||
|
|
||||||
if ! ssh-keygen -F "$BACKUP_REMOTE_HOST" -f "$known_hosts" >/dev/null 2>&1; then
|
if ! ssh-keygen -F "$BACKUP_REMOTE_HOST" -f "$known_hosts" >/dev/null 2>&1; then
|
||||||
log "Ajout de ${BACKUP_REMOTE_HOST}:${BACKUP_REMOTE_SSH_PORT} à known_hosts"
|
if [[ "$(to_bool_yes_no "$BACKUP_KNOWN_HOSTS_STRICT")" == "yes" ]]; then
|
||||||
|
fail "hôte ${BACKUP_REMOTE_HOST} absent de known_hosts en mode strict ; provisionner l'empreinte manuellement"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Ajout non strict de ${BACKUP_REMOTE_HOST}:${BACKUP_REMOTE_SSH_PORT} à known_hosts"
|
||||||
ssh-keyscan -p "$BACKUP_REMOTE_SSH_PORT" -H "$BACKUP_REMOTE_HOST" >>"$known_hosts" 2>/dev/null || \
|
ssh-keyscan -p "$BACKUP_REMOTE_SSH_PORT" -H "$BACKUP_REMOTE_HOST" >>"$known_hosts" 2>/dev/null || \
|
||||||
fail "échec de récupération de la clé hôte pour ${BACKUP_REMOTE_HOST}"
|
fail "échec de récupération de la clé hôte pour ${BACKUP_REMOTE_HOST}"
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
|
|
||||||
###############################################################################
|
|
||||||
# CIBLE : prod
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
# TARGET_HOST_prod=10.0.0.20
|
|
||||||
# TARGET_PORT_prod=22
|
|
||||||
# TARGET_BOOTSTRAP_USER_prod=backup_liot
|
|
||||||
# TARGET_BOOTSTRAP_SSH_KEY_prod=/home/matteo/.ssh/id_ed25519_target_prod
|
|
||||||
# TARGET_RUNTIME_USER_prod=backup_liot
|
|
||||||
# TARGET_ENABLE_BOOTSTRAP_prod=yes
|
|
||||||
# TARGET_BOOTSTRAP_ALLOW_PASSWORDLESS_SUDO_prod=yes
|
|
||||||
# TARGET_REPO_DIR_prod=/home/backup_liot/RebuildBdd
|
|
||||||
# TARGET_ENV_FILE_prod=/home/backup_liot/RebuildBdd/.env
|
|
||||||
# TARGET_ENV_NAME_prod=PROD
|
|
||||||
# TARGET_PGHOST_prod=127.0.0.1
|
|
||||||
# TARGET_PGPORT_prod=5432
|
|
||||||
# TARGET_PGUSER_prod=backup_liot
|
|
||||||
# TARGET_PGPASSWORD_prod=change_me_prod_password
|
|
||||||
# TARGET_DBS_prod="sirh inventory ferme"
|
|
||||||
# TARGET_BACKUP_SUBDIR_prod=bdd-prod
|
|
||||||
# TARGET_BACKUP_LOG_DIR_prod=/home/backup_liot/logs/rebuild_bdd
|
|
||||||
# TARGET_LOCAL_RESTORE_BASE_DIR_prod=/home/backup_liot/RebuildBdd/restore_tmp
|
|
||||||
# TARGET_SSH_KEY_prod=/home/backup_liot/.ssh/id_ed25519_backup_readonly
|
|
||||||
# TARGET_REMOTE_ROLES_DIR_NAME_prod=user
|
|
||||||
# TARGET_EXCLUDED_RESTORE_ROLES_prod="postgres"
|
|
||||||
# TARGET_AUTO_INSTALL_POSTGRES_prod=yes
|
|
||||||
# TARGET_AUTO_CREATE_PGUSER_prod=yes
|
|
||||||
# TARGET_PGUSER_SUPERUSER_prod=no
|
|
||||||
# TARGET_AUTO_CONFIGURE_SUDOERS_prod=no
|
|
||||||
42
RebuildBdd/Config/Targets/prod.env.exemple
Normal file
42
RebuildBdd/Config/Targets/prod.env.exemple
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
###############################################################################
|
||||||
|
# config/targets/prod.env.exemple
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
# SSH bootstrap cible
|
||||||
|
TARGET_HOST=192.168.1.60
|
||||||
|
TARGET_PORT=22
|
||||||
|
TARGET_BOOTSTRAP_USER=backup_liot
|
||||||
|
TARGET_BOOTSTRAP_SSH_KEY=/home/matteo/.ssh/id_ed25519_target_prod
|
||||||
|
TARGET_RUNTIME_USER=backup_liot
|
||||||
|
|
||||||
|
# Bootstrap
|
||||||
|
TARGET_ENABLE_BOOTSTRAP=yes
|
||||||
|
TARGET_BOOTSTRAP_ALLOW_PASSWORDLESS_SUDO=yes
|
||||||
|
|
||||||
|
# Repo local cible
|
||||||
|
TARGET_REPO_DIR=/home/backup_liot/RebuildBdd
|
||||||
|
TARGET_ENV_FILE=/home/backup_liot/RebuildBdd/.env
|
||||||
|
|
||||||
|
# PostgreSQL cible
|
||||||
|
TARGET_ENV_NAME=PROD
|
||||||
|
TARGET_PGHOST=127.0.0.1
|
||||||
|
TARGET_PGPORT=5432
|
||||||
|
TARGET_PGUSER=backup_liot
|
||||||
|
TARGET_PGPASSWORD=change_me_pg_password
|
||||||
|
TARGET_DBS="sirh inventory ferme"
|
||||||
|
|
||||||
|
# Backup cible
|
||||||
|
TARGET_BACKUP_SUBDIR=bdd-prod
|
||||||
|
|
||||||
|
# Logs / tmp / ssh cible
|
||||||
|
TARGET_BACKUP_LOG_DIR=/home/backup_liot/logs/rebuild_bdd
|
||||||
|
TARGET_LOCAL_RESTORE_BASE_DIR=/home/backup_liot/RebuildBdd/restore_tmp
|
||||||
|
TARGET_SSH_KEY=/home/backup_liot/.ssh/id_ed25519_backup_readonly
|
||||||
|
|
||||||
|
# Options cible
|
||||||
|
TARGET_REMOTE_ROLES_DIR_NAME=user
|
||||||
|
TARGET_EXCLUDED_RESTORE_ROLES="postgres"
|
||||||
|
TARGET_AUTO_INSTALL_POSTGRES=yes
|
||||||
|
TARGET_AUTO_CREATE_PGUSER=yes
|
||||||
|
TARGET_PGUSER_SUPERUSER=no
|
||||||
|
TARGET_AUTO_CONFIGURE_SUDOERS=no
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
# config/targets/test.env.example
|
# config/targets/test.env.exemple
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
# SSH bootstrap cible
|
# SSH bootstrap cible
|
||||||
@@ -46,7 +46,7 @@ Le projet utilise deux niveaux de configuration :
|
|||||||
Fichier :
|
Fichier :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
config/global.env
|
Config/global.env
|
||||||
````
|
````
|
||||||
|
|
||||||
Contient les paramètres stables, par exemple :
|
Contient les paramètres stables, par exemple :
|
||||||
@@ -62,7 +62,7 @@ Contient les paramètres stables, par exemple :
|
|||||||
Fichiers :
|
Fichiers :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
config/targets/<nom_cible>.env
|
Config/Targets/<nom_cible>.env
|
||||||
```
|
```
|
||||||
|
|
||||||
Chaque fichier cible contient :
|
Chaque fichier cible contient :
|
||||||
@@ -83,9 +83,9 @@ RebuildBdd/
|
|||||||
├── create-target-config.sh
|
├── create-target-config.sh
|
||||||
├── run-rebuild-bdd.sh
|
├── run-rebuild-bdd.sh
|
||||||
├── rebuild-bdd-core.sh
|
├── rebuild-bdd-core.sh
|
||||||
├── config/
|
├── Config/
|
||||||
│ ├── global.env
|
│ ├── global.env
|
||||||
│ └── targets/
|
│ └── Targets/
|
||||||
│ ├── test.env
|
│ ├── test.env
|
||||||
│ └── prod.env
|
│ └── prod.env
|
||||||
└── Checkup/
|
└── Checkup/
|
||||||
@@ -102,7 +102,7 @@ RebuildBdd/
|
|||||||
Crée ou met à jour un fichier cible dans :
|
Crée ou met à jour un fichier cible dans :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
config/targets/<cible>.env
|
Config/Targets/<cible>.env
|
||||||
```
|
```
|
||||||
|
|
||||||
Usage :
|
Usage :
|
||||||
@@ -233,6 +233,7 @@ Doit disposer de :
|
|||||||
* `scp`
|
* `scp`
|
||||||
* `git`
|
* `git`
|
||||||
* `python3`
|
* `python3`
|
||||||
|
* `jq` si vous consommez les JSON côté tooling
|
||||||
|
|
||||||
### Machine cible
|
### Machine cible
|
||||||
|
|
||||||
@@ -240,7 +241,8 @@ Le bootstrap suppose :
|
|||||||
|
|
||||||
* accès SSH fonctionnel ;
|
* accès SSH fonctionnel ;
|
||||||
* utilisateur bootstrap existant ;
|
* utilisateur bootstrap existant ;
|
||||||
* soit `root`, soit `sudo -n` déjà disponible pour le bootstrap initial.
|
* soit `root`, soit `sudo -n` déjà disponible pour le bootstrap initial ;
|
||||||
|
* `known_hosts` correctement provisionné si le mode strict SSH est activé vers le serveur de backup.
|
||||||
|
|
||||||
### Serveur de backup
|
### Serveur de backup
|
||||||
|
|
||||||
@@ -250,6 +252,20 @@ Doit :
|
|||||||
* accepter la clé de lecture backup ;
|
* accepter la clé de lecture backup ;
|
||||||
* contenir les dumps dans l’arborescence attendue.
|
* contenir les dumps dans l’arborescence attendue.
|
||||||
|
|
||||||
|
## Sécurité / déploiement
|
||||||
|
|
||||||
|
### Clés hôtes SSH
|
||||||
|
|
||||||
|
Si `GLOBAL_BACKUP_KNOWN_HOSTS_STRICT=yes`, l’empreinte du serveur de backup doit déjà être présente dans le `known_hosts` de la cible. Le bootstrap et les checks ne font plus d’ajout aveugle en mode strict.
|
||||||
|
|
||||||
|
### Répertoires de clone
|
||||||
|
|
||||||
|
Les scripts refusent maintenant les chemins de clone manifestement dangereux comme `/`, `/root`, `/home` ou `/home/<user>` pour éviter un `rm -rf` destructeur dû à une mauvaise configuration.
|
||||||
|
|
||||||
|
### Ubuntu Server
|
||||||
|
|
||||||
|
Le flux de bootstrap est pensé pour des cibles Ubuntu Server avec `apt`, `systemctl` et `sudo -n`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Structure des backups attendue
|
## Structure des backups attendue
|
||||||
@@ -290,13 +306,13 @@ Le script recherche :
|
|||||||
Copier :
|
Copier :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
config/global.env.example
|
Config/.env.exemple
|
||||||
```
|
```
|
||||||
|
|
||||||
vers :
|
vers :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
config/global.env
|
Config/global.env
|
||||||
```
|
```
|
||||||
|
|
||||||
Renseigner ensuite :
|
Renseigner ensuite :
|
||||||
@@ -317,13 +333,13 @@ Deux possibilités.
|
|||||||
Créer un fichier :
|
Créer un fichier :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
config/targets/test.env
|
Config/Targets/test.env
|
||||||
```
|
```
|
||||||
|
|
||||||
à partir de :
|
à partir de :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
config/targets/test.env.example
|
Config/Targets/test.env.exemple
|
||||||
```
|
```
|
||||||
|
|
||||||
#### B. Via script
|
#### B. Via script
|
||||||
@@ -400,7 +416,7 @@ Ces informations doivent être stockées dans la configuration serveur.
|
|||||||
|
|
||||||
Le flux recommandé est :
|
Le flux recommandé est :
|
||||||
|
|
||||||
1. créer ou mettre à jour `config/targets/<cible>.env`
|
1. créer ou mettre à jour `Config/Targets/<cible>.env`
|
||||||
2. lancer `bootstrap-target-host.sh --target <cible>`
|
2. lancer `bootstrap-target-host.sh --target <cible>`
|
||||||
3. lancer ensuite `run-rebuild-bdd.sh --target <cible> ...`
|
3. lancer ensuite `run-rebuild-bdd.sh --target <cible> ...`
|
||||||
|
|
||||||
|
|||||||
@@ -221,6 +221,14 @@ if [[ -n "$TARGET_REPO_SUBDIR" ]]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
for critical_dir in "$TARGET_CLONE_DIR" "$TARGET_SCRIPT_DIR" "$TARGET_REPO_DIR"; do
|
||||||
|
[[ -n "$critical_dir" ]] || fail "répertoire critique vide"
|
||||||
|
[[ "$critical_dir" != "/" ]] || fail "répertoire critique dangereux refusé : $critical_dir"
|
||||||
|
[[ "$critical_dir" != "/root" ]] || fail "répertoire critique dangereux refusé : $critical_dir"
|
||||||
|
[[ "$critical_dir" != "/home" ]] || fail "répertoire critique dangereux refusé : $critical_dir"
|
||||||
|
[[ ! "$critical_dir" =~ ^/home/[^/]+$ ]] || fail "répertoire critique dangereux refusé : $critical_dir"
|
||||||
|
done
|
||||||
|
|
||||||
[[ -n "$TARGET_ENV_NAME_VALUE" ]] || fail "TARGET_ENV_NAME manquante"
|
[[ -n "$TARGET_ENV_NAME_VALUE" ]] || fail "TARGET_ENV_NAME manquante"
|
||||||
[[ -n "$TARGET_PGHOST_VALUE" ]] || fail "TARGET_PGHOST/GLOBAL_PGHOST manquant"
|
[[ -n "$TARGET_PGHOST_VALUE" ]] || fail "TARGET_PGHOST/GLOBAL_PGHOST manquant"
|
||||||
[[ -n "$TARGET_PGPORT_VALUE" ]] || fail "TARGET_PGPORT/GLOBAL_PGPORT manquant"
|
[[ -n "$TARGET_PGPORT_VALUE" ]] || fail "TARGET_PGPORT/GLOBAL_PGPORT manquant"
|
||||||
@@ -258,7 +266,7 @@ SSH_OPTS=(
|
|||||||
-p "$BOOTSTRAP_PORT"
|
-p "$BOOTSTRAP_PORT"
|
||||||
-o IdentitiesOnly=yes
|
-o IdentitiesOnly=yes
|
||||||
-o BatchMode=yes
|
-o BatchMode=yes
|
||||||
-o StrictHostKeyChecking=accept-new
|
-o StrictHostKeyChecking=yes
|
||||||
-o ConnectTimeout=8
|
-o ConnectTimeout=8
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -339,6 +347,7 @@ BACKUP_LOG_DIR=$(shell_quote "$TARGET_BACKUP_LOG_DIR_VALUE")
|
|||||||
LOCAL_RESTORE_BASE_DIR=$(shell_quote "$TARGET_LOCAL_RESTORE_BASE_DIR_VALUE")
|
LOCAL_RESTORE_BASE_DIR=$(shell_quote "$TARGET_LOCAL_RESTORE_BASE_DIR_VALUE")
|
||||||
REMOTE_ROLES_DIR_NAME=$(shell_quote "$TARGET_REMOTE_ROLES_DIR_NAME_VALUE")
|
REMOTE_ROLES_DIR_NAME=$(shell_quote "$TARGET_REMOTE_ROLES_DIR_NAME_VALUE")
|
||||||
SSH_KEY=$(shell_quote "$TARGET_SSH_KEY_VALUE")
|
SSH_KEY=$(shell_quote "$TARGET_SSH_KEY_VALUE")
|
||||||
|
BACKUP_KNOWN_HOSTS_STRICT=$(shell_quote "$TARGET_BACKUP_KNOWN_HOSTS_STRICT_VALUE")
|
||||||
|
|
||||||
AUTO_INSTALL_POSTGRES=$(shell_quote "$TARGET_AUTO_INSTALL_POSTGRES_VALUE")
|
AUTO_INSTALL_POSTGRES=$(shell_quote "$TARGET_AUTO_INSTALL_POSTGRES_VALUE")
|
||||||
AUTO_CREATE_PGUSER=$(shell_quote "$TARGET_AUTO_CREATE_PGUSER_VALUE")
|
AUTO_CREATE_PGUSER=$(shell_quote "$TARGET_AUTO_CREATE_PGUSER_VALUE")
|
||||||
@@ -385,6 +394,10 @@ if ! command -v ssh-keyscan >/dev/null 2>&1; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if ! ssh-keygen -F $(shell_quote "$TARGET_BACKUP_REMOTE_HOST_VALUE") -f $(shell_quote "$REMOTE_KNOWN_HOSTS") >/dev/null 2>&1; then
|
if ! ssh-keygen -F $(shell_quote "$TARGET_BACKUP_REMOTE_HOST_VALUE") -f $(shell_quote "$REMOTE_KNOWN_HOSTS") >/dev/null 2>&1; then
|
||||||
|
if [[ $(shell_quote "$STRICT_OPTION") == yes ]]; then
|
||||||
|
echo 'hôte backup absent de known_hosts en mode strict ; empreinte à provisionner manuellement' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
ssh-keyscan -p $(shell_quote "$TARGET_BACKUP_REMOTE_SSH_PORT_VALUE") -H $(shell_quote "$TARGET_BACKUP_REMOTE_HOST_VALUE") >> $(shell_quote "$REMOTE_KNOWN_HOSTS") 2>/dev/null
|
ssh-keyscan -p $(shell_quote "$TARGET_BACKUP_REMOTE_SSH_PORT_VALUE") -H $(shell_quote "$TARGET_BACKUP_REMOTE_HOST_VALUE") >> $(shell_quote "$REMOTE_KNOWN_HOSTS") 2>/dev/null
|
||||||
fi
|
fi
|
||||||
"
|
"
|
||||||
@@ -488,6 +501,10 @@ REMOTE_REPO_CMD="
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
if [[ ! -d $(shell_quote "${TARGET_CLONE_DIR}/.git") ]]; then
|
if [[ ! -d $(shell_quote "${TARGET_CLONE_DIR}/.git") ]]; then
|
||||||
|
if [[ $(shell_quote "$TARGET_CLONE_DIR") == / || $(shell_quote "$TARGET_CLONE_DIR") == /root || $(shell_quote "$TARGET_CLONE_DIR") == /home || $(shell_quote "$TARGET_CLONE_DIR") =~ ^/home/[^/]+$ ]]; then
|
||||||
|
echo 'TARGET_CLONE_DIR dangereux refusé' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
rm -rf $(shell_quote "$TARGET_CLONE_DIR")
|
rm -rf $(shell_quote "$TARGET_CLONE_DIR")
|
||||||
git clone --branch $(shell_quote "$TARGET_REPO_BRANCH") --single-branch $(shell_quote "$TARGET_REPO_URL") $(shell_quote "$TARGET_CLONE_DIR")
|
git clone --branch $(shell_quote "$TARGET_REPO_BRANCH") --single-branch $(shell_quote "$TARGET_REPO_URL") $(shell_quote "$TARGET_CLONE_DIR")
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -83,6 +83,8 @@ print_stdout() {
|
|||||||
[[ "$JSON_ONLY" == "yes" ]] || echo "$*"
|
[[ "$JSON_ONLY" == "yes" ]] || echo "$*"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG_FILE=/dev/stderr
|
||||||
|
|
||||||
log() {
|
log() {
|
||||||
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] $*"
|
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] $*"
|
||||||
echo "$msg" >>"$LOG_FILE"
|
echo "$msg" >>"$LOG_FILE"
|
||||||
@@ -220,6 +222,7 @@ RESTORE_ROLES="$(to_bool_yes_no "$RESTORE_ROLES_RAW")" || {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[ "$PGPORT" =~ ^[0-9]+$ ]] || fail "PGPORT invalide"
|
[[ "$PGPORT" =~ ^[0-9]+$ ]] || fail "PGPORT invalide"
|
||||||
|
[[ "$ENV_NAME" =~ ^[a-zA-Z0-9_-]+$ ]] || fail "ENV_NAME invalide"
|
||||||
[[ "$BACKUP_REMOTE_SSH_PORT" =~ ^[0-9]+$ ]] || fail "BACKUP_REMOTE_SSH_PORT invalide"
|
[[ "$BACKUP_REMOTE_SSH_PORT" =~ ^[0-9]+$ ]] || fail "BACKUP_REMOTE_SSH_PORT invalide"
|
||||||
|
|
||||||
mkdir -p "$BACKUP_LOG_DIR" || {
|
mkdir -p "$BACKUP_LOG_DIR" || {
|
||||||
|
|||||||
@@ -195,6 +195,14 @@ if [[ -n "$TARGET_REPO_SUBDIR" ]]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
for critical_dir in "$TARGET_CLONE_DIR" "$TARGET_SCRIPT_DIR" "$TARGET_REPO_DIR"; do
|
||||||
|
[[ -n "$critical_dir" ]] || fail "répertoire critique vide"
|
||||||
|
[[ "$critical_dir" != "/" ]] || fail "répertoire critique dangereux refusé : $critical_dir"
|
||||||
|
[[ "$critical_dir" != "/root" ]] || fail "répertoire critique dangereux refusé : $critical_dir"
|
||||||
|
[[ "$critical_dir" != "/home" ]] || fail "répertoire critique dangereux refusé : $critical_dir"
|
||||||
|
[[ ! "$critical_dir" =~ ^/home/[^/]+$ ]] || fail "répertoire critique dangereux refusé : $critical_dir"
|
||||||
|
done
|
||||||
|
|
||||||
TARGET_ENABLE_BOOTSTRAP="$(to_bool_yes_no "$TARGET_ENABLE_BOOTSTRAP")" || fail "TARGET_ENABLE_BOOTSTRAP invalide"
|
TARGET_ENABLE_BOOTSTRAP="$(to_bool_yes_no "$TARGET_ENABLE_BOOTSTRAP")" || fail "TARGET_ENABLE_BOOTSTRAP invalide"
|
||||||
|
|
||||||
BOOTSTRAP_SCRIPT_LOCAL="${SCRIPT_DIR}/bootstrap-target-host.sh"
|
BOOTSTRAP_SCRIPT_LOCAL="${SCRIPT_DIR}/bootstrap-target-host.sh"
|
||||||
@@ -261,7 +269,7 @@ SSH_OPTS=(
|
|||||||
-p "$TARGET_PORT"
|
-p "$TARGET_PORT"
|
||||||
-o IdentitiesOnly=yes
|
-o IdentitiesOnly=yes
|
||||||
-o BatchMode=yes
|
-o BatchMode=yes
|
||||||
-o StrictHostKeyChecking=accept-new
|
-o StrictHostKeyChecking=yes
|
||||||
-o ConnectTimeout=8
|
-o ConnectTimeout=8
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -294,6 +302,10 @@ mkdir -p \"\$(dirname \"\$CLONE_DIR\")\"
|
|||||||
mkdir -p \"\$(dirname \"\$REPO_DIR\")\"
|
mkdir -p \"\$(dirname \"\$REPO_DIR\")\"
|
||||||
|
|
||||||
if [[ ! -d \"\$CLONE_DIR/.git\" ]]; then
|
if [[ ! -d \"\$CLONE_DIR/.git\" ]]; then
|
||||||
|
if [[ \"\$CLONE_DIR\" == / || \"\$CLONE_DIR\" == /root || \"\$CLONE_DIR\" == /home || \"\$CLONE_DIR\" =~ ^/home/[^/]+$ ]]; then
|
||||||
|
echo '{\"status\":\"error\",\"message\":\"TARGET_CLONE_DIR dangereux refusé\"}'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
rm -rf \"\$CLONE_DIR\"
|
rm -rf \"\$CLONE_DIR\"
|
||||||
git clone --branch \"\$REPO_BRANCH\" --single-branch \"\$REPO_URL\" \"\$CLONE_DIR\" >/dev/null 2>&1
|
git clone --branch \"\$REPO_BRANCH\" --single-branch \"\$REPO_URL\" \"\$CLONE_DIR\" >/dev/null 2>&1
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -47,14 +47,13 @@ Les scripts fonctionnent indépendamment mais utilisent le même principe :
|
|||||||
|
|
||||||
Environnement Linux recommandé.
|
Environnement Linux recommandé.
|
||||||
|
|
||||||
Packages nécessaires :
|
Packages nécessaires sur Ubuntu Server :
|
||||||
|
|
||||||
```
|
```
|
||||||
postgresql-client
|
postgresql-client
|
||||||
curl
|
curl
|
||||||
jq
|
jq
|
||||||
ssh
|
openssh-client
|
||||||
scp
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Commandes PostgreSQL requises :
|
Commandes PostgreSQL requises :
|
||||||
@@ -116,11 +115,18 @@ ssh-copy-id -i ~/.ssh/id_backup_postgres.pub backup@192.168.1.50
|
|||||||
Tester la connexion sans mot de passe :
|
Tester la connexion sans mot de passe :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ssh -i ~/.ssh/id_backup_postgres backup@192.168.1.50
|
ssh -i ~/.ssh/id_backup_postgres -o StrictHostKeyChecking=yes backup@192.168.1.50
|
||||||
```
|
```
|
||||||
|
|
||||||
La connexion doit fonctionner **sans demander de mot de passe**.
|
La connexion doit fonctionner **sans demander de mot de passe**.
|
||||||
|
|
||||||
|
Provisionner aussi `known_hosts` avant le premier run :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh-keyscan -H 192.168.1.50 >> ~/.ssh/known_hosts
|
||||||
|
chmod 600 ~/.ssh/known_hosts
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Sécuriser les permissions
|
### Sécuriser les permissions
|
||||||
@@ -153,13 +159,18 @@ cp backup.env.exemple .env
|
|||||||
|
|
||||||
Puis modifier les variables.
|
Puis modifier les variables.
|
||||||
|
|
||||||
|
Variables SSH supplémentaires désormais supportées :
|
||||||
|
|
||||||
|
```
|
||||||
|
BACKUP_REMOTE_SSH_PORT
|
||||||
|
BACKUP_KNOWN_HOSTS_STRICT
|
||||||
|
BACKUP_KNOWN_HOSTS_FILE
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# 5. Script : backup-bdd-recette.sh
|
# 5. Script : backup-bdd-recette.sh
|
||||||
|
|
||||||
Script :
|
|
||||||
|
|
||||||
|
|
||||||
## Objectif
|
## Objectif
|
||||||
|
|
||||||
Sauvegarder plusieurs bases PostgreSQL et transférer les dumps vers un serveur distant.
|
Sauvegarder plusieurs bases PostgreSQL et transférer les dumps vers un serveur distant.
|
||||||
@@ -205,6 +216,8 @@ Suppression des sauvegardes plus anciennes que :
|
|||||||
10 jours
|
10 jours
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Le script utilise maintenant des options SSH strictes et refuse les clés privées symboliques.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Exécution
|
## Exécution
|
||||||
@@ -217,9 +230,6 @@ Suppression des sauvegardes plus anciennes que :
|
|||||||
|
|
||||||
# 6. Script : check-statut-recette.sh
|
# 6. Script : check-statut-recette.sh
|
||||||
|
|
||||||
Script :
|
|
||||||
|
|
||||||
|
|
||||||
## Objectif
|
## Objectif
|
||||||
|
|
||||||
Vérifier la disponibilité des applications web.
|
Vérifier la disponibilité des applications web.
|
||||||
@@ -306,6 +316,8 @@ Le script :
|
|||||||
9. restaure la base via `pg_restore`
|
9. restaure la base via `pg_restore`
|
||||||
10. envoie une notification Discord
|
10. envoie une notification Discord
|
||||||
|
|
||||||
|
Le script supporte désormais le port SSH distant, un fichier `known_hosts` dédié et l’exclusion configurable des rôles via `EXCLUDED_RESTORE_ROLES`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Sélection de la base
|
## Sélection de la base
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
umask 077
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# backup-bdd-recette.sh
|
# backup-bdd-recette.sh
|
||||||
@@ -67,15 +68,82 @@ set +a
|
|||||||
|
|
||||||
read -r -a DBS_ARRAY <<< "$DBS"
|
read -r -a DBS_ARRAY <<< "$DBS"
|
||||||
|
|
||||||
|
validate_db_name() {
|
||||||
|
local db_name="$1"
|
||||||
|
|
||||||
|
[[ -n "$db_name" ]] || {
|
||||||
|
echo "ERROR: nom de base vide dans DBS" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ "$db_name" =~ ^[a-zA-Z0-9_]+$ ]] || {
|
||||||
|
echo "ERROR: nom de base invalide dans DBS : $db_name" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for DB in "${DBS_ARRAY[@]}"; do
|
||||||
|
validate_db_name "$DB"
|
||||||
|
done
|
||||||
|
|
||||||
IA_SSH="${BACKUP_REMOTE_USER}@${BACKUP_REMOTE_HOST}"
|
IA_SSH="${BACKUP_REMOTE_USER}@${BACKUP_REMOTE_HOST}"
|
||||||
IA_BASE_DIR="${BACKUP_REMOTE_DIR}"
|
|
||||||
RETENTION_DAYS=10
|
RETENTION_DAYS=10
|
||||||
|
BACKUP_REMOTE_SSH_PORT="${BACKUP_REMOTE_SSH_PORT:-22}"
|
||||||
|
BACKUP_KNOWN_HOSTS_STRICT="${BACKUP_KNOWN_HOSTS_STRICT:-yes}"
|
||||||
|
BACKUP_KNOWN_HOSTS_FILE="${BACKUP_KNOWN_HOSTS_FILE:-${HOME}/.ssh/known_hosts}"
|
||||||
|
|
||||||
|
[[ "$BACKUP_REMOTE_SSH_PORT" =~ ^[0-9]+$ ]] || {
|
||||||
|
echo "ERROR: BACKUP_REMOTE_SSH_PORT invalide" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ "$PGPORT" =~ ^[0-9]+$ ]] || {
|
||||||
|
echo "ERROR: PGPORT invalide" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ "$SSH_TIMEOUT" =~ ^[0-9]+$ ]] || {
|
||||||
|
echo "ERROR: SSH_TIMEOUT invalide" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ "$PGUSER" =~ ^[a-zA-Z0-9_][a-zA-Z0-9_-]*$ ]] || {
|
||||||
|
echo "ERROR: PGUSER invalide" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${BACKUP_KNOWN_HOSTS_STRICT,,}" in
|
||||||
|
yes|y|oui|o|true|1) BACKUP_KNOWN_HOSTS_STRICT="yes" ;;
|
||||||
|
no|n|non|false|0) BACKUP_KNOWN_HOSTS_STRICT="no" ;;
|
||||||
|
*)
|
||||||
|
echo "ERROR: BACKUP_KNOWN_HOSTS_STRICT invalide" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
mkdir -p "$(dirname "$BACKUP_KNOWN_HOSTS_FILE")"
|
||||||
|
chmod 700 "$(dirname "$BACKUP_KNOWN_HOSTS_FILE")" || true
|
||||||
|
touch "$BACKUP_KNOWN_HOSTS_FILE"
|
||||||
|
chmod 600 "$BACKUP_KNOWN_HOSTS_FILE" || true
|
||||||
|
|
||||||
SSH_OPTS=(
|
SSH_OPTS=(
|
||||||
-i "$SSH_KEY"
|
-i "$SSH_KEY"
|
||||||
|
-p "$BACKUP_REMOTE_SSH_PORT"
|
||||||
-o IdentitiesOnly=yes
|
-o IdentitiesOnly=yes
|
||||||
-o BatchMode=yes
|
-o BatchMode=yes
|
||||||
-o ConnectTimeout="${SSH_TIMEOUT}"
|
-o ConnectTimeout="${SSH_TIMEOUT}"
|
||||||
|
-o StrictHostKeyChecking="${BACKUP_KNOWN_HOSTS_STRICT}"
|
||||||
|
-o UserKnownHostsFile="${BACKUP_KNOWN_HOSTS_FILE}"
|
||||||
|
)
|
||||||
|
|
||||||
|
SCP_OPTS=(
|
||||||
|
-i "$SSH_KEY"
|
||||||
|
-P "$BACKUP_REMOTE_SSH_PORT"
|
||||||
|
-o IdentitiesOnly=yes
|
||||||
|
-o BatchMode=yes
|
||||||
|
-o ConnectTimeout="${SSH_TIMEOUT}"
|
||||||
|
-o StrictHostKeyChecking="${BACKUP_KNOWN_HOSTS_STRICT}"
|
||||||
|
-o UserKnownHostsFile="${BACKUP_KNOWN_HOSTS_FILE}"
|
||||||
)
|
)
|
||||||
|
|
||||||
LOG_DIR="${BACKUP_LOG_DIR}"
|
LOG_DIR="${BACKUP_LOG_DIR}"
|
||||||
@@ -85,8 +153,10 @@ TS="$(date +'%Y-%m-%d_%H-%M-%S')"
|
|||||||
BACKUP_DIR_NAME="backup_${TS}"
|
BACKUP_DIR_NAME="backup_${TS}"
|
||||||
LOG_FILE="${LOG_DIR}/${BACKUP_DIR_NAME}.log"
|
LOG_FILE="${LOG_DIR}/${BACKUP_DIR_NAME}.log"
|
||||||
|
|
||||||
TMP_DIR="/tmp/pg_dump_${BACKUP_DIR_NAME}"
|
TMP_DIR="$(mktemp -d /tmp/pg_dump_XXXXXX)" || {
|
||||||
mkdir -p "$TMP_DIR"
|
echo "ERROR: impossible de créer le dossier temporaire" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
exec > >(tee -a "$LOG_FILE") 2>&1
|
exec > >(tee -a "$LOG_FILE") 2>&1
|
||||||
|
|
||||||
@@ -96,19 +166,46 @@ require_cmd() {
|
|||||||
command -v "$1" >/dev/null 2>&1
|
command -v "$1" >/dev/null 2>&1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
safe_remove_dir() {
|
||||||
|
local dir="${1:-}"
|
||||||
|
[[ -n "$dir" ]] || return 0
|
||||||
|
[[ "$dir" == /tmp/pg_dump_* ]] || {
|
||||||
|
log "WARNING: suppression refusée pour le chemin inattendu : $dir"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
rm -rf -- "$dir"
|
||||||
|
}
|
||||||
|
|
||||||
export PGPASSWORD
|
export PGPASSWORD
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Vérification dépendances minimales
|
# Vérification dépendances minimales
|
||||||
#######################################
|
#######################################
|
||||||
|
|
||||||
for cmd in ssh scp curl jq pg_dump pg_dumpall; do
|
for cmd in ssh scp curl jq pg_dump pg_dumpall mktemp; do
|
||||||
require_cmd "$cmd" || {
|
require_cmd "$cmd" || {
|
||||||
echo "ERROR: commande manquante : $cmd" >&2
|
echo "ERROR: commande manquante : $cmd" >&2
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
done
|
done
|
||||||
|
|
||||||
|
[[ -f "$SSH_KEY" ]] || {
|
||||||
|
echo "ERROR: clé SSH introuvable : $SSH_KEY" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ -r "$SSH_KEY" ]] || {
|
||||||
|
echo "ERROR: clé SSH non lisible : $SSH_KEY" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ ! -L "$SSH_KEY" ]] || {
|
||||||
|
echo "ERROR: la clé SSH ne doit pas être un lien symbolique : $SSH_KEY" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
chmod 600 "$SSH_KEY" || true
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Configuration Discord
|
# Configuration Discord
|
||||||
#######################################
|
#######################################
|
||||||
@@ -271,19 +368,21 @@ if ! mkdir "$LOCK_DIR" 2>/dev/null; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
trap 'rm -rf "$LOCK_DIR" "$TMP_DIR"' EXIT
|
cleanup() {
|
||||||
|
rm -rf -- "$LOCK_DIR"
|
||||||
|
safe_remove_dir "$TMP_DIR" || true
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Préparation du dossier distant
|
# Préparation du dossier distant
|
||||||
#######################################
|
#######################################
|
||||||
|
|
||||||
REMOTE_DIR="${IA_BASE_DIR}"
|
|
||||||
|
|
||||||
log "Creating remote directories"
|
log "Creating remote directories"
|
||||||
|
|
||||||
MKDIR_CMD="mkdir -p '${REMOTE_DIR}/user'"
|
MKDIR_CMD="mkdir -p '${BACKUP_REMOTE_DIR}/user'"
|
||||||
for DB in "${DBS_ARRAY[@]}"; do
|
for DB in "${DBS_ARRAY[@]}"; do
|
||||||
MKDIR_CMD+=" '${REMOTE_DIR}/${DB}'"
|
MKDIR_CMD+=" '${BACKUP_REMOTE_DIR}/${DB}'"
|
||||||
done
|
done
|
||||||
|
|
||||||
if ! ssh "${SSH_OPTS[@]}" "$IA_SSH" "$MKDIR_CMD"; then
|
if ! ssh "${SSH_OPTS[@]}" "$IA_SSH" "$MKDIR_CMD"; then
|
||||||
@@ -320,7 +419,7 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n "${USERS_EXPORT_OK:-}" ]]; then
|
if [[ -n "${USERS_EXPORT_OK:-}" ]]; then
|
||||||
scp "${SSH_OPTS[@]}" "$ROLES_FILE" "$IA_SSH:${REMOTE_DIR}/user/"
|
scp "${SCP_OPTS[@]}" "$ROLES_FILE" "$IA_SSH:${BACKUP_REMOTE_DIR}/user/"
|
||||||
RET=$?
|
RET=$?
|
||||||
|
|
||||||
if [[ $RET -ne 0 ]]; then
|
if [[ $RET -ne 0 ]]; then
|
||||||
@@ -364,7 +463,7 @@ for DB in "${DBS_ARRAY[@]}"; do
|
|||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
scp "${SSH_OPTS[@]}" "$FILE" "$IA_SSH:${REMOTE_DIR}/${DB}/"
|
scp "${SCP_OPTS[@]}" "$FILE" "$IA_SSH:${BACKUP_REMOTE_DIR}/${DB}/"
|
||||||
RET=$?
|
RET=$?
|
||||||
|
|
||||||
if [[ $RET -ne 0 ]]; then
|
if [[ $RET -ne 0 ]]; then
|
||||||
@@ -384,7 +483,7 @@ log "Starting remote rotation: delete backups older than ${RETENTION_DAYS} days"
|
|||||||
|
|
||||||
set +e
|
set +e
|
||||||
|
|
||||||
ssh "${SSH_OPTS[@]}" "$IA_SSH" "find '${REMOTE_DIR}/user' -type f -name 'user_*.sql' -mtime +${RETENTION_DAYS} -delete"
|
ssh "${SSH_OPTS[@]}" "$IA_SSH" "find '${BACKUP_REMOTE_DIR}/user' -type f -name 'user_*.sql' -mtime +${RETENTION_DAYS} -delete"
|
||||||
RET=$?
|
RET=$?
|
||||||
|
|
||||||
if [[ $RET -ne 0 ]]; then
|
if [[ $RET -ne 0 ]]; then
|
||||||
@@ -394,7 +493,7 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
for DB in "${DBS_ARRAY[@]}"; do
|
for DB in "${DBS_ARRAY[@]}"; do
|
||||||
ssh "${SSH_OPTS[@]}" "$IA_SSH" "find '${REMOTE_DIR}/${DB}' -type f -name '${DB}_*.dump' -mtime +${RETENTION_DAYS} -delete"
|
ssh "${SSH_OPTS[@]}" "$IA_SSH" "find '${BACKUP_REMOTE_DIR}/${DB}' -type f -name '${DB}_*.dump' -mtime +${RETENTION_DAYS} -delete"
|
||||||
RET=$?
|
RET=$?
|
||||||
|
|
||||||
if [[ $RET -ne 0 ]]; then
|
if [[ $RET -ne 0 ]]; then
|
||||||
@@ -412,7 +511,7 @@ log "Remote rotation finished"
|
|||||||
# Nettoyage local
|
# Nettoyage local
|
||||||
#######################################
|
#######################################
|
||||||
|
|
||||||
rm -rf "$TMP_DIR"
|
safe_remove_dir "$TMP_DIR" || true
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Bilan final Discord
|
# Bilan final Discord
|
||||||
|
|||||||
@@ -44,9 +44,18 @@ BACKUP_REMOTE_DIR=/home/.../backups/bdd-recette
|
|||||||
# Clé SSH utilisée pour se connecter au serveur distant
|
# Clé SSH utilisée pour se connecter au serveur distant
|
||||||
SSH_KEY=/home/.../.ssh/id_ed25519_backup
|
SSH_KEY=/home/.../.ssh/id_ed25519_backup
|
||||||
|
|
||||||
|
# Port SSH du serveur de backup
|
||||||
|
BACKUP_REMOTE_SSH_PORT=22
|
||||||
|
|
||||||
# Timeout de connexion SSH (secondes)
|
# Timeout de connexion SSH (secondes)
|
||||||
SSH_TIMEOUT=10
|
SSH_TIMEOUT=10
|
||||||
|
|
||||||
|
# Validation stricte des clés hôtes SSH (yes/no)
|
||||||
|
BACKUP_KNOWN_HOSTS_STRICT=yes
|
||||||
|
|
||||||
|
# Fichier known_hosts utilisé par ssh/scp
|
||||||
|
BACKUP_KNOWN_HOSTS_FILE=/home/.../.ssh/known_hosts
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# LOGS
|
# LOGS
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|||||||
@@ -201,8 +201,6 @@ check_site() {
|
|||||||
#######################################
|
#######################################
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
trap '[[ -n "$STDERR_TMP" ]] && rm -f "$STDERR_TMP"' EXIT
|
|
||||||
|
|
||||||
local failures=0
|
local failures=0
|
||||||
|
|
||||||
for site in "${SITES[@]}"; do
|
for site in "${SITES[@]}"; do
|
||||||
|
|||||||
@@ -65,8 +65,10 @@ set +a
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
LOCAL_RESTORE_DIR="${LOCAL_RESTORE_DIR:-${SCRIPT_DIR}/restore_tmp}"
|
LOCAL_RESTORE_DIR="${LOCAL_RESTORE_DIR:-${SCRIPT_DIR}/restore_tmp}"
|
||||||
REMOTE_ROLES_DIR_NAME="${REMOTE_ROLES_DIR_NAME:-user}"
|
REMOTE_ROLES_DIR_NAME="${REMOTE_ROLES_DIR_NAME:-user}"
|
||||||
|
BACKUP_REMOTE_SSH_PORT="${BACKUP_REMOTE_SSH_PORT:-22}"
|
||||||
SSH_CONNECT_TIMEOUT="${SSH_CONNECT_TIMEOUT:-8}"
|
SSH_CONNECT_TIMEOUT="${SSH_CONNECT_TIMEOUT:-8}"
|
||||||
DISCORD_WEBHOOK_URL="${DISCORD_WEBHOOK_URL:-}"
|
DISCORD_WEBHOOK_URL="${DISCORD_WEBHOOK_URL:-}"
|
||||||
|
EXCLUDED_RESTORE_ROLES="${EXCLUDED_RESTORE_ROLES:-postgres}"
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Préparation des dossiers locaux
|
# Préparation des dossiers locaux
|
||||||
@@ -115,6 +117,35 @@ require_cmd() {
|
|||||||
command -v "$1" >/dev/null 2>&1
|
command -v "$1" >/dev/null 2>&1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sql_escape_literal() {
|
||||||
|
local s="${1:-}"
|
||||||
|
s="${s//\'/\'\'}"
|
||||||
|
printf "%s" "$s"
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_db_name() {
|
||||||
|
local db_name="$1"
|
||||||
|
|
||||||
|
[[ -n "$db_name" ]] || fail "nom de base vide"
|
||||||
|
[[ "$db_name" =~ ^[A-Za-z0-9_]+$ ]] || \
|
||||||
|
fail "nom de base invalide : seuls les lettres, chiffres et underscores sont autorisés"
|
||||||
|
}
|
||||||
|
|
||||||
|
build_excluded_roles_regex() {
|
||||||
|
local role regex=""
|
||||||
|
|
||||||
|
for role in $EXCLUDED_RESTORE_ROLES; do
|
||||||
|
[[ -z "$role" ]] && continue
|
||||||
|
[[ "$role" =~ ^[a-zA-Z_][a-zA-Z0-9_-]*$ ]] || fail "rôle exclu invalide : ${role}"
|
||||||
|
if [[ -n "$regex" ]]; then
|
||||||
|
regex+="|"
|
||||||
|
fi
|
||||||
|
regex+="$role"
|
||||||
|
done
|
||||||
|
|
||||||
|
printf '%s' "$regex"
|
||||||
|
}
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Envoi Discord
|
# Envoi Discord
|
||||||
#
|
#
|
||||||
@@ -151,15 +182,28 @@ send_discord_message() {
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
[[ -f "$SSH_KEY" ]] || fail "clé SSH introuvable : $SSH_KEY"
|
[[ -f "$SSH_KEY" ]] || fail "clé SSH introuvable : $SSH_KEY"
|
||||||
[[ -r "$SSH_KEY" ]] || fail "clé SSH non lisible : $SSH_KEY"
|
[[ -r "$SSH_KEY" ]] || fail "clé SSH non lisible : $SSH_KEY"
|
||||||
|
[[ "$PGPORT" =~ ^[0-9]+$ ]] || fail "PGPORT invalide"
|
||||||
|
[[ "$BACKUP_REMOTE_SSH_PORT" =~ ^[0-9]+$ ]] || fail "BACKUP_REMOTE_SSH_PORT invalide"
|
||||||
|
[[ "$PGUSER" =~ ^[a-zA-Z0-9_][a-zA-Z0-9_-]*$ ]] || fail "PGUSER invalide"
|
||||||
|
|
||||||
export PGPASSWORD
|
export PGPASSWORD
|
||||||
|
|
||||||
SSH_OPTS=(
|
SSH_OPTS=(
|
||||||
-i "$SSH_KEY"
|
-i "$SSH_KEY"
|
||||||
|
-p "$BACKUP_REMOTE_SSH_PORT"
|
||||||
-o IdentitiesOnly=yes
|
-o IdentitiesOnly=yes
|
||||||
-o BatchMode=yes
|
-o BatchMode=yes
|
||||||
-o ConnectTimeout="$SSH_CONNECT_TIMEOUT"
|
-o ConnectTimeout="$SSH_CONNECT_TIMEOUT"
|
||||||
-o StrictHostKeyChecking=accept-new
|
-o StrictHostKeyChecking=yes
|
||||||
|
)
|
||||||
|
|
||||||
|
SCP_OPTS=(
|
||||||
|
-i "$SSH_KEY"
|
||||||
|
-P "$BACKUP_REMOTE_SSH_PORT"
|
||||||
|
-o IdentitiesOnly=yes
|
||||||
|
-o BatchMode=yes
|
||||||
|
-o ConnectTimeout="$SSH_CONNECT_TIMEOUT"
|
||||||
|
-o StrictHostKeyChecking=yes
|
||||||
)
|
)
|
||||||
|
|
||||||
REMOTE_SSH="${BACKUP_REMOTE_USER}@${BACKUP_REMOTE_HOST}"
|
REMOTE_SSH="${BACKUP_REMOTE_USER}@${BACKUP_REMOTE_HOST}"
|
||||||
@@ -217,7 +261,7 @@ if [[ "$POSTGRES_INSTALLED" == "true" ]]; then
|
|||||||
log "Création du rôle PostgreSQL ${PGUSER} suite à une installation neuve..."
|
log "Création du rôle PostgreSQL ${PGUSER} suite à une installation neuve..."
|
||||||
|
|
||||||
sudo -u postgres psql -d postgres -c \
|
sudo -u postgres psql -d postgres -c \
|
||||||
"CREATE ROLE \"${PGUSER}\" WITH LOGIN SUPERUSER CREATEDB CREATEROLE PASSWORD '${PGPASSWORD}';" \
|
"CREATE ROLE \"${PGUSER}\" WITH LOGIN SUPERUSER CREATEDB CREATEROLE PASSWORD '$(sql_escape_literal "$PGPASSWORD")';" \
|
||||||
>>"$LOG_FILE" 2>&1 || fail "échec de création du rôle ${PGUSER}"
|
>>"$LOG_FILE" 2>&1 || fail "échec de création du rôle ${PGUSER}"
|
||||||
|
|
||||||
log "Rôle PostgreSQL ${PGUSER} créé."
|
log "Rôle PostgreSQL ${PGUSER} créé."
|
||||||
@@ -251,9 +295,10 @@ if [[ "${USE_LIST,,}" == "oui" || "${USE_LIST,,}" == "o" ]]; then
|
|||||||
DB="${DBS_ARRAY[$((DB_INDEX - 1))]}"
|
DB="${DBS_ARRAY[$((DB_INDEX - 1))]}"
|
||||||
else
|
else
|
||||||
read -r -p "Nom exact de la base à restaurer : " DB
|
read -r -p "Nom exact de la base à restaurer : " DB
|
||||||
[[ -n "$DB" ]] || fail "nom de base vide"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
validate_db_name "$DB"
|
||||||
|
|
||||||
log "Environnement : $ENV_NAME"
|
log "Environnement : $ENV_NAME"
|
||||||
log "Base cible sélectionnée : $DB"
|
log "Base cible sélectionnée : $DB"
|
||||||
|
|
||||||
@@ -312,7 +357,7 @@ LOCAL_DB_DUMP_FILE="${LOCAL_RESTORE_DIR}/$(basename "$LAST_REMOTE_DB_DUMP")"
|
|||||||
LOCAL_ROLES_FILE=""
|
LOCAL_ROLES_FILE=""
|
||||||
|
|
||||||
log "Téléchargement du dump..."
|
log "Téléchargement du dump..."
|
||||||
scp "${SSH_OPTS[@]}" "${REMOTE_SSH}:${LAST_REMOTE_DB_DUMP}" "$LOCAL_DB_DUMP_FILE" \
|
scp "${SCP_OPTS[@]}" "${REMOTE_SSH}:${LAST_REMOTE_DB_DUMP}" "$LOCAL_DB_DUMP_FILE" \
|
||||||
>>"$LOG_FILE" 2>&1 || fail "échec du téléchargement du dump principal"
|
>>"$LOG_FILE" 2>&1 || fail "échec du téléchargement du dump principal"
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
@@ -322,7 +367,7 @@ if [[ -n "$LAST_REMOTE_ROLES_FILE" ]]; then
|
|||||||
LOCAL_ROLES_FILE="${LOCAL_RESTORE_DIR}/$(basename "$LAST_REMOTE_ROLES_FILE")"
|
LOCAL_ROLES_FILE="${LOCAL_RESTORE_DIR}/$(basename "$LAST_REMOTE_ROLES_FILE")"
|
||||||
|
|
||||||
log "Téléchargement du fichier des rôles..."
|
log "Téléchargement du fichier des rôles..."
|
||||||
scp "${SSH_OPTS[@]}" "${REMOTE_SSH}:${LAST_REMOTE_ROLES_FILE}" "$LOCAL_ROLES_FILE" \
|
scp "${SCP_OPTS[@]}" "${REMOTE_SSH}:${LAST_REMOTE_ROLES_FILE}" "$LOCAL_ROLES_FILE" \
|
||||||
>>"$LOG_FILE" 2>&1 || fail "échec du téléchargement du fichier des rôles"
|
>>"$LOG_FILE" 2>&1 || fail "échec du téléchargement du fichier des rôles"
|
||||||
else
|
else
|
||||||
log "La restauration des rôles sera ignorée."
|
log "La restauration des rôles sera ignorée."
|
||||||
@@ -341,7 +386,7 @@ fi
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
DB_EXISTS="$(
|
DB_EXISTS="$(
|
||||||
psql -h "$PGHOST" -p "$PGPORT" -U "$PGUSER" -d postgres -tAc \
|
psql -h "$PGHOST" -p "$PGPORT" -U "$PGUSER" -d postgres -tAc \
|
||||||
"SELECT 1 FROM pg_database WHERE datname='${DB}'" 2>>"$LOG_FILE" || true
|
"SELECT 1 FROM pg_database WHERE datname='$(sql_escape_literal "$DB")'" 2>>"$LOG_FILE" || true
|
||||||
)"
|
)"
|
||||||
|
|
||||||
if [[ "$DB_EXISTS" == "1" ]]; then
|
if [[ "$DB_EXISTS" == "1" ]]; then
|
||||||
@@ -364,9 +409,14 @@ if [[ -n "$LOCAL_ROLES_FILE" ]]; then
|
|||||||
FILTERED_ROLES_FILE="${LOCAL_RESTORE_DIR}/filtered_$(basename "$LOCAL_ROLES_FILE")"
|
FILTERED_ROLES_FILE="${LOCAL_RESTORE_DIR}/filtered_$(basename "$LOCAL_ROLES_FILE")"
|
||||||
ROLES_CREATE_LIST="${LOCAL_RESTORE_DIR}/roles_to_create_$(basename "$LOCAL_ROLES_FILE")"
|
ROLES_CREATE_LIST="${LOCAL_RESTORE_DIR}/roles_to_create_$(basename "$LOCAL_ROLES_FILE")"
|
||||||
ROLES_APPLY_FILE="${LOCAL_RESTORE_DIR}/roles_apply_$(basename "$LOCAL_ROLES_FILE")"
|
ROLES_APPLY_FILE="${LOCAL_RESTORE_DIR}/roles_apply_$(basename "$LOCAL_ROLES_FILE")"
|
||||||
|
EXCLUDED_ROLES_REGEX="$(build_excluded_roles_regex)"
|
||||||
|
|
||||||
grep -viE '^(CREATE ROLE|ALTER ROLE) (backup_liot|postgres)\b' "$LOCAL_ROLES_FILE" \
|
if [[ -n "$EXCLUDED_ROLES_REGEX" ]]; then
|
||||||
> "$FILTERED_ROLES_FILE" || true
|
grep -viE "^(CREATE ROLE|ALTER ROLE) (${EXCLUDED_ROLES_REGEX})\\b" "$LOCAL_ROLES_FILE" \
|
||||||
|
> "$FILTERED_ROLES_FILE" || true
|
||||||
|
else
|
||||||
|
cp "$LOCAL_ROLES_FILE" "$FILTERED_ROLES_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
log "Fichier des rôles filtré généré : ${FILTERED_ROLES_FILE}"
|
log "Fichier des rôles filtré généré : ${FILTERED_ROLES_FILE}"
|
||||||
|
|
||||||
@@ -383,7 +433,7 @@ if [[ -n "$LOCAL_ROLES_FILE" ]]; then
|
|||||||
|
|
||||||
ROLE_EXISTS="$(
|
ROLE_EXISTS="$(
|
||||||
psql -h "$PGHOST" -p "$PGPORT" -U "$PGUSER" -d postgres -tAc \
|
psql -h "$PGHOST" -p "$PGPORT" -U "$PGUSER" -d postgres -tAc \
|
||||||
"SELECT 1 FROM pg_roles WHERE rolname='${role_name}'" 2>>"$LOG_FILE" || true
|
"SELECT 1 FROM pg_roles WHERE rolname='$(sql_escape_literal "$role_name")'" 2>>"$LOG_FILE" || true
|
||||||
)"
|
)"
|
||||||
|
|
||||||
if [[ "$ROLE_EXISTS" != "1" ]]; then
|
if [[ "$ROLE_EXISTS" != "1" ]]; then
|
||||||
|
|||||||
@@ -39,6 +39,9 @@ BACKUP_REMOTE_HOST=
|
|||||||
# Répertoire racine distant :
|
# Répertoire racine distant :
|
||||||
BACKUP_REMOTE_DIR=/home/.../backups/bdd-recette
|
BACKUP_REMOTE_DIR=/home/.../backups/bdd-recette
|
||||||
|
|
||||||
|
# Port SSH du serveur de backup
|
||||||
|
BACKUP_REMOTE_SSH_PORT=22
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# SSH
|
# SSH
|
||||||
###############################################################################
|
###############################################################################
|
||||||
@@ -50,6 +53,12 @@ SSH_KEY=/home/.../.ssh/id_ed25519_backup
|
|||||||
# Variable optionnelle dans le script, mais utile ici comme valeur par défaut
|
# Variable optionnelle dans le script, mais utile ici comme valeur par défaut
|
||||||
SSH_CONNECT_TIMEOUT=8
|
SSH_CONNECT_TIMEOUT=8
|
||||||
|
|
||||||
|
# Validation stricte des clés hôtes SSH (yes/no)
|
||||||
|
BACKUP_KNOWN_HOSTS_STRICT=yes
|
||||||
|
|
||||||
|
# Fichier known_hosts utilisé par ssh/scp
|
||||||
|
BACKUP_KNOWN_HOSTS_FILE=/home/.../.ssh/known_hosts
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# LOGS
|
# LOGS
|
||||||
###############################################################################
|
###############################################################################
|
||||||
@@ -72,6 +81,9 @@ LOCAL_RESTORE_DIR=/tmp/rebuild-bdd-recette
|
|||||||
# Nom du dossier distant contenant les exports SQL des rôles
|
# Nom du dossier distant contenant les exports SQL des rôles
|
||||||
REMOTE_ROLES_DIR_NAME=user
|
REMOTE_ROLES_DIR_NAME=user
|
||||||
|
|
||||||
|
# Rôles PostgreSQL à exclure lors de la restauration
|
||||||
|
EXCLUDED_RESTORE_ROLES="postgres"
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# DISCORD
|
# DISCORD
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ BACKUP_REMOTE_DIR=/home/.../backups/bdd-recette
|
|||||||
#############################################
|
#############################################
|
||||||
|
|
||||||
# Clé SSH utilisée pour se connecter au serveur distant
|
# Clé SSH utilisée pour se connecter au serveur distant
|
||||||
SSH_KEY=/home/.../.ssh/id_ed25519_backup
|
SSH_KEY=/home/<USER>/.ssh/id_ed25519_backup
|
||||||
|
|
||||||
# Timeout SSH (secondes)
|
# Timeout SSH (secondes)
|
||||||
SSH_TIMEOUT=10
|
SSH_TIMEOUT=10
|
||||||
|
|||||||
Reference in New Issue
Block a user