my_voice_assistant_v2/deploy
Dieter Schlüter 881a5ac2de feat(auth): Forward-Auth via JWT-Cookie (YunoHost yunohost.portal)
Discovery zeigte: YunoHost reicht den Usernamen nicht als Header durch, sondern im
signierten Cookie "yunohost.portal" (JWT, Claim "user"). Die Forward-Auth liest jetzt
die Identitaet aus Header ODER Cookie - nur von der Proxy-Quell-IP akzeptiert.
HS256-Signaturpruefung optional via TRUSTED_AUTH_JWT_SECRET (stdlib hmac, kein Dep).

- config: trusted_auth_cookie / _cookie_claim / _jwt_secret
- nginx-Vorlage + deploy/README: keine Identitaets-Header-Zeile mehr noetig; SSO-Schutz
  der Subdomain ist Pflicht (sonst Spoofing)
- Tests: Cookie-Extraktion, Signaturpruefung, Proxy-IP-Trust

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 08:44:33 +02:00
..
README.md feat(auth): Forward-Auth via JWT-Cookie (YunoHost yunohost.portal) 2026-06-18 08:44:33 +02:00
va.linix.de.nginx.conf feat(auth): Forward-Auth via JWT-Cookie (YunoHost yunohost.portal) 2026-06-18 08:44:33 +02:00
voice-assistant.env.example feat(web): Remote-Web-UI mit Mikrofon + Forward-Auth (YunoHost-SSO) 2026-06-18 04:37:16 +02:00
voice-assistant.service Initial commit: Voice Assistant Gateway mit Konfig-/Routing-Fundament 2026-06-17 01:48:56 +02:00

Remote-Betrieb über YunoHost (va.linix.de)

Web-UI + Mikrofon vom Handy/Browser, abgesichert per HTTPS und YunoHost-SSO. Topologie: https://va.linix.de → nginx@YunoHost (TLS, SSO) → über LAN → http://<GPU-Box>:8003 (Gateway). Der interne LAN-Hop ist unverschlüsselt (vertrautes LAN, wie bei Ollama).

Warum HTTPS Pflicht ist: Browser geben das Mikrofon (getUserMedia) nur in einem „secure context" frei also HTTPS oder http://localhost. Über einfaches http:// vom Handy gibt es kein Mikrofon.

1. Gateway auf der GPU-Box

deploy/voice-assistant.env.example/etc/voice-assistant/voice-assistant.env anpassen:

  • HOST = LAN-IP der GPU-Box (nicht 0.0.0.0), PORT=8003
  • AUTH_ENABLED=true
  • TRUSTED_AUTH_HEADER (nach Discovery, s. u.), TRUSTED_PROXY_IPS = LAN-IP von linix.de
  • ADMIN_USERS=atoor,dieterschlueter,dschlueter, SSO_LOGOUT_URL=…

Kein --forwarded-allow-ips setzen: Das Identitäts-Vertrauen prüft die direkte Quell-IP (= der Proxy). Würde uvicorn den Client aus X-Forwarded-For überschreiben, schlüge der Proxy-IP-Check fehl.

2. Drei Sicherheits-Pflichten

  1. Bind: Gateway nur an die LAN-IP (Schritt 1).
  2. Firewall: Port 8003 der GPU-Box nur von der linix.de-IP erlauben, z. B.:
    sudo ufw allow from <linix.de_LAN_IP> to any port 8003 proto tcp
    sudo ufw deny 8003
    
  3. Header überschreiben: nginx setzt den Identitäts-Header selbst; Client-Eingaben werden verworfen (siehe nginx-Conf). App-seitig zusätzlich der Proxy-IP-Check.

3. nginx auf YunoHost

deploy/va.linix.de.nginx.conf als Vorlage → auf dem YunoHost-Server unter /etc/nginx/conf.d/va.linix.de.d/assistant.conf ablegen, GPU_BOX_LAN_IP eintragen, die map $http_upgrade … einmalig im http{}-Kontext anlegen, dann nginx -t && systemctl reload nginx. Subdomain va.linix.de in YunoHost anlegen (Let's Encrypt) und per SSO schützen (nur erlaubte Tester/Gruppe).

Discovery (/api/admin/request-headers?key=<ADMIN_API_KEY> hinter dem SSO) zeigt: YunoHost reicht den Usernamen nicht als eigenen Header durch, sondern im JWT-Cookie yunohost.portal (Claim user). Das Gateway liest diesen Cookie direkt — daher:

# .env auf der GPU-Box:
TRUSTED_AUTH_COOKIE=yunohost.portal
TRUSTED_AUTH_COOKIE_CLAIM=user
TRUSTED_PROXY_IPS=<LAN-IP des YunoHost-Servers>
# optional (Härtung): HS256-Secret des Portals -> Signaturpruefung
# TRUSTED_AUTH_JWT_SECRET=...

In der nginx-Conf ist keine proxy_set_header-Identitätszeile nötig — Cookies werden ohnehin durchgereicht.

Sicherheit: Ohne TRUSTED_AUTH_JWT_SECRET wird die Cookie-Payload ungeprüft gelesen. Das ist nur sicher, weil (a) nur die Proxy-Quell-IP akzeptiert wird und (b) die Subdomain per SSO geschützt sein muss (dann lässt YunoHost nur validierte Cookies durch). Für Härtung das Portal-HS256-Secret in TRUSTED_AUTH_JWT_SECRET setzen → die Signatur wird dann selbst geprüft.

5. Test

  • https://va.linix.de/ lädt die UI, links „Angemeldet als ".
  • Text-Chat funktioniert; Mikrofon-Button nimmt auf und spielt die Antwort ab.
  • Admins (ADMIN_USERS) sehen den Admin-Bereich (Nutzerliste).