add admin stuff
This commit is contained in:
187
README.md
187
README.md
@ -1,23 +1,23 @@
|
||||
# Jumphost Gateway — Implementierung
|
||||
|
||||
Umsetzung des Konzepts `Jumphost_Konzept.md` (v0.2): browserbasiertes
|
||||
SSH/RDP-Gateway mit TOTP-Pflicht, Hostgruppen-RBAC, manipulationssicherem
|
||||
Audit-Log, SQLite/Python-Backend und Ansible-Deployment (mit/ohne nginx,
|
||||
mehrere TLS-Modi).
|
||||
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
|
||||
auth/ Login-Flow, RBAC-Dependencies
|
||||
admin/ Admin-API (User/Hosts/Hostgruppen/Rollen/SSH-Keys)
|
||||
catalog/ Sicht fuer normale Nutzer (nur zugewiesene Hosts)
|
||||
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
|
||||
static/, templates/ Frontend (Vanilla JS, xterm.js, guacamole-common-js)
|
||||
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
|
||||
@ -40,12 +40,70 @@ python scripts/create_admin.py --username admin # in zweitem Terminal
|
||||
```
|
||||
|
||||
Danach `http://127.0.0.1:8000/` oeffnen, anmelden, TOTP einrichten (QR-Code
|
||||
scannen). Fuer echte SSH-/RDP-Sessions muessen zuvor ueber die Admin-API
|
||||
(`/admin/host-groups`, `/admin/hosts`, `/admin/ssh-keys`,
|
||||
`/admin/hosts/{id}/ssh-keys/{id}`, `/admin/hosts/{id}/rdp-credentials`,
|
||||
`/admin/roles/grant`) Hostgruppen, Hosts, Schluessel/Zugangsdaten und
|
||||
Rollenzuweisungen angelegt werden. Fuer RDP muss zusaetzlich ein laufender
|
||||
`guacd` erreichbar sein (siehe `JUMPHOST_GUACD_HOST`/`_PORT`).
|
||||
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
|
||||
|
||||
@ -53,16 +111,34 @@ Rollenzuweisungen angelegt werden. Fuer RDP muss zusaetzlich ein laufender
|
||||
pytest -q
|
||||
```
|
||||
|
||||
27 Tests decken ab: Argon2id/TOTP-Grundfunktionen, Audit-Hash-Chain (inkl.
|
||||
Manipulationserkennung und Trigger-Durchsetzung), RBAC-Logik inkl.
|
||||
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, sowie
|
||||
17 dedizierte Security-/Pentest-Tests (`tests/test_pentest_security.py`) zu
|
||||
Auth-Bypass, Cookie-/Session-Manipulation, RBAC/IDOR, Injection-Versuchen,
|
||||
Rate-Limiting/Lockout, Filetransfer-Haertung, Security-Headern und
|
||||
Audit-Vollstaendigkeit. Details, Vorgehen und Ergebnisse: siehe
|
||||
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 -q` ausgefuehrt werden, da diese Sandbox keinen Netzwerkzugriff
|
||||
> auf PyPI hat und `fastapi`/`aiosqlite` dort nicht vorinstalliert sind.
|
||||
> Stattdessen wurden alle neuen/gaenderten SQL-Queries gegen eine echte
|
||||
> `sqlite3`-Instanz mit allen 5 Migrationen (inkl. der beiden neuen) manuell
|
||||
> durchgespielt, `app/security/api_tokens.py` und die neuen Pydantic-Schemas
|
||||
> direkt importiert und mit echten Assertions verifiziert, und alle
|
||||
> geaenderten Python-/JS-Dateien mit `py_compile`/`node --check` auf
|
||||
> Syntaxfehler geprueft. Bitte `pytest -q` lokal 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-
|
||||
@ -71,19 +147,23 @@ Chain-Verifikation per `/admin/audit-log/verify`.
|
||||
## Security-Tests & Haertungs-Nachweis
|
||||
|
||||
- **SAST**: `bandit -r app -c .bandit.yml` sowie `pip-audit` (Dependency-CVE-
|
||||
Scan) laufen sauber durch (0 Findings, 0 bekannte Schwachstellen) — Details
|
||||
inkl. vorher/nachher-Tabellen und der dabei gefundenen und gefixten
|
||||
Starlette-Regression in `Pentest_Report.md`.
|
||||
- **DAST**: `tests/test_pentest_security.py` (17 Tests, s.o.) simuliert
|
||||
konkrete Angriffsmuster gegen die laufende ASGI-App.
|
||||
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 in `Pentest_Report.md`.
|
||||
Fuer die in dieser Session neu hinzugekommenen Dateien (Admin-Oberflaeche,
|
||||
Gruppen-RBAC, API-Tokens) steht ein erneuter `bandit`/`pip-audit`-Lauf noch
|
||||
aus (keine neuen Fremdabhaengigkeiten hinzugekommen).
|
||||
- **DAST**: `tests/test_pentest_security.py` (17 Tests) sowie
|
||||
`tests/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 dieser 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`.
|
||||
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.txt` exakt
|
||||
auf gegen `pip-audit` gepruefte Versionen gepinnt (u.a. fastapi 0.141.1,
|
||||
starlette 1.6.0, cryptography 50.0.0) — bewusste Reproduzierbarkeits-/
|
||||
@ -103,26 +183,28 @@ ansible-playbook -i inventory/production.ini site.yml --ask-vault-pass
|
||||
/ `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 dieser
|
||||
Session verifiziert); ein voller `--check`-Lauf gegen eine echte
|
||||
`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.
|
||||
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 dieser
|
||||
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:
|
||||
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:
|
||||
|
||||
1. **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 Security-Tests, siehe `Pentest_Report.md`).
|
||||
(17+14 Security-/Admin-Tests, siehe `Pentest_Report.md` bzw. oben).
|
||||
2. **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
|
||||
@ -135,10 +217,10 @@ massgebliche, aktuelle Fassung dieser Liste. Kurzfassung:
|
||||
`ansible-playbook site.yml --syntax-check` sowie YAML-/Jinja2-Parsing
|
||||
verifiziert, siehe `ansible/roles/os_hardening/CIS_STIG_MAPPING.md`.
|
||||
4. **OpenSCAP-Compliance-Scan** (`oscap xccdf eval`) gegen das zutreffende
|
||||
CIS/STIG-Profil — die `os_hardening`-Rolle wurde in dieser 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.
|
||||
CIS/STIG-Profil — die `os_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.
|
||||
5. **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.
|
||||
@ -154,3 +236,12 @@ massgebliche, aktuelle Fassung dieser Liste. Kurzfassung:
|
||||
9. **Social Engineering / physische Sicherheit / Lastest (DoS)** wurden
|
||||
nicht getestet — ausserhalb des Scopes eines Code-/Konfigurations-Reviews
|
||||
in dieser Sandbox-Umgebung.
|
||||
10. **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.
|
||||
11. 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).
|
||||
</content>
|
||||
|
||||
Reference in New Issue
Block a user