Compare commits

1 Commits

Author SHA1 Message Date
AkiNoKure
37fe2f5239 feat : script deploiement de script 2026-03-13 10:22:29 +01:00
18 changed files with 1242 additions and 775 deletions

View File

@@ -2,9 +2,6 @@
# VAULTWARDEN BACKUP CONFIGURATION
#############################################
# Webhook Discord pour notifications (optionnel)
DISCORD_WEBHOOK_URL=
# Répertoire contenant les données Vaultwarden
DATA_DIR=

View File

@@ -1,3 +1,4 @@
markdown
# README — Mise en place du script de sauvegarde Vaultwarden
Ce script permet dautomatiser la sauvegarde de Vaultwarden afin de conserver une copie du dossier `data`, de la transférer vers un serveur distant et denvoyer une notification Discord en cas de succès ou déchec.
@@ -66,8 +67,8 @@ Elles doivent être placées dans un fichier `.env`.
```bash
WEBHOOK_URL=https://discord.com/api/webhooks/...
REMOTE_USER=<USER>
REMOTE_HOST=<IP_SERVEUR>
REMOTE_USER=backup
REMOTE_HOST=192.168.1.50
SSH_KEY=/home/matt/.ssh/id_ed25519_vaultwarden_backup
DATA_DIR=/opt/vaultwarden/data
REMOTE_DIR=/home/backup/backups/vaultwarden
@@ -88,49 +89,70 @@ REMOTE_DIR=/home/backup/backups/vaultwarden
# 5. Chargement des variables dans le script
Le script charge directement le fichier `.env` avec `source` et exporte automatiquement les variables pendant le chargement.
Le script récupère les variables du fichier `.env`.
Mécanisme utilisé :
Exemple :
```bash
set -a
source "$ENV_FILE"
set +a
REMOTE_USER=$(grep -E '^REMOTE_USER=' .env | cut -d '=' -f2-)
```
Explication :
* `set -a` exporte automatiquement les variables définies ensuite
* `source "$ENV_FILE"` lit et exécute le contenu du fichier `.env` dans le shell courant
* `set +a` désactive ensuite l'export automatique
* `grep` recherche la variable dans `.env`
* `cut` récupère uniquement la valeur après `=`
* la variable shell reçoit la valeur correspondante
Cela permet :
* de charger toutes les variables du fichier `.env` en une seule fois
* de conserver la configuration en dehors du script
* de rester aligné avec le comportement réel du script
* d'améliorer la sécurité
* de modifier la configuration sans toucher au script
---
### 6. Connexion au serveur de sauvegarde (Machine IA)
# 6. Connexion au serveur de sauvegarde (Machine IA)
Le transfert des sauvegardes utilise une **clé SSH** afin de permettre une connexion automatique au serveur distant sans mot de passe.
Le transfert des sauvegardes vers la machine IA repose sur une **authentification par clé SSH**.
Cette méthode permet au script de se connecter automatiquement au serveur distant sans mot de passe.
#### 1. Génération de la clé
La clé utilisée pour ce script est :
Sur la machine exécutant les scripts :
```
~/.ssh/id_ed25519_bitwarden
````
---
## 6.1 Vérifier la présence de la clé SSH
Sur la machine exécutant le script, vérifier que la clé existe :
```bash
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_bitwarden
ls ~/.ssh/id_ed25519_bitwarden*
````
Les fichiers attendus sont :
```
~/.ssh/id_ed25519_bitwarden
~/.ssh/id_ed25519_bitwarden.pub
```
#### 2. Copie de la clé vers le serveur distant
* `id_ed25519_bitwarden` → clé privée utilisée par le script
* `id_ed25519_bitwarden.pub` → clé publique autorisée sur la machine IA
---
## 6.2 Copier la clé publique sur la machine IA
Envoyer la clé publique vers la machine IA :
```bash
ssh-copy-id -i ~/.ssh/id_ed25519_bitwarden.pub <USER>@<IP_SERVEUR>
ssh-copy-id -i ~/.ssh/id_ed25519_bitwarden.pub backup@192.168.0.179
```
Cette commande ajoute la clé dans :
Cette commande ajoute automatiquement la clé dans :
```
~/.ssh/authorized_keys
@@ -138,28 +160,27 @@ Cette commande ajoute la clé dans :
sur la machine IA.
#### 3. Vérification de la connexion
---
## 6.3 Ajout manuel de la clé (si ssh-copy-id n'est pas disponible)
Afficher la clé publique :
```bash
ssh -i ~/.ssh/id_ed25519_bitwarden backup@192.168.0.179
cat ~/.ssh/id_ed25519_bitwarden.pub
```
#### 4. Vérification des fichiers de clé
```bash
ls ~/.ssh/id_ed25519_bitwarden*
```
Fichiers attendus :
Copier son contenu puis lajouter sur la machine IA dans :
```
~/.ssh/id_ed25519_bitwarden
~/.ssh/id_ed25519_bitwarden.pub
~/.ssh/authorized_keys
```
#### 5. Permissions SSH
---
Machine locale :
## 6.4 Vérifier les permissions SSH
Sur la machine locale :
```bash
chmod 700 ~/.ssh
@@ -167,20 +188,40 @@ chmod 600 ~/.ssh/id_ed25519_bitwarden
chmod 644 ~/.ssh/id_ed25519_bitwarden.pub
```
Machine distante :
Sur la machine IA :
```bash
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
```
#### 6. Déclaration dans `.env`
---
## 6.5 Tester la connexion
Tester la connexion SSH avec la clé :
```bash
ssh -i ~/.ssh/id_ed25519_bitwarden backup@192.168.0.179
```
Si la configuration est correcte :
* la connexion se fait **sans mot de passe**
* la machine IA accepte la clé SSH
* le script pourra envoyer les sauvegardes automatiquement
---
## 6.6 Déclaration dans le fichier `.env`
La clé utilisée par le script doit être déclarée dans `.env` :
```bash
SSH_KEY=/home/matt/.ssh/id_ed25519_bitwarden
```
Cette clé sera utilisée automatiquement par les scripts (`scp` / `ssh`) pour transférer les sauvegardes.
Cette clé sera utilisée automatiquement par `scp` lors du transfert des sauvegardes.
# 7. Sauvegarde des données Vaultwarden

View File

