feat(agent): v0.3.5 Windows inbound forwarding, UI actions, lifecycle

- Configure tailscale serve automatically for each instance on Windows userspace networking.
- Add local UI buttons: start/stop/reset/delete instances (stop/start preserve volumes).
- Clean shutdown: stop tailscaled and instances, notify server with instance_stopped.
- Restart tailscaled on agent boot using persisted state when pre-auth key is absent.
- Sync instance stopped/deleted status to dashboard (server/lib/websocket.ts).
- Security: include prior authz/scoping changes across API routes, ephemeral pre-auth keys, ACL policy, internal API key.
- Update SUIVI_VPN_ONDEMAND.md and docs/ONBOARDING_CLIENT.md.
- Bump agent version to 0.3.5.
This commit is contained in:
EduBox Dev
2026-06-25 22:59:09 +00:00
parent 331187e9b5
commit a414f03a59
33 changed files with 3075 additions and 340 deletions
+549
View File
@@ -0,0 +1,549 @@
# Deployeur studioE5 — Onboarding dun nouvel établissement
## Objectif
Ce document décrit le fonctionnement du **deployeur studioE5**, cest-à-dire lapplication / loutil qui provisionne et configure un nouvel environnement client (un établissement) prêt à accueillir lapplication studioE5.
Lapplication studioE5 elle-même (agent, VPN on-demand, resolver, Caddy, Headscale, etc.) est documentée dans `SUIVI_VPN_ONDEMAND.md`. Le deployeur est loutil qui **déploie** cette application sur un VPS dédié au client.
---
## Public cible
- Équipe produit / développement du deployeur
- Équipe ops / déploiement
- Référents techniques du client A
---
## Glossaire
| Terme | Définition |
|-------|------------|
| **Deployeur** | Application qui provisionne un VPS, déploie la stack studioE5 et configure le DNS/certificats pour un nouvel établissement. |
| **Hub central** | Dashboard superadmin studioE5 qui orchestre les déploiements et la gestion multi-clients. |
| **Établissement** | Entité client (école, lycée, université, entreprise). |
| **Tag établissement** | Slug unique et court identifiant l’établissement dans les URLs et le DNS. |
| **Domaine géré** | Sous-domaine fourni par studioE5 : `*.tag.edudeploy.com`. |
| **Domaine propre** | Domaine détenu par l’établissement : `*.tag.monetablissement.fr`. |
| **Application studioE5** | Stack complète déployée sur le VPS : `server`, `resolver`, `resolver-vpn`, `caddy`, `headscale`, `postgres`, etc. |
| **Agent générique** | Binaire agent unique, capable de se connecter à nimporte quel serveur studioE5 via résolution dURL à lactivation. |
---
## Architecture : deployeur vs application studioE5
```
┌─────────────────────────────────────────────────────────────┐
│ Hub central studioE5 │
│ (superadmin, gestion des établissements, monitoring) │
└───────────────────────┬─────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Deployeur studioE5 │
│ (provisionning VPS, DNS, certificats, déploiement stack) │
└───────────────────────┬─────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Application studioE5 (un par client) │
│ Caddy — Resolver — Resolver-VPN — Headscale — Server — DB │
│ ▲ │
│ │ WebSocket / VPN on-demand │
│ ▼ │
│ Agent élève (Windows/Linux) │
└─────────────────────────────────────────────────────────────┘
```
---
## Flux donboarding par le deployeur (vue densemble)
```
Création de l’établissement dans le hub
Choix du domaine (géré ou propre)
Génération du tag établissement
Provisionning du VPS
Configuration DNS wildcard
Génération du certificat wildcard
Déploiement de la stack studioE5 (Docker Compose)
Initialisation de Headscale et création des clés
Création du compte administrateur de l’établissement
Génération des codes dactivation
Build et mise à disposition de lagent dédié
Activation de lagent par un élève
Création dune première instance (validation du déploiement)
```
---
## 1. Création de l’établissement dans le hub
Le superadmin crée un nouvel établissement dans le hub central.
Données minimales :
- Nom officiel
- Type d’établissement (école, lycée, université, entreprise)
- Pays / fuseau horaire
- Contact administrateur
- Choix du mode de domaine (`managed` ou `custom`)
---
## 2. Choix du domaine
### Option A — Domaine géré par studioE5 (MVP)
Le deployeur crée automatiquement un sous-domaine du domaine maître :
```
*.tag.edudeploy.com
```
Le hub gère le DNS chez le registrar studioE5 (actuellement Infomaniak).
### Option B — Domaine propre de l’établissement (évolution)
L’établissement fournit son propre domaine :
```
*.tag.monetablissement.fr
```
Prérequis :
- Le client pointe son DNS wildcard vers lIP du VPS provisionné.
- Le deployeur dispose dun token API du registrar du client pour le challenge DNS-01.
---
## 3. Génération du tag établissement
Le tag est un slug court, unique au niveau du hub, utilisé dans les URLs et le DNS.
### Règles
- Uniquement `[a-z0-9-]`
- Pas de tiret au début ni à la fin
- Longueur conseillée : 2 à 20 caractères
- Vérification dunicité en base
### Exemples
| Nom d’établissement | Tag |
|---------------------|-----|
| Lycée Jules Ferry | `ljf` |
| Institut Supérieur du Digital | `isd` |
| École Notre-Dame | `end` |
### Gestion des collisions
- `ljf``ljf-2`, `ljf-3`, etc.
---
## 4. Provisionning du VPS
Le deployeur provisionne un VPS dédié pour l’établissement.
### Prérequis sur le VPS vierge
- OS Linux (Ubuntu LTS recommandé)
- Docker + Docker Compose installés
- Accès SSH avec clé
- Ports ouverts : 22, 80, 443
### Actions automatisées par le deployeur
1. Installation de Docker et Docker Compose si absent.
2. Création de la structure de dossiers (`/opt/studioe5-<tag>/`).
3. Génération des secrets (`.env`) :
- `INTERNAL_API_KEY`
- `HEADSCALE_API_KEY`
- `HEADSCALE_AUTH_KEY` (réutilisable, taguée `tag:student-agent`)
- `HEADSCALE_RESOLVER_AUTH_KEY`
- `INFOMANIAK_API_TOKEN` (si domaine géré)
- `NEXTAUTH_SECRET`, `DATABASE_URL`, etc.
4. Récupération des images Docker depuis le registry privé (ou build sur place en attendant).
5. Génération des fichiers de configuration (`Caddyfile`, `docker-compose.yml`, `headscale/config.yaml`, `headscale/acl_policy.hujson`).
---
## 5. Configuration DNS wildcard
### Domaine géré
Le deployeur appelle lAPI du registrar pour créer :
```dns
*.tag.edudeploy.com A <IP_DU_VPS>
```
### Domaine propre
Le deployeur vérifie que lenregistrement existe :
```dns
*.tag.monetablissement.fr A <IP_DU_VPS>
```
---
## 6. Certificat wildcard
### Principe
Un seul certificat wildcard couvre toutes les instances futures de l’établissement.
### Mise en œuvre avec Caddy
Le deployeur génère le `Caddyfile` :
```caddy
*.tag.edudeploy.com {
tls {
dns infomaniak {env.INFOMANIAK_API_TOKEN}
}
reverse_proxy resolver:2020 {
header_up Host {host}
}
}
```
Pour un domaine propre, le provider DNS est celui du client.
### Renouvellement
Géré automatiquement par Caddy.
---
## 7. Déploiement de la stack studioE5
Le deployeur lance la stack Docker Compose complète :
```bash
cd /opt/studioe5-<tag>
docker compose up -d
```
Services déployés :
- `server` : API + WebSocket + UI Next.js
- `resolver` : reverse proxy interne vers les instances
- `resolver-vpn` : sidecar Tailscale dans le netns du resolver
- `caddy` : reverse proxy public + TLS
- `headscale` : contrôleur Tailscale
- `postgres` : base de données
---
## 8. Initialisation de Headscale
Le deployeur initialise Headscale et crée les clés nécessaires :
```bash
# Création de lutilisateur dédié au resolver
docker compose exec headscale headscale users create resolver
# Création de la clé pré-auth réutilisable pour les agents
docker compose exec headscale headscale preauthkeys create \
--user studioe5 \
--reusable \
--tags tag:student-agent \
-e 87600h
# Création de la clé pré-auth pour le resolver
docker compose exec headscale headscale preauthkeys create \
--user resolver \
--tags tag:resolver \
-e 87600h
# Création dune clé API Headscale valable 10 ans
docker compose exec headscale headscale apikeys create -e 87600h
```
Ces secrets sont stockés dans le `.env` du serveur.
---
## 9. Création du compte administrateur de l’établissement
Une fois la stack déployée, le deployeur (ou le hub) crée le premier compte administrateur de l’établissement via lAPI du serveur nouvellement déployé.
Rôles :
- `admin` : gestion des élèves, instances, agents.
- `teacher` : gestion limitée à certaines classes/groupes.
- `superadmin` (studioE5) : accès transverse.
Ladministrateur reçoit un lien dactivation sécurisé.
---
## 10. Génération des codes dactivation
Le deployeur configure le serveur pour permettre la génération de codes dactivation.
### Règles de sécurité (implémentées côté application studioE5)
- Génération avec `crypto.randomBytes`
- Alphabet sans ambiguïté : `ABCDEFGHJKLMNPQRSTUVWXYZ23456789`
- 6 caractères
- Expiration après 60 minutes
- Invalidation après usage
- Rate-limiting : 5 tentatives par code / 5 tentatives par `nodeId` sur 15 minutes
### Flux
1. Ladministrateur génère un code pour un élève.
2. L’élève saisit le code dans lagent.
3. Le serveur valide et renvoie :
- lidentité de l’élève
- lURL Headscale
- une clé pré-auth Headscale éphémère
4. Lagent démarre automatiquement le VPN.
---
## 11. Build et mise à disposition de lagent
### Principe
Lagent est un binaire générique, mais il doit être capable de se connecter au bon serveur. Le deployeur génère un agent pré-configuré ou un installeur qui embarque lURL du serveur de l’établissement.
### Build
```bash
cd /opt/studioe5-<tag>/agent
./download-tailscale-bins.sh 1.98.4
./build.sh
```
Artifacts générés :
- `studioE5-agent-vX.Y.Z-windows.zip`
- `studioE5-agent-vX.Y.Z.exe`
- `studioE5-agent-vX.Y.Z` (Linux)
### Mise à disposition
Les fichiers sont servis par Caddy depuis `server/public/agent/` :
```
https://tag.edudeploy.com/studioE5-agent-vX.Y.Z-windows.zip
```
---
## 12. Activation de lagent
### Activation zéro-config
1. L’élève télécharge lagent depuis lURL de l’établissement.
2. Il extrait larchive et lance `studioE5-agent.exe`.
3. Il ouvre `http://localhost:7070`.
4. Il saisit le code dactivation à 6 caractères.
5. Lagent contacte le serveur, récupère la configuration et démarre le VPN.
> Les détails techniques du VPN on-demand (named pipes Windows, logs, ACL, tokens, clés éphémères) sont documentés dans `SUIVI_VPN_ONDEMAND.md`.
---
## 13. Création dune instance et construction de lURL (validation)
Le deployeur ou ladministrateur crée une première instance pour valider le déploiement.
### Format dURL
```
<appli>-<initiales><id-court>.<tag>.<domaine>
```
Exemple :
```
wp-jd47.ljf.edudeploy.com
```
Avec :
- `wp` : type dapplication
- `jd` : initiales de l’élève
- `47` : identifiant court unique
- `ljf` : tag de l’établissement
- `edudeploy.com` : domaine de base
### Mapping type dapplication → préfixe
| Application | Préfixe |
|-------------|---------|
| WordPress | `wp` |
| PrestaShop | `ps` |
| Moodle | `mdl` |
| Nextcloud | `nc` |
### Protection de lidentité
- LURL ne contient pas le nom complet de l’élève.
- Seules les initiales + un identifiant court opaque sont exposées.
---
## 14. Modèles de données du deployeur
### Table / modèle `Organization` (établissement dans le hub)
```json
{
"id": "uuid",
"name": "Lycée Jules Ferry",
"tag": "ljf",
"domainMode": "managed",
"baseDomain": "edudeploy.com",
"adminEmail": "admin@ljf.fr",
"status": "active",
"createdAt": "2026-06-25T17:28:07Z"
}
```
### Table / modèle `Deployment` (déploiement sur un VPS)
```json
{
"id": "uuid",
"organizationId": "uuid",
"serverIp": "203.0.113.10",
"serverHostname": "ljf.studioe5.edudeploy.com",
"wildcardDnsConfigured": true,
"wildcardCertificateReady": true,
"dnsProvider": "infomaniak",
"dnsProviderTokenRef": "env:INFOMANIAK_TOKEN_LJF",
"headscaleApiKeyRef": "env:HEADSCALE_API_KEY_LJF",
"status": "ready",
"deployedAt": "2026-06-25T17:28:07Z"
}
```
### Table / modèle `Student` (dans lapplication studioE5 déployée)
```json
{
"id": "uuid",
"organizationId": "uuid",
"firstName": "Jean",
"lastName": "Dupont",
"initials": "jd",
"activationCode": "AB3D9F",
"activationCodeExpiresAt": "2026-06-25T18:28:07Z",
"nodeId": "vps-8fc665eb",
"nodeToken": "..."
}
```
### Table / modèle `Instance` (dans lapplication studioE5 déployée)
```json
{
"id": "cmqqgrur20001lw67t2bdgzkg",
"organizationId": "uuid",
"studentId": "uuid",
"nodeId": "vps-8fc665eb",
"templateId": "wordpress-wordpress-latest",
"applicationPrefix": "wp",
"shortId": "47",
"subdomain": "wp-jd47",
"fqdn": "wp-jd47.ljf.edudeploy.com",
"port": 8001,
"status": "running"
}
```
---
## 15. Sécurité et RGPD
### Protection de lidentité de l’élève
- LURL publique ne contient pas le nom complet de l’élève.
- Seules les initiales + un identifiant court opaque sont exposées.
### Isolation réseau
- Les agents élèves ne peuvent pas communiquer entre eux (ACL Headscale).
- Le resolver est le seul service autorisé à joindre les agents sur leurs ports dinstance.
### Authentification
- Token unique par agent (`node.token`).
- Clé API interne pour les endpoints serveur → agent.
- Sessions NextAuth sur les routes API métier.
### Clés pré-auth Headscale
- Éphémères, à usage unique, 15 minutes dexpiration.
- Non persistées côté agent.
---
## 16. Checklist de validation du deployeur
À lissue dun onboarding, les points suivants doivent être validés :
- [ ] L’établissement est créé dans le hub avec un tag unique.
- [ ] Le VPS est provisionné et accessible en SSH.
- [ ] Docker et Docker Compose sont installés.
- [ ] Le DNS wildcard est résolu (`*.tag.edudeploy.com` → IP du VPS).
- [ ] Le certificat wildcard est obtenu et valide.
- [ ] La stack studioE5 est démarrée (`docker compose ps`).
- [ ] Headscale est initialisé avec les utilisateurs et clés nécessaires.
- [ ] Le compte administrateur de l’établissement est créé.
- [ ] Un code dactivation peut être généré pour un élève.
- [ ] Lagent est buildé et téléchargeable depuis le serveur de l’établissement.
- [ ] Lagent sactive avec le code zéro-config.
- [ ] Une instance peut être créée et son URL est accessible en HTTPS.
- [ ] Deux instances différentes reçoivent des URL uniques.
- [ ] Le flux HTTPS complet retourne bien HTTP 200.
---
## 17. Roadmap du deployeur
### Court terme (MVP)
- Déploiement manuel ou semi-automatisé dun nouvel établissement sur un VPS.
- Domaine géré par studioE5 uniquement.
- Build des images sur le VPS cible.
- Agent avec URL serveur hardcodée ou fournie à lactivation.
### Moyen terme
- **Agent générique** : déterminer lURL serveur cible à lactivation (code structuré, hub de résolution, ou champ URL).
- **Script de provisionning** : installation Docker, déploiement stack, génération secrets, DNS wildcard.
- **Registry dimages privé** : builder une fois, déployer partout.
- Support de domaines propres à l’établissement.
- Support multi-registrar DNS.
### Long terme
- **Hub central multi-clients** : dashboard superadmin, gestion des versions, logs distants.
- **Mises à jour à distance** : pousser une nouvelle version du serveur et de lagent sur tous les déploiements.
- **Monitoring / support** : alertes serveur down, certificat expiré, agent hors ligne.
- **Tests automatisés** : validation du flux activation → VPN → instance → HTTPS public à chaque déploiement.
- **Console/log intégré et barre de progression** dans lagent.
- Génération automatique de codes dactivation par import CSV.