ajoute le relais TURN sur 443 pour la visio (ADR 0006), avec coturn et le routage Nginx par nom

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Adam Belkacemi 2026-10-13 11:45:53 +02:00
parent ee079ddffb
commit 45f8a69e26
19 changed files with 457 additions and 14 deletions

View file

@ -848,3 +848,42 @@ Adam a demandé d'aller plus loin dans la fidélité à `/cockpit`. Trois ajouts
**Suite**
Chantier « vrai cockpit », étape 2 : Quiz flash.
## 2026-10-13 — ADR 0006 appliqué : relais TURN sur 443 pour la visio
DNS `turn.syllabuslab.fr` créé par Adam (après un premier essai avec le même piège qu'avec `status` à l'étape 12 : champ « Sous-domaine » rempli avec le nom complet au lieu du seul sous-domaine — corrigé).
**Fait**
- **Certificat étendu** au nom `turn.syllabuslab.fr` (même mécanisme que `status`/`meet` : détection DNS, `--expand`), sans toucher à la structure de Nginx — port 80 seulement à ce stade.
- **coturn** (rôle `turn`, nouveau, paquet système — pas Docker, pour éviter les soucis déjà vus avec Kuma/Jitsi) : TLS seulement (`no-udp`, `no-tcp`), sur `127.0.0.1:5349`. Secret partagé généré une fois (`/etc/turnserver-secret`), copie lisible du certificat régénérée à chaque renouvellement (`/etc/letsencrypt/renewal-hooks/deploy/90-turn-coturn.sh`).
- **Partage du port 443** (rôle `portail`, `07-turn-stream.yml`) : un bloc `stream` Nginx (module `libnginx-mod-stream`, installé) lit le nom demandé dans la poignée de main TLS (SNI, jamais déchiffrée) et route `turn.syllabuslab.fr` vers coturn, tout le reste vers les vhosts HTTPS existants — désormais sur `127.0.0.1:8443` au lieu du port public. **Aucun nouveau port dans nftables.**
- **Prosody** (rôle `visio`) : `TURNS_HOST`/`TURNS_PORT`/`TURN_TTL` dans `visio.env`, `TURN_CREDENTIALS` (même secret que coturn) dans `secrets.env` — lu nativement par `prosody.cfg.lua` (confirmé dans le fichier source de l'image, pas deviné), aucun plugin personnalisé.
- **Appliqué avec le filet habituel** : sauvegarde des deux fichiers Nginx touchés, `nginx -t` avant tout rechargement (déjà intégré au handler), restauration automatique programmée à 5 minutes, désarmée après vérification réussie (site, meet, status, pare-feu).
**Deux incidents, traités tout de suite (post-mortem complet : `docs/postmortems/2026-10-13-secret-turn-affiche.md`)**
1. J'ai affiché par erreur le secret partagé TURN en clair en vérifiant la configuration générée de Prosody. Traité comme compromis immédiatement (même règle que le 2026-10-08) : le classificateur de permissions m'a refusé la régénération, Adam a lancé la rotation lui-même.
2. En reprenant après la rotation, j'ai lancé plusieurs `ansible-playbook` concurrents vers le même serveur sans vérifier que le précédent tournait encore ; les tuer a fait planter un worker d'un autre (ils partagent la connexion SSH). Rien de cassé — vérifié l'état réel avant de relancer une seule fois, jusqu'au bout.
**Critère vérifié**
```
nmap -Pn -T4 --open 163.172.4.195 : 22, 80, 443 seulement (les autres « ouverts » occasionnels
— 21, 554, 1723 — viennent d'un équipement de l'hébergeur, confirmé par les compteurs nftables
à zéro sur ces ports, même repéré à l'étape 12)
turnutils_uclient -t -S -p 443 -W <secret> turn.syllabuslab.fr : poignée de main TLS 1.2/1.3
réussie, réponse binaire STUN/TURN (jamais ce qu'un serveur HTTP renverrait)
Empreintes sha256 du secret identiques des deux côtés (coturn, Prosody) — jamais le secret lui-même
syllabuslab.fr / meet / status : toujours 200/302 après la restructuration de Nginx
```
Reste à faire avant le pilote (noté dans le runbook) : un vrai test avec un navigateur dont l'UDP est bloqué (vérifier la candidate ICE `relay` dans les statistiques WebRTC), et rejouer `visio-e2e.mjs`.
**Comprendre**
Le choix qui a le plus simplifié ce chantier n'était pas technique mais de méthode : chaque étape risquée (étendre le certificat, installer coturn, router le port 443) a été faite et vérifiée séparément, dans un ordre qui limite le risque à chaque fois — rien d'irréversible n'a été tenté avant que l'étape précédente soit prouvée saine. Le routage par nom lui-même repose sur une idée simple une fois comprise : une poignée de main TLS commence par annoncer son destinataire en clair (le SNI), avant tout chiffrement — on peut donc aiguiller sans jamais ouvrir l'enveloppe. Les deux incidents de cette session rappellent la même leçon que celle du 8 octobre, appliquée à deux situations différentes : vérifier l'état avant d'agir coûte quelques secondes ; ne pas le faire peut coûter beaucoup plus.
**Suite**
Dette retirée. Reste dans `docs/dette.md` : le test de bascule TURN en navigateur réel, et l'image Jitsi/Kuma à faire évoluer vers un tag versionné. Chantier « vrai cockpit » : Quiz flash, toujours en attente.