Set-OPS-Public/roles/client_journal/defaults/main.yml
Daniel Allaire f3bb9caee3 chiffrement : metriques et journaux du site en TLS, et la frontiere certifiee par sa propre autorite
Metriques et journaux (CHANGELOG 142). Le site pose les quatre interrupteurs TLS
que chaque locataire pose dans ses group_vars : node_exporter et Loki servaient
en HTTP sur les neuf VM, le certificat etait la, inutilise. test_parite_tls_site.py
compare desormais le site aux locataires. Les hyperviseurs poussent leurs
journaux en HTTPS verifie, avec la racine du site comme simple fichier.
L'exportateur PostgreSQL sert en HTTPS partout, sur l'interrupteur de PostgreSQL
lui-meme, que Prometheus lit pour choisir son schema.

La frontiere (CHANGELOG 143). Une autorite subordonnee signee par la racine du
site, bornee (pathlen 0, noms sous le domaine et adresses du site, contrainte
critique), cle nee sur la boite (scripts/frontiere_pki.py). Syslog vers Loki en
TLS mutuel (seule la frontiere peut ecrire), exportateur en HTTPS, interface web
sur le certificat de services ; les clients d'API verifient la frontiere contre
la racine du site. La lecture du magasin passe par config.xml : l'API de
recherche renvoie les cles privees.

Deploye et mesure au site, chez les deux locataires et sur la frontiere ; 95 preuves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 14:25:28 -04:00

120 lines
6.8 KiB
YAML

