Postfix

Rôle

Point d'entrée SMTP interne (MTA minimal) de l'infrastructure Indio : reçoit le courrier applicatif adressé à @infra.indio (notifications, tickets, alertes) et le livre localement dans la boîte Unix root sur le nœud qui l'a reçu.

Ce n'est pas un relais SMTP sortant

Aucun relayhost n'est configuré dans main.cf : ce service ne relaie aucun courrier vers une messagerie externe (Gmail, etc.) ni vers Internet. C'est un MTA de livraison locale pour le domaine interne, restreint aux réseaux internes (mynetworks) — pas un smarthost sortant.

Architecture

  • 2 nœuds, zone service (seg-service) : INDSERV009 (10.100.2.138), INDSERV010 (10.100.2.139) (nommés postfix-01/postfix-02 avant la migration vers la convention IND<SEGMENT><NNN>, comme en atteste le journal apply.log du dépôt), 1 vCPU / 2 Go chacun, clones du template Rocky 9.6 durci.
  • Détruites le 2026-07-07 (round de décommissionnement SOC/service, voir Historique des décommissionnements), redéployées le 2026-07-17 (VM nues d'abord, code Terraform inchangé), puis dotées d'un rôle Ansible applicatif le même jour (postfix_relay) suite à l'alerting Zabbix SLA qui a mis en évidence l'absence de service mail fonctionnel.
  • IP allouées dynamiquement via NetBox (data netbox_ip_addresses, une entrée par nœud).
  • Aucune répartition de charge ni haute disponibilité (pas de VIP keepalived) : les 2 nœuds sont des instances Postfix indépendantes et identiques, un client doit choisir explicitement l'un des deux — aucun mécanisme de bascule automatique.
  • mynetworks = 127.0.0.0/8, 10.100.0.0/16 (zone admin), 10.15.0.0/16 (zone management) — tout le reste est rejeté (reject_unauth_destination).
  • mydestination inclut infra.indio : Postfix se considère responsable de la livraison finale pour ce domaine (livraison locale, pas de relais vers un MX externe).

Structure du dépôt

Fichier / dossier Contenu
main.tf Ressource vsphere_virtual_machine.postfix, for_each sur var.nodes
variables.tf nodes par défaut [INDSERV009, INDSERV010], cpu=1, ram=2048
ansible/site.yml Rôle unique postfix_relay
ansible/roles/postfix_relay/tasks/main.yml Paquet, main.cf, alias, firewalld
ansible/roles/postfix_relay/templates/main.cf.j2 Config Postfix (mynetworks, mydestination, restrictions)
ansible/group_vars/postfix.yml Domaine, réseaux autorisés, alias

Flux de courrier

flowchart LR
    App["Applications internes<br/>(GLPI, Zabbix, scripts...)"] -->|"SMTP 25<br/>mynetworks 10.100.0.0/16 + 10.15.0.0/16"| PFX1["INDSERV009<br/>10.100.2.138"]
    App -->|"SMTP 25<br/>(nœud alternatif, pas de VIP/LB)"| PFX2["INDSERV010<br/>10.100.2.139"]
    PFX1 -->|"mydestination = infra.indio<br/>livraison locale"| MB1[("/var/mail/root<br/>sur INDSERV009")]
    PFX2 -->|"mydestination = infra.indio<br/>livraison locale"| MB2[("/var/mail/root<br/>sur INDSERV010")]
    NoRelay["Aucun relayhost —<br/>pas de sortie vers Internet"]
    PFX1 -.- NoRelay
    PFX2 -.- NoRelay

Provisioning Terraform

  • main.tf : ressource vsphere_virtual_machine.postfix avec for_each sur var.nodes (2 objets name), même schéma multi-nœuds que le dépôt k8s.
  • Variables clés (variables.tf) : nodes par défaut [INDSERV009, INDSERV010], vsphere_network = seg-service, vm_cpu = 1, vm_ram = 2048.
  • Providers (versions.tf) : hashicorp/vsphere + e-breuninger/netbox.
  • Sortie vms : map nom de VM → adresse IP.

Configuration Ansible

Playbook ansible/site.yml, rôle unique postfix_relay sur le groupe postfix (inventory.ini) :

  • Installe le paquet distro postfix (pas de tarball ni de source tierce).
  • Déploie main.cf (template main.cf.j2) : myhostname dérivé de inventory_hostname | lower (Postfix n'exige pas de hostname minuscule comme FreeIPA, mais la convention est appliquée par cohérence), mydomain = infra.indio, myorigin = $mydomain, inet_interfaces = all, inet_protocols = ipv4, mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain, mynetworks = liste postfix_mynetworks (group_vars), smtpd_relay_restrictions/smtpd_recipient_restrictions = permit_mynetworks, reject_unauth_destination, compatibility_level = 2.
  • Alias locaux (/etc/aliases, ansible.builtin.lineinfile par entrée de postfix_aliases) : bjeyakumar → root — régénération de la base (newaliases) uniquement si un alias a changé.
  • Ouvre le service smtp en firewalld (zone drop).
  • Démarre et active le service.

Variables (group_vars/postfix.yml) : postfix_domain: infra.indio, postfix_mynetworks (3 CIDR), postfix_aliases (liste name/dest).

Aucun secret ansible-vault dans ce rôle — pas d'authentification SMTP, pas de TLS configuré (smtpd_tls_* absent de main.cf), cohérent avec un service restreint aux réseaux internes uniquement.

Procédure de déploiement

  1. Réservation IP NetBox préalable obligatoire : la data source netbox_ip_addresses du main.tf échoue (no result) si INDSERV009.infra.indio/INDSERV010.infra.indio n'ont pas déjà une IP réservée côté NetBox — terraform plan/apply ne créent aucune IP eux-mêmes. Script dédié idempotent : python3 /root/netbox/seed/add_postfix_vms.py (ne rejoue pas tout le seed, voir NetBox).
  2. terraform apply → provisionne les 2 VM nues.
  3. ansible-playbook site.yml → installe et configure Postfix (mynetworks, alias, firewalld) sur les 2 nœuds.

Contrôle de santé / Vérification

systemctl status postfix
postqueue -p                      # file d'attente
journalctl -u postfix -f          # ou /var/log/maillog selon la distro
# Test d'envoi depuis un hôte du réseau mynetworks :
echo "test" | mail -s "test postfix" root@infra.indio -S smtp=10.100.2.138:25
ssh indio-adm@10.100.2.138 'sudo tail /var/mail/root'   # confirme la livraison locale

Testé bout en bout le 2026-07-17 (curl SMTP depuis INDSUPV001 → queue → livraison confirmée dans /var/mail/root).

Points d'attention

  • Consommateur identifié mais non branché : le rôle Ansible GLPI (glpi/ansible/roles/glpi/tasks/main.yml) active le booléen SELinux httpd_can_sendmail par anticipation pour ses notifications de tickets par email, mais aucun relayhost n'est configuré côté GLPI vers Postfix à ce jour — l'intégration reste à faire (voir GLPI).
  • Pas de TLS sur le SMTP interne (smtpd_tls_* absent de main.cf) — acceptable tant que le service reste restreint aux réseaux internes de confiance (mynetworks), mais toute extension future (SMTP authentifié, exposition plus large) nécessiterait de l'ajouter.
  • Aucune haute disponibilité réelle malgré 2 nœuds : pas de VIP keepalived ni de round-robin DNS documenté — un client doit choisir explicitement un nœud, sans bascule automatique en cas de panne.
  • Courrier consultable uniquement par SSH (/var/mail/root, format mailbox Unix) — pas de webmail, pas d'IMAP/POP3 : décision volontairement laissée au user plutôt que prise à sa place, un vrai relais vers une messagerie externe reste un gap fonctionnel identifié si le besoin se présente.
  • Aucune autre référence croisée à Postfix/SMTP trouvée dans les autres dépôts examinés (Zabbix, HAProxy) au-delà de GLPI : si d'autres services (alertes Zabbix, notifications diverses) doivent utiliser ce relais, l'intégration reste à faire au cas par cas.