diff --git a/docs/adr/0006-turn-443-visio.md b/docs/adr/0006-turn-443-visio.md new file mode 100644 index 0000000..7f5974f --- /dev/null +++ b/docs/adr/0006-turn-443-visio.md @@ -0,0 +1,93 @@ +# ADR 0006 — Relais TURN pour la visio, sur le port 443 + +- **Date** : 2026-10-12 +- **Statut** : proposé (attend le DNS et l'accord d'Adam — pas encore appliqué) + +## Contexte + +Dette depuis l'étape 15 (ADR 0005) : sur un réseau scolaire qui bloque tout +sauf le port 443 (CLAUDE.md, section 6 : « Tout passe par le port 443 »), la +visio Jitsi n'a ni son ni image, car JVB n'écoute qu'en UDP sur le port 10000. +Un relais TURN sur 443 est la solution standard de Jitsi pour ce cas. + +Recherche faite dans la documentation officielle (pas de mémoire) : +- [Jitsi Handbook — Setting up TURN](https://jitsi.github.io/handbook/docs/devops-guide/turn/) +- fichier source `prosody/rootfs/defaults/prosody.cfg.lua` de l'image + `ghcr.io/jitsi/prosody:stable-11248` (celle déployée, lue directement, + pas résumée) +- `README.turnserver` du dépôt officiel `coturn/coturn` + +## Décisions + +1. **coturn, paquet Debian (`apt`), service systemd — pas en conteneur + Docker.** Comme `correcteur` et `proxy-console` : évite tout le lot de + soucis déjà rencontrés avec Docker (pont absent, `iptables: false`, + `br_netfilter`). Un seul process système à durcir et superviser. +2. **coturn n'écoute qu'en TLS (`tls-listening-port`), sur `127.0.0.1` ** — + jamais directement sur l'IP publique. `no-udp` et `no-tcp` (pas de + client en clair : TURNS seulement). Le relais vers JVB (`udp-relay`, + RFC 5766, en local) reste actif — c'est le sens inverse (coturn → JVB), + indispensable et jamais exposé à Internet. +3. **Partage du port 443 par SNI**, sans toucher au TLS existant : un bloc + `stream {}` Nginx (module `libnginx-mod-stream`, à installer — absent + aujourd'hui) avec `ssl_preread` lit le nom de domaine demandé dans la + poignée de main TLS **sans la déchiffrer**, puis route : + - `turn.syllabuslab.fr` → `127.0.0.1:5349` (coturn, qui termine son + propre TLS avec son propre certificat) ; + - tout le reste (`syllabuslab.fr`, `www`, `status`, `meet`) → + `127.0.0.1:8443` (le Nginx HTTP actuel, qui passe du port public 443 à + ce port interne — **inchangé sinon**). + `/etc/nginx/nginx.conf` passe de `include /etc/nginx/sites-enabled/*` à + une structure à deux niveaux (`http {}` sur le port interne, nouveau + `stream {}` sur le port public) : seul changement structurel du projet. +4. **Authentification par secret partagé (TURN REST API / XEP-0215)**, + mécanisme natif des deux côtés, aucun module ni plugin personnalisé : + - côté coturn : `use-auth-secret`, `static-auth-secret=`, + `realm=syllabuslab.fr` ; + - côté Prosody (variables d'environnement déjà lues par + `prosody.cfg.lua`, confirmé dans le fichier source) : + `TURNS_HOST=turn.syllabuslab.fr`, `TURNS_PORT=443`, + `TURN_CREDENTIALS=`. Prosody calcule alors lui-même, pour + chaque participant, un couple nom d'utilisateur/mot de passe TURN + valable 24 h (`TURN_TTL`, défaut `86400`), sans jamais exposer le + secret au navigateur. + - Le secret est généré une fois sur le serveur (comme les autres secrets + de la visio), jamais dans Git. +5. **Aucun nouveau port à ouvrir dans nftables.** Le relais UDP de coturn + vers JVB reste en boucle locale (les deux tournent sur le même serveur) : + l'intérêt du TURN-sur-TCP est justement que tout le trafic de l'élève — + contrôle *et* médias — passe par la seule connexion TCP/443 déjà établie + ; coturn se charge seul de parler en UDP à JVB, sans jamais demander au + navigateur de contacter une autre adresse. +6. **Certificat** : `turn.syllabuslab.fr` ajouté au certificat Let's Encrypt + existant (comme `meet`/`status`), obtenu une fois le DNS créé. + +## Prérequis avant d'appliquer quoi que ce soit + +- **DNS** : `turn.syllabuslab.fr → 163.172.4.195`, pas d'AAAA (comme `meet` + et `status`). **À faire par Adam.** +- Accord explicite d'Adam sur le diff exact de Nginx (changement structurel + le plus visible de ce chantier) et sur l'ouverture d'aucun nouveau port — + seule une restructuration interne du 443 existant. + +## Alternatives écartées + +- **coturn en conteneur Docker** : repasserait par les soucis de réseau + Docker déjà vus avec Kuma et Jitsi (étapes 9, 15) pour un gain nul (un + seul process, pas besoin d'isolation supplémentaire). +- **`mod_turncredentials.lua` personnalisé** (ancienne méthode documentée + dans des guides tiers) : l'image `prosody:stable-11248` le fait déjà + nativement par variables d'environnement — ne pas réinventer ce qui existe. +- **Ouvrir une plage de ports UDP pour le relais coturn → JVB** : inutile, + cette liaison reste locale au serveur. + +## Conséquences + +- Nouveau paquet système (`coturn`) et nouveau module Nginx + (`libnginx-mod-stream`) à faire vivre (mises à jour de sécurité comme le + reste : `unattended-upgrades` les couvre déjà). +- Restructuration de `/etc/nginx/nginx.conf` : à vérifier avec la même + prudence qu'un changement de pare-feu (filet anti-coupure, accord + explicite), même si techniquement aucune règle nftables ne change. +- Dette retirée une fois vérifié par un vrai test (client forcé en TCP, + comme documenté dans le Handbook Jitsi, ou réseau dont l'UDP est bloqué).