From 3e7c85506c5ccce4912557bfda5c39b3cb51e429 Mon Sep 17 00:00:00 2001 From: Daniel Allaire Date: Tue, 7 Jul 2026 03:25:24 -0400 Subject: [PATCH] =?UTF-8?q?Recette=20:=20valider=20=E2=80=94=20courriel=20?= =?UTF-8?q?bout-en-bout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- CHANGELOG.md | 7 ++++--- playbooks/valider.yml | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5091159..0a8cf52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,10 @@ - **`make valider` — recette d'acceptation fonctionnelle (phase 4, v1).** Vérifie que les services *fonctionnent*, pas juste qu'ils sont déployés (complète les `*-verifier` statiques). `playbooks/valider.yml`, lecture seule : **cibles Prometheus toutes UP** (API `/targets`) + **vhosts HTTPS exposés répondent** - (dérivés des `server_name` réels de l'edge, filtrés sur `domaine_interne` — générique). Éprouvé sur la - flotte vivante : 7 cibles UP, 8 vhosts OK (via l'edge, sous pare-feu actif). À venir : courriel - bout-en-bout (envoi→IMAP), restauration de sauvegarde. + (dérivés des `server_name` réels de l'edge, filtrés sur `domaine_interne` — générique) + **courriel + bout-en-bout** (envoi via le MTA → LDAP → LMTP → Maildir, remise vérifiée par `doveadm` sur le + compte `testmail`, message de test nettoyé). Éprouvé sur la flotte vivante sous pare-feu actif : + 7 cibles UP, 8 vhosts OK, courriel remis. À venir : restauration de sauvegarde (restic). - **Pare-feu nftables activé sur TOUTE la flotte (14 nœuds, activation prudente).** Les 14 hôtes actifs tournent sous `policy drop` avec leur ruleset **résolu moindre-privilège** (flux est-ouest déclarés autorisés par source, reste refusé). Vérifié en conditions réelles : flux déclarés OPEN diff --git a/playbooks/valider.yml b/playbooks/valider.yml index 59812c4..a5fe83a 100644 --- a/playbooks/valider.yml +++ b/playbooks/valider.yml @@ -68,3 +68,46 @@ 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