---
client_journal_paquets:
- alloy
client_journal_service: "alloy"
client_journal_utilisateur: "alloy"
client_journal_config: "/etc/alloy/config.alloy"
# Point de collecte Loki (obs-01, serveur_loki, VLAN 14).
# Hôte Loki dérivé du groupe serveur_loki (FQDN via le plancher) ; override par instance au besoin.
# LE SCHEMA SUIT L'INTERRUPTEUR TLS (2026-10-12) — meme defaut que Grafana le 2026-09-28 :
# une URL `http://` ecrite a cote d'un `client_journal_loki_tls: true` parlerait en clair a
# un Loki qui n'ecoute qu'en HTTPS.
client_journal_loki_url: >-
{{ 'https' if client_journal_loki_tls | bool else 'http' }}://{{
(groups.get('serveur_loki') or ['obs-01']) | first }}.{{ domaine_interne }}:3100/loki/api/v1/push
# Depot apt officiel Grafana (partage avec serveur_loki / serveur_grafana).
client_journal_depot_cle_url: "{{ client_journal_depot_schema }}://apt.grafana.com/gpg-full.key"
client_journal_depot_cle_fichier: "/etc/apt/keyrings/grafana.asc"
client_journal_depot_source: "deb [signed-by=/etc/apt/keyrings/grafana.asc] {{ client_journal_depot_schema }}://apt.grafana.com stable main"
# --- TLS (zero-confiance) : Alloy pousse vers Loki en https + verifie root_ca ---
client_journal_loki_tls: false
client_journal_loki_ca: "/etc/step/certs/root_ca.crt"
# UNE MACHINE SANS PKI PEUT QUAND MEME VERIFIER (2026-10-12). Un hyperviseur n'a pas
# `client_pki` : aucune racine sous /etc/step. Pour verifier Loki, il lui suffit du
# certificat PUBLIC de l'autorite — pas d'un certificat a lui. Non vide, ce contenu est
# pose a `client_journal_loki_ca` (au site, `ac-racine-site.crt` lu par l'inventaire).
client_journal_loki_ca_contenu: ""
# Port de l'interface HTTP locale d'Alloy (diagnostic). DECLARE ici parce que son defaut
# amont — 12345 — entrait en collision avec `serveur_dovecot_sasl_port`, qui valait 12345
# lui aussi (SASL reseau, pour la soumission :587 ; retire le 2026-10-12 — il passait en
# clair). Le port reste declare : le defaut amont, lui, n'a pas change.
#
# Sur `infra-mail-01`, les deux cohabitent : le premier demarre gagne, l'autre boucle sur
# « bind: address already in use ». Constate le 2026-08-08 lors de la premiere
# reconstruction from-zero, ou l'ordre des couches fait demarrer Dovecot bien avant Alloy.
# En exploitation courante le conflit dormait : Alloy tenait le port depuis toujours, et
# c'est l'ecoute SASL de Dovecot qui echouait — en silence.
#
# Le vrai defaut n'est pas le numero, c'est qu'un port SUBI ne se declare nulle part et
# qu'aucun controle ne peut donc voir la collision.
client_journal_http_port: 12346
client_journal_http_adresse: "127.0.0.1"
# --- Sonde de supervision (voir meta/supervision.yml) ---
# L'interface de diagnostic d'Alloy, la ou il tient le compte de ce qu'il a expedie et de
# ce qu'il a jete. Locale : personne d'autre n'a a la joindre.
client_journal_sonde_url: >-
http://{{ client_journal_http_adresse }}:{{ client_journal_http_port }}
# La memoire d'un passage a l'autre : sans elle, un compteur cumulatif ne dit pas QUAND.
client_journal_sonde_etat: "/var/lib/setops/journaux-jetees"
# --- SCHEMA DES DEPOTS TIERS (2026-09-10) --------------------------------------------
#
# `http` DES QU'UN CACHE EST DANS LE CHEMIN, `https` sinon. Ce n'est pas un relachement :
# le cache RELAIE ces depots en https vers le fournisseur (voir `serveur_artefacts`,
# `Remap-*`), et l'integrite vient des SIGNATURES du depot, qu'apt verifie de toute facon.
# Le meme raisonnement vaut deja pour `deb.debian.org` depuis toujours.
#
# Sans cette derivation, chaque machine sortait elle-meme sur Internet : le mandataire ne
# vaut que pour `http`, et le socle pose deliberement `Acquire::https::Proxy "DIRECT"`
# parce qu'un cache sans remap refuse les tunnels. Le remap leve ce refus ; encore
# faut-il DEMANDER en http.
#
# DEGRADE, JAMAIS DEVINE : pas de cache d'amorcage declare, pas de reecriture.
client_journal_depot_schema: >-
{{ 'http' if (artefacts_amorcage | default('') | string | length > 0) else 'https' }}
# --- RECEPTEUR SYSLOG (vide = pas de recepteur) ---------------------------------------
#
# CE QUI NE PEUT PAS PORTER D'AGENT DOIT QUAND MEME ETRE ENTENDU. La frontiere OPNsense
# n'accueille rien ; elle sait emettre du syslog. Le collecteur du site l'ecoute et le
# traduit vers Loki.
#
# CE QUE CA A COUTE DE NE PAS L'AVOIR : la destination syslog de la frontiere pointait une
# VM de TENANT, rasee depuis. Une cible morte a arrete TOUTE la journalisation d'OPNsense
# pendant dix jours, et rien ne l'a signale — c'est le meme silence qui a motive le `ttl`
# des sondes. La destination a ete eteinte pour reparer, et jamais remplacee : la frontiere
# ne journalisait plus nulle part.
#
# ET LA CIBLE ETAIT CHEZ UN LOCATAIRE, ce que D-87 refuse dans l'autre sens : les journaux
# du site ne vivent pas chez un tenant, pas plus que l'inverse. Le site a son Loki depuis
# le 2026-09-10 ; c'est la que ses equipements parlent.
#
# Vide par defaut : un tenant n'a pas de frontiere a ecouter.
client_journal_syslog_ecoute: ""
client_journal_syslog_protocole: "tcp"
# Le nom sous lequel les journaux recus apparaitront. Derive de la carte par l'inventaire
# du site — jamais fabrique ici.
client_journal_syslog_emetteur: "frontiere"
# LE RECEPTEUR SYSLOG EN TLS, AUTHENTIFIANT SES CLIENTS (2026-10-12). Le syslog de la
# frontiere passait en clair. Vrai : Alloy sert le certificat de la machine (client_pki,
# recopie la ou `alloy` le lit, et a chaque renouvellement) et EXIGE un certificat client
# signe par une autorite de `client_journal_syslog_clients_ca_contenu` — au site, celle de
# la frontiere seule : personne d'autre ne peut y ecrire.
client_journal_syslog_tls: false
client_journal_syslog_tls_dir: "/etc/alloy/tls"
client_journal_syslog_tls_source_cert: "/etc/step/certs/{{ ansible_fqdn | default(ansible_hostname) }}.crt"
client_journal_syslog_tls_source_cle: "/etc/step/certs/{{ ansible_fqdn | default(ansible_hostname) }}.key"
client_journal_syslog_clients_ca_contenu: ""
# LE JOURNAL D'AUDIT, EXPEDIE COMME LE RESTE (2026-09-11).
#
# DERIVE DE L'APPARTENANCE AU GROUPE, pas declare par instance : `auditd` vient avec
# `serveur_durci`, donc la machine qui a l'un a l'autre. Ecrire la liste a la main serait
# une liste de plus qui suit une autre — et qui prendrait du retard.
client_journal_audit_actif: "{{ 'serveur_durci' in group_names }}"
client_journal_audit_chemin: "/var/log/audit/audit.log"
# LES MACHINES QUI SONDENT — celles qui portent `client_sante`, donc qui jouent la sonde
# « connectivite » chaque minute. Leurs connexions de sonde ne sont pas expediees (voir le
# gabarit). Derive de l'inventaire : une machine ajoutee y entre sans qu'on l'ecrive.
# Vide = aucun filtre.
client_journal_sondeurs: >-
{{ groups.get('client_sante', []) | map('extract', hostvars)
| map(attribute='ansible_host', default='') | select('match', '^[0-9.]+$') | list }}