Files
MABEA/deploy/install_server.sh
patrickandClaude Sonnet 5 ceddeb1bf4
CI / backend-tests (push) Failing after 19s
CI / frontend-build (push) Successful in 25s
Multi-Agent-Review: Race Conditions, DB-Indizes, TLS/Security-Härtung
Konsolidierte Funde aus postgres-/sql-/jwt-/owasp-top10-expert-Review:

- Race Conditions gefixt: doppelte aktive Kontrolle (SAVEPOINT + partieller
  Unique-Index), doppelte Mindermengen-Genehmigung (FOR UPDATE + Unique-Index),
  Lost-Update bei Nachfüllung (FOR UPDATE auf Fehlbestand/Objektposition).
- Migration 0007: partielle Unique-Indizes als DB-Sicherheitsnetz + fehlende
  FK-Indizes (fehlbestand.material_id, kontrolle(objekt_id,status),
  zustaendigkeit, benutzer_rolle.rolle, objektposition.ablaufdatum u.a.).
- Connection-Pool explizit begrenzt (pool_size=5, max_overflow=5) - ohne das
  könnte jeder uvicorn-Worker den Postgres max_connections-Wert sprengen.
- Timing-Angriff bei Login-Enumeration gefixt (konstante Antwortzeit über
  Dummy-Hash), JWT-Decode verlangt jetzt exp/sub-Claims.
- App-seitiges Rate-Limiting (slowapi, 5/min) auf /auth/login als Verteidigung
  in der Tiefe zusätzlich zum nginx-Limit.
- nginx: TLS mit selbstsigniertem Zertifikat (LAN-Betrieb, keine Domain),
  HSTS, Content-Security-Policy, Permissions-Policy ergänzt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 18:47:06 +02:00

