fix(deploy): passe de DuckDNS à deSEC, filtré par l'école
Le filtrage du réseau de l'école bloque duckdns.org, site et API, depuis les postes comme depuis la VM : sans API, pas de défi DNS-01. deSEC (dedyn.io) répond depuis les deux. - Domaine enervision-g3.dedyn.io ; provision-host.sh publie par l'API deSEC l'enregistrement du domaine et son joker vers la VM. - make tls-desec remplace tls-duckdns. acme.sh recopie le jeton dans acme/account.conf : le dossier est retiré aux autres comptes. - deploy.yml ne demande un certificat qu'à un .env déjà réaligné sur le domaine deSEC, pour ne pas faire échouer un déploiement en cours de migration.
This commit is contained in:
+22
-14
@@ -1,4 +1,4 @@
|
||||
# 0018 - Noms DuckDNS, certificats Let's Encrypt par DNS-01 et frontal SNI sans port
|
||||
# 0018 - Noms deSEC, certificats Let's Encrypt par DNS-01 et frontal SNI sans port
|
||||
|
||||
- Statut : accepté
|
||||
- Date : 2026-09-23
|
||||
@@ -13,21 +13,24 @@ rien de présentable à un jury, et rien d'utilisable par quelqu'un qui n'a pas
|
||||
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.
|
||||
joignent, et le réseau de l'école ne doit pas être touché. Vérifications faites le 23/09 : les
|
||||
résolveurs de l'école rendent bien une adresse privée pour un nom public, la VM sort en HTTPS
|
||||
vers Let's Encrypt et vers l'API de deSEC, mais le filtrage de l'école bloque duckdns.org, site
|
||||
et API, depuis les postes comme depuis la VM.
|
||||
|
||||
## 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 noms publics qui visent l'IP privée.** `enervision-g3.dedyn.io`, zone gratuite de deSEC,
|
||||
porte la prod, et un enregistrement joker `*` porte `rec.` et `dev.`. `provision-host.sh` publie
|
||||
ces deux enregistrements par l'API deSEC : le DNS est décrit par le code comme le reste. 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
|
||||
**Des certificats Let's Encrypt par défi DNS-01.** Le défi passe par l'API deSEC, qui pose
|
||||
l'enregistrement TXT : Let's Encrypt n'a jamais à joindre la VM. `make tls-desec` (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.
|
||||
déploiement et chaque nuit par cron. Un certificat par environnement plutôt qu'un joker : chaque
|
||||
stack garde le sien, et la clé de la prod n'est pas lisible depuis le clone de dev.
|
||||
|
||||
**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,
|
||||
@@ -49,6 +52,8 @@ clone de la prod, en retard sur `main`, sans dépendre de son `.env.example`.
|
||||
|
||||
- **Garder `/etc/hosts` et l'auto-signé** : trois manipulations par poste et trois
|
||||
avertissements, précisément ce qu'il fallait supprimer.
|
||||
- **DuckDNS** : premier choix, inscription en un clic, mais bloqué par le filtrage de l'école :
|
||||
sans son API, pas de défi DNS-01.
|
||||
- **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.
|
||||
@@ -67,9 +72,12 @@ clone de la prod, en retard sur `main`, sans dépendre de son `.env.example`.
|
||||
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.yml` le relance à chaque
|
||||
déploiement de la prod, et son `restart: unless-stopped` le 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
|
||||
- Le jeton deSEC vit dans `/srv/enervision/desec.token`, jamais dans git, GitHub ni le state
|
||||
Terraform ; acme.sh en garde une copie dans `infra/proxy/acme/`, retirée à la lecture des
|
||||
autres comptes. Qui le détient peut repointer les trois noms.
|
||||
- deSEC 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.
|
||||
- Un filtrage de l'école qui viendrait à bloquer deSEC arrêterait les renouvellements, pas les
|
||||
noms : la résolution passe par les serveurs DNS de l'école, pas par le site.
|
||||
- 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.
|
||||
@@ -238,7 +238,7 @@ Deux conséquences se propagent jusqu'à l'application, et elles ne se devinent
|
||||
Statut : `En cours`. Décision et motifs dans
|
||||
l'[ADR 0009](../adr/0009-deux-environnements-compose-sur-la-vm-eni.md), étendue à un troisième
|
||||
environnement par l'[ADR 0017](../adr/0017-environnement-dev-a-la-demande.md) ; noms,
|
||||
certificats et frontal sans port dans l'[ADR 0018](../adr/0018-noms-duckdns-certificats-dns01-et-frontal-sni.md).
|
||||
certificats et frontal sans port dans l'[ADR 0018](../adr/0018-noms-desec-certificats-dns01-et-frontal-sni.md).
|
||||
La VM `eadl-2025-nantes-g3` porte le développement, la recette et la production, chacun dans son
|
||||
clone du dépôt, son `.env` et son projet Compose. Le nom de projet préfixe volumes, réseau et
|
||||
conteneurs : rien n'est partagé. `scripts/provision-host.sh` prépare les trois dossiers, génère
|
||||
@@ -248,20 +248,20 @@ les secrets et les certificats, et ne démarre rien.
|
||||
|---|---|---|---|
|
||||
| Branche, environnement GitHub | toute branche lancée à la main, `dev` | `dev`, `rec` | `main`, `prod` |
|
||||
| Dossier, projet Compose | `/srv/enervision/dev`, `enervision-dev` | `/srv/enervision/rec`, `enervision-rec` | `/srv/enervision/prod`, `enervision-prod` |
|
||||
| URL | `https://dev.enervision-g3.duckdns.org` | `https://rec.enervision-g3.duckdns.org` | `https://enervision-g3.duckdns.org` |
|
||||
| URL | `https://dev.enervision-g3.dedyn.io` | `https://rec.enervision-g3.dedyn.io` | `https://enervision-g3.dedyn.io` |
|
||||
| Proxy HTTP, HTTPS, PROXY protocol, sur `127.0.0.1` | `8083`, `9443`, `9444` | `8081`, `8443`, `8444` | `10080`, `10443`, `10444` |
|
||||
| PostgreSQL, Mailpit, Airflow, sur `127.0.0.1` | `5435`, `8027`, `8084` | `5434`, `8026`, `8082` | `5433`, `8025`, `8080` |
|
||||
| Supervision (profil `monitoring`) | à la demande, `make monitoring-up` | à la demande, `make monitoring-up` | active, `COMPOSE_PROFILES=monitoring` |
|
||||
| Grafana, Prometheus, Alertmanager, sur `127.0.0.1` | `3003`, `9092`, `9095` | `3002`, `9091`, `9094` | `3001`, `9090`, `9093` |
|
||||
|
||||
Les trois noms sont publics chez DuckDNS et visent l'IP privée de la VM : rien à déclarer sur
|
||||
Les trois noms sont publics chez deSEC et visent l'IP privée de la VM : rien à déclarer sur
|
||||
les postes du réseau de l'école, et rien n'est joignable hors de ce réseau. Trois noms distincts
|
||||
sont nécessaires : le cookie `__Secure-ev_refresh` est posé par hôte, pas par port.
|
||||
|
||||
Aucune stack ne publie hors de la boucle locale. Le frontal `infra/front`, sur le réseau de
|
||||
l'hôte, écoute 80 et 443 : il redirige le premier, et aiguille le second d'après le nom demandé
|
||||
(SNI) vers l'écouteur PROXY protocol de la stack visée, sans déchiffrer le TLS. Chaque stack
|
||||
garde son certificat Let's Encrypt, obtenu par défi DNS-01 (`make tls-duckdns`) et renouvelé à
|
||||
garde son certificat Let's Encrypt, obtenu par défi DNS-01 (`make tls-desec`) et renouvelé à
|
||||
chaque déploiement ainsi que chaque nuit par `/etc/cron.d/enervision-tls`.
|
||||
|
||||
Le déploiement est décrit dans [50-cicd.md](50-cicd.md) : un runner GitHub Actions installé sur
|
||||
|
||||
Reference in New Issue
Block a user