fix : changelog plus readme a jour

This commit is contained in:
2026-03-18 21:24:30 +01:00
parent fac2a5b47f
commit 7b91691ef8
23 changed files with 653 additions and 278 deletions

View File

@@ -70,6 +70,8 @@ print_stdout() {
[[ "$JSON_ONLY" == "yes" ]] || echo "$*"
}
LOG_FILE=/dev/stderr
log() {
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] $*"
echo "$msg" >>"$LOG_FILE"
@@ -114,13 +116,16 @@ require_env_vars() {
validate_env_values() {
[[ "$PGPORT" =~ ^[0-9]+$ ]] || fail "PGPORT invalide"
[[ "$ENV_NAME" =~ ^[a-zA-Z0-9_-]+$ ]] || fail "ENV_NAME invalide"
[[ -n "$DBS" ]] || fail "DBS vide"
[[ "$PGUSER" =~ ^[a-zA-Z0-9_][a-zA-Z0-9_-]*$ ]] || fail "PGUSER invalide"
[[ -n "$BACKUP_REMOTE_HOST" ]] || fail "BACKUP_REMOTE_HOST vide"
[[ -n "$BACKUP_REMOTE_USER" ]] || fail "BACKUP_REMOTE_USER vide"
[[ -n "$BACKUP_REMOTE_DIR" ]] || fail "BACKUP_REMOTE_DIR vide"
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"
to_bool_yes_no "$BACKUP_KNOWN_HOSTS_STRICT" >/dev/null || fail "BACKUP_KNOWN_HOSTS_STRICT invalide"
}
prepare_log_file() {
@@ -193,7 +198,11 @@ prepare_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
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 || \
fail "échec de récupération de la clé hôte pour ${BACKUP_REMOTE_HOST}"
else

View File

@@ -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

View 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

View File

@@ -1,42 +1,42 @@
###############################################################################
# config/targets/test.env.example
###############################################################################
# SSH bootstrap cible
TARGET_HOST=192.168.1.50
TARGET_PORT=22
TARGET_BOOTSTRAP_USER=backup_liot
TARGET_BOOTSTRAP_SSH_KEY=/home/matteo/.ssh/id_ed25519_target_test
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=RECETTE
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-recette
# 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
###############################################################################
# config/targets/test.env.exemple
###############################################################################
# SSH bootstrap cible
TARGET_HOST=192.168.1.50
TARGET_PORT=22
TARGET_BOOTSTRAP_USER=backup_liot
TARGET_BOOTSTRAP_SSH_KEY=/home/matteo/.ssh/id_ed25519_target_test
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=RECETTE
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-recette
# 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

View File

@@ -46,7 +46,7 @@ Le projet utilise deux niveaux de configuration :
Fichier :
```bash
config/global.env
Config/global.env
````
Contient les paramètres stables, par exemple :
@@ -62,7 +62,7 @@ Contient les paramètres stables, par exemple :
Fichiers :
```bash
config/targets/<nom_cible>.env
Config/Targets/<nom_cible>.env
```
Chaque fichier cible contient :
@@ -83,9 +83,9 @@ RebuildBdd/
├── create-target-config.sh
├── run-rebuild-bdd.sh
├── rebuild-bdd-core.sh
├── config/
├── Config/
│ ├── global.env
│ └── targets/
│ └── Targets/
│ ├── test.env
│ └── prod.env
└── Checkup/
@@ -102,7 +102,7 @@ RebuildBdd/
Crée ou met à jour un fichier cible dans :
```bash
config/targets/<cible>.env
Config/Targets/<cible>.env
```
Usage :
@@ -233,6 +233,7 @@ Doit disposer de :
* `scp`
* `git`
* `python3`
* `jq` si vous consommez les JSON côté tooling
### Machine cible
@@ -240,7 +241,8 @@ Le bootstrap suppose :
* accès SSH fonctionnel ;
* 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
@@ -250,6 +252,20 @@ Doit :
* accepter la clé de lecture backup ;
* contenir les dumps dans larborescence attendue.
## Sécurité / déploiement
### Clés hôtes SSH
Si `GLOBAL_BACKUP_KNOWN_HOSTS_STRICT=yes`, lempreinte 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 dajout 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
@@ -290,13 +306,13 @@ Le script recherche :
Copier :
```bash
config/global.env.example
Config/.env.exemple
```
vers :
```bash
config/global.env
Config/global.env
```
Renseigner ensuite :
@@ -317,13 +333,13 @@ Deux possibilités.
Créer un fichier :
```bash
config/targets/test.env
Config/Targets/test.env
```
à partir de :
```bash
config/targets/test.env.example
Config/Targets/test.env.exemple
```
#### B. Via script
@@ -400,7 +416,7 @@ Ces informations doivent être stockées dans la configuration serveur.
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>`
3. lancer ensuite `run-rebuild-bdd.sh --target <cible> ...`

View File

@@ -221,6 +221,14 @@ if [[ -n "$TARGET_REPO_SUBDIR" ]]; then
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_PGHOST_VALUE" ]] || fail "TARGET_PGHOST/GLOBAL_PGHOST manquant"
[[ -n "$TARGET_PGPORT_VALUE" ]] || fail "TARGET_PGPORT/GLOBAL_PGPORT manquant"
@@ -258,7 +266,7 @@ SSH_OPTS=(
-p "$BOOTSTRAP_PORT"
-o IdentitiesOnly=yes
-o BatchMode=yes
-o StrictHostKeyChecking=accept-new
-o StrictHostKeyChecking=yes
-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")
REMOTE_ROLES_DIR_NAME=$(shell_quote "$TARGET_REMOTE_ROLES_DIR_NAME_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_CREATE_PGUSER=$(shell_quote "$TARGET_AUTO_CREATE_PGUSER_VALUE")
@@ -385,6 +394,10 @@ if ! command -v ssh-keyscan >/dev/null 2>&1; then
fi
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
fi
"
@@ -488,6 +501,10 @@ REMOTE_REPO_CMD="
set -euo pipefail
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")
git clone --branch $(shell_quote "$TARGET_REPO_BRANCH") --single-branch $(shell_quote "$TARGET_REPO_URL") $(shell_quote "$TARGET_CLONE_DIR")
else

View File

@@ -83,6 +83,8 @@ print_stdout() {
[[ "$JSON_ONLY" == "yes" ]] || echo "$*"
}
LOG_FILE=/dev/stderr
log() {
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] $*"
echo "$msg" >>"$LOG_FILE"
@@ -220,6 +222,7 @@ RESTORE_ROLES="$(to_bool_yes_no "$RESTORE_ROLES_RAW")" || {
}
[[ "$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"
mkdir -p "$BACKUP_LOG_DIR" || {

View File

@@ -195,6 +195,14 @@ if [[ -n "$TARGET_REPO_SUBDIR" ]]; then
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"
BOOTSTRAP_SCRIPT_LOCAL="${SCRIPT_DIR}/bootstrap-target-host.sh"
@@ -261,7 +269,7 @@ SSH_OPTS=(
-p "$TARGET_PORT"
-o IdentitiesOnly=yes
-o BatchMode=yes
-o StrictHostKeyChecking=accept-new
-o StrictHostKeyChecking=yes
-o ConnectTimeout=8
)
@@ -294,6 +302,10 @@ mkdir -p \"\$(dirname \"\$CLONE_DIR\")\"
mkdir -p \"\$(dirname \"\$REPO_DIR\")\"
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\"
git clone --branch \"\$REPO_BRANCH\" --single-branch \"\$REPO_URL\" \"\$CLONE_DIR\" >/dev/null 2>&1
else