serveur_rspamd (rspamd 3.x) : antispam + DKIM en milter Postfix — prouvé
Rôle antispam sur edge-mta : Redis local, worker proxy en mode milter auto-scan (:11332), signature DKIM sortante (clé générée idempotente, enregistrement DNS affiché pour l'Étape B). Config par local.d/. Postfix branché via smtpd_milters (option serveur_postfix_rspamd_milter, milter_default_action=accept = tolérant si rspamd down). Prouvé : courriel traversant le milter → scanné (rspamc stat: 1) + signé DKIM (DKIM-Signature d=...), livré, lu en IMAP. Étape A (courriel interne) complète : dovecot + postfix + rspamd. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
5846a08667
commit
8df1db3b47
11 changed files with 173 additions and 0 deletions
|
|
@ -19,6 +19,14 @@
|
|||
mis à jour. Réévaluer Stalwart ~2028.
|
||||
|
||||
### Ajouté
|
||||
- **Rôle `serveur_rspamd` (rspamd 3.x) — antispam + DKIM, en milter sur Postfix.** Installé
|
||||
sur le nœud edge-mta (avec Postfix), backend **Redis** local, worker proxy en **mode milter
|
||||
auto-scan** (`:11332`), **signature DKIM** sortante (clé générée par le rôle de façon
|
||||
idempotente ; enregistrement DNS public affiché pour l'Étape B). Config par surcharges
|
||||
`/etc/rspamd/local.d/`. Postfix branché via `smtpd_milters` (option `serveur_postfix_rspamd_milter`,
|
||||
`milter_default_action = accept` → tolérant si rspamd indisponible). **Prouvé** : un courriel
|
||||
traversant le milter ressort **scanné** (`rspamc stat` : 1) et **signé DKIM** (`DKIM-Signature:
|
||||
d=…`), puis livré et lu en IMAP. **Étape A (courriel interne) complète** : dovecot + postfix + rspamd.
|
||||
- **Flux courriel interne PROUVÉ de bout en bout (Étape A).** Envoi → Postfix (`edge-mta`,
|
||||
validation LDAP) → LMTP réseau → Dovecot (mail-store) → boîte Maildir → **lu en IMAP**
|
||||
(auth LDAP, TLS step_ca) : `status=sent`, message lu (sujet + corps). Réglages Dovecot 2.4
|
||||
|
|
|
|||
15
playbooks/groupes/serveur_rspamd.yml
Normal file
15
playbooks/groupes/serveur_rspamd.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
- name: Appliquer le groupe serveur_rspamd
|
||||
hosts: serveur_rspamd
|
||||
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_rspamd
|
||||
|
|
@ -24,6 +24,10 @@ serveur_postfix_ldap_base: "ou=people,dc={{ domaine_interne.split('.') | join(',
|
|||
serveur_postfix_ldap_bind_dn: "cn=admin,dc={{ domaine_interne.split('.') | join(',dc=') }}"
|
||||
serveur_postfix_ldap_bind_password: "{{ vault_openldap_admin | default('') }}"
|
||||
|
||||
# --- Milter rspamd (antispam + DKIM) — si rspamd est co-localisé (nœud edge-mta) ---
|
||||
serveur_postfix_rspamd_milter: false
|
||||
serveur_postfix_rspamd_milter_port: 11332
|
||||
|
||||
# --- 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"
|
||||
|
|
|
|||
|
|
@ -31,6 +31,14 @@ smtpd_tls_protocols = >=TLSv1.2, !SSLv2, !SSLv3
|
|||
smtp_tls_security_level = may
|
||||
{% endif %}
|
||||
|
||||
{% if serveur_postfix_rspamd_milter %}
|
||||
# --- Milter rspamd (antispam + signature DKIM), co-localisé sur edge-mta ---
|
||||
smtpd_milters = inet:localhost:{{ serveur_postfix_rspamd_milter_port }}
|
||||
non_smtpd_milters = $smtpd_milters
|
||||
milter_protocol = 6
|
||||
milter_default_action = accept
|
||||
{% endif %}
|
||||
|
||||
# --- Restrictions de base ---
|
||||
smtpd_helo_required = yes
|
||||
smtpd_recipient_restrictions = permit_mynetworks, reject_unauth_destination
|
||||
|
|
|
|||
23
roles/serveur_rspamd/defaults/main.yml
Normal file
23
roles/serveur_rspamd/defaults/main.yml
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
# rspamd 3.x (Debian 13) — antispam + signature DKIM, branché en MILTER sur Postfix
|
||||
# (nœud edge-mta). Backend Redis local. Config par surcharges dans /etc/rspamd/local.d/.
|
||||
# Cf. docs/courriel-conception.md. NE STOCKE AUCUNE BOÎTE.
|
||||
|
||||
serveur_rspamd_paquets:
|
||||
- rspamd
|
||||
- redis-server
|
||||
|
||||
serveur_rspamd_service: "rspamd"
|
||||
|
||||
# --- Backend Redis (local à ce nœud) ---
|
||||
serveur_rspamd_redis_serveur: "127.0.0.1:6379"
|
||||
|
||||
# --- Milter (worker proxy, auto-scan) — Postfix s'y branche via :11332 ---
|
||||
serveur_rspamd_milter_port: 11332
|
||||
|
||||
# --- Signature DKIM ---
|
||||
# Domaine signé : interne en bac à sable ; domaine PUBLIC en prod (Étape B).
|
||||
serveur_rspamd_dkim_actif: true
|
||||
serveur_rspamd_dkim_domaine: "{{ domaine_interne }}"
|
||||
serveur_rspamd_dkim_selecteur: "setops"
|
||||
serveur_rspamd_dkim_repertoire: "/var/lib/rspamd/dkim"
|
||||
6
roles/serveur_rspamd/handlers/main.yml
Normal file
6
roles/serveur_rspamd/handlers/main.yml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
- name: Redémarrer rspamd
|
||||
ansible.builtin.systemd:
|
||||
name: "{{ serveur_rspamd_service }}"
|
||||
state: restarted
|
||||
when: not ansible_check_mode
|
||||
7
roles/serveur_rspamd/meta/empreinte.yml
Normal file
7
roles/serveur_rspamd/meta/empreinte.yml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
# Empreinte ressources du logiciel — dimensionnement VM derive (scripts/instancier.py).
|
||||
# rspamd + Redis (backend). Sommee au socle SE + marge.
|
||||
setops_empreinte:
|
||||
coeurs: 1
|
||||
memoire_mo: 1024
|
||||
disque_go: 4
|
||||
82
roles/serveur_rspamd/tasks/main.yml
Normal file
82
roles/serveur_rspamd/tasks/main.yml
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
---
|
||||
- name: Installer rspamd et Redis
|
||||
ansible.builtin.apt:
|
||||
name: "{{ serveur_rspamd_paquets }}"
|
||||
state: present
|
||||
update_cache: true
|
||||
|
||||
- name: Activer et démarrer Redis (backend rspamd)
|
||||
ansible.builtin.systemd:
|
||||
name: redis-server
|
||||
enabled: true
|
||||
state: started
|
||||
when: not ansible_check_mode
|
||||
|
||||
# --- Clé DKIM (privée locale ; publique à publier en DNS — Étape B) ---
|
||||
- name: Créer le répertoire des clés DKIM
|
||||
ansible.builtin.file:
|
||||
path: "{{ serveur_rspamd_dkim_repertoire }}"
|
||||
state: directory
|
||||
owner: _rspamd
|
||||
group: _rspamd
|
||||
mode: "0750"
|
||||
when: serveur_rspamd_dkim_actif | bool
|
||||
|
||||
- name: Générer la clé DKIM (idempotent — seulement si absente)
|
||||
ansible.builtin.command:
|
||||
cmd: >-
|
||||
rspamadm dkim_keygen
|
||||
-s {{ serveur_rspamd_dkim_selecteur }}
|
||||
-d {{ serveur_rspamd_dkim_domaine }}
|
||||
-k {{ serveur_rspamd_dkim_repertoire }}/{{ serveur_rspamd_dkim_domaine }}.{{ serveur_rspamd_dkim_selecteur }}.key
|
||||
creates: "{{ serveur_rspamd_dkim_repertoire }}/{{ serveur_rspamd_dkim_domaine }}.{{ serveur_rspamd_dkim_selecteur }}.key"
|
||||
register: serveur_rspamd_dkim_gen
|
||||
when:
|
||||
- serveur_rspamd_dkim_actif | bool
|
||||
- not ansible_check_mode
|
||||
notify: Redémarrer rspamd
|
||||
|
||||
- name: Fixer les droits de la clé DKIM privée
|
||||
ansible.builtin.file:
|
||||
path: "{{ serveur_rspamd_dkim_repertoire }}/{{ serveur_rspamd_dkim_domaine }}.{{ serveur_rspamd_dkim_selecteur }}.key"
|
||||
owner: _rspamd
|
||||
group: _rspamd
|
||||
mode: "0640"
|
||||
when:
|
||||
- serveur_rspamd_dkim_actif | bool
|
||||
- not ansible_check_mode
|
||||
|
||||
- name: Afficher l'enregistrement DNS DKIM à publier (Étape B)
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ serveur_rspamd_dkim_gen.stdout_lines | default(['(clé déjà présente — cf. ' + serveur_rspamd_dkim_repertoire + ')']) }}"
|
||||
when: serveur_rspamd_dkim_actif | bool
|
||||
|
||||
# --- Surcharges de configuration (local.d) ---
|
||||
- name: Déployer les surcharges local.d (redis, proxy milter)
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}.j2"
|
||||
dest: "/etc/rspamd/local.d/{{ item }}"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
loop:
|
||||
- redis.conf
|
||||
- worker-proxy.inc
|
||||
notify: Redémarrer rspamd
|
||||
|
||||
- name: Déployer la signature DKIM (local.d)
|
||||
ansible.builtin.template:
|
||||
src: dkim_signing.conf.j2
|
||||
dest: /etc/rspamd/local.d/dkim_signing.conf
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
when: serveur_rspamd_dkim_actif | bool
|
||||
notify: Redémarrer rspamd
|
||||
|
||||
- name: Activer et démarrer rspamd
|
||||
when: not ansible_check_mode
|
||||
ansible.builtin.systemd:
|
||||
name: "{{ serveur_rspamd_service }}"
|
||||
enabled: true
|
||||
state: started
|
||||
9
roles/serveur_rspamd/templates/dkim_signing.conf.j2
Normal file
9
roles/serveur_rspamd/templates/dkim_signing.conf.j2
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# Géré par Set-OPS (rôle serveur_rspamd). Ne pas éditer à la main.
|
||||
# Signature DKIM du courrier sortant. La clé privée est générée par le rôle ;
|
||||
# la clé PUBLIQUE doit être publiée en DNS (enregistrement TXT) — Étape B pour le public.
|
||||
enabled = true;
|
||||
selector = "{{ serveur_rspamd_dkim_selecteur }}";
|
||||
path = "{{ serveur_rspamd_dkim_repertoire }}/$domain.$selector.key";
|
||||
use_domain = "header";
|
||||
allow_hdrfrom_mismatch = true;
|
||||
allow_username_mismatch = true;
|
||||
3
roles/serveur_rspamd/templates/redis.conf.j2
Normal file
3
roles/serveur_rspamd/templates/redis.conf.j2
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Géré par Set-OPS (rôle serveur_rspamd). Ne pas éditer à la main.
|
||||
# Backend Redis (statistiques, greylisting, ratelimit, etc.).
|
||||
servers = "{{ serveur_rspamd_redis_serveur }}";
|
||||
8
roles/serveur_rspamd/templates/worker-proxy.inc.j2
Normal file
8
roles/serveur_rspamd/templates/worker-proxy.inc.j2
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# Géré par Set-OPS (rôle serveur_rspamd). Ne pas éditer à la main.
|
||||
# Worker proxy en mode MILTER auto-scan : Postfix s'y branche (inet:localhost:{{ serveur_rspamd_milter_port }}).
|
||||
milter = yes;
|
||||
timeout = 120s;
|
||||
upstream "local" {
|
||||
default = yes;
|
||||
self_scan = yes;
|
||||
}
|
||||
Loading…
Reference in a new issue