docs: update hermes-hub-deploiement.md with WebSocket proxy bridge architecture and live test verification
This commit is contained in:
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
**Instance auteur** : gemini / nabil
|
**Instance auteur** : gemini / nabil
|
||||||
**Date** : 2026-08-20
|
**Date** : 2026-08-20
|
||||||
**Tags** : hermes, hub, multi-univers, vps, tailscale, cloudflare-access, fastapi, subdomains, filebrowser, dsh, basic-auth, security-audit, stateless-proxy
|
**Tags** : hermes, hub, multi-univers, vps, tailscale, cloudflare-access, fastapi, subdomains, filebrowser, dsh, basic-auth, security-audit, stateless-proxy, websocket-bridge
|
||||||
**Statut** : valide (testé et vérifié en direct sur VPS Contabo avec transport HTTP 100% sans état)
|
**Statut** : valide (testé et vérifié en direct sur VPS Contabo avec transport HTTP 100% sans état et passerelle WebSocket bidirectionnelle)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -17,24 +17,28 @@ Nabil dispose de 4 instances Hermes strictement cloisonnées :
|
|||||||
|
|
||||||
L'objectif est d'offrir une interface web unifiée sur le VPS Contabo (`100.94.90.119`) avec :
|
L'objectif est d'offrir une interface web unifiée sur le VPS Contabo (`100.94.90.119`) avec :
|
||||||
1. Un **Workspace Switcher** latéral fluide et étanche entre les 4 univers.
|
1. Un **Workspace Switcher** latéral fluide et étanche entre les 4 univers.
|
||||||
2. Un **Sélecteur Toggle DSH** (conception Claude Design) pour basculer instantanément entre la session et l'explorateur de fichiers DSH (`https://dsh.hub.yesminedor.tn/`).
|
2. Un **Sélecteur Toggle DSH** pour basculer instantanément entre la session et l'explorateur de fichiers DSH (`https://dsh.hub.yesminedor.tn/`).
|
||||||
3. L'absence totale de fuite de contexte, de mémoire JS ou de cookies de session entre univers.
|
3. L'absence totale de fuite de contexte, de mémoire JS ou de cookies de session entre univers.
|
||||||
4. La résolution 100% native des assets absolus (`/assets/main-*.js`) via un routage par **sous-domaine dédié** (`*.hub.yesminedor.tn`).
|
4. La résolution 100% native des assets absolus (`/assets/main-*.js`) via un routage par **sous-domaine dédié** (`*.hub.yesminedor.tn`).
|
||||||
5. La sécurisation intégrale via **Cloudflare Access** (OTP Email + 2FA) et **Basic Auth** scrypt avec secret de session cryptographique aléatoire 32 bytes (HMAC-SHA256).
|
5. La sécurisation intégrale via **Cloudflare Access** (OTP Email + 2FA) et **Basic Auth** scrypt avec secret de session cryptographique aléatoire 32 bytes (HMAC-SHA256).
|
||||||
6. L'étanchéité absolue du proxy via un transport HTTP **100% stateless** (`httpx.AsyncHTTPTransport`) interdisant toute rétention ou réutilisation de cookies en mémoire entre requêtes.
|
6. L'étanchéité absolue du proxy via un transport HTTP **100% stateless** (`httpx.AsyncHTTPTransport`) interdisant toute rétention ou réutilisation de cookies en mémoire entre requêtes.
|
||||||
|
7. Une **passerelle WebSocket bidirectionnelle full-duplex** (`proxy_websocket` via `websockets`) pour le streaming en temps réel des chats, des événements (`/api/events`), des terminaux interactifs (`/api/pty`) et de la console (`/api/console`).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Cause de l'incident et Résolution Architectural
|
## Architecture WebSocket Proxy
|
||||||
|
|
||||||
### 1. Cause racine identifiée
|
### 1. Mécanisme
|
||||||
Le proxy utilisait un singleton `httpx.AsyncClient` partagé. Par défaut dans HTTPX, un client gère un cookie jar interne (`client.cookies`). Lors d'un test de connexion administrateur via le Hub, HTTPX a extrait et conservé le cookie de session `hermes_session_at` dans sa mémoire globale, puis l'a injecté silencieusement dans les requêtes anonymes suivantes.
|
La route générique `@app.websocket("/{path:path}")` intercepte toutes les requêtes d'upgrade WebSocket :
|
||||||
|
- Résolution de la cible backend via l'en-tête `Host` (`tt.hub.yesminedor.tn`, `nabil.hub.yesminedor.tn`, etc.) ou par sous-chemin (`/u/{id}/*`).
|
||||||
|
- Établissement d'une connexion WebSocket amont vers l'instance Hermes ciblée (`ws://hermes-nabil:9119/api/ws?ticket=...`).
|
||||||
|
- Transfert transparent des cookies et headers d'authentification tout en filtrant les en-têtes hop-by-hop (`upgrade`, `sec-websocket-key`, etc.).
|
||||||
|
- Exécution de deux boucles asynchrones concurrentes (`client_to_upstream` et `upstream_to_client`) assurant le multiplexage des trames texte/binaire en duplex intégral.
|
||||||
|
|
||||||
### 2. Correctif architectural appliqué
|
### 2. Validation de bout en bout
|
||||||
Le module `app/proxy.py` a été migré vers **`httpx.AsyncHTTPTransport`** :
|
- Authentification réussie via Basic Auth et émission d'un ticket éphémère (`POST /api/auth/ws-ticket`).
|
||||||
- Transport HTTP brut de niveau réseau (sans aucune structure de stockage de cookies).
|
- Connexion WebSocket établie avec succès (`OPEN`) sur `ws://nabil.hub.yesminedor.tn/api/ws?ticket=...`.
|
||||||
- Aucune rétention de cookie possible en mémoire.
|
- Échange de trames JSON-RPC validé en direct (réception de la trame initiale `gateway.ready` contenant la configuration complète du thème, du branding et des événements).
|
||||||
- Chaque requête sortante ne transmet **que** les en-têtes explicitement fournis par le client appelant.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user