14 KiB
Jumphost Gateway — Implementierung
Umsetzung des Konzepts Jumphost_Konzept.md (v0.2): browserbasiertes
SSH/RDP-Gateway mit TOTP-Pflicht, Gruppen-/Hostgruppen-RBAC, manipulationssicherem
Audit-Log, SQLite/Python-Backend, browserbasierter Admin-Oberflaeche und
Ansible-Deployment (mit/ohne nginx, mehrere TLS-Modi).
Verzeichnisstruktur
app/ Backend (FastAPI, Python 3.11+)
security/ Crypto, Passwoerter, TOTP, Sessions, Audit-Hash-Chain, AV-Scan, API-Tokens
auth/ Login-Flow, RBAC-/Token-Dependencies
admin/ Admin-API (User/Gruppen/Hosts/Hostgruppen/Rollen/SSH-Keys/API-Tokens)
catalog/ Sicht fuer normale Nutzer (direkt und ueber Gruppen zugewiesene Hosts)
ssh_proxy/ SSH-Terminal-WebSocket + SFTP-Filetransfer
rdp_proxy/ Guacamole-Protokoll-Tunnel zu guacd
recordings/ Hash-verkettete Session-Aufzeichnung
db/ SQLite-Migrationen (0001-0005, laufen automatisch beim Start)
static/, templates/ Frontend (Vanilla JS, xterm.js, guacamole-common-js, Admin-Oberflaeche, API-Doku)
scripts/ Betriebs-/Hilfsskripte (Admin anlegen, Assets bauen)
ansible/ Deployment (Rollen, systemd-Unit-Templates)
tests/ pytest-Suite
Lokale Entwicklung / Ausprobieren
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements-dev.txt
bash scripts/fetch_frontend_assets.sh # vendored xterm.js / guacamole-common-js
export JUMPHOST_ENV=development
export JUMPHOST_DATA_DIR=/tmp/jumphost-dev
export JUMPHOST_DEV_KEK=$(python3 -c "import secrets;print(secrets.token_hex(32))")
export JUMPHOST_DEV_SESSION_SECRET=$(python3 -c "import secrets;print(secrets.token_hex(32))")
uvicorn app.main:app --reload --port 8000
python scripts/create_admin.py --username admin # in zweitem Terminal
Danach http://127.0.0.1:8000/ oeffnen, anmelden, TOTP einrichten (QR-Code
scannen). Auf dem Dashboard erscheint fuer Admin-Konten oben rechts der Link
"Admin-Bereich" (/admin) — darueber lassen sich Benutzer, Benutzergruppen,
Hostgruppen/Hosts/SSH-Keys/RDP-Zugangsdaten, Rollenzuweisungen (direkt und
gruppenweise) sowie API-Tokens vollstaendig ueber die Oberflaeche anlegen und
verwalten; ein manueller Umweg ueber die rohe JSON-API ist dafuer nicht mehr
noetig. Fuer RDP muss zusaetzlich ein laufender guacd erreichbar sein (siehe
JUMPHOST_GUACD_HOST/_PORT).
Die SQLite-Migrationen 0004 (user_groups) und 0005 (api_tokens) werden
beim naechsten Start automatisch angewendet (app/db.py, _apply_migrations)
— kein manueller Migrationsschritt noetig, auch nicht bei einem bestehenden
Datenbestand.
Admin-Oberflaeche, Gruppen-RBAC, API-Tokens und API-Dokumentation
In dieser Session wurde die bis dahin nur per JSON-API bedienbare Verwaltung
um eine vollstaendige, CSP-konforme Web-Oberflaeche unter /admin erweitert
(templates/admin.html, static/js/admin.js), erreichbar nur fuer Admin-
Konten. Tabs: Benutzer, Benutzergruppen, Hosts & Verbindungen (inkl.
Connection-Anlage: Hostgruppe, Host, SSH-Key bzw. RDP-Zugangsdaten in einem
Formular), Rollen, API-Tokens, Audit-Log.
Gruppen-RBAC (Migration 0004_user_groups.sql): Neu sind
Benutzergruppen (user_groups/user_group_members) als Teams von
Personen, unabhaengig von den bestehenden Hostgruppen (Server-Gruppen).
Eine Rolle kann einer Benutzergruppe auf eine Hostgruppe gewaehrt werden
(group_hostgroup_roles) — das ist das "Sharen einer Verbindung mit einer
Gruppe". Es gilt volle Rollen-Vererbung: jedes Mitglied einer Gruppe hat
automatisch alle Rollen, die dieser Gruppe gewaehrt wurden, zusaetzlich zu
seinen individuell zugewiesenen (user_hostgroup_roles, unveraendert
bestehen geblieben). app/rbac.py::user_has_role() prueft dafuer beide
Zuweisungswege (UNION-Query); app/catalog/routes.py (Host-Liste fuer
normale Nutzer) beruecksichtigt beide ebenso.
API-Tokens (Migration 0005_api_tokens.sql, app/security/api_tokens.py):
Jeder Admin kann unter dem Tab "API-Tokens" persoenliche Tokens erzeugen
(Authorization: Bearer <token>), mit granularen Read/Write-Scopes pro
Ressource (z. B. hosts:ro, hosts:rw, users:ro, groups:rw, ...
vollstaendige Liste unter GET /admin/scopes). Tokens werden nur gehasht
gespeichert (Klartext ist nur einmal direkt nach dem Anlegen sichtbar) und
koennen jederzeit widerrufen werden. app/auth/deps.py::require_admin_or_scope()
akzeptiert entweder eine gueltige Admin-Session (Cookie, wie bisher) oder
einen Token mit passendem Scope — niemals beides vermischt: sobald ein
Authorization-Header vorhanden ist, wird ausschliesslich er geprueft, ein
evtl. noch gueltiges Session-Cookie wird dabei ignoriert. Aus Gruenden der
Rechte-Eskalation sind die Token-Verwaltungs-Endpunkte selbst
(/admin/tokens/*) bewusst nicht per Token nutzbar, sondern ausschliesslich
per Admin-Session (require_global_admin) — ein geleaktes Token kann also nie
weitere Tokens anlegen, auflisten oder widerrufen. Tokens sind ausschliesslich
fuer die Management-API vorgesehen; SSH-/RDP-/SFTP-Sitzungen bleiben
Session-Cookie-authentifiziert.
API-Dokumentation (/docs, /openapi.json): Nur fuer eingeloggte Admins
sichtbar (Depends(require_global_admin) auf beiden Routen in app/main.py)
— das bestehende Haertungskonzept, /docs//redoc//openapi nicht oeffentlich
per FastAPI-Default auszuliefern (docs_url=None, redoc_url=None, openapi_url=None), bleibt unangetastet. Die Ansicht selbst
(templates/api_docs.html, static/js/api-docs.js) ist bewusst kein
vendored/CDN-bezogenes Swagger-UI-Bundle, sondern ein selbstgebauter,
CSP-konformer Viewer ohne jede Laufzeit-Abhaengigkeit zu Drittanbietern: er
liest /openapi.json per fetch() (credentials: "same-origin") und
rendert Endpunkte gruppiert nach Tag, ausschliesslich per
document.createElement/textContent (kein innerHTML, keine Inline-
Styles/-Scripts, siehe tests/test_csp_compliance.py).
Tests
pytest -q
46 Tests (vorher 27) decken ab: Argon2id/TOTP-Grundfunktionen, Audit-Hash-Chain
(inkl. Manipulationserkennung und Trigger-Durchsetzung), RBAC-Logik inkl.
Ablaufdaten, den vollstaendigen Login-Flow (Passwort -> TOTP-Enrollment ->
Session-Cookie -> geschuetzte Endpunkte) gegen die echte FastAPI-App, 17
dedizierte Security-/Pentest-Tests (tests/test_pentest_security.py), 5
CSP-Regressionstests (tests/test_csp_compliance.py, inkl. /admin und
/docs) sowie 14 neue Tests zu Gruppen-RBAC-Vererbung, Admin-Oberflaeche und
API-Tokens (tests/test_admin_groups_tokens.py): Rollen-Vererbung ueber
Gruppenmitgliedschaft, dass Gruppenrollen NICHT auf Nicht-Mitglieder wirken,
Admin-only-Durchsetzung fuer alle neuen Endpunkte, Token-Scope-Durchsetzung
(read/write/implizites read-bei-write/widerrufen/abgelaufen/unbekannter
Scope), dass ein Token niemals andere Tokens verwalten kann (Rechte-
Eskalationsschutz), sowie Admin-Gating von /docs und /openapi.json.
Details, Vorgehen und Ergebnisse der urspruenglichen 27 Tests: siehe
Pentest_Report.md.
Hinweis: Die 19 in dieser Session neu hinzugekommenen Tests (5 CSP + 14 Admin/Gruppen/Token) konnten in der verwendeten Cloud-Sandbox nicht mit
pytest -qausgefuehrt werden, da diese Sandbox keinen Netzwerkzugriff auf PyPI hat undfastapi/aiosqlitedort nicht vorinstalliert sind. Stattdessen wurden alle neuen/gaenderten SQL-Queries gegen eine echtesqlite3-Instanz mit allen 5 Migrationen (inkl. der beiden neuen) manuell durchgespielt,app/security/api_tokens.pyund die neuen Pydantic-Schemas direkt importiert und mit echten Assertions verifiziert, und alle geaenderten Python-/JS-Dateien mitpy_compile/node --checkauf Syntaxfehler geprueft. Bittepytest -qlokal ausfuehren und Ergebnis melden.
Manuell zusaetzlich verifiziert (siehe Entwicklungs-Log dieser Session):
Server-Start, Static-/Template-Auslieferung, Security-Header, vollstaendiger
Login+TOTP-Flow per curl, Admin-CRUD (Hostgruppe/Host anlegen), Audit-Log-
Chain-Verifikation per /admin/audit-log/verify.
Security-Tests & Haertungs-Nachweis
- SAST:
bandit -r app -c .bandit.ymlsowiepip-audit(Dependency-CVE- Scan) liefen zu Beginn dieser Implementierung sauber durch (0 Findings, 0 bekannte Schwachstellen) — Details inkl. vorher/nachher-Tabellen und der dabei gefundenen und gefixten Starlette-Regression inPentest_Report.md. Fuer die in dieser Session neu hinzugekommenen Dateien (Admin-Oberflaeche, Gruppen-RBAC, API-Tokens) steht ein erneuterbandit/pip-audit-Lauf noch aus (keine neuen Fremdabhaengigkeiten hinzugekommen). - DAST:
tests/test_pentest_security.py(17 Tests) sowietests/test_admin_groups_tokens.py(14 Tests, s.o.) simulieren konkrete Angriffsmuster gegen die laufende ASGI-App. - OS-Haertung (CIS/STIG): die
ansible/roles/os_hardening-Rolle wurde in einer frueheren Session um ~10 zusaetzliche Task-Dateien vertieft (Kernel-Module, sysctl, PAM/Passwort-Policy, erweiterte auditd-Regeln, AIDE, rkhunter, Banner, cron/at-Restriktion, Dateirechte/sudo-Logging, SSHD-Haertung). Vollstaendiges Mapping auf CIS-Controls inkl. bewusst nicht automatisierter Punkte (mit Begruendung, z.B. Partitionslayout, Bootloader-Passwort, Volltextverschluesselung, physische Sicherheit) und bekannter Einschraenkungen:ansible/roles/os_hardening/CIS_STIG_MAPPING.md. - Abhaengigkeiten sind in
requirements.txt/requirements-dev.txtexakt auf gegenpip-auditgepruefte Versionen gepinnt (u.a. fastapi 0.141.1, starlette 1.6.0, cryptography 50.0.0) — bewusste Reproduzierbarkeits-/ Haertungsmassnahme, siehePentest_Report.mdAbschnitt 2.
Deployment
cd ansible
cp inventory/production.ini.example inventory/production.ini # anpassen
cp inventory/group_vars/jumphost_with_nginx.yml.example inventory/group_vars/jumphost_with_nginx.yml
ansible-vault encrypt inventory/group_vars/vault.yml # vorher aus vault.yml.example befuellen
ansible-playbook -i inventory/production.ini site.yml --ask-vault-pass
enable_nginx_proxy und tls_mode (internal_pki / external_reverse_proxy
/ acme_public) steuern Proxy- und TLS-Verhalten, siehe Konzept Kap. 7.2/7.2a
und ansible/inventory/group_vars/all.yml.
ansible-playbook site.yml --syntax-check laeuft sauber durch (in einer
frueheren Session verifiziert); ein voller --check-Lauf gegen eine echte
Testumgebung (inkl. apt, systemd, guacd-Paketverfuegbarkeit auf der
Zieldistribution) steht noch aus. Ein Neustart des Dienstes (systemctl restart jumphost) reicht aus, damit die Migrationen 0004/0005 angewendet
werden.
Was bewusst noch offen ist
Diese Implementierung ist ein funktionsfaehiges, getestetes und in einer
frueheren Session per SAST+DAST geprueftes Grundgeruest, aber weiterhin
kein fertig auditiertes Produktivsystem. Der vollstaendige Befund inkl.
Methodik, Vorgehen und Restrisikobewertung steht in Pentest_Report.md — die
dortige Abschnitt-4-Tabelle ("Restrisiko / vor Produktivbetrieb noch zu tun")
ist die massgebliche, aktuelle Fassung dieser Liste. Kurzfassung:
- Echter Netzwerk-Penetrationstest gegen eine laufende Instanz
(Portscan, TLS-Konfiguration live, Session-Isolation unter Last,
Guacamole-Protokoll-Fuzzing) — in dieser Sandbox ohne Netzwerkzugriff auf
ein reales Zielsystem nicht durchfuehrbar. Was stattdessen gemacht wurde:
SAST (bandit, pip-audit) und ein DAST-Testlauf gegen die App im Prozess
(17+14 Security-/Admin-Tests, siehe
Pentest_Report.mdbzw. oben). - RDP/guacd-Integrationstest gegen echte Zielsysteme — die
Guacamole-Protokoll-Implementierung (
app/rdp_proxy/guacd_client.py) wurde gegen die Protokollspezifikation implementiert und die Handshake-Logik lokal auf Korrektheit der Kodierung geprueft, aber NICHT gegen einen laufendenguacd+ FreeRDP + Windows-Ziel end-to-end getestet (keine RDP-Zielumgebung in dieser Sitzung verfuegbar). Parameter-Namen/-Reihenfolge sollten gegen die tatsaechlich eingesetzte guacd-Version verifiziert werden. - Ansible-Rollout gegen ein reales Zielsystem (
--check-Dry-Run und echter Rollout in einer Staging-Umgebung) — bisher nuransible-playbook site.yml --syntax-checksowie YAML-/Jinja2-Parsing verifiziert, sieheansible/roles/os_hardening/CIS_STIG_MAPPING.md. - OpenSCAP-Compliance-Scan (
oscap xccdf eval) gegen das zutreffende CIS/STIG-Profil — dieos_hardening-Rolle wurde in einer frueheren Session um ca. 10 Task-Dateien vertieft (siehe CIS_STIG_MAPPING.md fuer das vollstaendige Mapping inkl. bewusst nicht automatisierter Punkte), ersetzt aber keinen zertifizierten Benchmark-Scan. - Verteiltes Rate-Limiting — der aktuelle Login-Rate-Limiter ist
In-Memory/Single-Process (siehe
app/security/rate_limit.py); bei horizontaler Skalierung durch einen geteilten Store ersetzen. - fail2ban-Filter setzt strukturierte Access-Logs mit
client_ip=-Feld voraus, die die App aktuell nicht schreibt — vor Produktivbetrieb ein Access-Log-Middleware ergaenzen oder auf das Audit-Log umstellen. - CSRF: SameSite=Strict-Cookies mindern das Risiko bereits deutlich; ein expliziter CSRF-Token fuer zustandsaendernde JSON-Requests ist als zusaetzliche Haertungsstufe vorgesehen, aber noch nicht implementiert.
- Alle in Konzept Kap. 12 genannten Erweiterungen (LDAP/AD, WebAuthn, PostgreSQL-Migrationspfad, Just-in-Time-Zugriff, HA) sind noch nicht umgesetzt.
- Social Engineering / physische Sicherheit / Lastest (DoS) wurden nicht getestet — ausserhalb des Scopes eines Code-/Konfigurations-Reviews in dieser Sandbox-Umgebung.
- API-Token-Rotation/-Ablaufrichtlinien: Tokens koennen zwar mit optionalem Ablaufdatum erzeugt und jederzeit widerrufen werden, aber es gibt noch keine erzwungene maximale Laufzeit, keine automatische Benachrichtigung vor Ablauf und keine "Token zuletzt benutzt vor X Tagen -> automatisch deaktivieren"-Routine.
- Ein erneuter
bandit/pip-audit-Lauf ueber die in dieser Session neu hinzugekommenen Dateien (Admin-Oberflaeche, Gruppen-RBAC, API-Tokens) steht noch aus (siehe oben).