@@ -33,7 +33,7 @@ set +a
#######################################
# Variables obligatoires
#######################################
: "${DISCORD_WEBHOOK_URL:=}"
: "${WEBHOOK_URL:=}"
: "${DATA_DIR:?Variable DATA_DIR manquante dans .env}"
: "${LOCAL_BACKUP:?Variable LOCAL_BACKUP manquante dans .env}"
: "${REMOTE_USER:?Variable REMOTE_USER manquante dans .env}"
@@ -47,12 +47,13 @@ set +a
DATE="$(date +'%Y-%m-%d_%H-%M-%S')"
BACKUP_PREFIX="vaultwarden-backup"
BACKUP_NAME="${BACKUP_PREFIX}-${DATE}.tar.gz"
LOCAL_BACKUP_FILE="${LOCAL_BACKUP}/${BACKUP_NAME}"
RETENTION_DAYS="${BACKUP_RETENTION_DAYS:-10}"
LOCAL_BACKUP_DIR="$LOCAL_BACKUP"
LOCAL_BACKUP_FILE="${LOCAL_BACKUP_DIR}/${BACKUP_NAME}"
RETENTION_DAYS=10
SSH_OPTS=(-i "$SSH_KEY" -o IdentitiesOnly=yes -o BatchMode=yes -o ConnectTimeout=10)
mkdir -p "$LOCAL_BACKUP"
mkdir -p "$LOCAL_BACKUP_DIR"
#######################################
# Notification Discord
@@ -61,7 +62,7 @@ discord_ping() {
local success="$1"
local details="${2:-}"
[[ -z "$DISCORD_WEBHOOK_URL" ]] && return 0
[[ -z "$WEBHOOK_URL" ]] && return 0
local icon status_line
if [[ "$success" == "true" ]]; then
@@ -80,9 +81,10 @@ discord_ping() {
msg+="Data transfer: ${status_line}\n"
[[ -n "$details" ]] && msg+="Détails: ${details}"
local payload
payload="$(jq -n --arg content "$msg" '{content: $content}')"
curl -fsS -H "Content-Type: application/json" -d "$payload" "$DISCORD_WEBHOOK_URL" >/dev/null || true
python3 - <<PY | curl -fsS -H "Content-Type: application/json" -d @- "$WEBHOOK_URL" >/dev/null || true
import json
print(json.dumps({"content": """$msg"""}))
PY
}
#######################################

View File

@@ -2,7 +2,7 @@
Liste des évolutions du projet Scripts Serveur
## [1.0.0]
## [0.0.1]
### Parameters
Ajouter dans le fichier /RecetteScripts/.env
SSH_TIMEOUT
@@ -35,9 +35,7 @@ SSH_KEY
* [#378] Script Backup BDD Vaultwarden
* [#381] Variabiliser tous les scripts
* [#384] Fix Correctif
* [#390] Rotation des script
* [#392] Scripts de reconstruction des bases de données
* [#427] Correctifs
* [#391] Script Déploiement de Scripts
### Changed
### Fixed

View File

@@ -3,4 +3,4 @@
#############################################
# Webhook Discord pour notifications
DISCORD_WEBHOOK_URL=
WEBHOOK_URL=

View File

@@ -18,23 +18,7 @@ La limite d'alerte est fixée à 70% d'utilisation, mais vous pouvez ajuster cet
3. ```bash
cd Scripts-Serveur/CheckStorage
```
### Génération de la clé SSH
Sur la machine exécutant les scripts :
```bash
ssh-keygen -t ed25519 -f ~/.ssh/check_storage_key
```
Copier la clé sur le serveur distant :
```bash
ssh-copy-id -i ~/.ssh/check_storage_key.pub user@serveur
```
Tester la connexion sans mot de passe :
```bash
ssh -i ~/.ssh/check_storage_key <USER>@<HOST>
```
## Utilisation du script
0. Copiez le fichier d'environnement exemple et modifiez les variables selon votre configuration :
```bash
@@ -62,4 +46,4 @@ ssh -i ~/.ssh/check_storage_key <USER>@<HOST>
```
## Avertissement
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.
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.

View File

@@ -56,7 +56,7 @@ if [ "$usage" -ge "$limit" ]; then
-H "Accept: application/json" \
-H "Content-Type: application/json; charset=utf-8" \
-d "$payload" \
"$DISCORD_WEBHOOK_URL"
"$WEBHOOK_URL"
fi
@@ -66,4 +66,4 @@ fi
echo "Espace disponible : ${avail_gb} GB"
echo "Espace utilise / espace total : ${used_gb} GB / ${total_gb} GB"
echo "Name: ${HOSTNAME}"
echo "Name: ${HOSTNAME}"

964
Deployment/Deployment.sh Normal file
View File

@@ -0,0 +1,964 @@
#!/usr/bin/env bash
set -Eeuo pipefail
###############################################################################
# bootstrap-backup-env.sh
#
# Prépare un environnement de déploiement pour :
# - backup-vaultwarden.sh
# - check-storage.sh
# - check-statut-recette.sh
# - backup-bdd-recette.sh
# - rebuild-bdd-recette.sh
#
# Fonctionnalités :
# - idempotent : relançable sans erreur ;
# - installation / mise à jour des dépendances ;
# - création des dossiers ;
# - permissions ;
# - génération des clés SSH si absentes ;
# - récupération depuis un dépôt Git privé volumineux via sparse-checkout ;
# - mise à jour du .env ;
# - injection des valeurs sensibles dans le .env si fournies ;
# - ajout automatique de la clé publique backup sur le serveur distant
# si un accès SSH bootstrap est disponible ;
# - questions interactives si lancé en local et que des variables obligatoires
# sont absentes ;
# - génération d'un fichier scripts.json pour un futur affichage web ;
# - exécutable en local ou envoyé via SSH sur un serveur distant.
###############################################################################
#######################################
# Valeurs par défaut
#######################################
REPO_URL=""
REPO_BRANCH="main"
REPO_SUBDIR=""
INSTALL_DIR="/opt/malio-backup"
DEPLOY_USER="${SUDO_USER:-${USER}}"
DEPLOY_GROUP=""
ENV_FILE_NAME=".env"
GIT_DIR_NAME="repo"
SCRIPTS_DIR_NAME="scripts"
CONFIG_DIR_NAME="config"
LOG_DIR_NAME="logs"
DATA_DIR_NAME="data"
TMP_DIR_NAME="tmp"
SSH_DIR_NAME="ssh"
BACKUP_SSH_KEY_NAME="id_ed25519_backup"
REPO_SSH_KEY_NAME="id_ed25519_repo"
FORCE_CHOWN="false"
NON_INTERACTIVE="false"
# Paramètres fonctionnels
ENV_NAME="RECETTE"
PGHOST="localhost"
PGPORT="5432"
PGUSER_VALUE=""
PGPASSWORD_VALUE=""
DBS_VALUE="sirh inventory ferme"
BACKUP_REMOTE_USER="backup"
BACKUP_REMOTE_HOST=""
BACKUP_REMOTE_DIR="/home/backup/backups/bdd-recette"
SSH_CONNECT_TIMEOUT="10"
RETENTION_DAYS="10"
DISCORD_WEBHOOK_URL_VALUE=""
DISCORD_PING_VALUE=""
WEBHOOK_URL_VALUE=""
VAULTWARDEN_DATA_DIR_VALUE="/var/lib/vaultwarden"
CHECK_STORAGE_PATHS_VALUE="/ /var /home"
APP_1_NAME_VALUE="ferme"
APP_1_URL_VALUE="https://ferme.malio-dev.fr"
APP_2_NAME_VALUE="sirh"
APP_2_URL_VALUE="https://sirh.malio-dev.fr"
APP_3_NAME_VALUE="inventory"
APP_3_URL_VALUE="https://inventory.malio-dev.fr"
# Bootstrap SSH vers le serveur de destination
BOOTSTRAP_SSH_USER=""
BOOTSTRAP_SSH_PORT="22"
BOOTSTRAP_SSH_KEY=""
BOOTSTRAP_SSH_STRICT="accept-new"
INSTALL_BACKUP_KEY_ON_REMOTE="true"
#######################################
# Scripts attendus
#######################################
EXPECTED_SCRIPTS=(
"backup-vaultwarden.sh"
"check-storage.sh"
"check-statut-recette.sh"
"backup-bdd-recette.sh"
"rebuild-bdd-recette.sh"
)
#######################################
# Journalisation
#######################################
timestamp() {
date '+%Y-%m-%d %H:%M:%S'
}
log() {
echo "[$(timestamp)] [INFO] $*"
}
warn() {
echo "[$(timestamp)] [WARN] $*" >&2
}
err() {
echo "[$(timestamp)] [ERROR] $*" >&2
}
die() {
err "$*"
exit 1
}
#######################################
# Gestion erreurs
#######################################
on_error() {
local exit_code=$?
err "Échec ligne ${BASH_LINENO[0]} : ${BASH_COMMAND}"
exit "$exit_code"
}
trap on_error ERR
#######################################
# Aide
#######################################
usage() {
cat <<'EOF'
Usage:
bootstrap-backup-env.sh [options]
Options dépôt :
--repo-url URL
--repo-branch BRANCH
--repo-subdir PATH
Options installation :
--install-dir PATH
--deploy-user USER
--deploy-group GROUP
--env-file-name NAME
--force-chown true|false
--non-interactive true|false
Options configuration applicative :
--env-name NAME
--pghost HOST
--pgport PORT
--pguser USER
--pgpassword PASSWORD
--dbs "sirh inventory ferme"
--backup-remote-user USER
--backup-remote-host HOST
--backup-remote-dir PATH
--ssh-connect-timeout SECONDS
--retention-days DAYS
--discord-webhook-url URL
--discord-ping VALUE
--webhook-url URL
--vaultwarden-data-dir PATH
--check-storage-paths "/ /var /home"
--app-1-name NAME
--app-1-url URL
--app-2-name NAME
--app-2-url URL
--app-3-name NAME
--app-3-url URL
Options bootstrap SSH distant :
--bootstrap-ssh-user USER
--bootstrap-ssh-port PORT
--bootstrap-ssh-key PATH
--bootstrap-ssh-strict accept-new|yes|no
--install-backup-key-on-remote true|false
Divers :
--help
Notes :
- si le script est lancé localement en mode interactif, il posera les
questions nécessaires pour compléter les champs obligatoires ;
- la clé publique backup peut être installée automatiquement sur le serveur
distant uniquement si un accès SSH bootstrap existe déjà ;
- le .env peut être rempli automatiquement si les valeurs sont passées en
arguments ou via variables d'environnement avant exécution.
EOF
}
#######################################
# Parsing arguments
#######################################
while [[ $# -gt 0 ]]; do
case "$1" in
--repo-url) REPO_URL="${2:-}"; shift 2 ;;
--repo-branch) REPO_BRANCH="${2:-}"; shift 2 ;;
--repo-subdir) REPO_SUBDIR="${2:-}"; shift 2 ;;
--install-dir) INSTALL_DIR="${2:-}"; shift 2 ;;
--deploy-user) DEPLOY_USER="${2:-}"; shift 2 ;;
--deploy-group) DEPLOY_GROUP="${2:-}"; shift 2 ;;
--env-file-name) ENV_FILE_NAME="${2:-}"; shift 2 ;;
--force-chown) FORCE_CHOWN="${2:-}"; shift 2 ;;
--non-interactive) NON_INTERACTIVE="${2:-}"; shift 2 ;;
--env-name) ENV_NAME="${2:-}"; shift 2 ;;
--pghost) PGHOST="${2:-}"; shift 2 ;;
--pgport) PGPORT="${2:-}"; shift 2 ;;
--pguser) PGUSER_VALUE="${2:-}"; shift 2 ;;
--pgpassword) PGPASSWORD_VALUE="${2:-}"; shift 2 ;;
--dbs) DBS_VALUE="${2:-}"; shift 2 ;;
--backup-remote-user) BACKUP_REMOTE_USER="${2:-}"; shift 2 ;;
--backup-remote-host) BACKUP_REMOTE_HOST="${2:-}"; shift 2 ;;
--backup-remote-dir) BACKUP_REMOTE_DIR="${2:-}"; shift 2 ;;
--ssh-connect-timeout) SSH_CONNECT_TIMEOUT="${2:-}"; shift 2 ;;
--retention-days) RETENTION_DAYS="${2:-}"; shift 2 ;;
--discord-webhook-url) DISCORD_WEBHOOK_URL_VALUE="${2:-}"; shift 2 ;;
--discord-ping) DISCORD_PING_VALUE="${2:-}"; shift 2 ;;
--webhook-url) WEBHOOK_URL_VALUE="${2:-}"; shift 2 ;;
--vaultwarden-data-dir) VAULTWARDEN_DATA_DIR_VALUE="${2:-}"; shift 2 ;;
--check-storage-paths) CHECK_STORAGE_PATHS_VALUE="${2:-}"; shift 2 ;;
--app-1-name) APP_1_NAME_VALUE="${2:-}"; shift 2 ;;
--app-1-url) APP_1_URL_VALUE="${2:-}"; shift 2 ;;
--app-2-name) APP_2_NAME_VALUE="${2:-}"; shift 2 ;;
--app-2-url) APP_2_URL_VALUE="${2:-}"; shift 2 ;;
--app-3-name) APP_3_NAME_VALUE="${2:-}"; shift 2 ;;
--app-3-url) APP_3_URL_VALUE="${2:-}"; shift 2 ;;
--bootstrap-ssh-user) BOOTSTRAP_SSH_USER="${2:-}"; shift 2 ;;
--bootstrap-ssh-port) BOOTSTRAP_SSH_PORT="${2:-}"; shift 2 ;;
--bootstrap-ssh-key) BOOTSTRAP_SSH_KEY="${2:-}"; shift 2 ;;
--bootstrap-ssh-strict) BOOTSTRAP_SSH_STRICT="${2:-}"; shift 2 ;;
--install-backup-key-on-remote) INSTALL_BACKUP_KEY_ON_REMOTE="${2:-}"; shift 2 ;;
--help|-h) usage; exit 0 ;;
*) die "Option inconnue : $1" ;;
esac
done
#######################################
# Surcharge par variables d'environnement
#######################################
PGPASSWORD_VALUE="${PGPASSWORD_VALUE:-${PGPASSWORD:-}}"
DISCORD_WEBHOOK_URL_VALUE="${DISCORD_WEBHOOK_URL_VALUE:-${DISCORD_WEBHOOK_URL:-}}"
DISCORD_PING_VALUE="${DISCORD_PING_VALUE:-${DISCORD_PING:-}}"
WEBHOOK_URL_VALUE="${WEBHOOK_URL_VALUE:-${WEBHOOK_URL:-}}"
#######################################
# Détection mode interactif local
#######################################
is_interactive() {
[[ -t 0 && -t 1 && "${NON_INTERACTIVE}" != "true" ]]
}
#######################################
# Questions interactives
#######################################
prompt_value() {
local var_name="$1"
local prompt_label="$2"
local default_value="${3:-}"
local secret="${4:-false}"
local required="${5:-false}"
local current_value
current_value="${!var_name:-}"
if [[ -n "$current_value" ]]; then
return 0
fi
if ! is_interactive; then
if [[ "$required" == "true" ]]; then
die "Valeur obligatoire manquante : ${var_name}. Fournissez-la en argument ou variable d'environnement."
fi
return 0
fi
local input=""
while true; do
if [[ "$secret" == "true" ]]; then
if [[ -n "$default_value" ]]; then
read -r -s -p "${prompt_label} [valeur masquée, Entrée pour conserver la valeur par défaut] : " input
else
read -r -s -p "${prompt_label} : " input
fi
echo
else
if [[ -n "$default_value" ]]; then
read -r -p "${prompt_label} [${default_value}] : " input
else
read -r -p "${prompt_label} : " input
fi
fi
if [[ -z "$input" && -n "$default_value" ]]; then
input="$default_value"
fi
if [[ "$required" == "true" && -z "$input" ]]; then
warn "Cette valeur est obligatoire."
continue
fi
printf -v "$var_name" '%s' "$input"
break
done
}
ask_required_local_configuration() {
if ! is_interactive; then
return 0
fi
log "Mode interactif local détecté : collecte des données obligatoires."
prompt_value REPO_URL "URL SSH du dépôt Git privé" "$REPO_URL" false true
prompt_value REPO_BRANCH "Branche Git" "$REPO_BRANCH" false true
prompt_value REPO_SUBDIR "Sous-dossier du dépôt contenant les scripts" "$REPO_SUBDIR" false true
prompt_value INSTALL_DIR "Répertoire d'installation" "$INSTALL_DIR" false true
prompt_value DEPLOY_USER "Utilisateur propriétaire du déploiement" "$DEPLOY_USER" false true
if [[ -z "$DEPLOY_GROUP" ]]; then
local deploy_group_default=""
if id "$DEPLOY_USER" >/dev/null 2>&1; then
deploy_group_default="$(id -gn "$DEPLOY_USER")"
fi
prompt_value DEPLOY_GROUP "Groupe propriétaire" "$deploy_group_default" false true
fi
prompt_value ENV_NAME "Nom de l'environnement" "$ENV_NAME" false true
prompt_value PGHOST "Host PostgreSQL" "$PGHOST" false true
prompt_value PGPORT "Port PostgreSQL" "$PGPORT" false true
if [[ -z "$PGUSER_VALUE" ]]; then
prompt_value PGUSER_VALUE "Utilisateur PostgreSQL" "$DEPLOY_USER" false true
fi
prompt_value PGPASSWORD_VALUE "Mot de passe PostgreSQL (PGPASSWORD)" "" true true
prompt_value DBS_VALUE "Bases PostgreSQL à gérer (séparées par des espaces)" "$DBS_VALUE" false true
prompt_value BACKUP_REMOTE_USER "Utilisateur du serveur de sauvegarde" "$BACKUP_REMOTE_USER" false true
prompt_value BACKUP_REMOTE_HOST "Host/IP du serveur de sauvegarde" "$BACKUP_REMOTE_HOST" false true
prompt_value BACKUP_REMOTE_DIR "Répertoire distant de sauvegarde" "$BACKUP_REMOTE_DIR" false true
prompt_value SSH_CONNECT_TIMEOUT "Timeout SSH en secondes" "$SSH_CONNECT_TIMEOUT" false true
prompt_value RETENTION_DAYS "Rétention en jours" "$RETENTION_DAYS" false true
prompt_value VAULTWARDEN_DATA_DIR_VALUE "Répertoire des données Vaultwarden" "$VAULTWARDEN_DATA_DIR_VALUE" false true
prompt_value CHECK_STORAGE_PATHS_VALUE "Chemins à surveiller pour le stockage" "$CHECK_STORAGE_PATHS_VALUE" false true
prompt_value APP_1_NAME_VALUE "Nom application 1" "$APP_1_NAME_VALUE" false true
prompt_value APP_1_URL_VALUE "URL application 1" "$APP_1_URL_VALUE" false true
prompt_value APP_2_NAME_VALUE "Nom application 2" "$APP_2_NAME_VALUE" false true
prompt_value APP_2_URL_VALUE "URL application 2" "$APP_2_URL_VALUE" false true
prompt_value APP_3_NAME_VALUE "Nom application 3" "$APP_3_NAME_VALUE" false true
prompt_value APP_3_URL_VALUE "URL application 3" "$APP_3_URL_VALUE" false true
prompt_value DISCORD_WEBHOOK_URL_VALUE "Discord webhook URL (optionnel)" "$DISCORD_WEBHOOK_URL_VALUE" true false
prompt_value DISCORD_PING_VALUE "Discord ping (optionnel)" "$DISCORD_PING_VALUE" false false
prompt_value WEBHOOK_URL_VALUE "Webhook URL générique (optionnel)" "$WEBHOOK_URL_VALUE" true false
if [[ "$INSTALL_BACKUP_KEY_ON_REMOTE" == "true" ]]; then
prompt_value BOOTSTRAP_SSH_USER "Utilisateur SSH bootstrap pour installer la clé distante" "${BOOTSTRAP_SSH_USER:-$BACKUP_REMOTE_USER}" false true
prompt_value BOOTSTRAP_SSH_PORT "Port SSH bootstrap" "$BOOTSTRAP_SSH_PORT" false true
prompt_value BOOTSTRAP_SSH_KEY "Chemin de la clé SSH bootstrap (optionnel si agent SSH ou accès existant)" "$BOOTSTRAP_SSH_KEY" false false
fi
}
#######################################
# Vérifications initiales
#######################################
validate_required_values() {
[[ -n "$REPO_URL" ]] || die "L'option --repo-url est obligatoire."
[[ -n "$REPO_SUBDIR" ]] || die "L'option --repo-subdir est obligatoire."
[[ -n "$BACKUP_REMOTE_HOST" ]] || die "L'option --backup-remote-host est obligatoire."
[[ -n "$DEPLOY_USER" ]] || die "L'utilisateur de déploiement est obligatoire."
if ! id "$DEPLOY_USER" >/dev/null 2>&1; then
die "Utilisateur inexistant : $DEPLOY_USER"
fi
if [[ -z "$DEPLOY_GROUP" ]]; then
DEPLOY_GROUP="$(id -gn "$DEPLOY_USER")"
fi
if [[ -z "$PGUSER_VALUE" ]]; then
PGUSER_VALUE="$DEPLOY_USER"
fi
}
#######################################
# Chemins calculés
#######################################
compute_paths() {
BASE_DIR="$INSTALL_DIR"
REPO_DIR="$BASE_DIR/$GIT_DIR_NAME"
APP_SCRIPTS_DIR="$BASE_DIR/$SCRIPTS_DIR_NAME"
CONFIG_DIR="$BASE_DIR/$CONFIG_DIR_NAME"
LOG_DIR="$BASE_DIR/$LOG_DIR_NAME"
DATA_DIR="$BASE_DIR/$DATA_DIR_NAME"
TMP_DIR="$BASE_DIR/$TMP_DIR_NAME"
APP_SSH_DIR="$BASE_DIR/$SSH_DIR_NAME"
ENV_FILE="$BASE_DIR/$ENV_FILE_NAME"
SCRIPTS_JSON="$CONFIG_DIR/scripts.json"
BACKUP_SSH_KEY="$APP_SSH_DIR/$BACKUP_SSH_KEY_NAME"
REPO_SSH_KEY="$APP_SSH_DIR/$REPO_SSH_KEY_NAME"
}
#######################################
# Wrapper sudo
#######################################
run_root() {
if [[ "$(id -u)" -eq 0 ]]; then
"$@"
else
sudo "$@"
fi
}
run_as_deploy_user() {
if [[ "$(id -un)" == "$DEPLOY_USER" ]]; then
"$@"
else
run_root sudo -u "$DEPLOY_USER" -H "$@"
fi
}
#######################################
# Détection package manager
#######################################
detect_pkg_manager() {
if command -v apt-get >/dev/null 2>&1; then
echo "apt"
elif command -v dnf >/dev/null 2>&1; then
echo "dnf"
elif command -v yum >/dev/null 2>&1; then
echo "yum"
elif command -v apk >/dev/null 2>&1; then
echo "apk"
elif command -v pacman >/dev/null 2>&1; then
echo "pacman"
else
echo ""
fi
}
install_packages() {
local packages=("$@")
[[ ${#packages[@]} -gt 0 ]] || return 0
case "$PKG_MANAGER" in
apt)
run_root apt-get update -y
run_root apt-get install -y "${packages[@]}"
;;
dnf)
run_root dnf install -y "${packages[@]}"
;;
yum)
run_root yum install -y "${packages[@]}"
;;
apk)
run_root apk add --no-cache "${packages[@]}"
;;
pacman)
run_root pacman -Sy --noconfirm "${packages[@]}"
;;
*)
die "Package manager non géré : $PKG_MANAGER"
;;
esac
}
ensure_cmd() {
local cmd="$1"
shift
local packages=("$@")
if command -v "$cmd" >/dev/null 2>&1; then
log "Dépendance OK : $cmd"
else
warn "Dépendance absente : $cmd"
install_packages "${packages[@]}"
fi
}
install_dependencies() {
case "$PKG_MANAGER" in
apt)
ensure_cmd git git
ensure_cmd ssh openssh-client
ensure_cmd ssh-keygen openssh-client
ensure_cmd rsync rsync
ensure_cmd curl curl
ensure_cmd jq jq
ensure_cmd psql postgresql-client
install_packages ca-certificates
;;
dnf|yum)
ensure_cmd git git
ensure_cmd ssh openssh-clients
ensure_cmd ssh-keygen openssh-clients
ensure_cmd rsync rsync
ensure_cmd curl curl
ensure_cmd jq jq
ensure_cmd psql postgresql
install_packages ca-certificates
;;
apk)
ensure_cmd git git
ensure_cmd ssh openssh-client
ensure_cmd ssh-keygen openssh-keygen
ensure_cmd rsync rsync
ensure_cmd curl curl
ensure_cmd jq jq
ensure_cmd psql postgresql-client
install_packages ca-certificates
;;
pacman)
ensure_cmd git git
ensure_cmd ssh openssh
ensure_cmd ssh-keygen openssh
ensure_cmd rsync rsync
ensure_cmd curl curl
ensure_cmd jq jq
ensure_cmd psql postgresql-libs
install_packages ca-certificates
;;
esac
}
#######################################
# Création dossiers
#######################################
ensure_dir() {
local dir="$1"
local mode="$2"
run_root mkdir -p "$dir"
run_root chmod "$mode" "$dir"
}
prepare_directories() {
ensure_dir "$BASE_DIR" 0755
ensure_dir "$REPO_DIR" 0755
ensure_dir "$APP_SCRIPTS_DIR" 0750
ensure_dir "$CONFIG_DIR" 0750
ensure_dir "$LOG_DIR" 0750
ensure_dir "$DATA_DIR" 0750
ensure_dir "$TMP_DIR" 0750
ensure_dir "$APP_SSH_DIR" 0700
}
#######################################
# Permissions
#######################################
apply_ownership() {
if [[ "$FORCE_CHOWN" == "true" ]]; then
run_root chown -R "${DEPLOY_USER}:${DEPLOY_GROUP}" "$BASE_DIR"
else
run_root chown "${DEPLOY_USER}:${DEPLOY_GROUP}" \
"$BASE_DIR" "$REPO_DIR" "$APP_SCRIPTS_DIR" "$CONFIG_DIR" \
"$LOG_DIR" "$DATA_DIR" "$TMP_DIR" "$APP_SSH_DIR"
fi
}
#######################################
# SSH
#######################################
ensure_ssh_keypair() {
local private_key="$1"
local comment="$2"
if [[ -f "$private_key" && -f "${private_key}.pub" ]]; then
log "Clé SSH déjà présente : $private_key"
run_root chmod 600 "$private_key"
run_root chmod 644 "${private_key}.pub"
run_root chown "${DEPLOY_USER}:${DEPLOY_GROUP}" "$private_key" "${private_key}.pub"
return 0
fi
log "Génération de la clé SSH : $private_key"
run_root ssh-keygen -t ed25519 -N "" -C "$comment" -f "$private_key" >/dev/null
run_root chmod 600 "$private_key"
run_root chmod 644 "${private_key}.pub"
run_root chown "${DEPLOY_USER}:${DEPLOY_GROUP}" "$private_key" "${private_key}.pub"
}
build_bootstrap_ssh_cmd() {
local target="$1"
local -a cmd=(ssh -p "$BOOTSTRAP_SSH_PORT" -o "StrictHostKeyChecking=$BOOTSTRAP_SSH_STRICT")
if [[ -n "$BOOTSTRAP_SSH_KEY" ]]; then
cmd+=(-i "$BOOTSTRAP_SSH_KEY" -o IdentitiesOnly=yes)
fi
cmd+=("$target")
printf '%q ' "${cmd[@]}"
}
install_backup_key_on_remote() {
[[ "$INSTALL_BACKUP_KEY_ON_REMOTE" == "true" ]] || {
log "Installation de la clé backup sur le serveur distant désactivée."
return 0
}
[[ -n "$BACKUP_REMOTE_HOST" ]] || {
warn "BACKUP_REMOTE_HOST vide, installation de la clé distante ignorée."
return 0
}
local bootstrap_user="${BOOTSTRAP_SSH_USER:-$BACKUP_REMOTE_USER}"
local remote_target="${bootstrap_user}@${BACKUP_REMOTE_HOST}"
local remote_auth_user="$BACKUP_REMOTE_USER"
local pubkey
pubkey="$(run_root cat "${BACKUP_SSH_KEY}.pub")"
log "Tentative d'installation de la clé publique backup sur ${remote_auth_user}@${BACKUP_REMOTE_HOST}"
local ssh_cmd
ssh_cmd="$(build_bootstrap_ssh_cmd "$remote_target")"
if ! eval "$ssh_cmd" "true" >/dev/null 2>&1; then
warn "Accès SSH bootstrap indisponible vers ${remote_target}. Clé backup non installée automatiquement."
return 0
fi
local escaped_pubkey
escaped_pubkey="$(printf '%q' "$pubkey")"
eval "$ssh_cmd" "sudo -u '$remote_auth_user' sh -c '
set -eu
umask 077
mkdir -p ~/.ssh
touch ~/.ssh/authorized_keys
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
grep -qxF $escaped_pubkey ~/.ssh/authorized_keys || printf \"%s\n\" $escaped_pubkey >> ~/.ssh/authorized_keys
'" >/dev/null
log "Clé publique backup installée / vérifiée sur ${remote_auth_user}@${BACKUP_REMOTE_HOST}"
}
#######################################
# .env
#######################################
ensure_env_file() {
if [[ ! -f "$ENV_FILE" ]]; then
log "Création du fichier : $ENV_FILE"
run_root touch "$ENV_FILE"
fi
run_root chmod 0640 "$ENV_FILE"
run_root chown "${DEPLOY_USER}:${DEPLOY_GROUP}" "$ENV_FILE"
}
set_env_value() {
local key="$1"
local value="$2"
local escaped
escaped="$(printf '%s' "$value" | sed 's/[\/&]/\\&/g')"
if run_root grep -qE "^${key}=" "$ENV_FILE"; then
run_root sed -i "s/^${key}=.*/${key}=${escaped}/" "$ENV_FILE"
else
printf '%s=%s\n' "$key" "$value" | run_root tee -a "$ENV_FILE" >/dev/null
fi
}
update_env_defaults() {
set_env_value "ENV_NAME" "$ENV_NAME"
set_env_value "BASE_DIR" "$BASE_DIR"
set_env_value "SCRIPTS_DIR" "$APP_SCRIPTS_DIR"
set_env_value "CONFIG_DIR" "$CONFIG_DIR"
set_env_value "LOG_DIR" "$LOG_DIR"
set_env_value "DATA_DIR" "$DATA_DIR"
set_env_value "TMP_DIR" "$TMP_DIR"
set_env_value "SSH_DIR" "$APP_SSH_DIR"
set_env_value "SSH_KEY" "$BACKUP_SSH_KEY"
set_env_value "REPO_SSH_KEY" "$REPO_SSH_KEY"
set_env_value "PGHOST" "$PGHOST"
set_env_value "PGPORT" "$PGPORT"
set_env_value "PGUSER" "$PGUSER_VALUE"
set_env_value "PGPASSWORD" "${PGPASSWORD_VALUE:-change_me}"
set_env_value "DBS" "\"$DBS_VALUE\""
set_env_value "BACKUP_REMOTE_USER" "$BACKUP_REMOTE_USER"
set_env_value "BACKUP_REMOTE_HOST" "$BACKUP_REMOTE_HOST"
set_env_value "BACKUP_REMOTE_DIR" "$BACKUP_REMOTE_DIR"
set_env_value "SSH_CONNECT_TIMEOUT" "$SSH_CONNECT_TIMEOUT"
set_env_value "RETENTION_DAYS" "$RETENTION_DAYS"
set_env_value "DISCORD_WEBHOOK_URL" "$DISCORD_WEBHOOK_URL_VALUE"
set_env_value "DISCORD_PING" "$DISCORD_PING_VALUE"
set_env_value "WEBHOOK_URL" "$WEBHOOK_URL_VALUE"
set_env_value "VAULTWARDEN_DATA_DIR" "$VAULTWARDEN_DATA_DIR_VALUE"
set_env_value "CHECK_STORAGE_PATHS" "\"$CHECK_STORAGE_PATHS_VALUE\""
set_env_value "APP_1_NAME" "$APP_1_NAME_VALUE"
set_env_value "APP_1_URL" "$APP_1_URL_VALUE"
set_env_value "APP_2_NAME" "$APP_2_NAME_VALUE"
set_env_value "APP_2_URL" "$APP_2_URL_VALUE"
set_env_value "APP_3_NAME" "$APP_3_NAME_VALUE"
set_env_value "APP_3_URL" "$APP_3_URL_VALUE"
}
#######################################
# Git privé + sparse checkout
#######################################
write_git_ssh_wrapper() {
local wrapper="$TMP_DIR/git_ssh_wrapper.sh"
cat > /tmp/.git_ssh_wrapper.$$ <<EOF
#!/usr/bin/env bash
exec ssh -i "$REPO_SSH_KEY" -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new "\$@"
EOF
run_root mv /tmp/.git_ssh_wrapper.$$ "$wrapper"
run_root chmod 0700 "$wrapper"
run_root chown "${DEPLOY_USER}:${DEPLOY_GROUP}" "$wrapper"
echo "$wrapper"
}
sync_repo() {
local wrapper
wrapper="$(write_git_ssh_wrapper)"
if [[ ! -d "$REPO_DIR/.git" ]]; then
log "Clone initial du dépôt"
run_root rm -rf "$REPO_DIR"
run_root mkdir -p "$REPO_DIR"
run_root chown "${DEPLOY_USER}:${DEPLOY_GROUP}" "$REPO_DIR"
run_as_deploy_user env GIT_SSH_COMMAND="$wrapper" \
git clone \
--filter=blob:none \
--no-checkout \
--branch "$REPO_BRANCH" \
"$REPO_URL" \
"$REPO_DIR"
run_as_deploy_user git -C "$REPO_DIR" sparse-checkout init --cone
run_as_deploy_user git -C "$REPO_DIR" sparse-checkout set "$REPO_SUBDIR"
run_as_deploy_user git -C "$REPO_DIR" checkout "$REPO_BRANCH"
else
log "Mise à jour du dépôt existant"
run_as_deploy_user git -C "$REPO_DIR" remote set-url origin "$REPO_URL"
run_as_deploy_user git -C "$REPO_DIR" sparse-checkout init --cone || true
run_as_deploy_user git -C "$REPO_DIR" sparse-checkout set "$REPO_SUBDIR"
run_as_deploy_user env GIT_SSH_COMMAND="$wrapper" \
git -C "$REPO_DIR" fetch origin "$REPO_BRANCH" --depth=1
run_as_deploy_user git -C "$REPO_DIR" checkout "$REPO_BRANCH"
run_as_deploy_user git -C "$REPO_DIR" reset --hard "origin/$REPO_BRANCH"
run_as_deploy_user git -C "$REPO_DIR" clean -fd
fi
}
#######################################
# Déploiement scripts
#######################################
deploy_scripts() {
local source_dir="$REPO_DIR/$REPO_SUBDIR"
[[ -d "$source_dir" ]] || die "Sous-dossier introuvable : $source_dir"
local script
for script in "${EXPECTED_SCRIPTS[@]}"; do
[[ -f "$source_dir/$script" ]] || die "Script manquant dans le dépôt : $source_dir/$script"
done
for script in "${EXPECTED_SCRIPTS[@]}"; do
log "Déploiement : $script"
run_root install -m 0750 -o "$DEPLOY_USER" -g "$DEPLOY_GROUP" \
"$source_dir/$script" "$APP_SCRIPTS_DIR/$script"
done
}
verify_scripts() {
local script
for script in "${EXPECTED_SCRIPTS[@]}"; do
[[ -f "$APP_SCRIPTS_DIR/$script" ]] || die "Script absent après déploiement : $APP_SCRIPTS_DIR/$script"
[[ -x "$APP_SCRIPTS_DIR/$script" ]] || die "Script non exécutable : $APP_SCRIPTS_DIR/$script"
done
}
#######################################
# Configuration web
#######################################
generate_scripts_json() {
local tmp_json
tmp_json="$(mktemp)"
cat > "$tmp_json" <<EOF
{
"generated_at": "$(date -Iseconds)",
"base_dir": "$BASE_DIR",
"env_file": "$ENV_FILE",
"scripts": [
{
"id": "backup-vaultwarden",
"label": "Backup Vaultwarden",
"path": "$APP_SCRIPTS_DIR/backup-vaultwarden.sh",
"web_enabled": true,
"params": [
{ "name": "env_file", "type": "string", "required": false, "default": "$ENV_FILE" },
{ "name": "dry_run", "type": "boolean", "required": false, "default": false },
{ "name": "json", "type": "boolean", "required": false, "default": true }
]
},
{
"id": "check-storage",
"label": "Vérification stockage",
"path": "$APP_SCRIPTS_DIR/check-storage.sh",
"web_enabled": true,
"params": [
{ "name": "env_file", "type": "string", "required": false, "default": "$ENV_FILE" },
{ "name": "verbose", "type": "boolean", "required": false, "default": false },
{ "name": "json", "type": "boolean", "required": false, "default": true }
]
},
{
"id": "check-statut-recette",
"label": "Vérification statut recette",
"path": "$APP_SCRIPTS_DIR/check-statut-recette.sh",
"web_enabled": true,
"params": [
{ "name": "env_file", "type": "string", "required": false, "default": "$ENV_FILE" },
{ "name": "timeout", "type": "integer", "required": false, "default": 10 },
{ "name": "json", "type": "boolean", "required": false, "default": true }
]
},
{
"id": "backup-bdd-recette",
"label": "Backup BDD recette",
"path": "$APP_SCRIPTS_DIR/backup-bdd-recette.sh",
"web_enabled": true,
"params": [
{ "name": "env_file", "type": "string", "required": false, "default": "$ENV_FILE" },
{ "name": "db", "type": "select", "required": false, "values": ["sirh", "inventory", "ferme"] },
{ "name": "dry_run", "type": "boolean", "required": false, "default": false },
{ "name": "json", "type": "boolean", "required": false, "default": true }
]
},
{
"id": "rebuild-bdd-recette",
"label": "Rebuild BDD recette",
"path": "$APP_SCRIPTS_DIR/rebuild-bdd-recette.sh",
"web_enabled": true,
"params": [
{ "name": "env_file", "type": "string", "required": false, "default": "$ENV_FILE" },
{ "name": "db", "type": "select", "required": true, "values": ["sirh", "inventory", "ferme"] },
{ "name": "source", "type": "string", "required": false, "default": "latest" },
{ "name": "force", "type": "boolean", "required": false, "default": false },
{ "name": "json", "type": "boolean", "required": false, "default": true }
]
}
]
}
EOF
run_root mv "$tmp_json" "$SCRIPTS_JSON"
run_root chmod 0640 "$SCRIPTS_JSON"
run_root chown "${DEPLOY_USER}:${DEPLOY_GROUP}" "$SCRIPTS_JSON"
}
#######################################
# Résumé
#######################################
print_summary() {
cat <<EOF
========================================================================
Bootstrap terminé
========================================================================
Utilisateur : $DEPLOY_USER:$DEPLOY_GROUP
Base : $BASE_DIR
Scripts : $APP_SCRIPTS_DIR
Config : $CONFIG_DIR
.env : $ENV_FILE
scripts.json : $SCRIPTS_JSON
Repo : $REPO_DIR
Clé SSH backup : $BACKUP_SSH_KEY
Clé SSH repo : $REPO_SSH_KEY
Remote backup : ${BACKUP_REMOTE_USER}@${BACKUP_REMOTE_HOST}:${BACKUP_REMOTE_DIR}
Clé publique repo :
$(run_root cat "${REPO_SSH_KEY}.pub")
Clé publique backup :
$(run_root cat "${BACKUP_SSH_KEY}.pub")
Vérifiez :
- la clé repo doit être ajoutée comme deploy key sur le dépôt Git privé ;
- la valeur PGPASSWORD dans $ENV_FILE ;
- les webhooks renseignés dans $ENV_FILE si nécessaires.
========================================================================
EOF
}
#######################################
# Main
#######################################
main() {
ask_required_local_configuration
validate_required_values
compute_paths
PKG_MANAGER="$(detect_pkg_manager)"
[[ -n "$PKG_MANAGER" ]] || die "Gestionnaire de paquets non supporté."
log "Vérification / installation des dépendances"
install_dependencies
log "Création des répertoires"
prepare_directories
log "Préparation du .env"
ensure_env_file
update_env_defaults
log "Préparation des clés SSH"
ensure_ssh_keypair "$BACKUP_SSH_KEY" "${DEPLOY_USER}@backup-runtime"
ensure_ssh_keypair "$REPO_SSH_KEY" "${DEPLOY_USER}@repo-deploy"
log "Installation de la clé publique backup sur le serveur distant"
install_backup_key_on_remote
log "Synchronisation du dépôt Git privé"
sync_repo
log "Déploiement des scripts"
deploy_scripts
verify_scripts
log "Génération de la configuration web scripts.json"
generate_scripts_json
log "Application des permissions"
apply_ownership
print_summary
}
main "$@"

