Set-OPS-Public/roles/serveur_ops/templates/nginx-gui.conf.j2
Daniel Allaire e93e8f4c1d console chez les locataires, collision de noms, et un fichier ecrase
Les deux locataires declarent leur console derriere oauth2-proxy. En oidc le
vestibule n ecoute que la boucle locale : le gabarit annoncait cette protection
en s en remettant au pare-feu, qui ouvrait le port depuis l edge — la console
etait joignable sans passer par la passerelle.

COLLISION REELLE : serveur_oauth2_proxy est mono-instance par machine, et la
table des noms publics etait indexee par GROUPE. La passerelle de la vigie se
croyait la console ; son URL de retour OIDC aurait vise l autre machine. Une
application nomme un COUPLE (machine, role). P67 ne le voyait pas parce qu elle
indexait comme la derivation qu elle garde — une garde qui reproduit le
raisonnement qu elle verifie ne verifie rien.

ET J AI ECRASE group_vars/serveur_ops.yml sans le regarder : 68 lignes
detruites, deux preuves tombees, et une explication fausse construite dessus. Le
git diff qui m avait rassure portait un glob developpe par le shell parent : il
n a rien matche et n a rien dit. Une commande qui ne trouve rien et une commande
qui trouve que rien n a change rendent le meme silence.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
2026-09-15 11:47:50 -04:00

53 lines
2.6 KiB
Django/Jinja

# GENERE par Set-OPS (role serveur_ops). Ne pas editer a la main.
#
# LE VESTIBULE DE LA CONSOLE. Le GUI, lui, n'ecoute que la boucle locale.
#
# TOUT CE QUI EST PUBLIE PASSE PAR ICI, et l'authentification est posee au niveau du
# `server` — pas d'un `location`. Placee dans le seul bloc de relais, elle laisserait
# passer tout chemin qu'un `location` plus specifique attraperait en premier. Une
# serrure qu'on contourne par la porte d'a cote n'est pas une serrure.
server {
listen {{ serveur_ops_gui_nginx_bind }}{{ serveur_ops_gui_port_public }};
{% if not serveur_ops_gui_nginx_bind %}
listen [::]:{{ serveur_ops_gui_port_public }};
{% endif %}
server_name {{ serveur_ops_hostname }};
{% if serveur_ops_gui_auth == 'locale' %}
# SANS ANNUAIRE : un mot de passe, et il vaut pour toute la fabric. C'est un repli
# assume, pas un choix — voir `serveur_ops_gui_auth` dans les defauts du role.
auth_basic "{{ serveur_ops_gui_realm }}";
auth_basic_user_file {{ serveur_ops_gui_htpasswd }};
{% else %}
# AVEC ANNUAIRE : `serveur_oauth2_proxy` se tient devant, sur la MEME machine, et
# c'est lui qui est publie. Ce vhost n'ecoute alors que la boucle locale
# (`serveur_ops_gui_nginx_bind`) — un port qui n'est pas ouvert ne se contourne pas.
#
# LA PREMIERE ECRITURE S'EN REMETTAIT AU PARE-FEU, et le pare-feu ouvrait ce port
# depuis `[edge, admin]` : l'edge pouvait donc joindre la console SANS passer par la
# passerelle. Le commentaire annoncait une protection que rien ne tenait.
{% endif %}
# LA CONSOLE DEPLOIE, ET UN DEPLOIEMENT EST LONG. Les delais par defaut de nginx
# (60 s) couperaient la reponse au milieu d'un `deployer`, et la page afficherait une
# erreur reseau pour une operation qui, elle, continue sur la machine. La pire forme
# de mensonge : l'ecran dit echec, la fabric dit succes.
proxy_read_timeout {{ serveur_ops_gui_delai | default(3600) }}s;
proxy_send_timeout {{ serveur_ops_gui_delai | default(3600) }}s;
# LA SORTIE D'UN DEPLOIEMENT ARRIVE AU FIL DE L'EAU. Sans ces deux lignes, nginx la
# retiendrait pour l'envoyer d'un bloc : la console resterait muette pendant des
# minutes, puis tout apparaitrait d'un coup.
proxy_buffering off;
gzip off;
location / {
proxy_pass http://{{ serveur_ops_gui_ecoute }}:{{ serveur_ops_gui_port }};
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}