113 lines
4.8 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# MABEA Server-Setup (Debian 13). Installiert PostgreSQL + nginx, legt DB/Rolle an,
# richtet nginx als Reverse-Proxy vor dem späteren FastAPI/Uvicorn-Backend ein.
# Idempotent: mehrfacher Aufruf überschreibt keine bestehende DB-Rolle/DB.
#
# Ausführung auf dem Zielserver als root:
# DB_PASSWORD=... APP_DOMAIN=mabea.example.org ./install_server.sh
# Ohne DB_PASSWORD wird ein zufälliges Passwort erzeugt und am Ende ausgegeben
# (sofort sichern, z. B. in backend/.env auf dem Server nicht committen).
set -euo pipefail
DB_NAME="${DB_NAME:-mabea}"
DB_USER="${DB_USER:-mabea}"
DB_PASSWORD="${DB_PASSWORD:-$(openssl rand -base64 24)}"
JWT_SECRET_KEY="${JWT_SECRET_KEY:-$(openssl rand -base64 48)}"
APP_DOMAIN="${APP_DOMAIN:-_}" # "_" = nginx catch-all, solange keine Domain feststeht
# Kein sudo-Dependency: minimale LXC-Images haben sudo oft nicht vorinstalliert,
# Skript läuft ohnehin als root (Ausführung dokumentiert das oben).
# SQL wird bewusst über stdin an psql gepiped statt als su-Argument übergeben
# vermeidet doppelte Shell-Quoting-/Word-Splitting-Fallstricke (Bugfix nach Testlauf).
run_psql() {
local db="$1" sql="$2"
printf '%s\n' "${sql}" | su -s /bin/bash postgres -c "psql -tA -d '${db}'"
}
echo "== apt update/install =="
export DEBIAN_FRONTEND=noninteractive
apt-get update -qq
apt-get install -y -qq postgresql nginx python3-venv python3-pip git openssl
echo "== PostgreSQL: Rolle + Datenbank =="
if [ "$(run_psql postgres "SELECT 1 FROM pg_roles WHERE rolname='${DB_USER}';")" != "1" ]; then
run_psql postgres "CREATE ROLE ${DB_USER} WITH LOGIN PASSWORD '${DB_PASSWORD}';"
echo "Rolle ${DB_USER} angelegt."
else
echo "Rolle ${DB_USER} existiert bereits, überspringe."
fi
if [ "$(run_psql postgres "SELECT 1 FROM pg_database WHERE datname='${DB_NAME}';")" != "1" ]; then
run_psql postgres "CREATE DATABASE ${DB_NAME} OWNER ${DB_USER};"
echo "Datenbank ${DB_NAME} angelegt."
else
echo "Datenbank ${DB_NAME} existiert bereits, überspringe."
fi
# gen_random_uuid() ist seit PG13 built-in, aber pgcrypto schadet nicht und macht es
# explizit/robust gegen ältere Backports (Review-Fund postgres-expert).
run_psql "${DB_NAME}" "CREATE EXTENSION IF NOT EXISTS pgcrypto;"
echo "== PostgreSQL: Speicher-Tuning für kleinen VPS (4GB RAM) =="
PG_CONF_DIR=$(run_psql postgres "SHOW config_file;" | xargs dirname)
mkdir -p "${PG_CONF_DIR}/conf.d"
cat > "${PG_CONF_DIR}/conf.d/mabea-tuning.conf" <<'PGCONF'
# MABEA: konservatives Tuning für ~4GB RAM VPS, nicht enterprise-scale.
shared_buffers = 1GB
effective_cache_size = 3GB
maintenance_work_mem = 256MB
work_mem = 8MB
max_connections = 50
PGCONF
grep -q "conf.d/\*.conf" "${PG_CONF_DIR}/postgresql.conf" || \
echo "include_dir = 'conf.d'" >> "${PG_CONF_DIR}/postgresql.conf"
echo "== TLS: selbstsigniertes Zertifikat (LAN-Betrieb ohne Domain, Karte owasp-Review) =="
mkdir -p /etc/nginx/ssl
if [ ! -f /etc/nginx/ssl/mabea.crt ]; then
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
-keyout /etc/nginx/ssl/mabea.key -out /etc/nginx/ssl/mabea.crt \
-subj "/CN=${APP_DOMAIN}"
chmod 600 /etc/nginx/ssl/mabea.key
echo "Selbstsigniertes Zertifikat erzeugt (10 Jahre gültig) - Browser warnen beim ersten Zugriff, bis manuell akzeptiert/importiert."
else
echo "Zertifikat existiert bereits, überspringe."
fi
echo "== nginx Reverse-Proxy Config (inkl. Security-Header, TLS) =="
sed -e "s/__APP_DOMAIN__/${APP_DOMAIN}/g" \
"$(dirname "$0")/nginx_mabea.conf.template" > /etc/nginx/sites-available/mabea.conf
ln -sf /etc/nginx/sites-available/mabea.conf /etc/nginx/sites-enabled/mabea.conf
rm -f /etc/nginx/sites-enabled/default
nginx -t
echo "== Dienste aktivieren =="
systemctl enable --now postgresql
systemctl restart postgresql # Tuning-Konfiguration laden
systemctl enable --now nginx
systemctl reload nginx
echo "== Zugangsdaten sichern =="
CRED_FILE="/root/mabea_db_credentials.env"
umask 077
cat > "${CRED_FILE}" <<EOF
DB_NAME=${DB_NAME}
DB_USER=${DB_USER}
DB_PASSWORD=${DB_PASSWORD}
DATABASE_URL=postgresql+asyncpg://${DB_USER}:${DB_PASSWORD}@localhost:5432/${DB_NAME}
JWT_SECRET_KEY=${JWT_SECRET_KEY}
EOF
chmod 600 "${CRED_FILE}"
echo
echo "=== Fertig ==="
echo "Zugangsdaten liegen (chmod 600) in ${CRED_FILE} NICHT auf stdout ausgegeben (Review-Fund: keine Secrets im Terminal-Scrollback)."
echo "DATABASE_URL von dort in backend/.env auf dem Server übernehmen (siehe backend/example.env)."
echo "Backend selbst ist noch nicht deployt siehe deploy/mabea-backend.service.template für den späteren systemd-Dienst."
echo
echo "nginx läuft über HTTPS mit selbstsigniertem Zertifikat (Port 80 leitet auf 443 um)."
echo "Browser warnen beim ersten Zugriff - Zertifikat manuell akzeptieren/importieren."
echo "Sobald eine echte Domain feststeht: ssl_certificate/-key in /etc/nginx/sites-available/mabea.conf"
echo "auf ein Let's-Encrypt-Zertifikat umstellen (certbot)."