feat(postfix): relay SMTP Gmail + suppression règles Conan nftables

- postfix_relay: switch Brevo → Gmail SMTP (smtp.gmail.com:587, App Password)
- smtp_generic_maps: réécriture expéditeur root@lab.localaliyesilkaya93@gmail.com
- nftables: suppression DNAT/NAT Conan Exiles (ports 7777/7778/27015)
- gateway handler: reloaded → restarted (flush complet des règles nft)
- hermes_agent: pip → uv pour installation qdrant-client (venv sans pip binaire)
- CLAUDE.md: corrections funk-cluster, hermes-switch, RAID5, postfix
- docs: admin/infra/email.md — procédure complète relay Gmail

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
alkatrazz 2026-05-17 16:46:42 +02:00
parent 24c0bf9e12
commit 8da92cb721
13 changed files with 552 additions and 145 deletions

View file

@ -2,4 +2,4 @@
- name: Reload nftables
ansible.builtin.systemd:
name: nftables
state: reloaded
state: restarted

View file

@ -69,6 +69,10 @@ table inet filter {
}
table ip nat {
chain prerouting {
type nat hook prerouting priority -100;
}
chain postrouting {
type nat hook postrouting priority 100;

View file

@ -76,14 +76,17 @@
# --- Packages Python pour les skills ---
- name: Install Python packages for Hermes skills
ansible.builtin.pip:
name: "qdrant-client>=1.12.0"
executable: "{{ hermes_home }}/.hermes/hermes-agent/venv/bin/pip"
state: present
- name: Install Python packages for Hermes skills (via uv)
ansible.builtin.command:
cmd: >
{{ hermes_home }}/.local/bin/uv pip install qdrant-client>=1.12.0
--python {{ hermes_home }}/.hermes/hermes-agent/venv/bin/python
environment:
UV_CACHE_DIR: /tmp/uv-cache
become: true
become_user: "{{ hermes_user }}"
become_user: root
when: hermes_binary.stat.exists
changed_when: false
# --- Configuration ---

View file

@ -0,0 +1,22 @@
---
postfix_relay_host: smtp-relay.brevo.com
postfix_relay_port: 587
postfix_relay_user: "" # à définir dans group_vars/gateway/vars.yml
postfix_relay_password: "" # depuis vault (vault_postfix_relay_password)
postfix_myhostname: "storage-01.lab.local"
postfix_myorigin: "$myhostname"
# Adresse expéditeur réécrite pour tous les mails sortants
postfix_sender_email: "" # à définir dans group_vars/gateway/vars.yml
# Réseaux autorisés à relayer — ajuster si besoin
postfix_mynetworks:
- "127.0.0.0/8"
- "[::1]/128"
- "192.168.10.0/24" # LAN cluster
- "10.42.0.0/16" # pods k8s
- "10.43.0.0/16" # services k8s
# Ouvrir le port 25 depuis le LAN cluster dans nftables
postfix_open_nftables: true

View file

@ -0,0 +1,10 @@
---
- name: Restart postfix
ansible.builtin.systemd:
name: postfix
state: restarted
- name: Reload nftables
ansible.builtin.systemd:
name: nftables
state: reloaded

View file

@ -0,0 +1,72 @@
---
- name: Install postfix and SASL auth library
ansible.builtin.dnf:
name:
- postfix
- cyrus-sasl-plain
- s-nail
state: present
- name: Deploy main.cf
ansible.builtin.template:
src: main.cf.j2
dest: /etc/postfix/main.cf
owner: root
group: root
mode: '0644'
notify: Restart postfix
- name: Deploy sasl_passwd
ansible.builtin.template:
src: sasl_passwd.j2
dest: /etc/postfix/sasl_passwd
owner: root
group: root
mode: '0600'
register: sasl_passwd_result
- name: Run postmap on sasl_passwd
ansible.builtin.command: postmap /etc/postfix/sasl_passwd
when: sasl_passwd_result.changed
changed_when: true
notify: Restart postfix
- name: Deploy generic sender rewrite map
ansible.builtin.copy:
dest: /etc/postfix/generic
content: |
# Réécriture expéditeur — géré par Ansible
@{{ postfix_myhostname }} {{ postfix_sender_email }}
root {{ postfix_sender_email }}
owner: root
group: root
mode: '0644'
register: generic_map_result
when: postfix_sender_email | length > 0
- name: Run postmap on generic map
ansible.builtin.command: postmap /etc/postfix/generic
when: generic_map_result is changed
changed_when: true
notify: Restart postfix
- name: Reset postfix failed state if any
ansible.builtin.command: systemctl reset-failed postfix.service
changed_when: false
failed_when: false
- name: Enable and start postfix
ansible.builtin.systemd:
name: postfix
enabled: true
state: started
daemon_reload: true
- name: Open port 25 from cluster LAN in nftables
ansible.builtin.lineinfile:
path: /etc/nftables.conf
insertafter: '# alertmanager-webhook'
line: " tcp dport 25 ip saddr 192.168.10.0/24 accept comment \"postfix-relay\""
state: present
when: postfix_open_nftables
notify: Reload nftables

View file

@ -0,0 +1,38 @@
# Postfix — relay-only — géré par Ansible (rôle postfix_relay)
# Ne pas éditer manuellement
compatibility_level = 2
myhostname = {{ postfix_myhostname }}
myorigin = {{ postfix_myorigin }}
# Relay SMTP externe
relayhost = [{{ postfix_relay_host }}]:{{ postfix_relay_port }}
# Écouter sur toutes les interfaces pour permettre au cluster de relayer
inet_interfaces = all
inet_protocols = ipv4
# Réseaux autorisés à relayer (pas un open relay)
mynetworks = {{ postfix_mynetworks | join(' ') }}
# Désactiver la livraison locale
mydestination =
local_recipient_maps =
local_transport = error:local delivery disabled
# TLS sortant
smtp_tls_security_level = encrypt
smtp_tls_CAfile = /etc/ssl/certs/ca-bundle.crt
smtp_tls_loglevel = 1
# Authentification SASL vers le relay
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_sasl_tls_security_options = noanonymous
# Réécriture expéditeur — remplace root@lab.local par une adresse réelle
{% if postfix_sender_email %}
smtp_generic_maps = hash:/etc/postfix/generic
{% endif %}

View file

@ -0,0 +1,2 @@
# Géré par Ansible — ne pas éditer manuellement
[{{ postfix_relay_host }}]:{{ postfix_relay_port }} {{ postfix_relay_user }}:{{ postfix_relay_password }}