View File

@@ -1,56 +1,43 @@
# Malio-Ops
# Malio-Ops MALIO
Ce dépôt sert au **versionnement des scripts utilisés dans linfrastructure du projet Ferme**.
Ce depot centralise les scripts d'exploitation et de maintenance utilises pour l'infrastructure MALIO. Il sert de base de versionnement pour les sauvegardes, la supervision, les operations PostgreSQL et la reconstruction de bases.
Lobjectif est de conserver un historique clair des scripts, suivre les évolutions et permettre leur amélioration progressive.
## Contenu du dépôt
Le dépôt peut contenir différents types de scripts utilisés pour lexploitation technique :
* scripts de **backup PostgreSQL**
* scripts de **monitoring des applications**
* scripts **dautomatisation système**
* scripts **dadministration ou de maintenance**
## Objectif
Le depot permet de :
Ce dépôt permet de :
* suivre les modifications des scripts dans le temps
* conserver des versions stables et reproductibles
* mutualiser la configuration et les bonnes pratiques d'exploitation
* centraliser la documentation technique associee
* suivre les **modifications des scripts dans le temps**
* garder une **version stable et reproductible**
* faciliter la **maintenance et les corrections**
* centraliser les scripts utilisés sur les serveurs
## Structure du depot
## Organisation
Le depot est organise par dossier fonctionnel :
Les évolutions importantes sont documentées dans le fichier :
* [CheckStorage](CheckStorage) : surveillance de l'espace disque et alertes Discord
* [BackupVaultWarden](BackupVaultWarden) : sauvegarde et transfert distant des donnees Vaultwarden
* [RecetteScripts](RecetteScripts) : scripts historiques de backup, monitoring et rebuild pour l'environnement de recette
* [RebuildBdd](RebuildBdd) : orchestration de reconstruction de bases PostgreSQL, bootstrap de cibles et checks de preparation
```
CHANGELOG.md
```
## Focus RebuildBdd
Ce fichier décrit les nouvelles fonctionnalités, corrections et modifications apportées aux scripts.
Le dossier [RebuildBdd](RebuildBdd) regroupe la nouvelle chaine de reconstruction de base. Il contient notamment :
## Remarque
* [run-rebuild-bdd.sh](/home/matte/Malio-ops/RebuildBdd/run-rebuild-bdd.sh) : point d'entree principal
* [rebuild-bdd-core.sh](/home/matte/Malio-ops/RebuildBdd/rebuild-bdd-core.sh) : logique de restauration
* [bootstrap-target-host.sh](/home/matte/Malio-ops/RebuildBdd/bootstrap-target-host.sh) : preparation de la machine cible
* [create-target-config.sh](/home/matte/Malio-ops/RebuildBdd/create-target-config.sh) : generation de configuration cible
* [Checkup](RebuildBdd/Checkup) : scripts de verification prealable
* [Config](RebuildBdd/Config) : fichiers d'exemple de configuration globale et par cible
Ce dépôt est dédié au **versionnement des scripts uniquement**.
Les configurations sensibles (mots de passe, clés, variables denvironnement) ne doivent pas être stockées directement dans le dépôt et doivent être placées dans des fichiers `.env` locaux.
La documentation detaillee est disponible dans [RebuildBdd/README.md](/home/matte/Malio-ops/RebuildBdd/README.md).
Ce projet contient des scripts pour la gestion et la maintenance des serveurs de MALIO.
## Prerequis
Les scripts du depot reposent principalement sur :
* `bash`
* `jq`
* `curl`
* `ssh`
* `scp`
Selon les scripts, d'autres outils peuvent etre necessaires, notamment PostgreSQL (`psql`, `pg_dump`, `pg_restore`) ou `tar`.
## Configuration
Un modele commun est disponible dans [global.env.exemple](global.env.exemple). Il sert de base pour les variables partagees entre plusieurs scripts.
Chaque dossier peut aussi contenir son propre fichier `.env.exemple` ou ses propres fichiers de configuration. Les secrets et webhooks ne doivent jamais etre versionnes dans git et doivent rester dans des fichiers locaux ignores.
## Documentation
Les evolutions importantes sont suivies dans [CHANGELOG.md](CHANGELOG.md).
## Scripts disponibles
* [CheckStorage] : Script de vérification de l'espace de stockage

