Tokens & API-Keys¶
Drei Token-Klassen, drei Speicher-Formen.
User-JWT¶
Standard-Login-Token nach erfolgreichem Login + 2FA.
| Feld | Wert |
|---|---|
| Format | RS256-signierter JWT |
| Claims | sub (User-ID), tenant_id, tenant_scope, permissions[], exp |
| Lebensdauer | Default 24 h, refreshbar |
| Secret | SECRET_KEY (RSA-Privatekey, eigentlich HMAC-Symmetric in default) |
| Speicherung | im Browser (HttpOnly Cookie + localStorage), in der Mobile-App AsyncStorage |
Refresh¶
Vor Ablauf wird automatisch ein neuer Token geholt — solange der Refresh-Token gültig ist (Default 7 Tage). Refresh-Token wird beim Logout invalidiert.
Invalidierung¶
Es gibt keinen serverseitigen JWT-Blocklist (kostet zu viel). Bei Logout: Frontend wirft den Token weg. Bei Account-Sperrung: users.active = false führt dazu, dass eine ResourceLookup auf den User in zukünftigen Requests fehlschlägt — der Token verfällt effektiv beim nächsten Request.
JWT-Token im Browser sind so sicher wie der Browser
XSS-Schutz ist Pflicht: CSP-Header strikt, keine User-Inhalte als HTML einbetten ohne Escape, Wiki-Markdown wird sanitized. Alles im Frontend.
Agent-Token¶
Für Agents auf überwachten Maschinen.
| Feld | Wert |
|---|---|
| Format | vesana_agent_<32 url-safe Base64> |
| Speicherung Server | SHA256-Hash in agent_tokens.token_hash |
| Speicherung Agent | Klartext in /etc/vesana-agent/config.yaml (chmod 600) |
| Lebensdauer | unbegrenzt |
| Bindung | 1:1 an einen Host |
| Auth-Header | X-Agent-Token: vesana_agent_xxxx |
Generierung¶
Nur in der UI auf der Host-Detail-Seite. Klartext wird genau einmal angezeigt. Backend speichert nur den Hash.
Rotation¶
Host-Detail-Seite → Token widerrufen → neuer Token. Auf der Maschine muss die Config angepasst werden, sonst meldet sich der Agent mit 401.
Alternativ: Re-Install via One-Command-Installer mit neuem Token.
Collector-API-Key¶
Für Collectors im Kundennetz.
| Feld | Wert |
|---|---|
| Format | vesana_<custom-prefix>_<32 Bytes> |
| Speicherung Server | SHA256-Hash in api_keys.key_hash |
| Speicherung Collector | Klartext in /etc/vesana/collector.env |
| Auth-Header | X-API-Key: vesana_xxxxx |
| Bindung | 1:1 an einen Collector |
key_prefix wird seit v0.x für neue Keys nicht mehr geschrieben (nur leerer String). Lookup im Receiver erfolgt ausschließlich über key_hash.
Personal-Access-Tokens¶
Über /profile → API-Keys können auch User persönliche API-Keys generieren — für CLI-Scripts, eigene Integrationen.
| Feld | Wert |
|---|---|
| Scope | read-only / read-write |
| Ablauf | Pflicht (max 1 Jahr) |
| Tenant-Scope | wie der User |
Nutzung: Authorization: Bearer <pat>.
Rotation: alten Key widerrufen → neuen erzeugen. Empfehlung: Keys mindestens jährlich tauschen.
Hashing¶
Alle Tokens sind als SHA256-Hash in der DB. Vorteil:
- DB-Leak verrät keinen funktionierenden Token
- Vergleich auch mit gehashten Werten ist O(1) bei Index
Wir nutzen kein Salt, weil Tokens selbst zufällig genug sind (32 Bytes Entropie >> brute-forcebar).
TLS-Pflicht¶
Tokens werden ausschließlich über HTTPS akzeptiert. Bei HTTP-Requests antwortet der Server mit Redirect (Frontend) oder 426 Upgrade-Required (API). Self-Signed-Certs sind ok für Tests, in Production: Let's-Encrypt oder eigenes Cert.
Audit¶
Token-Operationen (Create / Revoke) landen im Audit-Log mit action = agent_token.create / .revoke / api_key.create / .revoke.
Diebstahl-Erkennung¶
| Symptom | Mögliche Ursache |
|---|---|
| Agent-Token meldet sich von zwei IPs | Token kompromittiert oder Klon |
| API-Key wird plötzlich für ungewöhnliche Endpoints genutzt | PAT vielleicht in Repo gepushed |
| User-JWT ist auf zwei Geräten aktiv | normal — kein Problem |
Für Agent- und Collector-Tokens: Multi-IP-Heuristik in der UI (Spalte „Letzte IP") hilft, Anomalien zu sehen.