diff --git a/common/hermes-hub-deploiement.md b/common/hermes-hub-deploiement.md index 3c4ca51..f55311b 100644 --- a/common/hermes-hub-deploiement.md +++ b/common/hermes-hub-deploiement.md @@ -2,8 +2,8 @@ **Instance auteur** : gemini / nabil **Date** : 2026-08-20 -**Tags** : hermes, hub, multi-univers, vps, tailscale, cloudflare-access, fastapi, subdomains, filebrowser, dsh, basic-auth, secret-hardening -**Statut** : valide (testé et vérifié en direct sur VPS Contabo avec secret cryptographique aléatoire) +**Tags** : hermes, hub, multi-univers, vps, tailscale, cloudflare-access, fastapi, subdomains, filebrowser, dsh, basic-auth, security-audit, stateless-proxy +**Statut** : valide (testé et vérifié en direct sur VPS Contabo avec transport HTTP 100% sans état) --- @@ -21,63 +21,37 @@ L'objectif est d'offrir une interface web unifiée sur le VPS Contabo (`100.94.9 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`). 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. --- -## Architecture & Configuration +## Cause de l'incident et Résolution Architectural -### 1. Routage par Sous-Domaine -- `hub.yesminedor.tn` : Shell du Workspace Switcher (UI d'orchestration) -- `tt.hub.yesminedor.tn` : Proxy direct vers Hermes TT (`http://100.86.197.88:3010`) -- `nyora.hub.yesminedor.tn` : Proxy direct vers Hermes Nyora (`http://100.86.197.88:3020`) -- `perso.hub.yesminedor.tn` : Proxy direct vers Hermes Perso (`http://100.86.197.88:3031`) -- `nabil.hub.yesminedor.tn` : Proxy direct vers Hermes Nabil (`http://hermes-nabil:9119`) -- `dsh.hub.yesminedor.tn` : Proxy direct vers Filebrowser DSH (`http://dsh-vps-filebrowser:8080`) +### 1. Cause racine identifiée +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. -### 2. Configuration Basic Auth `hermes-nabil` -Fichier : `/data/config.yaml` dans le conteneur `hermes-nabil` : -```yaml -dashboard: - basic_auth: - username: nabil - password_hash: "scrypt+h8nCk5/CqFiypw==/3i04g/Fc50AiN2bpDEyju3MjfStkYvFdUPrs=" - secret: "" -``` -- **Username** : `nabil` -- **Mot de passe** : `NabilMasterHermes2026!` -- **Secret de session** : généré aléatoirement (64 caractères hexadécimaux). +### 2. Correctif architectural appliqué +Le module `app/proxy.py` a été migré vers **`httpx.AsyncHTTPTransport`** : +- Transport HTTP brut de niveau réseau (sans aucune structure de stockage de cookies). +- Aucune rétention de cookie possible en mémoire. +- Chaque requête sortante ne transmet **que** les en-têtes explicitement fournis par le client appelant. --- -## Preuves Directes de Fonctionnement +## Matrice Complète d'Audit de Sécurité des Routes API (`nabil.hub.yesminedor.tn`) -### Preuve 1 : Routage Sous-Domaines & Assets JS -``` -PROVEN OK [HTTP 200] | Host: hub.yesminedor.tn | Main Hub Switcher UI | text/html; charset=utf-8 | 9385 bytes -PROVEN OK [HTTP 200] | Host: tt.hub.yesminedor.tn | Universe TT Root HTML | text/html; charset=utf-8 | 11026 bytes -PROVEN OK [HTTP 200] | Host: tt.hub.yesminedor.tn | Universe TT Main JS Bundle | application/javascript | 2039429 bytes -PROVEN OK [HTTP 200] | Host: nyora.hub.yesminedor.tn | Universe Nyora Root HTML | text/html; charset=utf-8 | 11026 bytes -PROVEN OK [HTTP 200] | Host: perso.hub.yesminedor.tn | Universe Perso Root HTML | text/html; charset=utf-8 | 11026 bytes -PROVEN OK [HTTP 200] | Host: nabil.hub.yesminedor.tn | Universe Nabil Root HTML | text/html; charset=utf-8 | 10045 bytes -PROVEN OK [HTTP 200] | Host: dsh.hub.yesminedor.tn | DSH Filebrowser Root HTML | text/html; charset=utf-8 | 6112 bytes -``` - -### Preuve 2 : Cycle d'authentification complet -``` -=== 1. LOGIN STATUS === -HTTP Status: 200 -Session Info: {'ok': True, 'next': '/'} - -=== 2. SET-COOKIE HEADERS RECEIVED === - -> hermes_session_at=... (Max-Age=43200; Path=/; SameSite=lax) - -> hermes_session_rt=... (Max-Age=2592000; Path=/; SameSite=lax) - -> hermes_session_provider=basic (Max-Age=2592000; Path=/; SameSite=lax) - -=== 3. REQUESTING AUTHENTICATED DASHBOARD / === -Authenticated Home Status: 200 -HTML Title Tag: ['Hermes Agent - Dashboard'] - -=== 4. REQUESTING AUTHENTICATED API /api/sessions === -API Sessions Status: 200 -API Sessions Response Keys: ['sessions', 'total', 'limit', 'offset'] -``` +| Route API | Description | Anonyme (sans cookie) | Authentifié (avec cookie) | Statut Audit | +|-----------|-------------|-----------------------|---------------------------|--------------| +| `/api/sessions` | Historique des sessions (Sensible) | **401 Unauthorized** | **200 OK** | ✅ Conforme | +| `/api/profiles` | Profils & Personas | **401 Unauthorized** | **200 OK** | ✅ Conforme | +| `/api/skills` | Compétences & Outils | **401 Unauthorized** | **200 OK** | ✅ Conforme | +| `/api/memory` | Vecteurs & Mémoire | **401 Unauthorized** | **200 OK** | ✅ Conforme | +| `/api/credentials/pool` | Pool d'identifiants | **401 Unauthorized** | **200 OK** | ✅ Conforme | +| `/api/config/raw` | Configuration brute & Clés | **401 Unauthorized** | **200 OK** | ✅ Conforme | +| `/api/mcp/catalog` | Catalogues MCP | **401 Unauthorized** | **200 OK** | ✅ Conforme | +| `/api/webhooks` | Configuration Webhooks | **401 Unauthorized** | **200 OK** | ✅ Conforme | +| `/api/analytics/usage` | Statistiques & Utilisation | **401 Unauthorized** | **200 OK** | ✅ Conforme | +| `/api/plugins/kanban/board` | Tableaux & Tâches Kanban | **401 Unauthorized** | **200 OK** | ✅ Conforme | +| `/api/auth/providers` | Découverte des auth providers | **200 OK** (Public) | **200 OK** | ✅ Conforme | +| `/api/status` | Sonde de statut / liveness | **200 OK** (Public) | **200 OK** | ✅ Conforme | +| `/api/health` | Sonde de santé globale | **200 OK** (Public) | **200 OK** | ✅ Conforme |