View File

@@ -0,0 +1,81 @@
#############################################
# ENVIRONNEMENT
#############################################
# Nom de l'environnement (ex: DEV / RECETTE / PROD)
ENV_NAME=RECETTE
#############################################
# POSTGRESQL
#############################################
# Host PostgreSQL
PGHOST=localhost
# Port PostgreSQL
PGPORT=5432
# Utilisateur utilisé pour les dumps
PGUSER=nom_de_user
# Mot de passe PostgreSQL
PGPASSWORD=change_me_secure_password
# Bases à sauvegarder (séparées par espace)
DBS="sirh inventory ferme"
#############################################
# SERVEUR DE STOCKAGE DES BACKUPS
#############################################
# Utilisateur du serveur distant
BACKUP_REMOTE_USER=nom_de_user
# Host ou IP du serveur distant
BACKUP_REMOTE_HOST=192.168.1.50
# Dossier distant pour stocker les backups
BACKUP_REMOTE_DIR=/home/nom_de_user/backups/bdd-recette
#############################################
# SSH
#############################################
# Clé SSH utilisée pour envoyer les dumps
SSH_KEY=/home/nom_de_user/.ssh/id_ed25519_backup
# Timeout SSH (secondes)
SSH_TIMEOUT=10
#############################################
# LOGS
#############################################
# Dossier des logs backup
BACKUP_LOG_DIR=/var/log/pg_backup
# Dossier logs monitoring apps
APP_LOG_DIR=/var/log/app_health
#############################################
# DISCORD
#############################################
# Webhook Discord pour notifications
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/xxxxxxxxxxxxxxxx/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# Ping en cas d'erreur
DISCORD_PING=@here
#############################################
# HEALTH CHECK APPS
#############################################
# Timeout connexion HTTP
CHECK_CONNECT_TIMEOUT=3
# Timeout total curl
CHECK_MAX_TIME=8
# Applications à vérifier
APP_URLS="ferme.example.local sirh.example.local inventory.example.local"

