hosts_statiques : alias d'exposition dans le plancher /etc/hosts (résolution sûre)
Le plancher pose <IP edge> <FQDN exposé> sur chaque nœud, dérivé de expose + domaines.edge (même source que nginx/PowerDNS). DNS-indépendant, aucun risque. Chargement du plan best-effort (stat delegate_to localhost + become false). Prouvé : /etc/hosts d'obs-01 régénéré avec keycloak/grafana → edge (ligne manuelle éliminée), SSO Grafana fonctionne via le plancher (login: testmail). Boucle Phase 3 fermée : expose → vhost + SAN cert + A PowerDNS + alias plancher. Bugs corrigés : serveur_loki (groupe loki manquant) déjà committé ; stat sur cible→contrôle ; become inutile sur le contrôle. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
00ba515aad
commit
a870c9befe
4 changed files with 66 additions and 0 deletions
11
CHANGELOG.md
11
CHANGELOG.md
|
|
@ -13,6 +13,17 @@
|
|||
est **autoritatif, pas récursif** — pour que les nœuds *utilisent* ces A sans casser la résolution
|
||||
Internet, il faut un **récursif** (pdns-recursor : forward de la zone interne + récursion du reste)
|
||||
ou garder le plancher `/etc/hosts`. Ne PAS repointer naïvement `client_dns` vers l'autoritatif.
|
||||
- **`hosts_statiques` — alias d'exposition dans le plancher `/etc/hosts` (résolution client, sûre).**
|
||||
Le plancher pose désormais, sur **chaque nœud**, `<IP edge> <FQDN exposé>` pour chaque `expose`
|
||||
(dérivé de `domaines.edge`, même source que nginx/PowerDNS). Indépendant du DNS, aucun risque de
|
||||
couper la résolution (choix retenu vs pdns-recursor). Chargement du plan **best-effort**
|
||||
(`stat` **`delegate_to: localhost`** + `become: false` — les registres vivent sur le nœud de
|
||||
contrôle ; ignoré si le plan est absent, ex. préparation du template). **Prouvé** : `/etc/hosts`
|
||||
d'obs-01 régénéré avec `keycloak`/`grafana` → edge (ligne manuelle éliminée), `getent` OK, et le
|
||||
**flux SSO Grafana fonctionne via la résolution du plancher** (`login: testmail`). Boucle Phase 3
|
||||
fermée : déclarer `expose` → **vhost + SAN cert + A PowerDNS + alias plancher**, tout dérivé.
|
||||
Bugs corrigés en chemin : `serveur_loki` (groupe `loki` manquant), `stat` sur cible→contrôle,
|
||||
`become` inutile sur le contrôle.
|
||||
- **Bindings — Phase 1 : résolveur de liens dans `instancier.py` (relations service→service
|
||||
déclaratives).** Une application déclare ses `liens: [{vers, role}]` dans
|
||||
`plan/applications.yml` ; chaque rôle décrit les liens qu'il accepte dans `meta/liens.yml`
|
||||
|
|
|
|||
|
|
@ -3,3 +3,9 @@
|
|||
# serveur DNS. Permet à tout l'écosystème de se résoudre par nom même DNS éteint.
|
||||
hosts_statiques_actif: true
|
||||
hosts_statiques_domaine: "{{ domaine_interne | default('') }}"
|
||||
|
||||
# Alias d'exposition : poser <IP edge> <FQDN exposé> pour chaque application qui 'expose'
|
||||
# un FQDN (domaines.edge → l'edge qui le sert). Rend la résolution des services indépendante
|
||||
# du DNS. Best-effort : ignoré si le plan n'est pas disponible (ex. préparation du template).
|
||||
hosts_statiques_publier_expositions: true
|
||||
hosts_statiques_expositions: []
|
||||
|
|
|
|||
|
|
@ -1,4 +1,43 @@
|
|||
---
|
||||
# Alias d'exposition (best-effort) : dérivés du plan si celui-ci est disponible.
|
||||
- name: Vérifier la présence des registres du plan (sur le nœud de contrôle)
|
||||
ansible.builtin.stat:
|
||||
path: "{{ item }}"
|
||||
register: hosts_statiques_plan
|
||||
delegate_to: localhost # les registres du plan vivent sur le nœud de contrôle
|
||||
become: false # lire un fichier ne nécessite pas de privilèges
|
||||
loop:
|
||||
- "{{ setops_plan_dir }}/applications.yml"
|
||||
- "{{ setops_plan_dir }}/domaines.yml"
|
||||
loop_control:
|
||||
label: "{{ item | basename }}"
|
||||
when:
|
||||
- hosts_statiques_actif | bool
|
||||
- hosts_statiques_publier_expositions | bool
|
||||
- setops_plan_dir is defined
|
||||
|
||||
- name: Charger les registres applications et domaines (si présents)
|
||||
ansible.builtin.include_vars:
|
||||
file: "{{ item }}"
|
||||
loop:
|
||||
- "{{ setops_plan_dir }}/applications.yml"
|
||||
- "{{ setops_plan_dir }}/domaines.yml"
|
||||
loop_control:
|
||||
label: "{{ item | basename }}"
|
||||
when:
|
||||
- hosts_statiques_actif | bool
|
||||
- hosts_statiques_publier_expositions | bool
|
||||
- (hosts_statiques_plan.results | default([]) | selectattr('stat.exists', 'defined') | selectattr('stat.exists') | list | length) == 2
|
||||
|
||||
- name: Dériver les alias d'exposition (FQDN exposés → edge qui les sert)
|
||||
ansible.builtin.set_fact:
|
||||
hosts_statiques_expositions: >-
|
||||
{{ {'applications': applications | default({})}
|
||||
| expositions_des_applications({'domaines_publics': domaines_publics | default({})}) }}
|
||||
when:
|
||||
- hosts_statiques_actif | bool
|
||||
- hosts_statiques_publier_expositions | bool
|
||||
|
||||
- name: Générer /etc/hosts depuis l'inventaire (plancher de résolution, indépendant du DNS)
|
||||
ansible.builtin.template:
|
||||
src: hosts.j2
|
||||
|
|
|
|||
|
|
@ -10,3 +10,13 @@ ff02::2 ip6-allrouters
|
|||
{% for h in fleet if hostvars[h].ansible_host is defined %}
|
||||
{{ "%-15s" | format(hostvars[h].ansible_host) }} {{ h }}{{ (' ' ~ h ~ '.' ~ hosts_statiques_domaine) if hosts_statiques_domaine else '' }}
|
||||
{% endfor %}
|
||||
{% if hosts_statiques_publier_expositions | default(false) and hosts_statiques_expositions %}
|
||||
|
||||
# --- Alias d'exposition (FQDN publics → l'edge qui les sert) ---
|
||||
{% for expo in hosts_statiques_expositions %}
|
||||
{% set edge_hosts = groups.get(expo.edge, []) %}
|
||||
{% if edge_hosts and hostvars[edge_hosts[0]].ansible_host is defined %}
|
||||
{{ "%-15s" | format(hostvars[edge_hosts[0]].ansible_host) }} {{ expo.fqdn }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
|
|
|||
Loading…
Reference in a new issue