PostgreSQL — rend visibles deux defauts deja vecus ici : un reseau ECRIT dans pg_hba au lieu d'etre derive, et une ligne host en clair la ou il faut hostssl (verrou qui saute sans bruit, les clients verify-full continuant de marcher). Interroge pg_settings, jamais le fichier : un grep de postgresql.conf annonce ssl_cert_file=snakeoil alors que le serveur sert le certificat de l'AC — la valeur vient d'un conf.d que le grep ne voyait pas. L'instrument etait incomplet, pas la configuration. Courriel — chaque maillon interroge la ou il dit la verite : postmap -q pour la resolution LDAP de Postfix, doveadm user pour celle de Dovecot (le maillon exact ou la livraison avait bloque), vraies conversations SMTP/IMAP. Verifie aussi qu'une adresse INEXISTANTE ne resout pas — sinon la boite est un fourre-tout et le devis ne mesure plus rien. Trouve immediatement une divergence reelle : Dovecot connait la boite de sysadmin@chezlepro.internal, Postfix ne sait pas y router (query_filter (mail=%s), et l'attribut mail porte sysadmin@chezlepro.ca). Collision de roles : une identite ne porte qu'une adresse mail et on lui en demande deux — notification joignable hors du systeme, et cle de routage local. Arbitrage a rendre avant correction. Tests negatifs : PostgreSQL 3 ecarts nommes, code 1. Une variable morte trouvee dans une branche que le cas nominal n'emprunte jamais. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
118 lines
4.4 KiB
YAML
118 lines
4.4 KiB
YAML
---
|
|
# Devis du courriel — RELEVE seul. Ne modifie rien (D-23).
|
|
#
|
|
# La chaine est longue — Postfix -> LDAP -> LMTP -> Dovecot -> IMAP — et chaque maillon
|
|
# peut casser sans que le suivant s'en apercoive. On interroge donc chaque maillon la
|
|
# ou il dit la verite : `postmap -q` pour la resolution LDAP de Postfix, `doveadm user`
|
|
# pour celle de Dovecot (c'est precisement la ou la livraison avait bloque), et une vraie
|
|
# conversation SMTP pour ce que le serveur accepte.
|
|
#
|
|
# make courriel-plan
|
|
|
|
- name: Devis du courriel — Postfix
|
|
hosts: serveur_postfix
|
|
become: true
|
|
gather_facts: false
|
|
|
|
tasks:
|
|
- name: Résoudre la connexion à l'annuaire
|
|
ansible.builtin.include_role:
|
|
name: resoudre_annuaire
|
|
|
|
- name: Choisir un compte réel comme sonde
|
|
community.general.ldap_search:
|
|
dn: "{{ resoudre_annuaire_users_dn }}"
|
|
scope: onelevel
|
|
filter: "(objectClass=inetOrgPerson)"
|
|
attrs: ["uid"]
|
|
server_uri: "{{ resoudre_annuaire_uri }}"
|
|
bind_dn: "{{ resoudre_annuaire_bind_dn }}"
|
|
bind_pw: "{{ resoudre_annuaire_bind_password }}"
|
|
register: devis_courriel_comptes
|
|
changed_when: false
|
|
no_log: true
|
|
delegate_to: "{{ groups['serveur_openldap'] | first }}"
|
|
|
|
- name: Retenir l'adresse sonde
|
|
ansible.builtin.set_fact:
|
|
devis_courriel_sonde: "{{ (devis_courriel_comptes.results | first).uid }}@{{ domaine_interne }}"
|
|
|
|
- name: Relever Postfix (résolution LDAP, portée du relais, dialecte SMTP)
|
|
ansible.builtin.shell:
|
|
executable: /bin/bash
|
|
cmd: |
|
|
set -uo pipefail
|
|
echo "SONDE={{ devis_courriel_sonde }}"
|
|
echo "TROUVE=$(postmap -q '{{ devis_courriel_sonde }}' \
|
|
ldap:/etc/postfix/ldap-mailboxes.cf 2>/dev/null)"
|
|
# Une adresse qui n'existe pas DOIT rester sans reponse : sinon la boite est
|
|
# un fourre-tout et n'importe quel nom serait accepte.
|
|
echo "FANTOME=$(postmap -q 'nexistepas-{{ 999 | random }}@{{ domaine_interne }}' \
|
|
ldap:/etc/postfix/ldap-mailboxes.cf 2>/dev/null)"
|
|
echo "MYNETWORKS=$(postconf -h mynetworks)"
|
|
for P in 25 587; do
|
|
echo "PORT=$P"
|
|
exec 3<>/dev/tcp/127.0.0.1/$P || continue
|
|
read -r -t 5 _ <&3
|
|
printf 'EHLO devis.local\r\n' >&3
|
|
while read -r -t 5 L <&3; do
|
|
echo " $L"
|
|
[ "${L:3:1}" = " " ] && break
|
|
done
|
|
printf 'QUIT\r\n' >&3
|
|
exec 3<&- 3>&-
|
|
done
|
|
register: devis_courriel_postfix
|
|
changed_when: false
|
|
|
|
- name: Déposer le relevé Postfix
|
|
ansible.builtin.copy:
|
|
dest: "{{ playbook_dir }}/../../instance/devis-courriel.json.postfix"
|
|
mode: "0600"
|
|
content: >-
|
|
{{ {'hote': inventory_hostname, 'role': 'postfix',
|
|
'supernet': setops_supernet | default(''),
|
|
'brut': devis_courriel_postfix.stdout} | to_nice_json }}
|
|
delegate_to: localhost
|
|
become: false
|
|
|
|
- name: Devis du courriel — Dovecot
|
|
hosts: serveur_dovecot
|
|
become: true
|
|
gather_facts: false
|
|
|
|
tasks:
|
|
- name: Relever Dovecot (résolution userdb et dialecte IMAP)
|
|
ansible.builtin.shell:
|
|
executable: /bin/bash
|
|
cmd: |
|
|
set -uo pipefail
|
|
SONDE="{{ hostvars[groups['serveur_postfix'] | first]['devis_courriel_sonde'] }}"
|
|
echo "SONDE=$SONDE"
|
|
# `doveadm user` est le maillon exact ou la livraison avait bloque : c'est lui
|
|
# qui dit si Dovecot sait ou ecrire pour cette adresse.
|
|
echo "USERDB<<"
|
|
doveadm user "$SONDE" 2>&1 | head -12
|
|
echo ">>"
|
|
echo "PORT=143"
|
|
exec 3<>/dev/tcp/127.0.0.1/143 || exit 0
|
|
read -r -t 5 BANNIERE <&3
|
|
echo " $BANNIERE"
|
|
printf 'a CAPABILITY\r\n' >&3
|
|
while read -r -t 5 L <&3; do
|
|
echo " $L"
|
|
case "$L" in a\ *) break ;; esac
|
|
done
|
|
printf 'b LOGOUT\r\n' >&3
|
|
register: devis_courriel_dovecot
|
|
changed_when: false
|
|
|
|
- name: Déposer le relevé Dovecot
|
|
ansible.builtin.copy:
|
|
dest: "{{ playbook_dir }}/../../instance/devis-courriel.json.dovecot"
|
|
mode: "0600"
|
|
content: >-
|
|
{{ {'hote': inventory_hostname, 'role': 'dovecot',
|
|
'brut': devis_courriel_dovecot.stdout} | to_nice_json }}
|
|
delegate_to: localhost
|
|
become: false
|