View File

@@ -1,378 +1,121 @@
# RecetteScripts
# Scripts Recette
Scripts Bash permettant dautomatiser la gestion dun environnement **PostgreSQL de recette**.
Ce dossier contient les scripts utilisés pour lenvironnement **RECETTE** du projet **Ferme**.
Ces scripts permettent :
Les scripts permettent principalement :
* la **sauvegarde automatie des bases**
* la **surveillance de la disponibilité des applications**
* la **reconstruction dune base à partir dun dump**
Chaque script possède son propre **fichier `.env` dédié** afin de séparer les configurations.(un global.env.exemple est disponible à la racine du projet)
* la **sauvegarde automatique des bases de données PostgreSQL**
* la **vérification du statut des applications web**
---
# 0. Arborescence du projet
# Scripts disponibles
```
RecetteScripts
├── backup-bdd-recette.sh # script de sauvegarde PostgreSQL
├── backup.env.exemple # exemple de configuration backup
├── check-statut-recette.sh # script de monitoring des applications
├── check-statut.env.exemple # exemple de configuration monitoring
├── rebuild-bdd-recette.sh # script de restauration PostgreSQL
├── rebuild.env.exemple # exemple de configuration restauration
└── README.md
```
## backup-bdd-recette.sh
Script permettant de réaliser une **sauvegarde des bases de données PostgreSQL**.
Fonctionnement :
* export des bases PostgreSQL définies dans la configuration
* export des utilisateurs PostgreSQL
* création de dumps au format PostgreSQL (`pg_dump -Fc`)
* transfert des sauvegardes vers un serveur distant
* génération de logs locaux
* envoi de notifications Discord en cas de succès ou derreur
---
# 1. Principe général
## check-statut-recette.sh
Les scripts fonctionnent indépendamment mais utilisent le même principe :
Script permettant de **vérifier la disponibilité des applications web**.
1. chargement dun fichier `.env`
2. vérification des variables obligatoires
3. exécution de la tâche principale
4. génération de logs
5. notification Discord (optionnelle)
Le script effectue les vérifications suivantes :
* résolution DNS du site
* connexion HTTP au service
* vérification du code HTTP retourné
Une application est considérée :
* **OK** si le code HTTP est entre **200 et 399**
* **DOWN** si la résolution DNS échoue ou si une erreur HTTP est détectée
Chaque vérification est enregistrée dans un **fichier de log** et une notification peut être envoyée sur **Discord**.
---
# 2. Prérequis
# Installation
Environnement Linux recommandé.
Packages nécessaires :
```
postgresql-client
curl
jq
ssh
scp
```
Commandes PostgreSQL requises :
```
pg_dump
pg_dumpall
pg_restore
psql
createdb
dropdb
```
---
### 3 Connexion SSH
Une connexion SSH avec **clé privée** est nécessaire afin de permettre les transferts automatisés de fichiers vers le serveur distant (dump PostgreSQL, rôles, etc.).
### Génération de la clé SSH
Sur la machine exécutant les scripts :
1. Clonez le dépôt Git :
```bash
ssh-keygen -t ed25519 -f ~/.ssh/id_backup_postgres
git clone https://gitea.malio.fr/MALIO-DEV/Scripts-Serveur.git
```
Explication :
* `-t ed25519` : algorithme recommandé
* `-f` : chemin de la clé
Deux fichiers seront créés :
```
~/.ssh/id_backup_postgres
~/.ssh/id_backup_postgres.pub
```
---
### Copier la clé sur le serveur distant
Méthode recommandée :
2. Accédez au dossier des scripts :
```bash
ssh-copy-id -i ~/.ssh/id_backup_postgres.pub user@serveur
cd Scripts-Serveur/RecetteScripts
```
Exemple :
3. Copiez le fichier denvironnement :
```bash
ssh-copy-id -i ~/.ssh/id_backup_postgres.pub backup@192.168.1.50
cp .env.example .env
```
4. Modifiez les variables du fichier `.env` selon votre configuration.
---
### Vérifier la connexion
# Utilisation
Tester la connexion sans mot de passe :
Donnez les permissions dexécution aux scripts :
```bash
ssh -i ~/.ssh/id_backup_postgres backup@192.168.1.50
chmod +x backup-bdd-recette.sh
chmod +x check-statut-recette.sh
```
La connexion doit fonctionner **sans demander de mot de passe**.
---
### Sécuriser les permissions
Les permissions doivent être restreintes :
Exécution manuelle :
```bash
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_backup_postgres
chmod 644 ~/.ssh/id_backup_postgres.pub
```
---
# 4. Configuration
Chaque script possède un **fichier dexemple** :
```
backup.env.exemple
check-statut.env.exemple
rebuild.env.exemple
```
Pour utiliser les scripts :
```
cp backup.env.exemple .env
```
Puis modifier les variables.
---
# 5. Script : backup-bdd-recette.sh
Script :
## Objectif
Sauvegarder plusieurs bases PostgreSQL et transférer les dumps vers un serveur distant.
---
## Fonctionnement
Le script :
1. charge la configuration `.env`
2. vérifie les dépendances
3. empêche lexécution simultanée (lock)
4. exporte les rôles PostgreSQL
5. crée un dump de chaque base
6. transfère les dumps vers un serveur distant
7. applique une rotation des sauvegardes
8. envoie un résumé sur Discord
---
## Format des fichiers
Dump base :
```
base_TIMESTAMP.dump
```
Export utilisateurs :
```
user_TIMESTAMP.sql
```
---
## Rotation automatique
Suppression des sauvegardes plus anciennes que :
```
10 jours
```
---
## Exécution
```
./backup-bdd-recette.sh
./check-statut-recette.sh
```
---
# 6. Script : check-statut-recette.sh
# Exécution automatique avec Cron
Script :
## Objectif
Vérifier la disponibilité des applications web.
Ce script agit comme un **mini système de monitoring**.
---
## Vérifications
Pour chaque application :
1. résolution DNS
2. requête HTTP
3. analyse du code HTTP
Codes valides :
Ouvrez le crontab :
```bash
crontab -e
```
200 → 399
Exemple de planification :
Backup des bases tous les jours à 19h :
```bash
0 19 * * * /chemin/vers/le/script/backup-bdd-recette.sh
```
Vérification des applications tous les jours à 19h :
```bash
0 19 * * * /chemin/vers/le/script/check-statut-recette.sh
```
---
## Exemple de configuration
# Avertissement
```
APP_URLS="ferme.malio-dev.fr sirh.malio-dev.fr inventory.malio-dev.fr"
```
Assurez-vous que :
---
## Logs
Fichier généré :
```
app_health_YYYY-MM-DD.log
```
Format :
```
date | statut | host | détail
```
---
## Exemple de notification Discord
```
CHECK APP RECETTE 🟢
✅ ferme.malio-dev.fr : OK
✅ sirh.malio-dev.fr : OK
✅ inventory.malio-dev.fr : OK
```
---
# 7. Script : rebuild-bdd-recette.sh
Script :
## Objectif
Restaurer une base PostgreSQL à partir dun dump distant.
---
## Fonctionnement
Le script :
1. charge la configuration `.env`
2. installe PostgreSQL si nécessaire
3. démarre le service PostgreSQL
4. demande la base à restaurer
5. récupère le dernier dump sur le serveur distant
6. récupère le dernier export des rôles
7. crée les rôles manquants
8. supprime la base existante si nécessaire
9. restaure la base via `pg_restore`
10. envoie une notification Discord
---
## Sélection de la base
Les bases disponibles sont lues depuis :
```
DBS="sirh inventory ferme"
```
Exemple :
```
1) sirh
2) inventory
3) ferme
```
---
## Commande utilisée pour la restauration
```
pg_restore
--clean
--if-exists
--no-owner
--no-privileges
```
Ces options évitent les conflits entre environnements.
---
# 8. Logs
Les scripts produisent des logs détaillés :
```
backup logs
restore logs
app health logs
```
Ces logs permettent :
* diagnostic des erreurs
* audit des opérations
* suivi des backups
---
# 9. Automatisation recommandée
### Backup et check quotidien
```
0 19 * * * /scripts/backup-bdd-recette.sh
0 19 * * * /scripts/check-statut-recette.sh
```
---
# 10. Bonnes pratiques
Recommandé :
* isoler le **serveur de stockage**
* vérifier régulièrement les restaurations
---
* PostgreSQL est accessible depuis la machine exécutant le script
* la clé SSH pour le transfert des sauvegardes est configurée
* les variables du fichier `.env` sont correctement renseignées
* les commandes `curl`, `psql` et `pg_dump` sont installées sur le système

