ajoute l'ADR 0006 : plan du relais TURN sur 443, vérifié dans la documentation officielle (pas encore appliqué)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Adam Belkacemi 2026-10-12 21:42:32 +02:00
parent d47e8356fc
commit 97c04f1ad6

View file

@ -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=<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=<même secret>`. 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é).