Paillasse/docs/bilan.md
2026-10-12 21:12:43 +02:00

195 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Bilan de la mission de déploiement — Syllabus
Mission : `docs/prompt-deploiement-paillasse.md`, étapes 1 à 16, exécutée du
2026-10-07 au 2026-10-12 sur la Dedibox `163.172.4.195` (Debian 12, Xeon
D-1531, 32 Go, RAID 1). Le détail de chaque étape (commandes, problèmes,
explications) est dans `docs/journal.md` ; ce document en est la synthèse.
## Ce qui fonctionne, avec la preuve de chaque critère
| Étape | Critère | Preuve (journal) |
|---|---|---|
| 1. Reconnaissance | Inventaire, KVM, version de Kolla justifiée | `docs/inventaire-serveur.md` ; `/dev/kvm` présent ; Kolla 2025.2, seule série maintenue qui supporte Debian 12 (ADR 0001) |
| 2. Durcissement | Clé OK, mot de passe et root refusés, seuls 22/80/443 | `Permission denied (publickey)` pour le mot de passe et pour root ; `nmap` depuis le Mac : 22 seul ouvert (80/443 autorisés, rien n'écoutait encore) |
| 3. Sauvegardes | Une sauvegarde envoyée, un fichier restauré | `quotidienne-20261007.tar.zst.age` présente sur Dedibackup ; `etc/hostname` restauré dans `/tmp` (`sd-124443`) |
| 4. Réseau OpenStack | Après redémarrage : SSH, `dummy0`, veth, Internet | Redémarrage 11:37, SSH 11:39 ; interfaces et IP présentes ; ping 9.9.9.9 et DNS OK ; RAID `[UU]` |
| 5. Kolla | Services OK, aucune API joignable de l'extérieur | `openstack service list` et `compute service list` OK ; `nmap` sur tous les ports OpenStack + 1-1024 : 22 seul |
| 6. Console série | Invite affichée, commande exécutée | Script WebSocket : `localhost login:`, puis `whoami && hostname` → `eleve`, `localhost` |
| 7. Supervision | Une alerte de test reçue par Adam | Alerte injectée dans Alertmanager ; **reçue par Adam sur ntfy** |
| 8. Portail | Pest OK, élève fictif voit son tableau de bord | 11/11 tests ; `lea.m` connectée voit « Salut Léa » |
| 9. Console web | `ip a` dans le navigateur ; un autre élève refusé | Sortie de `ip a` par navigateur → Nginx → proxy Go → Nova ; autre élève : `403` ; écriture du prof ignorée côté serveur |
| 10. Heat, lab 08 | Stack `CREATE_COMPLETE`, terminaux ouverts | Stack créée en 26 s, 3 VM, topologie conforme au `lab.yaml` ; 3 terminaux ouverts ; expiration automatique vérifiée |
| 11. Stock et correction | < 5 s ; correct → réussi ; incorrect → échoué + message | 4,06 s (mesure pessimiste, voir étape 13) ; « Pas encore réussi » 6/10 avec les messages du lab, puis « Réussi » 10/10 ; 3 essais puis échec visible du prof, vérifiés |
| 12. HTTPS | Certificat valide, parcours prof → élève → lab → correction | Let's Encrypt, TLS 1.2/1.3, HSTS, CSP ; parcours en `https`/`wss` : 4,35 s, 6/10 puis 10/10 ; VM sans IP publique ni sortie |
| 13. Capacité et résistance | Chiffres écrits, restauration, retour seul après redémarrage | `docs/capacite.md` ; « RESTAURATION RÉUSSIE » (17 tables identiques) ; tout revenu seul en 11 min, parcours 10/10 ensuite ; ouverture mesurée à 2,80 / 2,85 / 2,85 s |
| 14. Légal et RGPD | Pages en ligne, purge prouvée par Pest | `/legal`, `/confidentialite` en 200, `/statut` → page de statut ; `PurgeRgpdTest` (5 tests) |
| 15. Visio | Prof + 2 élèves ; main levée → parole ; intrus refusé | Test Playwright à 3 navigateurs + intrus : « CRITÈRE DE L’ÉTAPE 15 : RÉUSSI » ; élève sans parole reste en sourdine ; intrus : « Authentication required » |
| 16. Nettoyage | Proposer le retrait de `90-adam` | Proposé avec ses conséquences ; **Adam a choisi de le garder jusqu'à la fin du bloc A** (voir risques) |
**État relevé le 2026-10-12 à la fin de la mission** : 0 unité systemd en
échec ; 53 conteneurs, 0 en mauvaise santé ; Nginx, PHP-FPM, Horizon, proxy
console, correcteur et relais d'alertes actifs ; `https://syllabuslab.fr` et
la page de statut en 200 ; certificat valable jusqu'au 2027-01-10 pour
`syllabuslab.fr`, `www`, `status` et `meet` ; une stack prête dans le stock
du lab 08 ; dernière sauvegarde le 2026-10-12 à 03:16, **test de restauration
automatique du 2026-10-12 à 04:30 réussi** ; 47 tests Pest et 4 tests Go.
## Temps réel passé par étape
Pas de chronométrage pendant la mission : ce sont des **fenêtres entre
commits**, pauses, attentes des réponses d'Adam et nuits comprises. Elles
majorent le temps de travail réel.
| Étape | Fenêtre | Durée | Ce qui a pris du temps |
|---|---|---|---|
| 1 | 2026-10-07, jusqu'à 06:54 | — | Accès SSH (passphrase de la clé) |
| 2 | 06:54 → 10:32 | ≈ 3 h 40 | Deux retours arrière du filet anti-coupure, auto-bannissement fail2ban (post-mortem) |
| 3 | 10:32 → 11:08 | ≈ 35 min | Identifiants Dedibackup corrigés par Adam |
| 4 | 11:08 → 11:40 | ≈ 30 min | Redémarrage avec accord |
| 5 | 11:40 → 15:57 | ≈ 4 h 15 | Deux `deploy` (ProxySQL contre MariaDB), tables IPv6 de Docker |
| 6 | 15:57 → 16:24 | ≈ 30 min | — |
| 7 | 16:24 → 21:20 | ≈ 5 h | Attente de l'adresse de notification, configuration oubliée sur le serveur (2 fois) |
| 8 | 21:20 → 10-08 02:01 | ≈ 4 h 40 | Taille du portail, deux guards, déploiement |
| 9 | 02:01 → 09:35 | ≈ 7 h 30 (nuit comprise) | — |
| 10 | 09:35 → 10:14, puis ADR jusqu'à 21:01 | ≈ 40 min + questions | Trust Heat refusé aux application credentials (ADR 0002) |
| 11 | 10-08 → 21:52 | > 1 h 30 (journal) | Trois défauts des étapes 8 et 9 trouvés par le parcours réel |
| 12 | 10-09 09:38 → 15:04 | ≈ 1 h + DNS de `status` | Faille XSS, `/cours` en 500 |
| 13 | 15:04 → 20:12 | ≈ 5 h | Test de capacité, sauvegarde du portail ajoutée, redémarrage |
| 14 | 20:12 → 22:18 | ≈ 2 h | Pages légales réécrites, polices auto-hébergées, retours d'Adam |
| 15 | 10-12 matin → 12:35 | une demi-journée | Pare-feu entre conteneurs (`br_netfilter`), rôles Jitsi |
| 16 et bilan | 10-12 après-midi | ≈ 1 h | — |
En tout : **six jours calendaires, dont environ quatre jours de travail**.
## Capacité mesurée
- **20 VM `eleve.petit` (1 vCPU, 768 Mo) en même temps**, sessions et stock chaud
compris : par exemple **une classe de 20 élèves** sur un lab à une VM, ou
**6 élèves** sur le lab 08 (3 VM chacun). Limite appliquée par Nova
(`reserved_host_memory_mb = 16500`) et par le portail (`LABS_CAPACITE_VM`).
- Pourquoi 20 : la mémoire est la limite (≈ 600 Mo par VM active, ≈ 250 Mo au
repos), pas le CPU (20 vCPU à 100 % → hôte à 89 %, correction en 0,6 s).
22 avant la visio, 20 depuis qu'1,5 Go est réservé à Jitsi.
- Ouverture d'un lab pris dans le stock : **2,8 s** (critère < 5 s). Lancement
à froid de 20 VM : 53 s en médiane, 75 s au p95. D'où le pré-remplissage
10 minutes avant une séance.
- Visio : non mesurée au-delà de 3 participants. Une classe de 30 en visio
est à tester au pilote (CPU de JVB, débit sortant).
Détails : `docs/capacite.md`.
## Dettes et risques connus
La liste complète, tenue à jour, est dans `docs/dette.md`. Les risques qui
comptent avant une vraie classe :
| Risque | Conséquence | Réponse |
|---|---|---|
| **Copie de la clé age non confirmée** | Si le serveur est perdu, aucune sauvegarde n'est déchiffrable | Adam (voir plus bas) |
| **Base OpenStack non sauvegardée** | Perte du serveur → projet, compte, gabarits et stacks à recréer à la main | `kolla-ansible mariadb_backup` dans la sauvegarde quotidienne |
| **Un seul serveur, pas de sonde extérieure** | Si le serveur tombe, aucune alerte, et la classe s'arrête | Sonde externe (à décider et commander par Adam) ; self-healing ne couvre pas la panne totale |
| **Visio sans TURN sur 443** | Sur un réseau scolaire qui bloque l'UDP : ni son ni image | coturn derrière 443 avant le pilote |
| **`sudo` sans mot de passe pour `adam`** | La clé SSH de Claude Code donne un accès root complet | Gardé par choix d'Adam jusqu'à la fin du bloc A ; retrait ensuite (commande prête ci-dessous) |
| Images Kuma non figée, Jitsi sans procédure de mise à jour | Mise à jour non testée au prochain redéploiement | Variables de version dans les rôles |
| Vitrine : Tailwind par CDN, scripts en ligne, Pyodide depuis jsDelivr | CSP de la vitrine moins stricte que celle de l'application | Compilation par Vite avant ouverture publique |
| Peu de vérifications dans un vrai navigateur | Hors visio et `/ide`, les pages n'ont été vérifiées qu'en HTML | Playwright est maintenant installé : l'étendre aux parcours clés |
| Kolla installé depuis une branche | Pas reproductible à l'identique | À régler lors de la montée de version |
Deux incidents de ma part, déjà traités : un secret d'application credential
de test affiché en clair (credential supprimée aussitôt) ; un déploiement en
échec pris pour un succès (règle depuis : toujours lire `PLAY RECAP`).
## Ce qu'Adam doit faire lui-même
**Secrets et sécurité**
1. **Copier la clé age hors du serveur et le prouver** : procédure dans
`docs/runbooks/sauvegardes.md` (déchiffrer `~/Desktop/test-cle-sauvegardes.age`
avec la copie). Ranger ensuite la copie dans un gestionnaire de mots de passe.
2. **Changer la passphrase SSH** si l'ancienne clé ou la même passphrase sert
ailleurs : elle avait été collée dans la conversation à l'étape 1.
3. **Retirer `/etc/sudoers.d/90-adam` à la fin du bloc A** (la clé de Claude
Code n'a pas de passphrase : ce fichier est la seule barrière entre elle et root). D'abord vérifier son mot de passe dans sa propre session
(`sudo -k && sudo -v`), garder cette session ouverte, puis :
`sudo rm /etc/sudoers.d/90-adam`. Les playbooks se lancent ensuite avec `-K`.
4. Faire tourner le mot de passe du compte `paillasse-service` une fois par an
(`docs/runbooks/compte-service-openstack.md`).
**Comptes et contenus**
5. Créer le premier vrai compte prof (le sien) sur `https://syllabuslab.fr/inscription`
et une vraie classe.
6. Compléter les CGU (article « Disponibilité et responsabilité ») et indiquer
un DPO s'il en désigne un.
7. Trancher les slogans « du lycée au master » et le sort des 32 pages d'aperçu.
8. Dire si l'ancien `storage/logs/laravel.log` peut être supprimé.
**Tests avec un prof**
9. Faire jouer une séance complète par un collègue prof, sur un vrai réseau
d'établissement : inscription des élèves (fiches et code de classe),
séance planifiée, lab 08, correction, visio (son et image à travers le
filtrage de l'établissement, c'est là que l'absence de TURN se verra),
archivage de la classe.
10. Vérifier dans son navigateur : `/ide` (Python et SQL), une console de lab,
la visio sur Chromebook ou vieux PC.
**Décisions et achats (jamais par Claude)**
11. Sonde de supervision hors du serveur (petite VM ailleurs, ou service
externe) et nom DNS `turn.syllabuslab.fr` pour la visio.
**Décision d'Adam (2026-10-12) : pas de montée de version d'OpenStack.** La
2025.2 reste en place (stable, préférée aux dernières versions) ; la semaine
7 du CLAUDE.md est donc écartée pour l'instant.
## Mise à jour du 2026-10-12 : sauvegarde d'OpenStack et self-healing
Après la fin de la mission initiale, Adam a demandé de continuer le bloc A
(sans montée de version) :
- **Base d'OpenStack désormais sauvegardée** (Keystone, Nova, Neutron,
Glance, Heat, Placement) et testée chaque semaine comme celle du portail.
Dette retirée. Détails : `docs/journal.md`, `docs/runbooks/sauvegardes.md`.
- **Self-healing des VM fait** (semaine 6) : une VM muette (stock ou élève)
est détectée et réparée automatiquement par `labs:surveiller-vm`, chaque
minute. **Panne provoquée sur le serveur réel** (VM gelée, `virsh
suspend`) : détectée et redémarrée seule, sans intervention humaine.
Post-mortem : `docs/postmortems/2026-10-12-vm-figee-self-healing.md`.
Runbook : `docs/runbooks/self-healing.md`.
- Ne sont **pas** couverts par ce self-healing (hors sujet, déjà traités
ailleurs) : un service ou un conteneur Kolla arrêté (déjà
`Restart=always`/`unless-stopped`, vérifié le 2026-10-12 : 0 unité en
échec), et la panne du serveur lui-même (toujours sans sonde extérieure).
- Dette ajoutée : pas encore d'alerte Prometheus dédiée sur
`syllabus_vm_panne_generale` ni `syllabus_vm_irreparables`.
## Prochaines étapes du bloc A (restantes)
### Avant le pilote (semaine 8)
- TURN sur 443 pour la visio (réseaux scolaires qui bloquent l'UDP).
- Alerte Prometheus sur la panne générale des VM et les VM irréparables.
- Sonde de supervision hors du serveur.
- Les points « Adam doit faire lui-même » ci-dessus (clé age, CGU, test avec
un collègue prof…).
### Montée de version d'OpenStack (semaine 7) — écartée pour l'instant
Si Adam change d'avis : passer de la branche `stable/2025.2` à un tag (version figée), puis préparer
la série suivante. Attention : 2026.1 ne supporte plus Debian 12. Une montée
de version d'OpenStack passe donc d'abord par **Debian 13** (montée de
version de l'OS sur un serveur unique, à préparer avec le mode rescue).
- Runbook : sauvegarde des bases, `kolla-ansible upgrade` en service systemd,
vérifications (`capacite.py` réduit, `parcours-lab.py`, `visio-e2e.mjs`),
retour arrière. Retour d'expérience dans le journal.
### Pilote avec une vraie classe (semaine 8)
- Prérequis : TURN 443, clé age confirmée, sonde
extérieure, mentions légales complètes, test avec un collègue (point 9).
La base OpenStack est désormais sauvegardée.
- Pendant : relever le temps d'ouverture réel (p95), la mémoire, la charge de
la visio, les corrections réussies et échouées, les mains levées.
- Après : retours des élèves et du prof, métriques dans `docs/capacite.md`,
liste des priorités du bloc B.