View File

@@ -281,12 +281,7 @@ REMOTE_DIR="${IA_BASE_DIR}"
log "Creating remote directories"
MKDIR_CMD="mkdir -p '${REMOTE_DIR}/user'"
for DB in "${DBS_ARRAY[@]}"; do
MKDIR_CMD+=" '${REMOTE_DIR}/${DB}'"
done
if ! ssh "${SSH_OPTS[@]}" "$IA_SSH" "$MKDIR_CMD"; then
if ! ssh "${SSH_OPTS[@]}" "$IA_SSH" "mkdir -p '${REMOTE_DIR}/ferme' '${REMOTE_DIR}/sirh' '${REMOTE_DIR}/inventory' '${REMOTE_DIR}/user'"; then
log "ERROR: remote mkdir failed"
discord_msg_users_error "" "" "Remote mkdir failed"
exit 1

View File

@@ -1,65 +0,0 @@
###############################################################################
# ENVIRONNEMENT
###############################################################################
# Nom de l'environnement
ENV_NAME=RECETTE
###############################################################################
# POSTGRESQL
###############################################################################
# Host du serveur PostgreSQL
PGHOST=localhost
# Port PostgreSQL
PGPORT=5432
# Utilisateur utilisé pour réaliser les dumps
PGUSER=
# Mot de passe PostgreSQL
PGPASSWORD=
# Bases de données à sauvegarder (séparées par des espaces)
DBS="sirh inventory ferme"
###############################################################################
# SERVEUR DISTANT DE BACKUP
###############################################################################
# Utilisateur SSH du serveur de backup
BACKUP_REMOTE_USER=
# Host ou IP du serveur distant
BACKUP_REMOTE_HOST=
# Dossier distant où seront stockées les sauvegardes
BACKUP_REMOTE_DIR=/home/.../backups/bdd-recette
###############################################################################
# SSH
###############################################################################
# Clé SSH utilisée pour se connecter au serveur distant
SSH_KEY=/home/.../.ssh/id_ed25519_backup
# Timeout de connexion SSH (secondes)
SSH_TIMEOUT=10
###############################################################################
# LOGS
###############################################################################
# Dossier où seront stockés les logs du script
BACKUP_LOG_DIR=/var/log/script/
###############################################################################
# DISCORD (optionnel)
###############################################################################
# Webhook Discord pour envoyer les notifications
DISCORD_WEBHOOK_URL=
# Mention envoyée en cas d'erreur
DISCORD_PING=@here

