Les trois environnements passent sur enervision-g3.duckdns.org, rec. et dev. : noms publics qui visent l'IP privée de la VM, donc résolus sans /etc/hosts sur le réseau de l'école et injoignables ailleurs (ADR 0018). - infra/front : nginx sur le réseau de l'hôte, seul exposé en 80 et 443. Aiguille par SNI vers la stack visée sans déchiffrer le TLS, et lui transmet l'IP du client en PROXY protocol. - Proxy de stack : écouteur 4443 en PROXY protocol, real_ip_header ; sans lui, limit_req et get_client_ip() compteraient tous les postes comme un seul. PROXY_FRONT_PORT le publie sur 127.0.0.1. - make tls-duckdns : Let's Encrypt par défi DNS-01 via l'API DuckDNS (acme.sh 3.1.6), rejouable, rejoué à chaque déploiement et chaque nuit. - provision-host.sh fait foi pour l'adressage et les secrets : un .env existant garde ses secrets, reçoit ceux qui manquent (supervision) et voit hôte et ports réalignés. Planifie le renouvellement des certificats. - deploy.yml : nouvelles URL, sonde prod sur 10443, front-up en prod. - Terraform : variable domaine. CI : validation du frontal.
4.7 KiB
0018 - Noms DuckDNS, certificats Let's Encrypt par DNS-01 et frontal SNI sans port
- Statut : accepté
- Date : 2026-09-23
Contexte
Les trois environnements de la VM ENI (ADR 0009,
ADR 0017) répondaient sur enervision.local,
rec.enervision.local:8443 et dev.enervision.local:9443, avec des certificats auto-signés.
Chaque poste devait éditer son /etc/hosts et accepter trois avertissements du navigateur :
rien de présentable à un jury, et rien d'utilisable par quelqu'un qui n'a pas la main sur son
poste.
Contraintes : la VM n'a qu'une IP privée, 10.101.200.37, que ni Internet ni Let's Encrypt ne
joignent, et le réseau de l'école ne doit pas être touché. Deux vérifications faites le 23/09 :
les résolveurs de l'école rendent bien une adresse privée pour un nom public, et la VM sort en
HTTPS vers Let's Encrypt.
Décision
Des noms publics qui visent l'IP privée. enervision-g3.duckdns.org porte la prod,
rec. et dev. en sous-domaines, que DuckDNS résout d'office. Tout poste du réseau de l'école
les résout sans configuration ; hors de ce réseau, l'IP ne mène nulle part.
Des certificats Let's Encrypt par défi DNS-01. Le défi passe par l'API DuckDNS, qui pose
l'enregistrement TXT : Let's Encrypt n'a jamais à joindre la VM. make tls-duckdns (acme.sh
épinglé) le joue dans chaque stack ; il ne renouvelle qu'à échéance, d'où son rejeu à chaque
déploiement et chaque nuit par cron. Un certificat par environnement : DuckDNS ne tient qu'un
TXT à la fois, ce qui interdit un certificat unique pour le domaine et son joker.
Un frontal SNI sur 443, le seul composant exposé. infra/front, un nginx sur le réseau de
l'hôte, lit le nom demandé dans le ClientHello et relaie le flux TLS intact vers la stack visée,
publiée sur la boucle locale. Il ne détient aucun certificat. Le port 80 y redirige vers
HTTPS. Les URL perdent leur port.
Le PROXY protocol entre frontal et stacks. Relayé tel quel, le flux arriverait avec l'IP du
frontal : limit_req et get_client_ip() compteraient tous les postes comme un seul, et un
utilisateur bloquerait la connexion de tous. Chaque proxy de stack reçoit donc le frontal sur un
écouteur dédié, 4443, qui exige l'en-tête PROXY protocol et en tire l'IP du client. Le 443 de
la stack reste sans PROXY protocol, pour les postes de développement et la sonde du déploiement.
scripts/provision-host.sh fait foi pour l'adressage et les secrets. Un .env existant
garde ses secrets, reçoit ceux qui lui manquent et voit hôte, ports et profils réalignés sur le
tableau du script. C'est ce qui permet de migrer trois .env nés avant ce changement, et le
clone de la prod, en retard sur main, sans dépendre de son .env.example.
Alternatives écartées
- Garder
/etc/hostset l'auto-signé : trois manipulations par poste et trois avertissements, précisément ce qu'il fallait supprimer. - nip.io ou sslip.io : résolution sans compte, mais aucun moyen d'y obtenir un certificat.
- Services à certificat joker public (traefik.me, local-ip.co) : leur clé privée est publiée par conception, n'importe qui peut usurper ces noms.
- Tunnel vers Internet (Cloudflare Tunnel, Tailscale Funnel) : accès depuis l'extérieur, mais l'application serait exposée hors de l'école, décision refusée.
- Autorité de certification interne (mkcert, step-ca) : chaque poste devrait l'installer.
- Terminaison TLS au frontal : un seul endroit pour les certificats, mais les stacks recevraient du HTTP clair que leur proxy redirige vers HTTPS, et en-têtes de sécurité comme limitation de débit seraient à déplacer. Le relais SNI ne touche à rien de tout cela.
- Domaine acheté : plus présentable, mais un achat et un compte de plus pour un bénéfice nul
sur l'accès. Seule
DOMAINEchangerait.
Conséquences
- L'objection de l'ADR 0009 à un proxy frontal, qui aurait dû joindre plusieurs réseaux Compose aux services homonymes, tombe : le frontal ne joint que des ports de la boucle locale.
- Sans le frontal, plus rien n'est joignable sur la VM.
deploy.ymlle relance à chaque déploiement de la prod, et sonrestart: unless-stoppedle ramène après un redémarrage. - Le jeton DuckDNS vit dans
/srv/enervision/duckdns.token, jamais dans git, GitHub ni le state Terraform. Qui le détient peut repointer les trois noms. - DuckDNS devient une dépendance : s'il tombe, les noms cessent de résoudre et les renouvellements échouent. Les certificats valent 90 jours, la marge est large.
- Les noms sont publics mais ne mènent qu'à une IP privée : ils révèlent l'existence de la VM, pas son contenu.