serveur_dovecot (Dovecot 2.4) : IMAP + auth LDAP + TLS step_ca — prouvé
Rôle mail : IMAP :993/:143 + LMTP, auth/annuaire LDAP (serveur_openldap), stockage Maildir (user vmail), TLS via step_ca (pont de cert + resync au renouvellement), auth système par défaut neutralisée. Config drop-in en syntaxe Dovecot 2.4 (mail_driver, ssl_server_cert_file, passdb ldap), validée par doveconf au déploiement. Sockets Postfix conditionnels à la présence de l'utilisateur postfix (co-localisation). Déployé et prouvé sur infra-mail-01 : doveadm auth test — bon mot de passe accepté, mauvais refusé, cert IMAPS émis par step_ca. Format 2.4 validé empiriquement avant l'écriture (leçon « éprouver l'outil »). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
f3e78c55e1
commit
7549c61e75
10 changed files with 316 additions and 0 deletions
|
|
@ -19,6 +19,14 @@
|
|||
mis à jour. Réévaluer Stalwart ~2028.
|
||||
|
||||
### Ajouté
|
||||
- **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
|
||||
(user système `vmail`), **TLS via step_ca** (pont de cert + resync au renouvellement),
|
||||
neutralisation de l'auth système par défaut. Config en drop-in **syntaxe Dovecot 2.4**
|
||||
(`mail_driver`, `ssl_server_cert_file`, `passdb ldap`/`userdb static`, `%{user}`),
|
||||
**validée par `doveconf`** au déploiement. Sockets d'intégration Postfix **conditionnels**
|
||||
(rendus si l'utilisateur `postfix` est co-localisé). Prouvé : `doveadm auth test` — bon
|
||||
mot de passe accepté, mauvais refusé, sur cert step_ca. Secret de bind : `vault_openldap_admin`.
|
||||
- **`serveur_openldap` durci pour la prod : TLS via step_ca + organisation en intrant.**
|
||||
- **TLS (LDAPS + STARTTLS)** : le certificat d'hôte step_ca (déposé par `client_pki`,
|
||||
`root:root 600`) est synchronisé vers un emplacement lisible par `openldap` (`/etc/ldap/tls`)
|
||||
|
|
|
|||
15
playbooks/groupes/serveur_dovecot.yml
Normal file
15
playbooks/groupes/serveur_dovecot.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
- name: Appliquer le groupe serveur_dovecot
|
||||
hosts: serveur_dovecot
|
||||
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_dovecot
|
||||
37
roles/serveur_dovecot/defaults/main.yml
Normal file
37
roles/serveur_dovecot/defaults/main.yml
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
---
|
||||
# Dovecot 2.4 (Debian 13) — IMAP + LMTP + auth LDAP, stockage Maildir des boîtes virtuelles.
|
||||
# Config par drop-in conf.d/99-setops.conf (syntaxe 2.4). Cf. docs/courriel-conception.md.
|
||||
|
||||
serveur_dovecot_paquets:
|
||||
- dovecot-core
|
||||
- dovecot-imapd
|
||||
- dovecot-lmtpd
|
||||
- dovecot-ldap
|
||||
|
||||
serveur_dovecot_service: "dovecot"
|
||||
|
||||
# --- Stockage des boîtes virtuelles ---
|
||||
serveur_dovecot_vmail_utilisateur: "vmail"
|
||||
serveur_dovecot_vmail_uid: 5000
|
||||
serveur_dovecot_vmail_gid: 5000
|
||||
serveur_dovecot_vmail_base: "/var/vmail"
|
||||
# Maildir par domaine/utilisateur (variables 2.4).
|
||||
serveur_dovecot_mail_path: "{{ serveur_dovecot_vmail_base }}/%{user | domain}/%{user | username}"
|
||||
|
||||
# --- Annuaire/auth LDAP (vers serveur_openldap) ---
|
||||
serveur_dovecot_ldap_uris: "ldaps://id-ldap-01.{{ domaine_interne }}:636"
|
||||
serveur_dovecot_ldap_base: "dc={{ domaine_interne.split('.') | join(',dc=') }}"
|
||||
# Compte de service pour la recherche (bind DN). En bac à sable : l'admin LDAP.
|
||||
serveur_dovecot_ldap_bind_dn: "cn=admin,{{ serveur_dovecot_ldap_base }}"
|
||||
serveur_dovecot_ldap_bind_password: "{{ vault_openldap_admin | default('') }}"
|
||||
# Filtre de connexion : utilisateur = adresse courriel (attribut mail).
|
||||
serveur_dovecot_ldap_filter: "(&(objectClass=inetOrgPerson)(mail=%{user}))"
|
||||
|
||||
# --- TLS via le certificat d'hôte step_ca (client_pki) ---
|
||||
serveur_dovecot_tls_actif: true
|
||||
serveur_dovecot_tls_source_cert: "/etc/step/certs/{{ ansible_fqdn | default(ansible_hostname) }}.crt"
|
||||
serveur_dovecot_tls_source_cle: "/etc/step/certs/{{ ansible_fqdn | default(ansible_hostname) }}.key"
|
||||
serveur_dovecot_tls_dir: "/etc/dovecot/tls"
|
||||
|
||||
# --- Intégration Postfix (sockets sous le chroot Postfix) ---
|
||||
serveur_dovecot_postfix_socket_dir: "/var/spool/postfix/private"
|
||||
7
roles/serveur_dovecot/handlers/main.yml
Normal file
7
roles/serveur_dovecot/handlers/main.yml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
- name: Redémarrer dovecot
|
||||
ansible.builtin.systemd:
|
||||
name: "{{ serveur_dovecot_service }}"
|
||||
state: restarted
|
||||
daemon_reload: true
|
||||
when: not ansible_check_mode
|
||||
8
roles/serveur_dovecot/meta/empreinte.yml
Normal file
8
roles/serveur_dovecot/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: 5
|
||||
144
roles/serveur_dovecot/tasks/main.yml
Normal file
144
roles/serveur_dovecot/tasks/main.yml
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
---
|
||||
- name: Exiger le mot de passe de bind LDAP (Vault)
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- serveur_dovecot_ldap_bind_password | length > 0
|
||||
fail_msg: "serveur_dovecot_ldap_bind_password requis (via Ansible Vault, ex. vault_openldap_admin)."
|
||||
|
||||
- name: Installer Dovecot
|
||||
ansible.builtin.apt:
|
||||
name: "{{ serveur_dovecot_paquets }}"
|
||||
state: present
|
||||
update_cache: true
|
||||
|
||||
- name: Créer le groupe vmail
|
||||
ansible.builtin.group:
|
||||
name: "{{ serveur_dovecot_vmail_utilisateur }}"
|
||||
gid: "{{ serveur_dovecot_vmail_gid }}"
|
||||
system: true
|
||||
|
||||
- name: Créer l'utilisateur vmail
|
||||
ansible.builtin.user:
|
||||
name: "{{ serveur_dovecot_vmail_utilisateur }}"
|
||||
uid: "{{ serveur_dovecot_vmail_uid }}"
|
||||
group: "{{ serveur_dovecot_vmail_utilisateur }}"
|
||||
system: true
|
||||
home: "{{ serveur_dovecot_vmail_base }}"
|
||||
create_home: false
|
||||
shell: /usr/sbin/nologin
|
||||
|
||||
- name: Créer le répertoire de stockage des boîtes
|
||||
ansible.builtin.file:
|
||||
path: "{{ serveur_dovecot_vmail_base }}"
|
||||
state: directory
|
||||
owner: "{{ serveur_dovecot_vmail_utilisateur }}"
|
||||
group: "{{ serveur_dovecot_vmail_utilisateur }}"
|
||||
mode: "0750"
|
||||
|
||||
# --- Pont de certificat step_ca (déposé par client_pki) ---
|
||||
- name: TLS — créer le répertoire des certificats
|
||||
ansible.builtin.file:
|
||||
path: "{{ serveur_dovecot_tls_dir }}"
|
||||
state: directory
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0750"
|
||||
when: serveur_dovecot_tls_actif | bool
|
||||
|
||||
- name: TLS — déployer le script de synchronisation du certificat
|
||||
ansible.builtin.template:
|
||||
src: setops-dovecot-cert-sync.sh.j2
|
||||
dest: /usr/local/sbin/setops-dovecot-cert-sync
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0755"
|
||||
when: serveur_dovecot_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-dovecot-cert-sync.service.j2", d: "/etc/systemd/system/setops-dovecot-cert-sync.service" }
|
||||
- { s: "setops-dovecot-cert-sync.path.j2", d: "/etc/systemd/system/setops-dovecot-cert-sync.path" }
|
||||
loop_control:
|
||||
label: "{{ item.d | basename }}"
|
||||
when: serveur_dovecot_tls_actif | bool
|
||||
|
||||
- name: TLS — synchroniser le certificat maintenant
|
||||
ansible.builtin.command: /usr/local/sbin/setops-dovecot-cert-sync
|
||||
changed_when: false
|
||||
when:
|
||||
- serveur_dovecot_tls_actif | bool
|
||||
- not ansible_check_mode
|
||||
|
||||
- name: TLS — activer la surveillance du certificat (renouvellement)
|
||||
ansible.builtin.systemd:
|
||||
name: setops-dovecot-cert-sync.path
|
||||
enabled: true
|
||||
state: started
|
||||
daemon_reload: true
|
||||
when:
|
||||
- serveur_dovecot_tls_actif | bool
|
||||
- not ansible_check_mode
|
||||
|
||||
- name: TLS — vérifier que le certificat est en place
|
||||
ansible.builtin.stat:
|
||||
path: "{{ serveur_dovecot_tls_dir }}/cert.pem"
|
||||
register: serveur_dovecot_cert
|
||||
when: serveur_dovecot_tls_actif | bool
|
||||
|
||||
- name: TLS — exiger le certificat (intégration client_pki requise sur ce nœud)
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- serveur_dovecot_cert.stat.exists | default(false)
|
||||
fail_msg: >-
|
||||
Aucun certificat step_ca ({{ serveur_dovecot_tls_source_cert }}). Le nœud Dovecot doit
|
||||
porter l'intégration client_pki. Déploie-la, puis relance.
|
||||
when:
|
||||
- serveur_dovecot_tls_actif | bool
|
||||
- not ansible_check_mode
|
||||
|
||||
# --- Configuration ---
|
||||
- name: Détecter si Postfix est co-localisé (pour les sockets d'intégration)
|
||||
ansible.builtin.command: getent passwd postfix
|
||||
register: serveur_dovecot_postfix_check
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Mémoriser la présence de Postfix
|
||||
ansible.builtin.set_fact:
|
||||
serveur_dovecot_postfix_present: "{{ serveur_dovecot_postfix_check.rc == 0 }}"
|
||||
|
||||
- name: Déployer la configuration Set-OPS (drop-in Dovecot 2.4)
|
||||
ansible.builtin.template:
|
||||
src: 99-setops.conf.j2
|
||||
dest: /etc/dovecot/conf.d/99-setops.conf
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0640"
|
||||
no_log: true # contient le mot de passe de bind LDAP
|
||||
notify: Redémarrer dovecot
|
||||
|
||||
- name: Désactiver l'auth système par défaut (LDAP est l'unique autorité)
|
||||
ansible.builtin.replace:
|
||||
path: /etc/dovecot/conf.d/10-auth.conf
|
||||
regexp: '^!include auth-system\.conf\.ext'
|
||||
replace: '#!include auth-system.conf.ext'
|
||||
notify: Redémarrer dovecot
|
||||
|
||||
- name: Valider la configuration Dovecot (doveconf)
|
||||
ansible.builtin.command: doveconf -n
|
||||
changed_when: false
|
||||
when: not ansible_check_mode
|
||||
|
||||
- name: Activer et démarrer Dovecot
|
||||
when: not ansible_check_mode
|
||||
ansible.builtin.systemd:
|
||||
name: "{{ serveur_dovecot_service }}"
|
||||
enabled: true
|
||||
state: started
|
||||
daemon_reload: true
|
||||
58
roles/serveur_dovecot/templates/99-setops.conf.j2
Normal file
58
roles/serveur_dovecot/templates/99-setops.conf.j2
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
# Géré par Set-OPS (rôle serveur_dovecot). Ne pas éditer à la main. Syntaxe Dovecot 2.4.
|
||||
dovecot_config_version = 2.4.0
|
||||
|
||||
protocols {
|
||||
imap = yes
|
||||
lmtp = yes
|
||||
}
|
||||
|
||||
# --- Stockage Maildir (boîtes virtuelles) ---
|
||||
mail_driver = maildir
|
||||
mail_path = {{ serveur_dovecot_mail_path }}
|
||||
first_valid_uid = {{ serveur_dovecot_vmail_uid }}
|
||||
first_valid_gid = {{ serveur_dovecot_vmail_gid }}
|
||||
|
||||
# --- TLS (certificat step_ca, via le pont) ---
|
||||
ssl = required
|
||||
ssl_server_cert_file = {{ serveur_dovecot_tls_dir }}/cert.pem
|
||||
ssl_server_key_file = {{ serveur_dovecot_tls_dir }}/key.pem
|
||||
ssl_min_protocol = TLSv1.2
|
||||
|
||||
# --- Auth / annuaire LDAP (serveur_openldap) ---
|
||||
auth_mechanisms = plain login
|
||||
ldap_uris = {{ serveur_dovecot_ldap_uris }}
|
||||
ldap_base = {{ serveur_dovecot_ldap_base }}
|
||||
ldap_auth_dn = {{ serveur_dovecot_ldap_bind_dn }}
|
||||
ldap_auth_dn_password = {{ serveur_dovecot_ldap_bind_password }}
|
||||
|
||||
passdb ldap {
|
||||
ldap_filter = {{ serveur_dovecot_ldap_filter }}
|
||||
ldap_bind = yes
|
||||
}
|
||||
userdb static {
|
||||
fields {
|
||||
uid = {{ serveur_dovecot_vmail_utilisateur }}
|
||||
gid = {{ serveur_dovecot_vmail_utilisateur }}
|
||||
home = {{ serveur_dovecot_mail_path }}
|
||||
}
|
||||
}
|
||||
|
||||
# --- Sockets pour Postfix (remise LMTP + auth SASL) ---
|
||||
# Seulement si Postfix est co-localisé (l'utilisateur postfix existe). Sinon Dovecot
|
||||
# tourne en autonome (IMAP) ; les sockets seront ajoutés au déploiement de serveur_postfix.
|
||||
{% if serveur_dovecot_postfix_present | default(false) %}
|
||||
service lmtp {
|
||||
unix_listener {{ serveur_dovecot_postfix_socket_dir }}/dovecot-lmtp {
|
||||
user = postfix
|
||||
group = postfix
|
||||
mode = 0600
|
||||
}
|
||||
}
|
||||
service auth {
|
||||
unix_listener {{ serveur_dovecot_postfix_socket_dir }}/auth {
|
||||
user = postfix
|
||||
group = postfix
|
||||
mode = 0660
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
# Géré par Set-OPS (rôle serveur_dovecot). Ne pas éditer à la main.
|
||||
# Surveille le certificat step_ca : au renouvellement (client_pki), resynchronise vers
|
||||
# Dovecot et le recharge.
|
||||
[Unit]
|
||||
Description=Set-OPS — surveille le certificat step_ca de Dovecot
|
||||
|
||||
[Path]
|
||||
PathChanged={{ serveur_dovecot_tls_source_cert }}
|
||||
Unit=setops-dovecot-cert-sync.service
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
# Géré par Set-OPS (rôle serveur_dovecot). Ne pas éditer à la main.
|
||||
[Unit]
|
||||
Description=Set-OPS — synchronise le certificat step_ca vers Dovecot
|
||||
After=dovecot.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/local/sbin/setops-dovecot-cert-sync
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#!/bin/sh
|
||||
# Géré par Set-OPS (rôle serveur_dovecot). Ne pas éditer à la main.
|
||||
# Synchronise le certificat step_ca (déposé par client_pki, root:root 600) vers Dovecot,
|
||||
# puis recharge. Idempotent ; appelé au déploiement ET au renouvellement (unité path).
|
||||
# Dovecot lit le certificat via son maître (root), donc root:root suffit.
|
||||
set -eu
|
||||
|
||||
SRC_CERT="{{ serveur_dovecot_tls_source_cert }}"
|
||||
SRC_KEY="{{ serveur_dovecot_tls_source_cle }}"
|
||||
DST="{{ serveur_dovecot_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 root -m 0600 "$SRC_KEY" "$DST/key.pem"
|
||||
|
||||
if systemctl --quiet is-active dovecot 2>/dev/null; then
|
||||
systemctl reload dovecot 2>/dev/null || systemctl restart dovecot
|
||||
fi
|
||||
Loading…
Reference in a new issue