La supervision du SITE etait morte depuis 11:10 et rien ne le disait. icingadb refuse par pg_hba — hostssl impose cote serveur, connexion en clair cote client. icinga2 tournait, redis tournait, les sondes poussaient, et rien n atteignait la base : les verdicts se calculaient dans le vide. La cause est une seconde liste tenue a la main. tls_force allume hostssl ; chaque consommateur avait SON interrupteur a allumer dans les group_vars. Chezlepro avait les trois, le site avait le premier. serveur_forgejo disait pire que rien : sslmode disable ecrit en dur, le contraire de ce que le serveur imposait. resoudre_base expose resoudre_base_db_tls_force, lu dans les hostvars de la machine qui PORTE la base. Les trois interrupteurs en derivent. Un serveur qui ne declare rien ne force rien : on ne casse pas un ecosysteme qui n a pas bascule. P78 refuse une valeur ecrite chez un consommateur, et nomme les deux roles sans reglage TLS plutot que de rendre un vert muet sur eux. Apres : icingadb active, TLSv1.3 vu par PostgreSQL, 16 hotes et 88 services en base. Les cinq sondes des marqueurs du site, INCONNU faute de deploiement, rapportent leur phrase. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
96 lines
5.1 KiB
YAML
96 lines
5.1 KiB
YAML
---
|
|
# Rôle utilitaire (pas un groupe déployable) : résout l'entrée de base d'un
|
|
# consommateur depuis le registre partagé plan/bases-donnees.yml.
|
|
#
|
|
# Entrée : resoudre_base_groupe — le groupe consommateur (ex. serveur_keycloak).
|
|
# Sorties (facts) :
|
|
# resoudre_base_entree — l'entrée du registre {base, proprietaire, secret, serveur, ...}
|
|
# resoudre_base_db_password — mot de passe déréférencé depuis la voûte (no_log)
|
|
# resoudre_base_db_host — hôte du serveur de base
|
|
# resoudre_base_db_port — port du serveur de base (défaut 5432)
|
|
#
|
|
# Le secret ne quitte jamais le rôle consommateur (déréférencé par lookup('vars', ...)).
|
|
- name: Charger le registre des bases applicatives
|
|
ansible.builtin.include_vars:
|
|
file: "{{ setops_plan_dir }}/bases-donnees.yml"
|
|
|
|
# Le `consommateur` d'une base n'est PAS toujours un groupe : le validateur du registre
|
|
# (inventory_rules.py) accepte deux portées — `groupe` désigne un groupe opérationnel,
|
|
# `application` désigne une APPLICATION de plan/applications.yml. Chercher uniquement le
|
|
# nom du groupe faisait donc échouer toute base de portée `application` : Keycloak
|
|
# déclare `consommateur: keycloak`, le rôle demandait `serveur_keycloak`.
|
|
#
|
|
# Le lien entre les deux est DÉCLARÉ — chaque application nomme son `groupe`. On le suit
|
|
# plutôt que de retirer un préfixe à la main : une convention de nommage se contredit un
|
|
# jour, une déclaration se corrige.
|
|
- name: Charger le registre des applications (lien application → groupe)
|
|
ansible.builtin.include_vars:
|
|
file: "{{ setops_plan_dir }}/applications.yml"
|
|
|
|
- name: Établir les noms sous lesquels ce groupe peut être consommateur
|
|
ansible.builtin.set_fact:
|
|
resoudre_base_noms: >-
|
|
{{ [resoudre_base_groupe] + ((applications | default({})) | dict2items
|
|
| selectattr('value.groupe', 'defined')
|
|
| selectattr('value.groupe', 'equalto', resoudre_base_groupe)
|
|
| map(attribute='key') | list) }}
|
|
|
|
- name: Résoudre l'entrée de base (par consommateur, groupe ou application)
|
|
ansible.builtin.set_fact:
|
|
resoudre_base_entree: >-
|
|
{{ ((bases_donnees | default({})) | dict2items
|
|
| selectattr('value.consommateur', 'defined')
|
|
| selectattr('value.consommateur', 'in', resoudre_base_noms)
|
|
| map(attribute='value') | list | first) | default({}) }}
|
|
|
|
- name: Exiger une entrée de registre et son secret
|
|
ansible.builtin.assert:
|
|
that:
|
|
- resoudre_base_entree.base is defined
|
|
- resoudre_base_entree.proprietaire is defined
|
|
- resoudre_base_entree.secret is defined
|
|
fail_msg: >-
|
|
Aucune base dont le `consommateur` soit l'un de {{ resoudre_base_noms }}
|
|
dans instance/plan/bases-donnees.yml (portée `groupe` ou `application`).
|
|
|
|
- name: Résoudre le mot de passe de base (Vault)
|
|
ansible.builtin.set_fact:
|
|
resoudre_base_db_password: "{{ lookup('vars', resoudre_base_entree.secret) }}"
|
|
no_log: true
|
|
|
|
- name: Résoudre l'hôte (FQDN) et le port du serveur de base (registre)
|
|
ansible.builtin.set_fact:
|
|
# FQDN (pas le nom court) : non ambigu en fédération (data-sql-01 existe chez
|
|
# plusieurs tenants) + nom canonique pour la vérif TLS. Résolu par le plancher /etc/hosts.
|
|
resoudre_base_db_host: "{{ (serveurs_bd | default({}))[resoudre_base_entree.serveur].hote }}.{{ domaine_interne }}"
|
|
resoudre_base_db_port: "{{ (serveurs_bd | default({}))[resoudre_base_entree.serveur].port | default(5432) }}"
|
|
|
|
# LA POSTURE TLS DU SERVEUR, LUE CHEZ LE SERVEUR (2026-09-14).
|
|
#
|
|
# CE QUE ÇA A COÛTÉ. `serveur_postgresql_tls_force` pose `hostssl` dans `pg_hba` : toute
|
|
# connexion non chiffrée est refusée. Chaque consommateur avait alors SON propre
|
|
# interrupteur — `serveur_icinga_db_tls`, `serveur_keycloak_db_sslmode`,
|
|
# `serveur_forgejo_db_sslmode` — qu'il fallait allumer à la main, dans les `group_vars`,
|
|
# en même temps que celui du serveur.
|
|
#
|
|
# Chezlepro les avait tous les trois. Le site n'avait que celui du serveur. `icingadb` y
|
|
# est donc tombé le 2026-09-14 à 11:10 et n'est jamais remonté :
|
|
#
|
|
# aucune entrée dans pg_hba.conf pour l'hôte « 10.37.36.11 »,
|
|
# utilisateur « icingadb », base « icingadb », aucun chiffrement
|
|
#
|
|
# Une liste qui suit une autre prend du retard. Ici la seconde liste était tenue à la
|
|
# main dans un dépôt d'écosystème, et rien ne la comparait à la première.
|
|
#
|
|
# ON LIT DONC LA POSTURE CHEZ CELUI QUI LA DÉCIDE. Le serveur de base est un hôte de
|
|
# l'inventaire ; ce qu'il applique est dans ses `hostvars`. Un consommateur n'a plus à
|
|
# savoir qu'il doit chiffrer : il le déduit de ce que sert son serveur.
|
|
#
|
|
# `default(false)` : un serveur qui ne déclare rien ne force rien, et le consommateur
|
|
# reste en clair — c'était l'état de toute la flotte avant le zéro-confiance, et on ne
|
|
# casse pas un écosystème qui n'a pas encore basculé.
|
|
- name: Le serveur de base exige-t-il des connexions chiffrées ?
|
|
ansible.builtin.set_fact:
|
|
resoudre_base_db_tls_force: >-
|
|
{{ (hostvars[(serveurs_bd | default({}))[resoudre_base_entree.serveur].hote]
|
|
| default({})).get('serveur_postgresql_tls_force', false) | bool }}
|