fix: let the panel reach the API over plain HTTP, deliberately
The e-ink firmware carries a certificate-authority bundle fixed when it was built, so it cannot validate a chain rooted in an authority created afterwards. Let's Encrypt's ISRG Root YR was issued in May 2026 and is not even in an up-to-date Ubuntu CA bundle yet; the kit's firmware predates it. The handshake fails before a request is ever sent, which is why neither Traefik nor the application saw anything at all while the device reported "API connection cannot be established". Ruled out first, with evidence: TLS 1.2 and the ECDHE-RSA-AES-GCM suites an ESP32 needs are both offered, and the intermediate is not cross-signed by an older root, so no alternate path exists in what is served. A Traefik router now serves four device paths over :80, ahead of the entrypoint-wide redirect. The administration stays on TLS. The device token travels in clear; it is used for nothing else and is revocable from the settings page, and the image URL is an unguessable content hash. DEVICE_ALLOW_HTTP existed but was never read — a setting that does nothing misrepresents what it protects. The device routes now refuse an unencrypted request unless it is set, so opening this door is a written decision rather than the silent consequence of a proxy change. DEPLOY.md records the whole diagnosis, including the commands that distinguish a TLS failure from an application one, and what to do the day the firmware learns the new roots. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012cSY9pVhZmJUKNN7wf1Myd
This commit is contained in:
@@ -109,16 +109,60 @@ la sauvegarde préalable.
|
||||
|
||||
## Le panneau tombe sur le certificat TLS
|
||||
|
||||
Certains firmwares ESP32 échouent sur une chaîne de certificats que tous les
|
||||
navigateurs acceptent. Si l'écran n'arrive à joindre le serveur qu'en clair,
|
||||
`DEVICE_ALLOW_HTTP=true` existe — mais c'est le dernier recours, pas le premier.
|
||||
**C'est arrivé sur cette installation, et c'est réglé — voici pourquoi, pour le
|
||||
jour où ça recommence.**
|
||||
|
||||
Dans l'ordre :
|
||||
Le firmware de l'écran embarque un magasin d'autorités de certification **figé
|
||||
au moment de sa compilation**. Il ne peut donc pas valider une chaîne qui
|
||||
s'enracine sur une autorité créée après lui. Let's Encrypt a mis en service la
|
||||
racine `ISRG Root YR` le 13 mai 2026 ; le firmware du kit est antérieur, et la
|
||||
poignée de main TLS échoue **avant** qu'une seule requête soit émise — d'où le
|
||||
symptôme déroutant : l'écran affiche « API connection cannot be established »
|
||||
et ni Traefik ni l'application n'ont rien vu passer.
|
||||
|
||||
1. Vérifiez que l'écran atteint bien le domaine : `docker compose logs app | grep /api/setup`.
|
||||
2. Vérifiez la chaîne servie : `openssl s_client -connect horaires.ita-ito.com:443 -servername horaires.ita-ito.com | head -20`. Une chaîne incomplète est le cas le plus fréquent et se corrige côté Traefik, pas côté écran.
|
||||
3. En dernier recours seulement, exposez un hôte virtuel en clair réservé aux
|
||||
routes `/api/setup`, `/api/display`, `/api/log` et `/api/device/image/*`.
|
||||
Le jeton d'appareil circulerait alors en clair : il est distinct de tout
|
||||
autre secret et révocable depuis *Paramètres → Appareils*, ce qui rend
|
||||
l'arbitrage tenable — mais l'administration, elle, reste en TLS.
|
||||
Diagnostic, dans l'ordre :
|
||||
|
||||
1. **L'écran a-t-il seulement atteint le serveur ?**
|
||||
`docker compose logs app --since 30m | grep /api/setup` et
|
||||
`docker logs traefik --since 30m | grep horaires`.
|
||||
Si les deux sont vides, l'échec est dans la couche TLS, pas dans l'application.
|
||||
|
||||
2. **Quelle chaîne est servie, et jusqu'à quelle racine ?**
|
||||
```bash
|
||||
echo | openssl s_client -connect horaires.ita-ito.com:443 \
|
||||
-servername horaires.ita-ito.com 2>/dev/null | grep -E "^ *[0-9] s:"
|
||||
```
|
||||
Comparez la racine à ce que le système connaît :
|
||||
```bash
|
||||
openssl crl2pkcs7 -nocrl -certfile /etc/ssl/certs/ca-certificates.crt \
|
||||
| openssl pkcs7 -print_certs -noout | grep "Root YR"
|
||||
```
|
||||
Si une machine à jour ne la connaît pas, un firmware de 2025 encore moins.
|
||||
|
||||
3. **Le protocole est-il en cause ?** Souvent soupçonné, rarement coupable :
|
||||
```bash
|
||||
echo | openssl s_client -connect horaires.ita-ito.com:443 -tls1_2 | grep "Cipher is"
|
||||
```
|
||||
Un ESP32 a besoin de TLS 1.2 et d'une suite `ECDHE-RSA-AES*-GCM`.
|
||||
|
||||
Deux corrections possibles :
|
||||
|
||||
- **Préférer une racine ancienne.** `preferredChain: "ISRG Root X1"` sur le
|
||||
resolver dans `traefik.yml`, puis renouvellement. `ISRG Root X1` est dans à
|
||||
peu près tous les magasins depuis 2021. Aucun compromis de sécurité, mais
|
||||
cela dépend de ce que Let's Encrypt propose encore comme chaîne alternative,
|
||||
et cela touche le Traefik partagé par tous les sites.
|
||||
|
||||
- **Servir l'écran en clair** — ce qui est fait ici. Le routeur
|
||||
`horaires-device` dans `docker-compose.prod.yml` expose sur `:80` les seules
|
||||
routes `/api/setup`, `/api/display`, `/api/log` et `/api/device/`, avec une
|
||||
priorité qui passe devant la redirection HTTP→HTTPS générale. L'administration
|
||||
reste en TLS. Le jeton d'appareil circule alors en clair : il ne sert à rien
|
||||
d'autre et se révoque depuis *Paramètres → Appareils*.
|
||||
|
||||
L'application **refuse** une requête d'appareil non chiffrée tant que
|
||||
`DEVICE_ALLOW_HTTP=true` n'est pas posé : ouvrir cette porte est une décision
|
||||
écrite, pas la conséquence silencieuse d'une configuration de proxy.
|
||||
|
||||
Le jour où le firmware apprend les racines récentes, retirez le routeur
|
||||
`horaires-device` et remettez `DEVICE_ALLOW_HTTP=false`.
|
||||
|
||||
Reference in New Issue
Block a user