Thomas Stallinger cb820b9790 Security-Hardening vor öffentlicher Freigabe: Rate-Limiting, Passwort-Policy, Docs-Endpunkte, Security-Header
Sicherheits-Review 25.08.2026 vor geplanter öffentlicher Erreichbarkeit
über Pangolin (bisher nur Pangolin-interne Auth vorgeschaltet):

- auth.py: In-Memory-Rate-Limiting auf /login (je Email UND je Quell-IP,
  8 Fehlversuche / 10 Minuten), UserManager.validate_password() setzt
  jetzt eine Mindestlänge von 12 Zeichen durch (fastapi_users' Default
  war ein No-Op, ließ auch leere Passwörter zu).
- routers/admin_kunden.py, routers/organisation.py: fangen
  InvalidPasswordException/UserAlreadyExists jetzt sauber ab statt 500.
- app.py: /docs, /redoc, /openapi.json deaktiviert (legten zuvor die
  komplette Routenstruktur inkl. /admin/* offen), Security-Header-
  Middleware (X-Content-Type-Options, X-Frame-Options, Referrer-Policy,
  CSP).
- scripts/reset_password.py: neues Skript, Gegenstück zu create_user.py,
  für die im selben Review gefundenen aktiven Testaccounts mit dem
  Passwort 'test123' (einer davon Superuser) gebraucht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 12:14:34 +02:00
2026-08-06 08:29:51 +02:00

kundenplattform

Kunden-Web-UI für den Tuxflotte-Auftragskatalog — von provisioning-server (anode) bewusst getrennter Dienst, siehe ADR-0011.

Architektur

  • FastAPI + Jinja2 (serverseitig gerendert, kein Frontend-Build).
  • Eigene Postgres-Datenbank (benutzer-Tabelle: E-Mail/Passwort-Hash pro Organisation) — getrennt von provisioning-servers Datenbank, keine Cross-Database-Referenzen.
  • Spricht mit anode ausschließlich über dessen HTTP-API, authentifiziert mit einem eigenen Service-Token (TUXFLOTTE_KUNDENPLATTFORM_TOKEN, getrennt vom Admin-Token). Organisationszugehörigkeits-Prüfung (darf dieser Login auf dieses Gerät zugreifen?) passiert hier in der Anwendung, vor jedem Aufruf gegen anode — siehe find_device_in_organization() in app.py.

Setup (lokal)

python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
KUNDENPLATTFORM_DATABASE_URL=postgresql://... .venv/bin/psql ... -f migrations/0001_initial_schema.sql

Env-Variablen:

  • TUXFLOTTE_ANODE_URL (Default http://127.0.0.1:8080)
  • TUXFLOTTE_KUNDENPLATTFORM_TOKEN — muss mit dem gleichnamigen Wert in provisioning-servers /etc/tuxflotte/provisioning-server.env übereinstimmen
  • KUNDENPLATTFORM_DATABASE_URL
  • KUNDENPLATTFORM_SESSION_SECRET — beliebiger zufälliger String zum Signieren der Session-Cookie (z.B. openssl rand -base64 32)

Start: .venv/bin/uvicorn app:app --port 8081

Konto anlegen

Kein Self-Service in v1 (siehe ADR-0011) — Konten werden manuell angelegt:

KUNDENPLATTFORM_DATABASE_URL=... .venv/bin/python scripts/create_user.py \
    --organization-id <organization-uuid> \
    --email admin@schule-beispiel.de

Deploy (anode)

Wie bei provisioning-server, git-basiert statt scp:

git pull --ff-only
systemctl restart kundenplattform

Läuft unter einem eigenen, unprivilegierten System-User kundenplattform (nicht root, anders als provisioning-server) — siehe kundenplattform.service. Port 8081 (provisioning-server belegt 8080).

Öffentliche Erreichbarkeit über Pangolin ist nicht Teil dieses Repos — das ist ein separater Ops/DNS/Reverse-Proxy-Schritt.

Description
No description provided
Readme 310 KiB
Languages
Python 56.1%
HTML 42.3%
PLpgSQL 1.6%