serveur_postfix (Postfix 3.x) : MTA edge-mta — cartes LDAP + LMTP + TLS step_ca
Réception :25, validation des boîtes par carte LDAP (attribut mail), remise LMTP réseau vers le mail-store Dovecot (virtual_transport lmtp), TLS via step_ca (pont de cert), aucune boîte locale. main.cf + ldap-mailboxes.cf, validé par postfix check. Bind LDAP: vault_openldap_admin. Validé statiquement (ansible-lint, syntax, rendu main.cf) ; déploiement à suivre. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
a4b25018e6
commit
9480e585a5
11 changed files with 284 additions and 0 deletions
|
|
@ -19,6 +19,12 @@
|
||||||
mis à jour. Réévaluer Stalwart ~2028.
|
mis à jour. Réévaluer Stalwart ~2028.
|
||||||
|
|
||||||
### Ajouté
|
### Ajouté
|
||||||
|
- **Rôle `serveur_postfix` (Postfix 3.x) — MTA du nœud edge-mta.** Réception `:25`, cartes
|
||||||
|
**LDAP** (validation des boîtes via l'attribut `mail`), remise **LMTP réseau** vers le nœud
|
||||||
|
mail-store Dovecot (`virtual_transport = lmtp:inet:[…]:24`), TLS via **step_ca** (pont de
|
||||||
|
cert), aucune boîte locale. Config `main.cf` + carte `ldap-mailboxes.cf`, validée par
|
||||||
|
`postfix check`. Secret de bind : `vault_openldap_admin`. Nécessite `serveur_postfix_mailstore_hote`
|
||||||
|
(FQDN du mail-store). Validé statiquement ; déploiement réel à suivre.
|
||||||
- **Rôle `serveur_dovecot` (Dovecot 2.4) — déployé et prouvé.** IMAP `:993`/`:143` +
|
- **Rôle `serveur_dovecot` (Dovecot 2.4) — déployé et prouvé.** IMAP `:993`/`:143` +
|
||||||
LMTP, **auth/annuaire LDAP** (vers `serveur_openldap`, filtre `mail`), stockage Maildir
|
LMTP, **auth/annuaire LDAP** (vers `serveur_openldap`, filtre `mail`), stockage Maildir
|
||||||
(user système `vmail`), **TLS via step_ca** (pont de cert + resync au renouvellement),
|
(user système `vmail`), **TLS via step_ca** (pont de cert + resync au renouvellement),
|
||||||
|
|
|
||||||
15
playbooks/groupes/serveur_postfix.yml
Normal file
15
playbooks/groupes/serveur_postfix.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
---
|
||||||
|
- name: Appliquer le groupe serveur_postfix
|
||||||
|
hosts: serveur_postfix
|
||||||
|
become: true
|
||||||
|
gather_facts: true
|
||||||
|
|
||||||
|
pre_tasks:
|
||||||
|
- name: Vérifier que la cible est Debian
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- ansible_facts.distribution == "Debian"
|
||||||
|
fail_msg: "Ce playbook est prévu pour Debian."
|
||||||
|
|
||||||
|
roles:
|
||||||
|
- serveur_postfix
|
||||||
31
roles/serveur_postfix/defaults/main.yml
Normal file
31
roles/serveur_postfix/defaults/main.yml
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
---
|
||||||
|
# Postfix 3.x (Debian 13) — MTA du nœud edge-mta : réception :25, cartes LDAP (domaines,
|
||||||
|
# boîtes, alias), remise LMTP réseau vers le nœud mail-store (Dovecot). TLS via step_ca.
|
||||||
|
# NE STOCKE AUCUNE BOÎTE. Cf. docs/courriel-conception.md + docs/identite-sso.md.
|
||||||
|
|
||||||
|
serveur_postfix_paquets:
|
||||||
|
- postfix
|
||||||
|
- postfix-ldap
|
||||||
|
|
||||||
|
serveur_postfix_service: "postfix"
|
||||||
|
serveur_postfix_domaine: "{{ domaine_interne }}"
|
||||||
|
serveur_postfix_nom_hote: "{{ ansible_fqdn | default(ansible_hostname) }}"
|
||||||
|
# Réseaux internes de confiance (relais autorisé). À adapter au réseau de l'instance.
|
||||||
|
serveur_postfix_reseaux_confiance: "127.0.0.0/8 [::1]/128"
|
||||||
|
|
||||||
|
# --- Nœud mail-store (Dovecot) : remise LMTP réseau ---
|
||||||
|
# OBLIGATOIRE : le FQDN/nom du nœud qui héberge les boîtes (Dovecot LMTP).
|
||||||
|
serveur_postfix_mailstore_hote: ""
|
||||||
|
serveur_postfix_lmtp_port: 24
|
||||||
|
|
||||||
|
# --- Annuaire LDAP (validation domaines/boîtes/alias) ---
|
||||||
|
serveur_postfix_ldap_serveur: "ldaps://id-ldap-01.{{ domaine_interne }}:636"
|
||||||
|
serveur_postfix_ldap_base: "ou=people,dc={{ domaine_interne.split('.') | join(',dc=') }}"
|
||||||
|
serveur_postfix_ldap_bind_dn: "cn=admin,dc={{ domaine_interne.split('.') | join(',dc=') }}"
|
||||||
|
serveur_postfix_ldap_bind_password: "{{ vault_openldap_admin | default('') }}"
|
||||||
|
|
||||||
|
# --- TLS via le certificat d'hôte step_ca (client_pki) ---
|
||||||
|
serveur_postfix_tls_actif: true
|
||||||
|
serveur_postfix_tls_source_cert: "/etc/step/certs/{{ ansible_fqdn | default(ansible_hostname) }}.crt"
|
||||||
|
serveur_postfix_tls_source_cle: "/etc/step/certs/{{ ansible_fqdn | default(ansible_hostname) }}.key"
|
||||||
|
serveur_postfix_tls_dir: "/etc/postfix/tls"
|
||||||
6
roles/serveur_postfix/handlers/main.yml
Normal file
6
roles/serveur_postfix/handlers/main.yml
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
- name: Recharger postfix
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: "{{ serveur_postfix_service }}"
|
||||||
|
state: reloaded
|
||||||
|
when: not ansible_check_mode
|
||||||
8
roles/serveur_postfix/meta/empreinte.yml
Normal file
8
roles/serveur_postfix/meta/empreinte.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
# Empreinte ressources du logiciel — dimensionnement VM derive (scripts/instancier.py).
|
||||||
|
# Sommee au socle SE + marge pour estimer coeurs/RAM/disque de la VM hote.
|
||||||
|
# Override possible par hote dans le plan (serveurs.yml: coeurs/memoire/disque).
|
||||||
|
setops_empreinte:
|
||||||
|
coeurs: 1
|
||||||
|
memoire_mo: 512
|
||||||
|
disque_go: 3
|
||||||
137
roles/serveur_postfix/tasks/main.yml
Normal file
137
roles/serveur_postfix/tasks/main.yml
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
---
|
||||||
|
- name: Exiger le mot de passe de bind LDAP (Vault)
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- serveur_postfix_ldap_bind_password | length > 0
|
||||||
|
fail_msg: "serveur_postfix_ldap_bind_password requis (via Ansible Vault, ex. vault_openldap_admin)."
|
||||||
|
|
||||||
|
- name: Exiger le nœud mail-store (remise LMTP)
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- serveur_postfix_mailstore_hote | length > 0
|
||||||
|
fail_msg: "serveur_postfix_mailstore_hote requis (FQDN du nœud Dovecot qui héberge les boîtes)."
|
||||||
|
|
||||||
|
- name: Installer debconf-utils (requis par le module debconf)
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: debconf-utils
|
||||||
|
state: present
|
||||||
|
update_cache: true
|
||||||
|
cache_valid_time: 3600
|
||||||
|
|
||||||
|
- name: Préconfigurer Postfix (debconf, installation non interactive)
|
||||||
|
ansible.builtin.debconf:
|
||||||
|
name: postfix
|
||||||
|
question: "{{ item.question }}"
|
||||||
|
vtype: "{{ item.vtype }}"
|
||||||
|
value: "{{ item.value }}"
|
||||||
|
loop:
|
||||||
|
- { question: "postfix/main_mailer_type", vtype: "select", value: "Internet Site" }
|
||||||
|
- { question: "postfix/mailname", vtype: "string", value: "{{ serveur_postfix_domaine }}" }
|
||||||
|
loop_control:
|
||||||
|
label: "{{ item.question }}"
|
||||||
|
|
||||||
|
- name: Installer Postfix
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: "{{ serveur_postfix_paquets }}"
|
||||||
|
state: present
|
||||||
|
update_cache: true
|
||||||
|
|
||||||
|
# --- Pont de certificat step_ca (déposé par client_pki) ---
|
||||||
|
- name: TLS — créer le répertoire des certificats
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ serveur_postfix_tls_dir }}"
|
||||||
|
state: directory
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0755"
|
||||||
|
when: serveur_postfix_tls_actif | bool
|
||||||
|
|
||||||
|
- name: TLS — déployer le script de synchronisation du certificat
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: setops-postfix-cert-sync.sh.j2
|
||||||
|
dest: /usr/local/sbin/setops-postfix-cert-sync
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0755"
|
||||||
|
when: serveur_postfix_tls_actif | bool
|
||||||
|
|
||||||
|
- name: TLS — déployer les unités de synchronisation (service + path)
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: "{{ item.s }}"
|
||||||
|
dest: "{{ item.d }}"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
loop:
|
||||||
|
- { s: "setops-postfix-cert-sync.service.j2", d: "/etc/systemd/system/setops-postfix-cert-sync.service" }
|
||||||
|
- { s: "setops-postfix-cert-sync.path.j2", d: "/etc/systemd/system/setops-postfix-cert-sync.path" }
|
||||||
|
loop_control:
|
||||||
|
label: "{{ item.d | basename }}"
|
||||||
|
when: serveur_postfix_tls_actif | bool
|
||||||
|
|
||||||
|
- name: TLS — synchroniser le certificat maintenant
|
||||||
|
ansible.builtin.command: /usr/local/sbin/setops-postfix-cert-sync
|
||||||
|
changed_when: false
|
||||||
|
when:
|
||||||
|
- serveur_postfix_tls_actif | bool
|
||||||
|
- not ansible_check_mode
|
||||||
|
|
||||||
|
- name: TLS — activer la surveillance du certificat (renouvellement)
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: setops-postfix-cert-sync.path
|
||||||
|
enabled: true
|
||||||
|
state: started
|
||||||
|
daemon_reload: true
|
||||||
|
when:
|
||||||
|
- serveur_postfix_tls_actif | bool
|
||||||
|
- not ansible_check_mode
|
||||||
|
|
||||||
|
- name: TLS — vérifier que le certificat est en place
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: "{{ serveur_postfix_tls_dir }}/cert.pem"
|
||||||
|
register: serveur_postfix_cert
|
||||||
|
when: serveur_postfix_tls_actif | bool
|
||||||
|
|
||||||
|
- name: TLS — exiger le certificat (intégration client_pki requise sur ce nœud)
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- serveur_postfix_cert.stat.exists | default(false)
|
||||||
|
fail_msg: >-
|
||||||
|
Aucun certificat step_ca ({{ serveur_postfix_tls_source_cert }}). Le nœud Postfix doit
|
||||||
|
porter l'intégration client_pki. Déploie-la, puis relance.
|
||||||
|
when:
|
||||||
|
- serveur_postfix_tls_actif | bool
|
||||||
|
- not ansible_check_mode
|
||||||
|
|
||||||
|
# --- Configuration ---
|
||||||
|
- name: Déployer la carte LDAP des boîtes
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: ldap-mailboxes.cf.j2
|
||||||
|
dest: /etc/postfix/ldap-mailboxes.cf
|
||||||
|
owner: root
|
||||||
|
group: postfix
|
||||||
|
mode: "0640"
|
||||||
|
no_log: true # contient le mot de passe de bind LDAP
|
||||||
|
notify: Recharger postfix
|
||||||
|
|
||||||
|
- name: Déployer main.cf
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: main.cf.j2
|
||||||
|
dest: /etc/postfix/main.cf
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
notify: Recharger postfix
|
||||||
|
|
||||||
|
- name: Valider la configuration Postfix
|
||||||
|
ansible.builtin.command: postfix check
|
||||||
|
changed_when: false
|
||||||
|
when: not ansible_check_mode
|
||||||
|
|
||||||
|
- name: Activer et démarrer Postfix
|
||||||
|
when: not ansible_check_mode
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: "{{ serveur_postfix_service }}"
|
||||||
|
enabled: true
|
||||||
|
state: started
|
||||||
|
daemon_reload: true
|
||||||
10
roles/serveur_postfix/templates/ldap-mailboxes.cf.j2
Normal file
10
roles/serveur_postfix/templates/ldap-mailboxes.cf.j2
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
# Géré par Set-OPS (rôle serveur_postfix). Ne pas éditer à la main.
|
||||||
|
# Carte LDAP : valide qu'une adresse correspond à une boîte (attribut mail).
|
||||||
|
server_host = {{ serveur_postfix_ldap_serveur }}
|
||||||
|
search_base = {{ serveur_postfix_ldap_base }}
|
||||||
|
query_filter = (mail=%s)
|
||||||
|
result_attribute = mail
|
||||||
|
bind = yes
|
||||||
|
bind_dn = {{ serveur_postfix_ldap_bind_dn }}
|
||||||
|
bind_pw = {{ serveur_postfix_ldap_bind_password }}
|
||||||
|
version = 3
|
||||||
34
roles/serveur_postfix/templates/main.cf.j2
Normal file
34
roles/serveur_postfix/templates/main.cf.j2
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
# Géré par Set-OPS (rôle serveur_postfix). Ne pas éditer à la main.
|
||||||
|
compatibility_level = 3.6
|
||||||
|
myhostname = {{ serveur_postfix_nom_hote }}
|
||||||
|
mydomain = {{ serveur_postfix_domaine }}
|
||||||
|
myorigin = $mydomain
|
||||||
|
inet_interfaces = all
|
||||||
|
inet_protocols = ipv4
|
||||||
|
biff = no
|
||||||
|
append_dot_mydomain = no
|
||||||
|
readme_directory = no
|
||||||
|
smtpd_banner = $myhostname ESMTP
|
||||||
|
mynetworks = {{ serveur_postfix_reseaux_confiance }}
|
||||||
|
|
||||||
|
# Aucune remise locale : ce MTA ne fait QUE des boîtes virtuelles (via LDAP + LMTP).
|
||||||
|
mydestination =
|
||||||
|
local_recipient_maps =
|
||||||
|
|
||||||
|
# --- Boîtes virtuelles : validation LDAP + remise LMTP vers le nœud mail-store (Dovecot) ---
|
||||||
|
virtual_mailbox_domains = {{ serveur_postfix_domaine }}
|
||||||
|
virtual_mailbox_maps = ldap:/etc/postfix/ldap-mailboxes.cf
|
||||||
|
virtual_transport = lmtp:inet:[{{ serveur_postfix_mailstore_hote }}]:{{ serveur_postfix_lmtp_port }}
|
||||||
|
|
||||||
|
{% if serveur_postfix_tls_actif %}
|
||||||
|
# --- TLS (certificat step_ca) ---
|
||||||
|
smtpd_tls_cert_file = {{ serveur_postfix_tls_dir }}/cert.pem
|
||||||
|
smtpd_tls_key_file = {{ serveur_postfix_tls_dir }}/key.pem
|
||||||
|
smtpd_tls_security_level = may
|
||||||
|
smtpd_tls_protocols = >=TLSv1.2, !SSLv2, !SSLv3
|
||||||
|
smtp_tls_security_level = may
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
# --- Restrictions de base ---
|
||||||
|
smtpd_helo_required = yes
|
||||||
|
smtpd_recipient_restrictions = permit_mynetworks, reject_unauth_destination
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
# Géré par Set-OPS (rôle serveur_postfix). Ne pas éditer à la main.
|
||||||
|
[Unit]
|
||||||
|
Description=Set-OPS — surveille le certificat step_ca de Postfix
|
||||||
|
|
||||||
|
[Path]
|
||||||
|
PathChanged={{ serveur_postfix_tls_source_cert }}
|
||||||
|
Unit=setops-postfix-cert-sync.service
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
# Géré par Set-OPS (rôle serveur_postfix). Ne pas éditer à la main.
|
||||||
|
[Unit]
|
||||||
|
Description=Set-OPS — synchronise le certificat step_ca vers Postfix
|
||||||
|
After=postfix.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/local/sbin/setops-postfix-cert-sync
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# Géré par Set-OPS (rôle serveur_postfix). Ne pas éditer à la main.
|
||||||
|
# Synchronise le certificat step_ca (client_pki, root:root 600) vers Postfix, puis recharge.
|
||||||
|
# Idempotent ; appelé au déploiement ET au renouvellement (unité path). La clé est lisible
|
||||||
|
# par le groupe postfix (smtpd tourne sous postfix).
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
SRC_CERT="{{ serveur_postfix_tls_source_cert }}"
|
||||||
|
SRC_KEY="{{ serveur_postfix_tls_source_cle }}"
|
||||||
|
DST="{{ serveur_postfix_tls_dir }}"
|
||||||
|
|
||||||
|
[ -f "$SRC_CERT" ] && [ -f "$SRC_KEY" ] || exit 0
|
||||||
|
|
||||||
|
install -o root -g root -m 0644 "$SRC_CERT" "$DST/cert.pem"
|
||||||
|
install -o root -g postfix -m 0640 "$SRC_KEY" "$DST/key.pem"
|
||||||
|
|
||||||
|
if systemctl --quiet is-active postfix 2>/dev/null; then
|
||||||
|
systemctl reload postfix 2>/dev/null || systemctl restart postfix
|
||||||
|
fi
|
||||||
Loading…
Reference in a new issue