188 lines
7.8 KiB
Bash
Executable File
188 lines
7.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# =============================================================================
|
|
# Controle go / no-go avant ouverture au public
|
|
# =============================================================================
|
|
# export KUBECONFIG=~/.kube/xpeditis-prod.yaml
|
|
# bash scripts/preflight-check.sh
|
|
#
|
|
# Chaque point BLOQUANT en echec doit etre corrige avant d'ouvrir le service.
|
|
# Les points d'AVERTISSEMENT peuvent etre acceptes consciemment et notes dans
|
|
# le registre des risques.
|
|
set -uo pipefail
|
|
|
|
NAMESPACE=xpeditis-prod
|
|
API="${PROD_API_URL:-https://api.xpeditis.com}"
|
|
DB_HOST="${DB_PRIVATE_IP:-10.10.1.20}"
|
|
DB_PUBLIC_IP="${DB_PUBLIC_IP:-}"
|
|
|
|
BLOCK=0
|
|
WARN=0
|
|
|
|
ok() { printf ' \033[32m[OK]\033[0m %s\n' "$1"; }
|
|
block() { printf ' \033[31m[BLOQUANT]\033[0m %s\n' "$1"; BLOCK=$((BLOCK+1)); }
|
|
warn() { printf ' \033[33m[ATTENTION]\033[0m %s\n' "$1"; WARN=$((WARN+1)); }
|
|
|
|
section() { printf '\n\033[1m%s\033[0m\n' "$1"; }
|
|
|
|
# ---------------------------------------------------------------------------
|
|
section "1. Cluster"
|
|
|
|
if kubectl get nodes >/dev/null 2>&1; then
|
|
ok "Cluster joignable"
|
|
if kubectl get nodes --no-headers | grep -qv ' Ready'; then
|
|
block "Un noeud n'est pas Ready"
|
|
else
|
|
ok "Tous les noeuds sont Ready"
|
|
fi
|
|
else
|
|
block "Cluster injoignable : rien d'autre ne peut etre verifie"
|
|
fi
|
|
|
|
if kubectl -n "$NAMESPACE" get pods --no-headers 2>/dev/null | grep -qE 'CrashLoop|ImagePull|Error|Pending'; then
|
|
block "Des pods ne sont pas sains dans $NAMESPACE"
|
|
else
|
|
ok "Tous les pods de $NAMESPACE sont sains"
|
|
fi
|
|
|
|
for d in xpeditis-backend xpeditis-frontend; do
|
|
READY=$(kubectl -n "$NAMESPACE" get deploy "$d" -o jsonpath='{.status.readyReplicas}' 2>/dev/null || echo 0)
|
|
[[ "${READY:-0}" -ge 2 ]] && ok "$d : ${READY} replicas prets" \
|
|
|| warn "$d : ${READY:-0} replica(s) pret(s), 2 attendus (pas de haute disponibilite)"
|
|
done
|
|
|
|
# ---------------------------------------------------------------------------
|
|
section "2. Secrets"
|
|
|
|
if kubectl -n "$NAMESPACE" get secret xpeditis-backend-secrets >/dev/null 2>&1; then
|
|
ok "Secrets applicatifs presents"
|
|
JWT=$(kubectl -n "$NAMESPACE" get secret xpeditis-backend-secrets -o jsonpath='{.data.JWT_SECRET}' 2>/dev/null | base64 -d 2>/dev/null || echo "")
|
|
[[ ${#JWT} -ge 32 ]] && ok "JWT_SECRET fait ${#JWT} caracteres" || block "JWT_SECRET trop court (${#JWT} caracteres, 32 minimum)"
|
|
|
|
# Les secrets publies dans infra/preprod/docker-stack.preprod.yml sont dans
|
|
# l'historique Git : les retrouver en production serait une compromission.
|
|
for compromis in "4C4tQC8qym" "9Lc3M9qoPBeHLKHDXGUf1" "hXiy5GMPswMtxMZujjS2O" "RBJfD0QVXC5JDfAHCwdUW"; do
|
|
if kubectl -n "$NAMESPACE" get secret xpeditis-backend-secrets -o json 2>/dev/null \
|
|
| grep -q "$(printf '%s' "$compromis" | base64 | cut -c1-12)"; then
|
|
block "Un secret de preprod (present dans Git, donc compromis) est reutilise en production"
|
|
fi
|
|
done
|
|
ok "Aucun secret de preprod detecte"
|
|
|
|
STRIPE=$(kubectl -n "$NAMESPACE" get secret xpeditis-backend-secrets -o jsonpath='{.data.STRIPE_SECRET_KEY}' 2>/dev/null | base64 -d 2>/dev/null || echo "")
|
|
case "$STRIPE" in
|
|
sk_live_*) ok "Cle Stripe en mode LIVE" ;;
|
|
sk_test_*) block "Cle Stripe en mode TEST : aucun paiement reel ne sera encaisse" ;;
|
|
*) warn "Cle Stripe absente ou non reconnue" ;;
|
|
esac
|
|
else
|
|
block "Secrets applicatifs absents"
|
|
fi
|
|
|
|
if kubectl -n "$NAMESPACE" get secret regcred >/dev/null 2>&1; then
|
|
ok "Acces au registre configure"
|
|
else
|
|
block "Secret 'regcred' absent : aucune image ne pourra etre telechargee"
|
|
fi
|
|
|
|
if sudo k3s secrets-encrypt status 2>/dev/null | grep -qi 'Encryption Status: Enabled'; then
|
|
ok "Chiffrement des Secrets au repos actif"
|
|
else
|
|
warn "Chiffrement des Secrets au repos non verifiable depuis ce poste (a controler sur app-01)"
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
section "3. TLS et exposition"
|
|
|
|
CERT=$(kubectl -n "$NAMESPACE" get certificate xpeditis-wildcard -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}' 2>/dev/null || echo "")
|
|
[[ "$CERT" == "True" ]] && ok "Certificat wildcard emis" || block "Certificat wildcard non pret"
|
|
|
|
ISSUER=$(kubectl -n "$NAMESPACE" get certificate xpeditis-wildcard -o jsonpath='{.spec.issuerRef.name}' 2>/dev/null || echo "")
|
|
[[ "$ISSUER" == "letsencrypt-prod" ]] && ok "Emetteur : letsencrypt-prod" \
|
|
|| block "Emetteur '$ISSUER' : un certificat de staging n'est pas reconnu par les navigateurs"
|
|
|
|
if curl -sSI --max-time 15 "${API}/api/v1/health" 2>/dev/null | grep -qi '^strict-transport-security:'; then
|
|
ok "HSTS actif"
|
|
else
|
|
block "En-tete HSTS absent"
|
|
fi
|
|
|
|
if [[ -n "$DB_PUBLIC_IP" ]]; then
|
|
if command -v nc >/dev/null; then
|
|
if nc -z -w3 "$DB_PUBLIC_IP" 5432 2>/dev/null; then
|
|
block "PostgreSQL repond sur l'IP PUBLIQUE de db-01"
|
|
else
|
|
ok "PostgreSQL injoignable publiquement"
|
|
fi
|
|
if nc -z -w3 "$DB_PUBLIC_IP" 6379 2>/dev/null; then
|
|
block "Redis repond sur l'IP PUBLIQUE de db-01"
|
|
else
|
|
ok "Redis injoignable publiquement"
|
|
fi
|
|
fi
|
|
else
|
|
warn "DB_PUBLIC_IP non fournie : exposition de la base non verifiee"
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
section "4. Comptes de demonstration"
|
|
|
|
# La migration 1730000000007-SeedTestUsers creait admin@xpeditis.com avec le mot
|
|
# de passe "Password123!", ecrit en clair dans le depot. Elle ne s'execute plus
|
|
# en production (APP_ENV, a defaut NODE_ENV), et 1756000000000 neutralise ces
|
|
# comptes s'ils acceptent encore ce mot de passe.
|
|
#
|
|
# Ce controle verifie le RESULTAT en conditions reelles, pas l'intention : c'est
|
|
# le seul moyen de detecter un APP_ENV mal positionne ou une base restauree
|
|
# depuis une sauvegarde anterieure. Le controle le plus important de la liste.
|
|
for compte in admin manager user; do
|
|
CODE=$(curl -sS -o /dev/null -w '%{http_code}' --max-time 15 \
|
|
-X POST "${API}/api/v1/auth/login" \
|
|
-H 'Content-Type: application/json' \
|
|
-d "{\"email\":\"${compte}@xpeditis.com\",\"password\":\"Password123!\"}" 2>/dev/null || echo "000")
|
|
case "$CODE" in
|
|
200|201) block "Le compte de demonstration ${compte}@xpeditis.com accepte encore Password123! (HTTP ${CODE})" ;;
|
|
000) warn "Impossible de tester ${compte}@xpeditis.com (API injoignable)" ;;
|
|
*) ok "${compte}@xpeditis.com neutralise (HTTP ${CODE})" ;;
|
|
esac
|
|
done
|
|
|
|
echo " Verifier aussi qu'il n'existe qu'un seul ADMIN actif, sur db-01 :"
|
|
echo " SELECT email, role, is_active FROM users WHERE role = 'ADMIN';"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
section "5. Sauvegardes"
|
|
|
|
cat <<'MANUEL'
|
|
Ces points se verifient sur db-01, ils ne peuvent pas l'etre d'ici :
|
|
|
|
ssh deploy@<db-01>
|
|
systemctl list-timers 'xpeditis-*' # timers actifs
|
|
sudo journalctl -u xpeditis-backup -n 30 # derniere execution
|
|
sudo /opt/xpeditis/data-node/backup/pg-restore.sh verify
|
|
|
|
Une sauvegarde jamais restauree n'est pas une sauvegarde. Le test de
|
|
restauration DOIT avoir ete passe au moins une fois avant l'ouverture.
|
|
MANUEL
|
|
|
|
# ---------------------------------------------------------------------------
|
|
section "6. Fonctionnement"
|
|
|
|
if bash "$(dirname "${BASH_SOURCE[0]}")/smoke-test.sh" >/dev/null 2>&1; then
|
|
ok "Tests de fumee au vert"
|
|
else
|
|
block "Tests de fumee en echec (relancer smoke-test.sh pour le detail)"
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
printf '\n=========================================\n'
|
|
printf ' Bloquants : %d Avertissements : %d\n' "$BLOCK" "$WARN"
|
|
printf '=========================================\n'
|
|
|
|
if [[ "$BLOCK" -gt 0 ]]; then
|
|
printf '\n\033[31mNO-GO\033[0m : corrigez les points bloquants avant d ouvrir au public.\n'
|
|
exit 1
|
|
fi
|
|
printf '\n\033[32mGO\033[0m : les controles bloquants sont passes.\n'
|
|
[[ "$WARN" -gt 0 ]] && printf 'Consignez les %d avertissement(s) dans le registre des risques.\n' "$WARN"
|
|
exit 0
|