View File

@@ -1,5 +1,4 @@
#!/usr/bin/env bash
# -e omis volontairement : check_site retourne 1 pour les sites down
set -uo pipefail
###############################################################################
@@ -115,6 +114,7 @@ add_summary_line() {
#######################################
# Envoi du message Discord récapitulatif
#######################################
send_discord_summary() {
[[ -z "${DISCORD_WEBHOOK_URL:-}" ]] && return 0
@@ -201,8 +201,6 @@ check_site() {
#######################################
main() {
trap '[[ -n "$STDERR_TMP" ]] && rm -f "$STDERR_TMP"' EXIT
local failures=0
for site in "${SITES[@]}"; do

View File

@@ -1,42 +0,0 @@
###############################################################################
# ENVIRONNEMENT
###############################################################################
# Nom de l'environnement surveillé
ENV_NAME=RECETTE
###############################################################################
# LOGS
###############################################################################
# Dossier où seront stockés les logs du script
APP_LOG_DIR=/var/log/script
###############################################################################
# PARAMÈTRES DE VÉRIFICATION HTTP
###############################################################################
# Timeout de connexion à l'application (secondes)
# Si le serveur ne répond pas dans ce délai, la connexion échoue
CHECK_CONNECT_TIMEOUT=5
# Temps maximum total autorisé pour la requête HTTP (secondes)
CHECK_MAX_TIME=10
###############################################################################
# APPLICATIONS À SURVEILLER
###############################################################################
# Liste des applications à vérifier (séparées par des espaces)
APP_URLS="ferme.malio-dev.fr inventory.malio-dev.fr sirh.malio-dev.fr"
###############################################################################
# DISCORD
###############################################################################
# Webhook Discord pour envoyer le résumé des vérifications
DISCORD_WEBHOOK_URL=
# Mention Discord en cas de problème
DISCORD_PING=@here

View File

@@ -135,7 +135,7 @@ send_discord_message() {
return 0
fi
payload="$(jq -n --arg content "$message" '{content: $content}')" || {
payload="$(python3 -c 'import json,sys; print(json.dumps({"content": sys.argv[1]}))' "$message")" || {
log "Impossible de construire le payload JSON Discord."
return 0
}
@@ -376,10 +376,6 @@ if [[ -n "$LOCAL_ROLES_FILE" ]]; then
if [[ -s "$ROLES_CREATE_LIST" ]]; then
while IFS= read -r role_name; do
[[ -z "$role_name" ]] && continue
if [[ ! "$role_name" =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]]; then
log "WARNING: nom de rôle suspect ignoré : ${role_name}"
continue
fi
ROLE_EXISTS="$(
psql -h "$PGHOST" -p "$PGPORT" -U "$PGUSER" -d postgres -tAc \

View File

@@ -1,80 +0,0 @@
###############################################################################
# ENVIRONNEMENT
###############################################################################
# Nom de l'environnement
# Exemple : DEV / RECETTE / PROD
ENV_NAME=RECETTE
###############################################################################
# POSTGRESQL LOCAL
###############################################################################
# Hôte PostgreSQL local sur lequel la restauration sera effectuée
PGHOST=localhost
# Port PostgreSQL local
PGPORT=5432
# Utilisateur PostgreSQL utilisé pour créer la base et lancer la restauration
PGUSER=
# Mot de passe
PGPASSWORD=
# Liste des bases proposées à la restauration (séparées par des espaces)
# L'utilisateur pourra en choisir une dans le script
DBS="sirh inventory ferme"
###############################################################################
# SERVEUR DISTANT DE BACKUP
###############################################################################
# Utilisateur SSH du serveur distant contenant les dumps
BACKUP_REMOTE_USER=
# Hôte ou IP du serveur distant
BACKUP_REMOTE_HOST=
# Répertoire racine distant :
BACKUP_REMOTE_DIR=/home/.../backups/bdd-recette
###############################################################################
# SSH
###############################################################################
# Clé privée SSH utilisée pour se connecter au serveur distant
SSH_KEY=/home/.../.ssh/id_ed25519_backup
# Timeout de connexion SSH en secondes
# Variable optionnelle dans le script, mais utile ici comme valeur par défaut
SSH_CONNECT_TIMEOUT=8
###############################################################################
# LOGS
###############################################################################
# Dossier local dans lequel seront écrits les logs de restauration
BACKUP_LOG_DIR=/var/log/pg_backup
###############################################################################
# RESTAURATION LOCALE
###############################################################################
# Dossier local temporaire pour télécharger les fichiers avant restauration
# Optionnel : si absent, le script utilise ./restore_tmp
LOCAL_RESTORE_DIR=/tmp/rebuild-bdd-recette
###############################################################################
# RÔLES POSTGRESQL DISTANTS
###############################################################################
# Nom du dossier distant contenant les exports SQL des rôles
REMOTE_ROLES_DIR_NAME=user
###############################################################################
# DISCORD
###############################################################################
# Webhook Discord pour notifier le succès de la restauration
DISCORD_WEBHOOK_URL=

View File

@@ -1,132 +0,0 @@
###############################################################################
# FICHIER .env.example
#
# Ce fichier sert de modèle de configuration pour les scripts d'automatisation :
# - backup-bdd-recette.sh → sauvegarde PostgreSQL
# - rebuild-bdd-recette.sh → reconstruction d'une base PostgreSQL
# - check-statut-recette.sh → vérification disponibilité des applications
# - check-storage.sh → surveillance de l'espace disque
# - backup-vaultwarden.sh → sauvegarde du service Vaultwarden
#
# Copier ce fichier en .env puis remplir les valeurs.
###############################################################################
#############################################
# ENVIRONNEMENT
#############################################
# Nom de l'environnement (ex : DEV / RECETTE / PROD)
ENV_NAME=RECETTE
#############################################
# DISCORD
#############################################
# Webhook Discord utilisé pour envoyer les notifications
DISCORD_WEBHOOK_URL=
#############################################
# POSTGRESQL
#############################################
# Adresse du serveur PostgreSQL
PGHOST=localhost
# Port PostgreSQL
PGPORT=5432
# Utilisateur utilisé pour les dumps
PGUSER=
# Mot de passe
PGPASSWORD=
# Bases de données à sauvegarder (séparées par espace)
# Utilisé par backup-bdd-recette.sh
DBS="sirh inventory ferme"
#############################################
# BACKUPS LOCAUX
#############################################
# Dossier local où les dumps seront générés temporairement
BACKUP_LOCAL_DIR=/var/backups/postgresql
# Dossier des logs de sauvegarde
BACKUP_LOG_DIR=/var/log/script/...
#############################################
# SERVEUR DISTANT DE STOCKAGE
#############################################
# Utilisateur du serveur de backup distant
BACKUP_REMOTE_USER=
# Adresse IP ou hostname du serveur de stockage
BACKUP_REMOTE_HOST=
# Dossier distant où stocker les backups
BACKUP_REMOTE_DIR=/home/.../backups/bdd-recette
#############################################
# SSH
#############################################
# Clé SSH utilisée pour se connecter au serveur distant
SSH_KEY=/home/.../.ssh/id_ed25519_backup
# Timeout SSH (secondes)
SSH_TIMEOUT=10
#############################################
# ROTATION DES BACKUPS
#############################################
# Nombre de jours de conservation des sauvegardes
BACKUP_RETENTION_DAYS=10
#############################################
# APPLICATIONS À SURVEILLER
#############################################
# Liste des applications à vérifier
APPS="
ferme.malio-dev.fr
inventory.malio-dev.fr
sirh.malio-dev.fr
"
#############################################
# VAULTWARDEN
#############################################
# Dossier contenant les données Vaultwarden
VAULTWARDEN_DATA_DIR=/opt/vaultwarden/data
# Dossier local où stocker le backup
VAULTWARDEN_BACKUP_DIR=/var/backups/vaultwarden
#############################################
# SERVEUR IA / STOCKAGE CENTRAL
#############################################
# Utilisateur SSH du serveur distant
IA_SSH_USER=
# Host du serveur distant
IA_SSH_HOST=
# Dossier racine contenant les dumps PostgreSQL
IA_BASE_DIR=/home/.../backups/bdd-recette
# Dossier contenant les rôles PostgreSQL exportés
REMOTE_ROLES_NAME=user