Postfix avec MySQL et identification SASL (SMTP Auth)

Je vais détailler l’installation du serveur mail Postfix couplé à MySQL pour gérer simplement les domaines et les boites mails des utilisateurs. Ensuite, pour éviter que le serveur Mail ne devienne un relais à spam, il est possible d’utiliser une authentification SMTP pour envoyer des mails, ainsi, lorsqu’un utilisateur voudra envoyer un mail il devra être authentifié.

Installation de Postfix / MySQL

apt-get install postfix postfix-mysql

Utilisation de l’IP Failover

Avant de commencer ce tutoriel, nous allons configurer Postfix pour qu’il utilise la bonne IP.

Pour les serveurs RPS d’OVH, le RPS possède 2 IP :

  • 1 IP physique
  • 1 IP failover qui sera identique même si vous changez de serveur

Il faut donc que PostFix utilise l’IP de failover car elle possède [[http://www.serveur-rps.fr/manager_ovh/services#reverse|un reverse DNS]] ce qui vous évitera d’avoir des mails classés en SPAM avec l’erreur « said: 421 Refused. You have no reverse DNS entry« .

Lors d’un ipconfig sur mon serveur, voila ce que j’obtiens :

eth0 Lien encap:Ethernet HWaddr 00:19:D1:86:D4:8C
 inet adr:91.121.193.xxx Bcast:91.121.193.255 Masque:255.255.255.0
 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
 RX packets:6029245 errors:0 dropped:0 overruns:0 frame:0
 TX packets:8890768 errors:0 dropped:0 overruns:0 carrier:0
 collisions:0 lg file transmission:1000
 RX bytes:1273621622 (1.1 GiB) TX bytes:1861274124 (1.7 GiB)
 Interruption:16 Adresse de base:0x2000

eth0:0 Lien encap:Ethernet HWaddr 00:19:D1:86:D4:8C
 inet adr:91.121.36.xxx Bcast:91.255.255.255 Masque:255.255.255.255
 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
 Interruption:16 Adresse de base:0x2000
  • eth0 est l’IP physique
  • eth0:0 est l’IP failover

Pour que PostFix utilise l’IP failover il faut modifier le fichier /etc/postfix/main.cf et la variable inet_interfaces qui devra être égale à l’IP Failover :

nano /etc/postfix/main.cf

inet_interfaces = 91.121.36.xxx

Création des tables MySQL

Dans PhpMyAdmin (guide d’installation de PhpMyAdmin), nous allons créer les tables qui vont contenir les boîtes mails, les domaines, les alias :

CREATE TABLE `alias` (
`address` varchar(255) NOT NULL default '',
`goto` text NOT NULL,
`domain` varchar(255) NOT NULL default '',
`created` datetime NOT NULL default '0000-00-00 00:00:00',
`modified` datetime NOT NULL default '0000-00-00 00:00:00',
`active` tinyint(1) NOT NULL default '1',
PRIMARY KEY (address)
) TYPE=MyISAM COMMENT='Postfix Admin - Virtual Aliases';

CREATE TABLE `domain` (
`domain` varchar(255) NOT NULL default '',
`description` varchar(255) NOT NULL default '',
`aliases` int(10) NOT NULL default '0',
`mailboxes` int(10) NOT NULL default '0',
`maxquota` int(10) NOT NULL default '0',
`transport` varchar(255) default NULL,
`backupmx` tinyint(1) NOT NULL default '0',
`created` datetime NOT NULL default '0000-00-00 00:00:00',
`modified` datetime NOT NULL default '0000-00-00 00:00:00',
`active` tinyint(1) NOT NULL default '1',
PRIMARY KEY (domain)
) TYPE=MyISAM COMMENT='Postfix Admin - Virtual Domains';

CREATE TABLE `mailbox` (
`username` varchar(255) NOT NULL default '',
`password` varchar(255) NOT NULL default '',
`name` varchar(255) NOT NULL default '',
`maildir` varchar(255) NOT NULL default '',
`quota` int(10) NOT NULL default '0',
`domain` varchar(255) NOT NULL default '',
`created` datetime NOT NULL default '0000-00-00 00:00:00',
`modified` datetime NOT NULL default '0000-00-00 00:00:00',
`active` tinyint(1) NOT NULL default '1',
PRIMARY KEY (`username`)
) TYPE=MyISAM COMMENT='Postfix Admin - Virtual Mailboxes';

Création d’un utilisateur qui va contenir les boîtes Mails

Création d’un groupe Mail et création des utilisateurs :

groupadd -g 5000 grpmail
useradd -g grpmail -u 5000 usermail -d /usr/local/virtual -m

Les boîtes sont stockées dans /usr/local/virtual et l’utilisateur doit recevoir un email pour activer sa boite.

De plus, il n’a pas besoin d’accès SSH donc :

nano /etc/passwd

usermail:x:5000:5000::/usr/local/virtual:/bin/false

Configuration de Postfix : ajout de la gestion MySQL

Modification du fichier de configuration pour ajouter la gestion MySQL :

nano /etc/postfix/main.cf
# Support Mysql
virtual_alias_maps = mysql:/etc/postfix/mysql_virtual_alias_maps.cf
virtual_gid_maps = static:5000
virtual_mailbox_base = /usr/local/virtual
virtual_mailbox_domains = mysql:/etc/postfix/mysql_virtual_domains_maps.cf
virtual_mailbox_limit = 51200000
virtual_mailbox_maps = mysql:/etc/postfix/mysql_virtual_mailbox_maps.cf
virtual_minimum_uid = 5000
virtual_transport = virtual
virtual_uid_maps = static:5000
# Support du quota
#virtual_create_maildirsize = yes
#virtual_mailbox_extended = yes
#virtual_mailbox_limit_maps = mysql:/etc/postfix/mysql_virtual_mailbox_limit_maps.cf
#virtual_mailbox_limit_override = yes
#virtual_maildir_limit_message = Desole, la boite email de l'utilisateur est pleine, essayez plus tard.
#virtual_overquota_bounce = yes

# Suport du relay
relay_domains = mysql:/etc/postfix/mysql_relay_domains_maps.cf

Fichiers pour l’accès à MySQL

Création des fichiers qui vont se connecter à MySQL :

nano /etc/postfix/mysql_virtual_alias_maps.cf
user = root
password = mot_de_passe
hosts = 127.0.0.1
dbname = postfix
query = SELECT goto FROM alias WHERE address='%s' AND active = 1
nano /etc/postfix/mysql_virtual_domains_maps.cf

user = root
password = mot_de_passe
hosts = 127.0.0.1
dbname = postfix
query = SELECT domain FROM domain WHERE domain='%s'
#optional query to use when relaying for backup MX
#query = SELECT domain FROM domain WHERE domain='%s' and backupmx = '0' and active = '1'
nano /etc/postfix/mysql_virtual_mailbox_maps.cf

user = root
password = mot_de_passe
hosts = 127.0.0.1
dbname = postfix
query = SELECT maildir FROM mailbox WHERE username='%s' AND active = 1
nano /etc/postfix/mysql_virtual_mailbox_limit_maps.cf

user = root
password = mot_de_passe
hosts = 127.0.0.1
dbname = postfix
query = SELECT quota FROM mailbox WHERE username='%s'
nano /etc/postfix/mysql_relay_domains_maps.cf

user = root
password = mot_de_passe
hosts = 127.0.0.1
dbname = postfix
query = SELECT domain FROM domain WHERE domain='%s' and backupmx = '1'

Modification des droits pour que Postfix puisse lire les fichiers

Il faut ensuite donner les droits pour que Postfix puisse lire les fichiers de configuration MySQL :

chmod 640 mysql_*
chgrp postfix mysql_*

Déchrooter Postfix

Pour le bon fonctionnement, il faut déchrooter Postfix (avec le SMTP Auth activé, j’avais cette erreur : « postfix/smtpd[10776]: warning: SASL authentication failure: cannot connect to saslauthd server: No such file or directory« ) pour que tout fonctionne.

Il faut mettre « n » dans la colonne « chroot » à la ligne « smtp » :

nano /etc/postfix/master.cf

# ==========================================================================
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (yes) (never) (100)
# ==========================================================================
smtp inet n - n - - smtpd

Sécurisation et suppression des mails non conformes

Postfix va effectuer un 1er tri pour supprimer les mails qui sont mal formatés par les spammeurs ou autres « bots » mal configuré. Pour chaque ligne rajouté, son explication est donnée en commentaire.

nano /etc/postfix/main.cf

# définit la liste des adresses valides du domaine
#relay_recipient_maps = hash:/etc/postfix/relay_recipients
relay_domains = $mydomain
smtpd_client_restrictions = permit_mynetworks

# adresses d'expédition forgé avec "MAIL FROM:"
# reject_unknown_sender_domain -> rejette le mail si aucun enregistrement DNS A ou MX
# warn_if_reject -> enregistre avertissement au lieu de suppr le mail "reject_warning"
smtpd_sender_restrictions =
permit_mynetworks,
reject_unknown_sender_domain

# Restriction d'accès - adresses de destination avec "RCPT TO:"
# reject_unauth_destination -> fonctionne avec le fichier : relay_recipient_maps et rejette les domaines non valides
# reject_unknown_recipient_domain -> rejette le mail si aucun enregistrement DNS A ou MX
# reject_non_fqdn_recipient -> rejette si "RCPT TO:" est non conforme avec la RFC
smtpd_recipient_restrictions =
permit_mynetworks,
#reject_unauth_destination,
reject_unknown_recipient_domain

Installation de SASL (SMPT auth)

Cette partie va obliger les utilisateurs à s’authentifier pour envoyer des mails et donc empêcher que le serveur mail devienne « open relay » pour les spammeurs.

Installation des librairies SASL :

apt-get install libsasl2-2 libsasl2-modules libsasl2-modules-sql sasl2-bin libpam-mysql openssl

Activation de la gestion SASL dans la configuration Postfix

nano /etc/postfix/main.cf
# Support SASL
broken_sasl_auth_clients = yes
smtpd_recipient_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_non_fqdn_hostname,
reject_non_fqdn_sender,
reject_non_fqdn_recipient,
reject_unauth_destination,
reject_unauth_pipelining,
reject_invalid_hostname
smtpd_sasl_auth_enable = yes
smtpd_sasl_local_domain = $myhostname
smtpd_sasl_security_options = noanonymous

Par défaut, SASL lit un fichier pour effectuer la vérification du login et mot de passe afin de valider si l’utilisateur a le droit d’envoyer un email. Comme nous utilisons MySQL, nous allons indiquer à SASL d’utiliser MySQL car la base contient déjà le login et mot de passe de l’utilisateur, ainsi, l’utilisateur aura les mêmes identifications, que se soit pour lire sa boîte mail ou pour envoyer des mails.

Configuration du module d’authentification : saslauthd

nano /etc/default/saslauthd

START=yes
MECHANISMS="pam"
OPTIONS="-r"

Configuration du module PAM et MySQL

nano /etc/pam.d/smtp

auth required pam_mysql.so user=root passwd=mot_de_passe host=127.0.0.1 db=postfix table=mailbox usercolumn=username passwdcolumn=password crypt=1
account sufficient pam_mysql.so user=root passwd=mot_de_passe host=127.0.0.1 db=postfix table=mailbox usercolumn=username passwdcolumn=password crypt=1

/etc/init.d/saslauthd restart

# ajout de SASL au groupe POSTFIX
adduser postfix sasl

Création de la requête utilisée par SASL pour les informations des utilisateurs lors de l’authentification

nano /etc/postfix/sasl/smtpd.conf

pwcheck_method: saslauthd auxprop
mech_list: plain login
auxprop_plugin: sql
sql_engine: mysql
sql_hostnames: 127.0.0.1
sql_user: root
sql_database: postfix
sql_passwd: mot_de_passe
sql_select: select password from mailbox where username = '%u@%r'

Installation de Courier POP et IMAP

apt-get install courier-authdaemon courier-authlib-mysql courier-pop courier-pop-ssl courier-imap courier-imap-ssl

Configuration du module d’authentification de COURIER

nano /etc/courier/authdaemonrc

authmodulelist="authpam" -> authmodulelist="authmysql"

nano /etc/courier/authmysqlrc

MYSQL_SERVER 127.0.0.1
MYSQL_USERNAME root
MYSQL_PASSWORD mot_de_passe

#MYSQL_SOCKET /var/lib/mysql/mysql.sock
MYSQL_PORT 0
MYSQL_OPT 0

MYSQL_DATABASE postfix
MYSQL_USER_TABLE mailbox
MYSQL_CRYPT_PWFIELD password
#DEFAULT_DOMAIN domain.tld

MYSQL_UID_FIELD 5000
MYSQL_GID_FIELD 5000

MYSQL_LOGIN_FIELD username
MYSQL_HOME_FIELD "/usr/local/virtual"
MYSQL_NAME_FIELD name
MYSQL_MAILDIR_FIELD maildir

#MYSQL_QUOTA_FIELD quota
#MYSQL_WHERE_CLAUSE server='exemple.domain.tld'

Si vous avez des erreurs, il est possible que le démon affiche plus d’information dans les logs, dès lors, il est possible de voir les requètes MySQL exécutées, les logins et mots de passe utilisés pour débuguer:

nano /etc/courier/authdaemonrc
# modification du mode DEBUG
DEBUG_LOGIN=2
# redémarrage du démon pour afficher plus de logs
/etc/init.d/courier-authdaemon restart

Ainsi, avec une fenêtre qui affiche « tail -f /var/log/mail.log » on voit les requêtes SQL générées, avec les mots de passe, etc, c’est exactement ce qu’il nous faut pour débuguer ! Par exemple, « imapd: authentication error: Input/output error« .

Pour revenir par défaut : DEBUG_LOGIN=0.

Sous Thunderbird : « imapd: LOGIN FAILED » dans les logs -> bien vérifier la configuration

Redémarrer les démons

/etc/init.d/postfix restart
/etc/init.d/saslauthd restart
/etc/init.d/courier-authdaemon restart
/etc/init.d/courier-imap restart
/etc/init.d/courier-imap-ssl restart
/etc/init.d/courier-pop restart
/etc/init.d/courier-pop-ssl restart

SpamAssassin

SpamAssassin va scanner les mails et supprimer le Spam.

apt-get install spamassassin spamc razor

Configuration du démon SpamAssassin pour qu’il se lance au démarrage :

nano /etc/default/spamassassin

ENABLED=1

Configuration de SpamAssassin :

nano /etc/spamassassin/local.cf
rewrite_header Subject ***** SPAM *****
required_score 5.0
# ne place pas le mail considéré comme SPAM en pièce jointe. Pour activer, mettre "1"
report_safe 0
use_bayes 1
bayes_auto_learn 1
use_razor2 1

/etc/init.d/spamassassin restart

Création d’un utilisateur qui va stocker dans son répertoire HOME les données de Spamassassin. Puisqu’il n’a pas besoin d’une connexion au shell, nous utilisons l’argument -s /sbin/nologin.

useradd -s /sbin/nologin -d /home/spamuser spamuser
mkdir /home/spamuser
chown -R spamuser:spamuser /home/spamuser

Configuration du fichier master.cf pour que Postfix utilise Spamassassin à chaque mail reçu :

nano /etc/postfix/master.cf
# ==========================================================================
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (yes) (never) (100)
# ==========================================================================
smtp inet n - n - - smtpd -o content_filter=spamassassin

A la fin du fichier master.cf, on rajoute la référence à Spamassassin et l’utilisation de l’utilisateur spamuser (pour stocker les préférences, etc.) :

spamassassin
unix - n n - - pipe
user=spamuser argv=/usr/bin/spamc -e /usr/sbin/sendmail -oi -f ${sender} ${recipient}

Pour prendre en compte les modifications nous redémarrons Postfix :

/etc/init.d/postfix restart

Pour vérifier que tout va bien, il suffit d’envoyer un mail dans la boite mail d’un utilisateur :

tail -f /var/log/mail.log
Feb 2 23:40:37 stock spamd[11594]: spamd: connection from localhost.localdomain [127.0.0.1] at port 39160
Feb 2 23:40:37 stock spamd[11594]: spamd: setuid to spamuser succeeded
Feb 2 23:40:37 stock spamd[11594]: spamd: creating default_prefs: /home/spamuser/.spamassassin/user_prefs
Feb 2 23:40:37 stock spamd[11594]: config: created user preferences file: /home/spamuser/.spamassassin/user_prefs

L’utilisateur spamuser a bien stocké les préférences par défaut de Spamassassin dans son dossier home : /home/spamuser donc tout fonctionne !

Il est possible de faire un test pour vérifier que SpamAssassin détecte bien les spams, il suffit d’envoyer un mail vers le serveur mail (par exemple d’un adresse Gmail) avec dans le sujet la chaine : XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X

Dans les logs, la détection se fait bien :

Feb 2 23:45:46 stock spamd[11594]: spamd: identified spam (1001.6/5.0) for spamuser:5001 in 4.7 seconds, 3610 bytes.

Une fois que ThunderBird retire le mail de la boite gérée par Postfix, le champ de l’objet reçoit un entête ***** SPAM *****.