xpeditis2.0/infra/prod/scripts/01-setup-data-node.sh
2026-09-07 21:40:50 +02:00

171 lines
7.0 KiB
Bash
Executable File

#!/usr/bin/env bash
# =============================================================================
# 01 - Installation du noeud de donnees (db-01)
# =============================================================================
# Prerequis : 00-bootstrap-common.sh data deja execute sur ce serveur.
#
# sudo bash 01-setup-data-node.sh
#
# Ce script :
# 1. monte le volume Hetzner sur /var/lib/xpeditis/pgdata
# 2. installe Docker Engine depuis le depot officiel
# 3. genere le certificat TLS interne de PostgreSQL
# 4. installe age (chiffrement des dumps)
# 5. installe les unites systemd de sauvegarde
#
# Il ne demarre PAS la base : il faut d'abord deposer .env.data (SOPS).
set -euo pipefail
[[ "$EUID" -eq 0 ]] || { echo "Executer en root (sudo)." >&2; exit 1; }
APP_PRIVATE_IP="${APP_PRIVATE_IP:-10.10.1.10}"
DB_PRIVATE_IP="${DB_PRIVATE_IP:-10.10.1.20}"
BASE_DIR=/opt/xpeditis/data-node
DATA_ROOT=/var/lib/xpeditis
log() { printf '\n>>> %s\n' "$*"; }
# --- 1. Volume de donnees ----------------------------------------------------
log "Montage du volume PostgreSQL"
mkdir -p "${DATA_ROOT}"/{pgdata,redis,certs,dumps}
# Hetzner expose les volumes sous /dev/disk/by-id/scsi-0HC_Volume_<id>.
VOLUME_DEV="$(ls /dev/disk/by-id/scsi-0HC_Volume_* 2>/dev/null | head -1 || true)"
if [[ -n "$VOLUME_DEV" ]]; then
if ! blkid "$VOLUME_DEV" >/dev/null 2>&1; then
log "Formatage de $VOLUME_DEV en ext4 (volume vierge)"
mkfs.ext4 -F -L xpeditis-pgdata "$VOLUME_DEV"
else
log "Volume deja formate, conservation des donnees existantes"
fi
if ! grep -q "${DATA_ROOT}/pgdata" /etc/fstab; then
# `nofail` : si le volume est absent au boot, le serveur demarre quand meme
# et on diagnostique en SSH plutot que de se retrouver hors ligne.
echo "${VOLUME_DEV} ${DATA_ROOT}/pgdata ext4 discard,nofail,defaults 0 2" >> /etc/fstab
fi
mount -a
df -h "${DATA_ROOT}/pgdata"
else
echo "AVERTISSEMENT: aucun volume Hetzner detecte. Les donnees resteront sur le disque systeme."
fi
# L'UID/GID 999 est celui de l'utilisateur postgres dans l'image officielle.
chown -R 999:999 "${DATA_ROOT}/pgdata" "${DATA_ROOT}/redis" "${DATA_ROOT}/dumps"
chmod 700 "${DATA_ROOT}/pgdata"
# --- 2. Docker Engine --------------------------------------------------------
if ! command -v docker >/dev/null; then
log "Installation de Docker Engine (depot officiel)"
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
> /etc/apt/sources.list.d/docker.list
apt-get update -qq
apt-get install -y -qq docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
fi
log "Durcissement du demon Docker"
cat > /etc/docker/daemon.json <<'JSON'
{
"log-driver": "json-file",
"log-opts": { "max-size": "50m", "max-file": "5" },
"live-restore": true,
"userland-proxy": false,
"no-new-privileges": true,
"icc": false,
"default-address-pools": [
{ "base": "172.28.0.0/16", "size": 24 }
]
}
JSON
systemctl enable --now docker
systemctl restart docker
# --- 3. Certificat TLS de PostgreSQL ----------------------------------------
# Certificat auto-signe : PostgreSQL n'est joignable que depuis app-01 sur un
# reseau prive, il n'y a pas de tiers a authentifier. Ce certificat sert a
# CHIFFRER le transport, pas a prouver une identite publique.
# Cote client, DATABASE_SSL=true avec rejectUnauthorized:false accepte ce
# certificat : c'est coherent, et documente dans 04-noeud-donnees.md.
if [[ ! -f "${DATA_ROOT}/certs/server.key" ]]; then
log "Generation du certificat TLS PostgreSQL (10 ans)"
openssl req -new -x509 -days 3650 -nodes \
-newkey rsa:4096 \
-out "${DATA_ROOT}/certs/server.crt" \
-keyout "${DATA_ROOT}/certs/server.key" \
-subj "/CN=xpeditis-prod-db-01/O=Xpeditis/C=FR" \
-addext "subjectAltName=IP:${DB_PRIVATE_IP},DNS:postgres"
# PostgreSQL refuse de demarrer si la cle privee est lisible par d'autres.
chown 999:999 "${DATA_ROOT}/certs/server.key" "${DATA_ROOT}/certs/server.crt"
chmod 600 "${DATA_ROOT}/certs/server.key"
chmod 644 "${DATA_ROOT}/certs/server.crt"
else
log "Certificat TLS deja present, conserve"
fi
# --- 4. age (chiffrement des dumps) -----------------------------------------
if ! command -v age >/dev/null; then
log "Installation de age"
apt-get install -y -qq age
fi
mkdir -p /root/.config/xpeditis
chmod 700 /root/.config/xpeditis
# --- 5. Arborescence applicative --------------------------------------------
log "Preparation de ${BASE_DIR}"
mkdir -p "${BASE_DIR}"/{conf,backup}
chmod 750 "${BASE_DIR}"
# --- 6. Unites systemd de sauvegarde ----------------------------------------
if [[ -f "${BASE_DIR}/backup/xpeditis-backup.service" ]]; then
log "Installation des timers de sauvegarde"
install -m 0644 "${BASE_DIR}/backup/xpeditis-backup.service" /etc/systemd/system/
install -m 0644 "${BASE_DIR}/backup/xpeditis-backup.timer" /etc/systemd/system/
install -m 0644 "${BASE_DIR}/backup/xpeditis-backup-verify.service" /etc/systemd/system/
install -m 0644 "${BASE_DIR}/backup/xpeditis-backup-verify.timer" /etc/systemd/system/
chmod +x "${BASE_DIR}/backup/"*.sh
systemctl daemon-reload
systemctl enable --now xpeditis-backup.timer xpeditis-backup-verify.timer
systemctl list-timers 'xpeditis-*' --no-pager
else
echo "AVERTISSEMENT: ${BASE_DIR}/backup/ vide. Copiez infra/prod/data-node/ puis relancez ce script."
fi
# --- 7. Rappel du filtrage reseau -------------------------------------------
log "Regles UFW effectives"
ufw status numbered
cat <<NEXT
=============================================================================
Noeud de donnees pret.
=============================================================================
Etapes suivantes (depuis votre poste) :
1. Copier la configuration :
rsync -a infra/prod/data-node/ deploy@${DB_PRIVATE_IP}:/tmp/data-node/
ssh deploy@<ip-publique-db> 'sudo rsync -a /tmp/data-node/ ${BASE_DIR}/'
2. Dechiffrer et deposer les secrets :
sops -d --input-type dotenv --output-type dotenv \\
infra/prod/data-node/data-node.sops.env > /tmp/.env.data
scp /tmp/.env.data deploy@<ip-publique-db>:/tmp/
ssh deploy@<ip> 'sudo install -m600 -o root -g root /tmp/.env.data ${BASE_DIR}/.env.data && shred -u /tmp/.env.data'
3. Demarrer :
cd ${BASE_DIR} && sudo docker compose -f docker-compose.data.yml --env-file .env.data up -d --build
4. Premiere sauvegarde complete (obligatoire avant d'ouvrir au public) :
sudo systemctl start xpeditis-backup.service
sudo journalctl -u xpeditis-backup -f
Verifier que rien n'est expose publiquement, depuis un autre reseau :
nmap -Pn -p 5432,6379 <ip-publique-db> # doit repondre filtered
=============================================================================
NEXT