Paillasse/docs/prompt-deploiement-paillasse.md
2026-10-07 00:11:20 +02:00

298 lines
15 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.

# Prompt Claude Code : déploiement complet de Paillasse
> À coller dans Claude Code, lancé depuis la racine du dépôt `Paillasse` sur le Mac d'Adam.
> Remplacer les valeurs entre `<...>` avant de lancer.
---
## 0. Contexte
Tu vas déployer **Paillasse** de bout en bout sur un serveur bare metal, jusqu'à une version utilisable par une vraie classe.
Lis d'abord `CLAUDE.md` et `paillasse-contenus/README.md`. Ils contiennent le contexte complet du projet, la stack et les règles.
**Paillasse** : une plateforme de labs Linux et réseau pour les écoles. Chaque élève a une vraie VM Debian, avec une console dans le navigateur et une correction automatique par scripts. Pas d'IA dans le produit.
**Le serveur**
- Scaleway Dedibox **Start-2-L**, datacenter DC2 (France).
- Xeon D-1531 (6 cœurs / 12 threads), **32 Go de RAM**, 2 × 250 Go SSD.
- **Une seule IP publique** : `<IP_SERVEUR>`.
- Debian `<12 ou 13>`, installé par Adam depuis la console Dedibox.
- Accès SSH : `ssh <UTILISATEUR>@<IP_SERVEUR>`, avec la clé dédiée `~/.ssh/<CLE_CLAUDE>`. Crée l'alias `paillasse` dans `~/.ssh/config`.
- Sauvegardes : **Dedibackup 100 Go** (FTP, joignable uniquement depuis le serveur). Adam a déposé les identifiants dans `/root/.dedibackup` (`chmod 600`). Ne les affiche jamais.
**La forge** : `ssh://git@forge.adam.belkacemi.me:2222/adam/Paillasse.git`. Tu n'y fais que `git push` : aucune connexion SSH à la machine qui l'héberge.
**Le domaine** : `<DOMAINE>`. Adam l'achète et configure le DNS lui-même.
---
## 1. Règles non négociables
1. **Ne jamais toucher à `tripoli-cloud`** ni à aucune autre machine que le serveur Paillasse et le Mac d'Adam.
2. **Aucun secret** dans le code, dans Git, dans le journal ou dans la conversation.
- Les secrets vivent dans des fichiers `chmod 600` sur le serveur, ou dans un `.env` ignoré par Git.
- Les secrets Ansible passent par **Ansible Vault**. Le mot de passe du vault reste hors du dépôt.
- Kolla : `passwords.yml` n'est jamais commité en clair.
3. **Commandes à risque : explique, montre la commande, vérifie la sauvegarde, puis attends le « OK » d'Adam.** Sont concernés :
- suppressions (`rm -rf`, `DROP`, `kolla-ansible destroy`…) ;
- disques, partitions, RAID ;
- toute modification du **réseau**, du **pare-feu** ou de **SSH** ;
- redémarrage du serveur.
4. **Anti-coupure SSH** : avant toute modification du réseau, du pare-feu ou de SSH, programme un retour automatique à l'ancienne configuration dans 5 minutes (par exemple avec `systemd-run --on-active=5min`), puis annule-le une fois l'accès vérifié depuis une **nouvelle** session SSH.
5. **Tu ne commandes et ne paies jamais rien.**
6. **Élèves mineurs** : minimisation des données.
- Un élève = un pseudonyme et un code. Pas d'e-mail, pas de nom complet obligatoire.
- Suppression automatique 90 jours après l'archivage d'une classe.
7. **Tout est du code** :
- chaque configuration passe par un rôle Ansible idempotent dans `ansible/` ;
- une commande tapée à la main pour explorer doit ensuite être codifiée ;
- relancer un playbook ne doit rien casser.
8. **Vérifie les versions dans la documentation officielle**, jamais de mémoire : Kolla-Ansible, OS supportés, Laravel, PHP, Go. Utilise Context7 ou le web.
9. **Documentation en français** (docs, commentaires, messages de commit).
---
## 2. Méthode de travail
### Pour chaque étape
1. Annonce l'étape et son critère de réussite.
2. Fais le travail.
3. **Vérifie le critère par un test réel** et montre la sortie.
4. Écris dans `docs/journal.md` :
- ce qui a été fait ;
- les commandes clés ;
- les problèmes rencontrés et leur solution ;
- un paragraphe **« Comprendre »** de 3 à 6 phrases, qui explique simplement le pourquoi à Adam.
5. `git commit`, puis `git push`.
6. Passe à l'étape suivante sans attendre, sauf si une règle de la section 1 impose l'accord d'Adam.
### Limite de temps
**1 h 30 maximum par étape.** Si elle est dépassée :
- arrête-toi ;
- écris le blocage dans `docs/journal.md` (symptôme, pistes essayées, hypothèses) ;
- propose 2 options à Adam et attends sa décision.
### Arborescence du dépôt
```
ansible/ inventaire, playbooks, rôles
kolla/ globals.yml, inventaire all-in-one (passwords.yml : chiffré ou hors Git)
openstack/ modèles Heat, flavors, scripts de construction d'images
portail/ application Laravel
proxy-console/ service Go
labs/ copie de travail des labs YAML
docs/ journal.md, runbooks/, inventaire-serveur.md, post-mortems/
```
---
## 3. Les étapes
### Étape 1 : Reconnaissance (lecture seule)
- Relève sur le serveur :
- OS, noyau, CPU ;
- virtualisation matérielle (`vmx`) et `/dev/kvm` ;
- RAM, disques, RAID ;
- interfaces réseau, IP, passerelle, DNS.
- Vérifie quelle version stable de Kolla-Ansible supporte la Debian installée. Si elle ne supporte pas Debian 13, **arrête-toi** et recommande à Adam de réinstaller en Debian 12.
- Écris `docs/inventaire-serveur.md`.
**Critère :** inventaire écrit, KVM disponible, version de Kolla-Ansible choisie et justifiée.
### Étape 2 : Durcissement (Ansible depuis le Mac)
- Installe Ansible sur le Mac s'il manque. Crée `ansible/inventory.ini` et un rôle `durcissement` :
- utilisateur d'administration, `sudo` ;
- SSH par clé uniquement, `PermitRootLogin no` ;
- fail2ban, `unattended-upgrades`, chrony, fuseau `Europe/Paris` ;
- pare-feu nftables : seuls **22, 80 et 443** ouverts sur l'IP publique.
- Attention : `kolla-ansible bootstrap-servers` peut désactiver le pare-feu. Prévois-le dès maintenant (réglage Kolla adapté, ou rôle nftables rejoué après Kolla).
**Critère :**
- connexion par clé OK ;
- connexion par mot de passe refusée, root refusé ;
- depuis le Mac, `nmap <IP_SERVEUR>` ne montre que 22, 80 et 443.
### Étape 3 : Sauvegardes vers Dedibackup
- Utilise **restic**, chiffré, avec **rclone** comme backend FTP vers Dedibackup.
- Le mot de passe restic est dans un fichier root en `chmod 600`.
- À sauvegarder : `/etc`, `/home`, `/root`, `/etc/kolla` (plus tard), les dumps MariaDB de l'app (plus tard), le dossier du portail.
- Programmation : timer systemd quotidien, rétention 7 jours / 4 semaines / 3 mois.
- Écris `docs/runbooks/sauvegardes.md`.
**Critère :** une sauvegarde est faite et **un fichier est restauré avec succès** dans `/tmp`.
### Étape 4 : Réseau pour OpenStack (accord d'Adam obligatoire)
L'objectif est de ne jamais mettre Neutron sur l'interface publique.
- Crée une interface `dummy0` avec une IP privée (par exemple `10.10.0.1/24`). Elle servira à `network_interface` et `kolla_internal_vip_address` (Kolla sans HAProxy).
- Crée une paire veth. `neutron_external_interface` utilise un bout de la paire. L'autre bout porte la passerelle du réseau externe OpenStack, avec un NAT masquerade nftables.
- Rends le tout persistant avec systemd-networkd et le rôle Ansible `reseau-openstack`.
- Applique la règle anti-coupure SSH, puis **redémarre, avec l'accord d'Adam**.
**Critère :** après redémarrage, le SSH répond, `dummy0` et la paire veth sont présents, et Internet reste joignable depuis le serveur.
### Étape 5 : Kolla-Ansible tout-en-un
- Dans un venv Python : la version de Kolla-Ansible choisie à l'étape 1, puis `kolla-ansible install-deps`.
- Dans `kolla/globals.yml` (**vérifie les noms exacts dans la doc de la version**), les idées sont :
- `enable_haproxy: "no"`, `enable_horizon: "no"` ;
- `enable_heat: "yes"`, `enable_nova_serialconsole_proxy: "yes"` ;
- `nova_compute_virt_type: "kvm"` ;
- `enable_prometheus` et `enable_grafana` si c'est le plus simple pour l'étape 7.
- Mots de passe : `kolla-genpwd`. Jamais de `passwords.yml` en clair dans Git.
- Lance `bootstrap-servers`, `prechecks`, `deploy`, puis `post-deploy`. Installe le client `openstack`.
- Rejoue le rôle pare-feu si Kolla l'a modifié.
**Critère :**
- `openstack service list` et `openstack compute service list` sont OK ;
- aucune API OpenStack n'est joignable depuis l'IP publique (vérifie avec `nmap`).
### Étape 6 : Première VM en console série
1. Crée le projet `paillasse` et un utilisateur de service avec des **application credentials**, stockés dans un fichier `chmod 600`.
2. Construis l'image `paillasse-debian` avec `virt-customize`, à partir de l'image cloud Debian officielle :
- `qemu-guest-agent` ;
- un getty sur `ttyS0` ;
- l'utilisateur `eleve` ;
- les outils réseau des labs (iproute2, iputils, tcpdump, traceroute, dnsutils, et frr si le lab l'exige).
3. Propriété de l'image : `hw_qemu_guest_agent=yes`.
4. Crée la flavor `eleve.petit` : 1 vCPU, 768 Mo, 5 Go.
5. Démarre une VM et récupère l'adresse de sa console série avec l'API Nova `remote-consoles` (protocole `serial`).
**Critère :** un petit script (websocat ou Python) connecté au WebSocket de la console série affiche l'invite de connexion, et une commande tapée s'exécute.
### Étape 7 : Supervision et alertes
- Prometheus, node_exporter et Grafana : ceux de Kolla si possible.
- Uptime Kuma en conteneur Docker, écoutant sur `127.0.0.1`.
- Alertes : disque > 80 %, RAM > 90 %, service OpenStack arrêté, dernière sauvegarde de plus de 26 h, serveur injoignable.
- Notifications par webhook : l'URL est un secret.
- Tant qu'il n'y a pas de domaine, accès par tunnel SSH uniquement.
**Critère :** une alerte de test est **reçue** par Adam.
### Étape 8 : Portail Laravel minimal
- Nginx et PHP-FPM, avec une version de PHP compatible avec la dernière version de Laravel.
- MariaDB et Redis **pour l'app** en Docker Compose, liés à `127.0.0.1`, sur des ports différents de ceux de Kolla (par exemple 3307 et 6380).
- Laravel, avec Inertia et React (starter kit officiel), dans `portail/`.
- Modèles :
- `Etablissement`, `User` (prof), `Classe`, `Eleve` (pseudonyme et code uniquement) ;
- `Lab`, `Seance`, `LabSession` (élève, lab, id de la stack ou des VM, état, expiration).
- Connexion :
- le prof avec un e-mail et un mot de passe ;
- l'élève avec un code de classe et un code élève, sur un seul écran `/connexion`.
- Un prof crée une classe et génère les codes de ses élèves.
- Design : la palette et les polices de `CLAUDE.md`, sobre.
- Tests **Pest** pour la connexion et la création de classe.
**Critère :** les tests Pest passent, et un élève fictif se connecte et voit son tableau de bord.
### Étape 9 : Proxy console Go et xterm.js
- Service Go dans `proxy-console/`, écoutant sur `127.0.0.1:8081`, lancé par systemd. Nginx relaie `/console` en WebSocket sur le port 443.
- Déroulé :
1. Laravel demande à Nova l'adresse de la console série.
2. Laravel la range dans Redis sous un **jeton aléatoire**, pour 5 minutes.
3. Le navigateur reçoit uniquement ce jeton.
4. Le proxy lit Redis, ouvre le WebSocket vers nova-serialproxy et recopie les octets dans les deux sens.
- La console série n'accepte qu'**une seule connexion** : c'est le proxy qui duplique le flux vers la vue du prof, en lecture seule.
- Côté front : xterm.js, avec un onglet par VM du lab.
**Critère :** dans le navigateur, l'élève tape `ip a` dans sa VM et voit le résultat, et un autre élève ne peut pas ouvrir cette console.
### Étape 10 : Liaison Laravel ↔ OpenStack et lab 08
- Client OpenStack dans Laravel, avec le client HTTP de Laravel ou `php-opencloud/openstack`, via les application credentials.
- Modèle Heat du lab 08 (deux LAN et un routeur), d'après `paillasse-contenus/` :
- réseaux de lab **sans DHCP**, avec `port_security_enabled: false` ;
- **aucun routeur vers l'extérieur** : les VM des labs n'ont pas accès à Internet.
- Jobs dans une file Redis :
- `CreerStackLab` ;
- `SupprimerStackLab` ;
- expiration automatique des sessions.
**Critère :** le bouton « Lancer le lab 08 » crée une stack `CREATE_COMPLETE`, et les terminaux de chacune de ses VM s'ouvrent.
### Étape 11 : Stock chaud et correction automatique
**Stock chaud**
- Une liste Redis de stacks prêtes par lab, remplie par un job.
- Taille par défaut : calculée par toi selon la RAM disponible, et configurable.
- Pré-remplissage automatique 10 minutes avant une séance.
**Correction**
- Un petit service `correcteur`, lancé par systemd, écoutant sur un socket Unix.
- Il accepte **uniquement** : uuid d'instance, id du lab, id de la vérification.
- Il exécute les vérifications **définies dans le YAML du lab** avec `guest-exec` de l'agent QEMU (par `virsh`, dans le conteneur `nova_libvirt`).
- Jamais de commande libre venant du portail.
- Laravel enregistre la note et le message pour l'élève.
**Critère :**
- un lab pris dans le stock s'ouvre en **moins de 5 s** ;
- une configuration correcte donne « réussi » ;
- une configuration incorrecte donne « échoué » avec un message utile.
### Étape 12 : Domaine, HTTPS et sécurité (Adam a configuré le DNS)
- Certificat Let's Encrypt (certbot, plugin Nginx) et renouvellement automatique.
- En-têtes de sécurité : HSTS, CSP adaptée à xterm.js, etc.
- Grafana et Uptime Kuma derrière authentification, et la page de statut publique.
- Vérifie à nouveau que seuls 22, 80 et 443 sont ouverts, et qu'aucune VM élève n'a d'IP publique ni d'accès sortant.
**Critère :** `https://<DOMAINE>` affiche un certificat valide, et le parcours prof → élève → lab → correction fonctionne en HTTPS.
### Étape 13 : Tests de capacité et de résistance
- Lance 20 VM `eleve.petit` en même temps. Mesure la RAM, le CPU et les temps de démarrage, puis écris `docs/capacite.md`.
- Restaure une sauvegarde complète du portail sur une copie de test.
- **Avec l'accord d'Adam**, redémarre le serveur : tout doit revenir seul (Kolla, portail, proxy, correcteur, supervision).
**Critère :**
- les chiffres de capacité sont écrits ;
- la restauration est réussie ;
- tout est revenu seul après le redémarrage.
### Étape 14 : Pages légales et RGPD
Pages à créer :
- `/legal` : mentions légales (Esquisse Formation ; le SIREN et l'adresse sont à compléter par Adam) ;
- la politique de confidentialité ;
- la page de statut.
Job de purge : suppression 90 jours après l'archivage d'une classe.
Interdits :
- logo Marianne ou ministère ;
- drapeau de l'UE ;
- faux « logo RGPD » ;
- KPI inventés ou faux clients.
Formulations autorisées : « Hébergé en France » (c'est vrai), et « Conforme au RGPD » avec un lien vers la politique de confidentialité.
**Critère :** pages en ligne, et un test Pest prouve que la purge fonctionne.
---
## 4. Fin de mission
Écris `docs/bilan.md`, avec :
- ce qui fonctionne, avec la preuve de chaque critère ;
- le temps réel passé par étape ;
- la capacité mesurée (nombre d'élèves en même temps) ;
- les dettes et les risques connus ;
- **ce qu'Adam doit faire lui-même** : secrets à changer, comptes à créer, tests avec un prof, etc. ;
- les prochaines étapes du bloc A :
- self-healing et post-mortem ;
- montée de version d'OpenStack ;
- pilote avec une vraie classe.
Commence par l'étape 1.