#!/bin/bash # GENERE par Set-OPS (role serveur_ops). Ne pas editer a la main. # # SONDE « console-ops » — la console repond-elle, et son vestibule tient-il ? # # PAS UNE ENVELOPPE DE GREFFON, ET C'EST ASSUME. `check_http` sait dire « ce service # repond ». La verite d'ici est l'inverse : « ce service REFUSE-t-il encore ceux qui # n'ont pas de quoi entrer ». Aucun greffon standard ne pense a mesurer une serrure. # # ═══ LA SERRURE N'EST PAS LA MEME DES DEUX COTES (2026-09-20) ═══ # # Cette sonde a crie au trou de securite pendant cinq jours sur les deux runners de # locataire : « LE VESTIBULE EST OUVERT », HTTP 200, sur des consoles qui etaient # parfaitement fermees. Elle frappait `127.0.0.1:{{ serveur_ops_gui_port_public }}` — # le seul endroit d'ou, en mode `oidc`, un 200 est le resultat ATTENDU. # # `locale` — nginx EST le vestibule. Il ecoute pour l'edge, et c'est lui qui demande # le mot de passe. Un 200 anonyme est alors une porte ouverte : une panne. # `oidc` — la passerelle SSO est le vestibule, et nginx est reduit a la boucle # locale pour qu'on ne puisse pas la contourner. Un 200 depuis la boucle # locale prouve seulement que le relais fonctionne. Ce qu'il faut mesurer # ici, c'est que PERSONNE D'AUTRE que cette boucle n'atteint ce port. # # L'INSTRUMENT DOIT DIRE D'OU IL MESURE. Une sonde qui ne connait pas le mode du service # qu'elle surveille fabrique des pannes, et une panne permanente finit par ne plus etre # lue du tout. # # CE QU'ELLE NE MESURE PAS, ET POURQUOI. En `oidc`, le refus de la passerelle elle-meme # est l'affaire de la sonde « passerelle » de `serveur_oauth2_proxy`, posee sur ce meme # hote. Deux sondes, deux serrures, aucune qui devine le port de l'autre. set -uo pipefail GUI={{ serveur_ops_gui_ecoute }}:{{ serveur_ops_gui_port }} VESTIBULE=127.0.0.1:{{ serveur_ops_gui_port_public }} PORT_PUBLIC={{ serveur_ops_gui_port_public }} NOM='{{ serveur_ops_hostname }}' MODE='{{ serveur_ops_gui_auth }}' # 1. LE GUI VIT-IL ? On frappe la boucle locale, la ou il est le seul a pouvoir repondre. code=$(curl -s -o /dev/null -w '%{http_code}' --max-time 10 "http://${GUI}/" 2>/dev/null) if [[ "${code}" != "200" ]]; then echo "La console ne repond pas sur ${GUI} (HTTP ${code:-aucune reponse}) — plus personne ne pilote cet ecosysteme depuis le navigateur." exit 2 fi # 2. LE VESTIBULE. On frappe SANS justificatif, avec le bon `Host` : c'est ainsi que nginx # choisit son vhost, et sans cet en-tete on mesurerait le serveur par defaut — c'est-a-dire # autre chose. vu=$(curl -s -o /dev/null -w '%{http_code}' --max-time 10 \ -H "Host: ${NOM}" "http://${VESTIBULE}/" 2>/dev/null) if [[ "${MODE}" == "oidc" ]]; then # EN `oidc`, LA SERRURE EST UNE ADRESSE D'ECOUTE, PAS UN CODE HTTP. # # `ss -H -lnt` rend une ligne par ecoute, sans en-tete ; la 4e colonne porte l'adresse. # Tout ce qui n'est pas la boucle locale est une seconde porte sur la console, ouverte # a qui atteint l'hote — `deployer`, `creer` et `raser` sans passer par Keycloak. hors_boucle=$(ss -H -lnt "sport = :${PORT_PUBLIC}" 2>/dev/null \ | awk '{print $4}' | grep -vE '^(127\.0\.0\.1|\[::1\]):' || true) if [[ -n "${hors_boucle}" ]]; then echo "LE VESTIBULE ECOUTE HORS DE LA BOUCLE LOCALE (${hors_boucle//$'\n'/, }) : en mode oidc la passerelle SSO est la seule porte, et ce port-la la contourne." exit 2 fi if [[ "${vu}" == "200" ]]; then echo "Console vivante, vestibule (oidc) reduit a la boucle locale : le relais repond ici, et ce port n'est joignable de nulle part ailleurs." exit 0 fi echo "Le relais local ne sert plus la console : HTTP ${vu:-aucune reponse} sur ${VESTIBULE}. La passerelle SSO n'a plus rien a relayer." exit 2 fi # EN `locale`, NGINX EST LE VESTIBULE : c'est lui qui doit refuser. # # UN 200 ICI EST LA PIRE DES REPONSES. Il veut dire que le vestibule laisse entrer : la # console est alors ouverte a quiconque atteint l'adresse, avec `deployer`, `creer` et # l'edition du plan. On le traite comme une panne, parce que c'en est une. case "${vu}" in 401|403) echo "Console vivante, vestibule (${MODE}) en place : une requete anonyme rend HTTP ${vu}." exit 0 ;; 30[12478]) # Une redirection en mode locale signifie que le `auth_basic` n'est plus applique. echo "LE VESTIBULE NE DEMANDE PLUS RIEN : en mode locale, une requete anonyme devrait rendre 401, elle rend ${vu}." exit 2 ;; 200) echo "LE VESTIBULE EST OUVERT : une requete anonyme obtient la console (HTTP 200). Deployer, creer et raser sont a la portee de qui trouve l'adresse." exit 2 ;; "" | 000) echo "Le vestibule ne repond pas sur ${VESTIBULE} — la console vit, mais l'edge ne peut plus l'atteindre." exit 2 ;; *) echo "Reponse inattendue du vestibule : HTTP ${vu}." exit 1 ;; esac