Set-OPS-Public/playbooks/maintenance/devis-expositions.yml
Daniel Allaire 0cc04177fb devis des expositions : une vraie requete, depuis deux points de vue
Troisieme devis de service. Chaque expose: du plan repond-il, et si non, ou
ca casse.

- requete HTTPS complete avec la racine de l'AC, jamais un connect() : a
  travers l'OPNsense (anti-spoofing) toute connexion TCP reussit, et en TLS
  le silence apres connect() ne distingue pas un service sain d'un trou.
- deux points de vue : depuis l'edge (edge + dorsal) et depuis le poste
  (DNS + frontiere + edge + dorsal). Leur difference diagnostique.
- un code n'est pas un verdict : mon premier comparateur laissait passer un
  502 des deux cotes. Trouve par le test negatif, pas par la relecture.

Etat : les 6 expositions repondent des deux cotes. Test negatif (frontiere
qui bloque + dorsal tombe) : 2 ecarts nommes distinctement, code 1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 07:33:49 -04:00

89 lines
3.5 KiB
YAML

---
# Devis des expositions web — RELEVE seul. Ne modifie rien (D-23).
#
# Question posee : chaque `expose:` du plan repond-il VRAIMENT ? Et si non, ou ca casse.
#
# UNE VRAIE REQUETE, jamais un `connect()`. A travers l'OPNsense (anti-spoofing), toute
# connexion TCP reussit — y compris vers une adresse ou aucune machine n'existe. Et
# « lire des donnees apres connexion » ne vaut rien en TLS, ou c'est le CLIENT qui parle
# en premier : le port 443 d'un edge sain se comporte exactement comme un port mort.
# Seul le code de retour d'une requete HTTPS complete tranche.
#
# DEUX POINTS DE VUE, et c'est la difference entre les deux qui diagnostique :
# - depuis l'edge, avec `--resolve` vers 127.0.0.1 : edge + dorsal, sans la frontiere
# - depuis le poste : DNS + frontiere + edge + dorsal, le chemin d'un vrai utilisateur
# L'un repond et pas l'autre => ce n'est pas le service, c'est le chemin.
#
# make expositions-plan
- name: Devis des expositions — depuis l'edge
# Un seul edge suffit : le devis mesure les expositions, pas les hotes.
hosts: serveur_nginx[0]
become: true
gather_facts: false
tasks:
- name: Charger le registre des applications
ansible.builtin.include_vars:
file: "{{ setops_plan_dir }}/applications.yml"
- name: Recenser les expositions déclarées au plan
ansible.builtin.set_fact:
devis_expositions: >-
{{ applications | dict2items
| selectattr('value.expose', 'defined')
| map(attribute='value.expose') | flatten | unique | sort }}
- name: Interroger chaque exposition depuis l'edge (edge + dorsal, sans la frontière)
ansible.builtin.uri:
url: "https://{{ item }}/"
ca_path: "/etc/step/certs/root_ca.crt"
status_code: [200, 301, 302, 303, 307, 401, 403]
follow_redirects: none
timeout: 10
register: devis_expo_edge
failed_when: false
changed_when: false
loop: "{{ devis_expositions }}"
loop_control:
label: "{{ item }}"
# `--resolve` de curl n'existe pas dans `uri` : l'edge se resout lui-meme par le
# DNS interne, ce qui est le comportement reel des services du tenant.
- name: Récupérer la racine de l'AC sur le contrôleur
ansible.builtin.fetch:
src: /etc/step/certs/root_ca.crt
dest: "{{ playbook_dir }}/../../instance/.racine-ac.crt"
flat: true
- name: Interroger chaque exposition depuis le poste (le chemin d'un vrai utilisateur)
ansible.builtin.uri:
url: "https://{{ item }}/"
ca_path: "{{ playbook_dir }}/../../instance/.racine-ac.crt"
status_code: [200, 301, 302, 303, 307, 401, 403]
follow_redirects: none
timeout: 10
register: devis_expo_poste
failed_when: false
changed_when: false
delegate_to: localhost
become: false
loop: "{{ devis_expositions }}"
loop_control:
label: "{{ item }}"
- name: Déposer le relevé sur le contrôleur
ansible.builtin.copy:
dest: "{{ playbook_dir }}/../../instance/devis-expositions.json"
mode: "0600"
content: >-
{{ {
'edge': inventory_hostname,
'expositions': devis_expositions,
'depuis_edge': devis_expo_edge.results | map('combine', {}) | list
| zip(devis_expositions) | list,
'poste': devis_expo_poste.results | map('combine', {}) | list
| zip(devis_expositions) | list,
} | to_nice_json }}
delegate_to: localhost
become: false