Set-OPS-Public/playbooks/valider.yml
Daniel Allaire 3e7c85506c Recette : valider — courriel bout-en-bout
Ajoute au make valider la preuve fonctionnelle du service courriel souverain :
envoi via le MTA (sendmail -> postfix -> LDAP -> LMTP) puis vérification de la
remise dans le Maildir avec doveadm (compte testmail), message de test nettoyé.

Éprouvé sur la flotte vivante, sous pare-feu actif : remise confirmée.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 03:25:24 -04:00

113 lines
4.7 KiB
YAML

---
# make valider — RECETTE D'ACCEPTATION : les services FONCTIONNENT (pas juste déployés).
# Lecture seule / faible impact. Complète les *-verifier (statiques, sur le plan)
# et verifier-hote (niveau hôte) par une vérif FONCTIONNELLE de bout en bout.
#
# v1 : cibles Prometheus UP + endpoints HTTPS exposés répondent.
# À venir : courriel bout-en-bout (envoi→IMAP), restauration de sauvegarde.
- name: "Recette — Prometheus : toutes les cibles de supervision UP"
hosts: serveur_prometheus
gather_facts: false
become: false
tasks:
- name: Interroger l'API des cibles actives
ansible.builtin.uri:
url: "http://localhost:9090/api/v1/targets?state=active"
return_content: true
register: prom_targets
- name: Analyser up / down
vars:
cibles: "{{ (prom_targets.content | from_json).data.activeTargets }}"
en_panne: "{{ cibles | rejectattr('health', 'equalto', 'up') | list }}"
ansible.builtin.set_fact:
recette_prom_total: "{{ cibles | length }}"
recette_prom_down: "{{ en_panne | map(attribute='labels.instance') | list }}"
- name: "✔ Prometheus"
ansible.builtin.assert:
that: "recette_prom_down | length == 0"
success_msg: "OK — {{ recette_prom_total }} cibles, toutes UP."
fail_msg: "ÉCHEC — cibles DOWN : {{ recette_prom_down }}"
- name: "Recette — Edge : les vhosts HTTPS exposés répondent"
hosts: serveur_nginx
gather_facts: false
become: true
tasks:
- name: Lister les valeurs de la directive server_name (première colonne exacte)
ansible.builtin.shell:
cmd: >-
nginx -T 2>/dev/null | awk '$1=="server_name"{for(i=2;i<=NF;i++){gsub(/;/,"",$i);
print $i}}' | sort -u
register: recette_server_names
changed_when: false
- name: Retenir les vhosts du domaine interne (exclut défauts/placeholders)
ansible.builtin.set_fact:
recette_fqdns: >-
{{ recette_server_names.stdout_lines
| select('search', '\.' ~ (domaine_interne | regex_escape) ~ '$') | list }}
- name: Interroger chaque vhost exposé en HTTPS (via l'edge)
ansible.builtin.uri:
url: "https://{{ item }}/"
validate_certs: false
status_code: [200, 301, 302, 401, 403]
follow_redirects: none
timeout: 10
loop: "{{ recette_fqdns }}"
register: recette_http
failed_when: false
- name: "✔ Endpoints HTTPS"
vars:
echecs: "{{ recette_http.results | rejectattr('status', 'in', [200, 301, 302, 401, 403]) | list }}"
ansible.builtin.assert:
that: "echecs | length == 0"
success_msg: "OK — {{ recette_http.results | length }} vhosts répondent : {{ recette_fqdns }}"
fail_msg: "ÉCHEC — vhosts KO : {{ echecs | map(attribute='item') | list }} (statuts {{ echecs | map(attribute='status') | list }})"
- name: "Recette — Courriel bout-en-bout (MTA -> LMTP -> Maildir)"
hosts: serveur_dovecot
gather_facts: true
become: true
vars:
recette_mail_dest: "testmail@{{ domaine_interne }}"
recette_mail_from: "recette@{{ domaine_interne }}"
tasks:
- name: Jeton unique du message de test
ansible.builtin.set_fact:
recette_mail_token: "SETOPS-VALIDER-{{ ansible_date_time.iso8601_basic_short }}-{{ 999999 | random }}"
- name: Envoyer via le MTA (sendmail — flux réel postfix -> LDAP -> LMTP -> Dovecot)
ansible.builtin.shell:
cmd: >-
printf 'Subject: %s\nFrom: %s\nTo: %s\n\nRecette d acceptation Set-OPS.\n'
'{{ recette_mail_token }}' '{{ recette_mail_from }}' '{{ recette_mail_dest }}'
| /usr/sbin/sendmail -f '{{ recette_mail_from }}' '{{ recette_mail_dest }}'
delegate_to: "{{ groups['serveur_postfix'][0] }}"
changed_when: true
- name: Attendre la remise dans la boîte (doveadm, LMTP asynchrone)
ansible.builtin.command:
cmd: "doveadm search -u {{ recette_mail_dest }} mailbox INBOX subject {{ recette_mail_token }}"
register: recette_mail_search
until: recette_mail_search.stdout | trim | length > 0
retries: 10
delay: 3
changed_when: false
failed_when: false
- name: "✔ Courriel"
ansible.builtin.assert:
that: "recette_mail_search.stdout | trim | length > 0"
success_msg: "OK — courriel remis à {{ recette_mail_dest }} (envoi -> LMTP -> Maildir prouvé)."
fail_msg: "ÉCHEC — courriel NON remis à {{ recette_mail_dest }} après 30 s."
- name: Nettoyer le message de test (best-effort)
ansible.builtin.command:
cmd: "doveadm expunge -u {{ recette_mail_dest }} mailbox INBOX subject {{ recette_mail_token }}"
changed_when: true
failed_when: false