Les trois consoles portaient le moteur du jour et servaient celui du 16 septembre. Le clone du genome ne notifiait rien et la tache de service demande state: started, qui ne fait rien quand le service tourne deja ; inventory_gui.py lit son code au demarrage, et seulement la. Le role retient desormais si le MOTEUR a avance — designe par serveur_ops_depot_moteur, jamais un chemin recopie — et redemarre la console dans ce seul cas : un plan qui avance ne coupe pas les pages ouvertes. La sonde console-ops criait au vestibule ouvert sur les deux runners de locataire, sur des consoles fermees. Elle frappait la boucle locale, seul endroit d'ou un 200 est le resultat attendu en mode oidc, ou nginx est reduit a 127.0.0.1 pour qu'on ne contourne pas la passerelle SSO. Elle connait maintenant son mode : en locale le verdict ne bouge pas, en oidc la serrure mesuree est l'adresse d'ecoute. Le refus de la passerelle reste l'affaire de la sonde passerelle de serveur_oauth2_proxy, sur le meme hote. Valide : --syntax-check sur playbooks/groupes/serveur_ops.yml, ansible-lint sur le role (profil production, 0 echec, 0 avertissement, 14 fichiers), le gabarit rendu dans ses deux modes sans reste Jinja et bash -n propre, le filtre d'ecoute eprouve sur cinq formes d'adresses, l'expression du when sur cinq cas dont le mode check. Le role est applique aux trois runners, failed=0, et la sonde rejouee sur chacun rend 0. Limite : le redemarrage automatique ne s'est pas declenche, les clones etant deja au niveau de la forge — la tache s'est correctement abstenue. La preuve du declenchement viendra au prochain genome pousse. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
99 lines
4.8 KiB
Django/Jinja
99 lines
4.8 KiB
Django/Jinja
#!/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
|