Construction d'un serveur d'email

Construction d'un serveur d'email
Sommaire

Photo by Thanhy Nguyen on Unsplash


A l’occasion d’un changement de serveur, j’ai remis à plat (et à jour) ce document d’installation et configuration d’un serveur de courrier complet (SMTP, IMAP, Webmail, antivirus, antispam, etc.).

I. Objectif

L’objectif est de proposer un serveur de mail complet capable de gérer plusieurs domaines avec les protocoles SMTP/S (Submission), IMAP/S ainsi qu’un antispam (RSpamd), un système de règles de classifications (Sieve) et un webmail avec gestion des contacts intégrée.

II. Prérequis

  • Un serveur dédié à cette activité, connecté de façon permanente à Internet
  • Une adresse IPv4 (éventuellement v6) fixe.
  • Un nom de domaine dont vous contrôlez pleinement le DNS (c’est important).
  • Définir un nom pour le serveur et créer deux enregistrements A et PTR dans le DNS pour faire correspondre nom et IP de façon bijective (c’est essentiel pour les antispam).

Pour l’exemple, j’utiliserai :

  • Domaine : mondomaine.tld
  • Nom du serveur : mail.mondomaine.tld

Remarque : sauf mention contraire, toutes les commandes données seront exécutées en root ou en sudo (selon votre préférence).

III. Liste des logiciels mis en oeuvre

Dans l’installation du serveur de mail, je vais mettre en oeuvre les lgoiciels suivants :

  • Debian Buster (10 au moment de l'écriture de cet article) : le système d’exploitation
  • Apache : un serveur web, pour accéder aux interfaces d’administration
  • Postfix : le serveur permettant de recevoir des emails
  • Dovecot : le serveur permettant aux utilisateurs de consulter les mails reçus
  • RSpamd : un logiciels de filtrage et d’antispam/antivirus
  • Sieve : un logiciel pour établir des règles de classement
  • MariaDB : un système de gestion de bases de données
  • PostfixAdmin : une interface web d’administration des comptes emails
  • RainLoop : un webmail moderne et facile d’utilisation

IV. Système d’exploitation

Je rédige ce document en me basant sur une Debian 10 (Buster). La plupart des infos sont facilement adaptables à une autre distribution. L’installation du serveur proprement dit ne rentre pas dans le cadre de ce document.

Un point à vérifier : si un firewall est installé, il faut laisser passer les ports suivants en entrée :

  • 25 (SMTP) - réception de mails
  • 80 (HTTP) - redirigeant systématiquement sur le 443
  • 443 (HTTPS) - sites d’administration
  • 465 (SMTPS) - réception sécurisée de mails
  • 993 (IMAPS) - consultation sécurisée des mails

et éventuellement

  • 995 (POP3S) - consultation sécurisée par le propocole POP3

V. Les différents types d’adresses mails

Un serveur comme Postfix est capable de gérer trois types de mails différents :

  • les comptes locaux : les comptes de ces domaines sont directement mappés sur les comptes du serveurs Linux (les comptes décrits dans le fichier /etc/passwd). La liste des domaines gérés de cette façon est donnée dans la variable mydestination de Postfix.
  • les comptes virtuels : les comptes de ces domaines ne correspondent à aucun compte réel mais sont simplement mappés sur des répertoires.
  • les comptes d’alias virtuels : ces comptes “rebondissent” sur d’autres adresses (locales, virtuelles ou même distantes).

VI. Installation des paquets principaux

VI.1 La base de données : MariaDB

Je commence par l’installation de la base de données. Debian a remplacé par défaut MySQL par MariaDB. L’installation se fait avec :

apt install mariadb-server

Je peux vérifier sa bonne installation en entrant dans le shell avec la commande mysql. Si tout va bien, une invite de commande MariaDB s’affichera sans avoir à saisir de mot de passe. La commande exit permet de quitter le shell.

VI.2 Le serveur de mail : Postfix

J’installe ensuite le serveur de mails avec son extension pour gérer les données dans MariaDB. La commande est :

apt install postfix postfix-mysql postfix-pcre libsasl2-modules libsasl2-modules-sql

VI.3 Le serveur Apache et le langage PHP

La plupart des interfaces d’administration sont en mode web. Il est nécessaire d’avoir un serveur. J’utilise celui que je connais le mieux, c’est à dire Apache. Et j’installe également le langage PHP qui est nécessaire pour les logiciels d’admin.

apt install apache2 php php-mysql php-mbstring php-imap

Remarque : la configuration détaillée de Apache n’entre pas dans le cadre de ce document. Je me contenterai de donner les précisions nécessaires pour ce qui est des interfaces d’administration de mail.

VI.4 Le logiciel d’antispam : RSpamd

RSpamd est un logiciel plus récent, plus simple d’administration et moins gourmand en ressources que les célèbres AmaVis et SpamAssassin. J’ai décidé de l’utiliser dans cette deuxième version du guide. Depuis Debian 10, il est inclus en standard :

apt install rspamd

VI.5 Le logiciel de lecture de mail : Dovecot

Dovecot permettra aux utilisateurs de consulter leurs mails. Je n’installe volontairement pas l’extension pour prendre en charge le protocole POP3 mais il suffit d’ajouter le package dovecot-pop3 si on le souhaite. L’extension dovecot-managesieved permet de gérer le protocle Sieve, un puissant langage de classement de mails.

apt install dovecot-mysql dovecot-imapd dovecot-managesieved dovecot-lmtpd

VII. Configuration des certificats TLS

Les certificats TLS (successeur de SSL) sont aujourd’hui indispensables pour assurer la sécurité et la confidentialité des échanges. Je vais utiliser l’authorité de certification Let’s Encrypt pour mes services de mails, comme je le fait déjà pour mes sites web.

Par chance, il suffit d’un seul certificat pour protéger à la fois Apache (HTTP/S), Postfix (SMTP/S) et Dovecot (IMAP/S) et Let’s Encrypt est capable de le générer quasi automatiquement.

Je commence par créer un site virtuel dans Apache pour mon domaine mail.mondomaine.tld. Je fais bien sûr pointer l’entrée de DNS (A et/ou AAAA) sur l’IP de ma machine. Dans un premier temps, je me contente d’un site http (sur le port 80) qui pointe sur un répertoire avec une simple page html vide.

La configuration d’Apache sera quelque chose du genre :

<VirtualHost *:80>
	ServerName mail.mondomaine.tld
	DocumentRoot /var/www/srvmail
</VirtualHost> 

Pour créer les certificats TLS, il faut un client de Let’s Encrypt. Le plus courant est certbot celui de l’EFF. Je ne rentrerai pas ici dans le détail de son installation. Pour obtenir un certificat pour votre domaine, la ligne de commande est :

certbot certonly --webroot --webroot-path /var/www/srvmail -d mail.mondomaine.tld

Maintenant que j’ai un certificat TLS, je peux ajouter une deuxième partie à la configuration de mon site virtuel :

<VirtualHost *:443>
	ServerName mail.mondomaine.tld
	DocumentRoot /var/www/srvmail
	SSLEngine on
	SSLCertificateFile /etc/letsencrypt/live/mail.mondomaine.tld/fullchain.pem
	SSLCertificateKeyFile /etc/letsencrypt/live/mail.mondomaine.tld/privkey.pem
</VirtualHost>

Remarque : pour utiliser le même serveur pour plusieurs domaines, plusieurs solutions sont possibles. Soit le serveur de mail du domaine 2 appartient au domaine 1, soit il faut obtenir un certificat TLS multi-domaines (en ajoutant d’autres -d dans la ligne de commande de certbot).

Remarque (2) : il est plus sûr de forcer toutes les requêtes HTTP a être converties en HTTP/S. Cela peut se faire en ajoutant les trois lignes suivantes dans le bloc <VirtualHost *.80> :

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI}

Remarque (3) : la configuration au plus sûr de Apache dépasse le cadre de ce document mais une bonne piste de départ se trouve ici : https://mozilla.github.io/server-side-tls/ssl-config-generator/ Il est facile de tester la ‘qualité’ d’une configuration avec le test de Qualys : https://www.ssllabs.com/ssltest/

Les certificats de Let’s Encrypt sont valables 90 jours. Ils se renouvellent automatiquement (certbot a normalement ajouté automatiquement une tâche dans le cron pour ça). Pour être sûr que mes trois serveurs (Apache, Postfix et Dovecot) prennent bien en compte la présence d’un nouveau certificat, j’ajoute une étape post-renouvellement sous la forme d’un petit script shell :

#!/bin/bash
systemctl reload apache2
systemctl reload postfix
systemctl reload dovecot

Je sauve ce fichier dans /usr/local/bin/certbot-post-hook et je le rend exécutable avec chmod u+x. Maintenant, il faut indiquer à certbot qu’il doit lancer ce fichier quand il a renouvellé un certificat. Pour celà, il faut surcharger la configuration de certbot dans systemd :

cp /lib/systemd/system/certbot.service /etc/systemd/system/

Et éditer la commande ExecStart dans le fichier /etc/systemd/system/certbot.service :

[Unit]
Description=Certbot
Documentation=file:///usr/share/doc/python-certbot-doc/html/index.html
Documentation=https://letsencrypt.readthedocs.io/en/latest/
[Service]
Type=oneshot
ExecStart=/usr/bin/certbot -q --post-hook /usr/local/bin/certbot-post-hook renew
PrivateTmp=true

Pour prendre en compte ce nouveau fichier : systemctl daemon-reload.

VIII. Configuration de la base de données

Je vais utiliser une base de données MariaDB pour conserver la configuration des comptes emails. Pour simplifier les choses, comme je compte installer PostfixAdmin pour administrer les comptes, c’est également cet outil qui va définir la structure de la base. Je n’utilise pas la version de PostfixAdmin présente dans le dépôt Debian car elle est un peu ancienne. Je vais aller chercher directement la version la plus récente (3.3.11 au moment de l'écriture de ce document) :

cd /usr/share
mkdir postfixadmin
cd postfixadmin
wget https://github.com/postfixadmin/postfixadmin/archive/postfixadmin-3.3.11.tar.gz
tar xzvf postfixadmin-3.3.11.tar.gz
mv postfixadmin-postfixadmin-3.3.11/* .
mkdir templates_c
chown www-data /usr/share/postfixadmin/templates_c/

Je vais ensuite créer deux utilisateurs dans mon serveur MariaDB : mailadmin et mailservice. Le premier sera utilisé par l’interface d’administration Postfixadmin pour écrire dans les tables de données, le second sera utilisé par les services d’email pour lire ces tables. Bien entendu, le second n’aura pas les permissions pour modifier les données. Voici les commandes que j’utilise (toutes ces commandes sont en SQL, je les lance depuis l’invite de commande de mysql) :

CREATE DATABASE postfixadmin;
DROP USER 'postfixadmin'@'localhost';
CREATE USER 'mailservice'@'%' IDENTIFIED BY 'un bon mot de passe';
GRANT SELECT ON postfixadmin.* TO 'mailservice'@'%';
CREATE USER 'mailadmin'@'localhost' IDENTIFIED BY 'un autre bon mot de passe';
GRANT ALL ON postfixadmin.* TO 'mailadmin'@'localhost';
FLUSH PRIVILEGES;
exit

Remarque : n’oubliez pas de notez soigneusement tous les mots de passe à chaque étape de l’installation. Comme il y a de nombreux logiciels et comptes, il y a de nombreux mots de passe. Ne mettez pas le même partout !

Pour configurer PostfixAdmin, il faut tout d’abord créer le fichier /usr/share/postfixadmin/config.local.php contenant les éléments suivants :

<?php
$CONF['configured'] = true;
$CONF['default_language'] = 'fr';
$CONF['database_type'] = 'mysqli';
$CONF['database_host'] = 'localhost';
$CONF['database_user'] = 'mailadmin';
$CONF['database_password'] = 'le mot de passe choisi';
$CONF['database_name'] = 'postfixadmin';
$CONF['admin_email'] = 'postmaster@mondomaine.tld';
?>

Puis il faut se rendre à l’URL : https://srvmail.mondomaine.tld/postfixadmin/setup.php

Cette URL va créer la base de données. Cette opération peut prendre quelques instants (une minute environ sur mon serveur). A la fin, la page de setup demande de choisir le mot de passe de setup de PostfixAdmin. Ce mot de passe sert uniquement à relancer la configuration de l’outil. La validation de ce mot de passe affichera une ligne de la forme :

$CONF['setup_password'] = 'un hash ';

qu’il faut retourner mettre dans /etc/postfixadmin/config.local.php.

Note : recharger la page pour que le fichier de config php soit relu !

Le mot de passe de setup est ensuite utilisé pour créer le compte administrateur de PostfixAdmin.

Je peux enfin me connecter à l’utilitaire à l’URL https://srvmail.mondomaine.tld/postfixadmin/login.php et créer mes domaines et boites mails. Un problème subsiste : ni Postfix, ni Dovecot n’ont connaissance de ces boites. Il va maintenant falloir les configurer pour lire les infos dans la base de données.

IX. Configuration de Postfix

La configuration de Postfix se fait dans le fichier /etc/postfix/main.cf. Ce fichier est constitué de directives de configuration qui surchargent les valeurs par défaut. Il y a environ un millier de directives mais seules certaines vont nous concerner.

Pour que Postfix reconnaisse les domaines et les adresses stockés dans la base MariaDB, il faut lui fournir ces infos dans deux directives de configuration : virtual_mailbox_domains et virtual_mailbox_maps.

J'édite donc le fichier /etc/postfix/main.cf pour lui ajouter les directives suivantes :

virtual_mailbox_domains = proxy:mysql:/etc/postfix/sql/mysql_virtual_domains_maps.cf
virtual_alias_maps =
    proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_maps.cf,
    proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_maps.cf,
    proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_catchall_maps.cf
virtual_mailbox_maps = proxy:mysql:/etc/postfix/sql/mysql_virtual_mailbox_maps.cf,
    proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_mailbox_maps.cf

Cela indique à Postfix que pour résoudre la directive virtual_mailbox_domains qui donne la liste des domaines virtuels, il devra exécuter la requête SQL décrite dans le fichier /etc/postfix/sql/mysql_virtual_domains_maps.cf. L’emplacement de ce fichier n’a pas une réelle importance mais il est capital que seul l’utilisateur postfix puisse le lire car il contient l’utilisateur et le mot de passe de la base de données (l’utilisateur qui accède en lecture seule pour plus de sécurité).

Pour définir les bons droits sur tous ces fichiers :

chgrp postfix /etc/postfix/sql/mysql*
chmod u=rw,g=r,o= /etc/postfix/sql/mysql*

Voici le contenu des différents fichiers contenant les requêtes SQL :

/etc/postfix/sql/mysql_virtual_domains_maps.cf : liste des domaines virtuels (un domaine virtuel est la partie droite d’une adresse email, après le @ qui doit être gérée par le serveur)

user = mailservice
password = le mot de passe de l'utilisateur
hosts = 127.0.0.1
dbname = postfixadmin
query = SELECT domain FROM domain WHERE domain='%s' AND active = '1'

/etc/postfix/sql/mysql_virtual_alias_maps.cf : liste des alias d’adresses (un alias est une adresse qui renvoit tous les emails vers une autre adresse, éventuellement d’un autre domaine)

user = mailservice
password = le mot de passe de l'utilisateur
hosts = 127.0.0.1
dbname = postfixadmin
query = SELECT goto FROM alias WHERE address='%s' AND active = '1'
#expansion_limit = 100

Le paramètre expansion_limit permet d’indiquer combien de rebonds sont autorisés (pour éviter les boucles), 100 est la valeur par défaut.

/etc/postfix/sql/mysql_virtual_alias_domain_maps.cf : liste des alias de domaines (un alias de domaine permet de rendre deux domaines synonymes. Par exemple si @monautredomaine.tld est un alias de @mondomaine.tld, tous les mails envoyés à une adresse en @monautredomaine.tld seront reçu dans la boite de même nom du domaine @mondomaine.tld)

user = mailservice
password = le mot de passe de l'utilisateur
hosts = 127.0.0.1
dbname = postfixadmin
query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' and alias.address = CONCAT('%u', '@', alias_domain.target_domain) AND alias.active = 1 AND alias_domain.active='1'

/etc/postfix/sql/mysql_virtual_alias_domain_catchall_maps.cf : liste des boites “catch all” (un catch all est une boite spéciale qui reçoit tous les emails envoyés à des adresses inexistantes sur le domaine)

user = mailservice
password = le mot de passe de l'utilisateur
hosts = 127.0.0.1
dbname = postfixadmin
query  = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' and alias.address = CONCAT('@', alias_domain.target_domain) AND alias.active = 1 AND alias_domain.active='1'

/etc/postfix/sql/mysql_virtual_mailbox_maps.cf : liste des boites virtuelles (là, il s’agit vraiment des adresses des utilisateurs)

user = mailservice
password = le mot de passe de l'utilisateur
hosts = 127.0.0.1
dbname = postfixadmin
query = SELECT maildir FROM mailbox WHERE username='%s' AND active = '1'

/etc/postfix/sql/mysql_virtual_alias_domain_mailbox_maps.cf : liste des alias de boites

user = mailservice
password = le mot de passe de l'utilisateur
hosts = 127.0.0.1
dbname = postfixadmin
query = SELECT maildir FROM mailbox,alias_domain WHERE alias_domain.alias_domain = '%d' and mailbox.username = CONCAT('%u', '@', alias_domain.target_domain) AND mailbox.active = 1 AND alias_domain.active='1'

/etc/postfix/sql/mysql_virtual_mailbox_limit_maps.cf : liste des quotas

user = mailservice
password = le mot de passe de l'utilisateur
hosts = 127.0.0.1
dbname = postfixadmin
query = SELECT quota FROM mailbox WHERE username='%s' AND active = '1'

X. Configuration de Dovecot

Maintenant que Postfix est configuré pour recevoir des emails, je dois configurer Dovecot pour pouvoir les lire. Par sécurité, je vais dédier un compte spécifique du système d’exploitation à la manipulation des emails. Je l’appelerai facteur. Pour le créer :

groupadd -g 3000 facteur
useradd -g facteur -u 3000 facteur -d /var/vmail -m -s /bin/false

Remarque : je force les identifiants de l’utilisateur et du groupe à 3000. Cette valeur n’a pas vraiment d’importance tant qu’elle n’est pas déjà utilisée mais je dois la noter car je vais m’en reservir par la suite.

On continue en allant éditer les fichiers de configuration de Dovecot dans /etc/dovecot/conf.d.

/etc/dovecot/conf.d/10-auth.conf : mécanismes d’authentification

A la fin du fichier, il faut commenter (avec un #) la ligne auth-system.conf.ext et décommenter celle de auth-sql.conf.ext pour permettre à Dovecot d’authentifier les utilisateurs en utilisant la base MariaDB.

/etc/dovecot/conf.d/auth-sql.conf.ext : paramètres d’authentification SQL

On ne garde que la partie userdb de type static en utilisant le facteur défini juste avant :

userdb {
    driver = static
    args = uid=facteur gid=facteur home=/var/vmail/%d/%u
}

Cela indique de créer les boites mails dans le dossier /var/mail avec un sous-répertoire pour le domaine (%d) et un pour le nom d’utilisateur (%u).

/etc/dovecot/conf.d/10-mail.conf : paramètres de stockage des emails

Il faut ajuster l’emplacement selon ce qui a été défini dans auth-sql.conf.ext :

mail_location = maildir:/var/vmail/%d/%n/Maildir

/etc/dovecot/conf.d/10-master.conf : paramètres de communication de Dovecot

Dans ce fichier, il faut décommenter la section Postfix smtp-auth pour permettre de déléguer l’authentification des utilisateurs de Postfix à Dovecot (pour bénéficier d’un système d’authentification unique et permettre l’envoi de mail de façon sécurisée sans transformer le Postfix en open relay) :

service auth {
    unix_listener /var/spool/postfix/private/auth {
        mode = 0660
        user = postfix
        group = postfix
    }
}

/etc/dovecot/conf.d/10-ssl.conf : paramètres de TLS

Rien de spécial, j’indique les chemins des certificats que j’ai créé au début :

ssl = yes
ssl_cert = </etc/letsencrypt/live/mail.mondomaine.tld/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.mondomaine.tld/privkey.pem

Remarque : attention à bien laisser le caractère < au début de la valeur, il indique qu’il s’agit d’un nom de fichier !

Générer un “Diffie-Hellman” avec openssl dhparam -out /etc/dovecot/dh.pem 4096

Paramétrer les boites spéciales dans 15-Mailboxes.conf (Junk, Trash…)

XI. Mise en place du webmail

J’installe la version standard de RainLoop, elle est gratuite pour une utilisation personnelle et non commerciale. Elle dépend de package PHP pas encore installés.

apt install php-curl php-xml unzip
mkdir /var/www/rainloop
wget https://www.rainloop.net/repository/webmail/rainloop-latest.zip
unzip rainloop-latest.zip -d /var/www/rainloop
rm rainloop-latest.zip
cd /var/www/rainloop
find . -type d -exec chmod 755 {} \;
find . -type f -exec chmod 644 {} \;
chown -R www-data:www-data .

Puis je modifie le fichier d’hote virtuel pour faire pointer la racine de mail.mondomaine.tld vers /var/www/rainloop/ et pour interdire le répertoire des données :

<VirtualHost *:80>
    ServerName mail.mondomaine.tld

    DocumentRoot /var/www/rainloop

    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI}
</VirtualHost>

<VirtualHost *:443>
    ServerName mail.mondomaine.tld
    DocumentRoot /var/www/rainloop
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/mail.mondomaine.tld/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/mail.mondomaine.tld/privkey.pem

    Alias /postfixadmin /usr/share/postfixadmin/public

    <Directory /var/www/rainloop/data/>
            Require all denied
    </Directory>
</VirtualHost>

La configuration de RainLoop se fait à l’adresse https://mail.mondomaine.tld/?admin

La connexion initiale se fait avec le login “admin” et le mot de passe “12345”. Bien entendu, il faut les changer immédiatement !

La configuration de Rainloop se fait dans son interface. Voici les points à changer :

  • Passer la langue en français
  • Modifier la taille max des pièces jointes (attention de modifier les paramètres upload_max_filesize et post_max_size de PHP dans /etc/php/7.0/apache2/php.ini en conséquence).
  • Ajouter le domaine domaine.tld dans les domaines autorisés (et éventuellement supprimer les domaines par défaut). Les paramètres du domaine sont les suivants :
    • Nom : domaine.tld
    • Serveur IMAP : localhost
    • Port IMAP : 993
    • Sécurité : SSL/TLS
    • Ne pas utiliser l’identifiant court
    • Serveur SMTP : localhost
    • Port SMTP : 25
    • Sécurité : Aucune
    • Utiliser l’authentification
    • Ne pas utiliser l’identifiant court
    • Ne pas utiliser la fonction mail de PHP
    • Autoriser les scripts Sieve
    • Autoriser les scripts personnels
    • Serveur Sieve : localhost
    • Port Sieve : 4190
    • Sécurité : STARTTLS

XII. Configuration de Postfix pour la réception et le relai authentifié

Je passe maintenant à une partie extrêmement importante de la configuration : celle qui vera que Postfix ne va pas devenir un relai ouvert (et donc le serveur une source de SPAM). Pour celà, il faut que le serveur n’accepte des mails de sources non authentifées que à destination des domaines qu’ils sert conjointement avec Dovecot. Tous les autres domaines devront passer par une connexion authentifée. Ça se fait dans le fichier /etc/postfix/main.cf avec :

smtpd_sasl_type=dovecot         # L'authentification se fait avec Dovecot
smtpd_sasl_path=private/auth    # Socket de dialogue (dans le chroot de Postfix)
smtpd_sasl_auth_enable=yes      # Active l'authentification

Ces lignes de configuration indiquent à Postfix qu’il doit communiquer avec Dovecot pour réaliser l’authentification en utilisant le fichier de socket dans private/auth (que j’ai configuré précédement dans Dovecot).

J’ajoute ensuite le chiffrement et les certificats :

smtpd_tls_security_level=may    # Le TLS est autorisé (mais pas obligatoire par compat avec les anciens serveurs)
smtpd_tls_auth_only=yes         # Le TLS est obligatoire si on veut s'authentifier
smtpd_tls_cert_file=/etc/letsencrypt/live/mondomaine.tld/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/mondomaine.tld/privkey.pem

Je vais également activer le service submission sur le port 587. Il faut pour cela éditer l’autre fichier de postfix : /etc/postfix/master.cf de la façon suivante :

submission inet n - - - - smtpd
    -o syslog_name=postfix/submission
    -o smtpd_tls_security_level=encrypt
    -o smtpd_sasl_auth_enable=yes
    -o smtpd_sasl_type=dovecot
    -o smtpd_sasl_path=private/auth
    -o smtpd_sasl_security_options=noanonymous
    -o smtpd_sender_login_maps=mysql:/etc/postfix/sql/mysql-email2email.cf
    -o smtpd_sender_restrictions=reject_sender_login_mismatch
    -o smtpd_sasl_local_domain=$myhostname
    -o smtpd_client_restrictions=permit_sasl_authenticated,reject
    -o smtpd_recipient_restrictions=reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject

Remarque : toutes les lignes avec -o sont des options pour la commande smtpd et doivent donc être indentées ! Elles surchargent les valeurs définies dans le main.cf. Voici une explication :

  • syslog_name=postfix/submission : Préfixe dans le fichier de log (pour faciliter la lecture)
  • smtpd_tls_security_level=encrypt : Sur ce service, le TLS est obligatoire
  • smtpd_sasl_security_options=noanonymous : L’authentification est obligatoire
  • smtpd_sender_login_maps=mysql:/etc/postfix/sql/mysql-email2email.cf : méthode de mise en relation des login avec les comptes emails (utilise la base de données, voir juste en dessous…)
  • smtpd_sender_restrictions=reject_sender_login_mismatch : rejette les demandes d’authentification si l’expéditeur de l’email n’est pas le compte qui s’est authentifié (attention : si vous voulez envoyer des emails pour plusieurs comptes avec le même utilisateur connecté en SMTP, il ne faut pas mettre ce paramètre !)
  • smtpd_sasl_local_domain=$myhostname : Les domaines des utilisateurs autorisés à s’identifier seront ceux qui sont acceptés en reception par le serveur
  • smtpd_client_restrictions=permit_sasl_authenticated,reject : Seuls les clients authentifiés sont autorisés à poster, les autres sont rejetés
  • smtpd_recipient_restrictions=reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject : Rejette les mails dont les destinataires n’ont pas une adresse correctement formée, rejette les destinataires dont le domaine est inconnu (ni A, ni MX dans le DNS), autorise les expéditeurs si ils sont correctement authentifiés et rejette le reste.

Le contenu du fichier /etc/postfix/sql/mysql-email2email.cf est le suivant :

user = mailservice
password = Le mot de passe choisi plus haut
hosts = 127.0.0.1
dbname = postfixadmin
query = SELECT username FROM mailbox WHERE username='%s' AND active = '1'

Cette dernière option est un peu compliquée : elle indique à Postfix de rechercher dans la base de données si l’expéditeur du mail est bien l’utilisateur qui a réalisé l’authentification. Elle empêche un utilisateur authentifié d’envoyer des mails avec d’autres adresses d’expéditeur que la sienne. C’est une sécurité supplémentaire particulièrement utile si vous avez beaucoup d’utilisateurs ou des utilisateurs que vous ne connaissez pas.

Quand toute cette configuration est terminée, je peux redémarrer Pöstfix avec un systemctl restart postfix et vérifier avec netstat -antp | grep LISTEN qu’il écoute bien sur les ports 25 et 587. Ne pas oublier d’ouvrir ces ports dans le firewall :

ufw allow 25/tcp
ufw allow 587/tcp

XII.2 Sécurité des envois

Pour renforcer un peu la sécurité et améliorer la confidentialité des échanges (même si l’idéal est de chiffrer son courier avec S/MIME ou PGP par exemple), il est possible de configurer Postfix pour qu’il tente de se connecter en TLS aux autres serveurs SMTP lorsqu’il envoie des messages. Cela se fait toujours dans le fichier /etc/postfix/main.cf en ajoutant les directives :

smtp_tls_security_level = may
smtp_tls_ciphers = medium
smtp_tls_protocols = !SSLv2, !SSLv3

XIII. Filtrage avec rspamd

Pour activer le filtrage des mails avec rspamd, on modifie de nouveau main.cf :

smtpd_milters=inet:127.0.0.1:11332
non_smtpd_milters=inet:127.0.0.1:11332
milter_protocol=6
milter_mail_macros=i {mail_addr} {client_addr} {client_name} {auth_authen}

La configuration de rspamd est dans le répertoire /etc/rspamd. Il ne faut pas modifier les fichiers qui s’y trouvent. Pour ajouter une config personnelle, deux solutions sont possibles : soit créer un fichier dans /etc/rspamd/local.d qui va compléter les directives par défaut, soit surcharger certaines directives en créant un fichier dans /etc/rspamd/override.d.

Dans ma configuration, je veux que rspamd ajoute des entêtes de détection de spam. Je crée un fichier /etc/rspamd/override.d/milter_headers.conf contenant :

extended_spam_headers = true;

Pour vérifier la syntaxe de la configuration de rspamd, il faut utiliser la commande : rspamadm configtest et pour voir toutes les directives utilisées : rspamadm configdump.

Quand la configuration de rspamd est faite, redémarrer le service avec systemctl restart rspamd.

XIV. Traitement automatique des spams

On va revenir sur la configuration de Dovecot pour activer le filtre Sieve. Sieve est un langage de classement automatique de mails. On va l’utiliser pour déplacer automatiquement dans le dossier “spam” tous les mails que rspamd aura classé comme tels. Pour celà, il faut commencer par activer sieve. Dans le fichier /etc/dovecot/conf.d/90-sieve.conf, j’ajoute la ligne suivante :

sieve_after = /etc/dovecot/sieve-after

On va créer ce répertoire. Tous les fichiers en .sieve qu’il contiendra seront exécuté par ordre croissant de nom (c’est donc une bonne idée de les préfixer avec des nombres).

mkdir /etc/dovecot/sieve-after

On crée le fichier 10-spam.sieve de filtrage du spam (qui sera donc commun à tous les utilsateurs) :

require ["fileinto","mailbox"];

if header :contains "X-Spam" "Yes" {
    fileinto :create "INBOX.Junk";
    stop;
}

Avant de l’utiliser, il faut compiler la règle Sieve : sievec 10-spam.sieve et redémarrer Dovecot : systemctl restart dovecot.

Ensuite, on va ajouter une directive dans la configuration de rspamd pour activer son mode d’auto apprentissage. Créez le fichier /etc/rspamd/override.d/classifier-bayes.conf contenant :

autolearn = true;

Et relancez rspamd.

Enfin, nous allons ajouter une paire de filtres supplémenatires pour que rspamd apprenne avec les actions de l’utilisateur : quand l’utilisateur place un mail dans le dossier spam, rspamd apprendra que c’est un spam et inversement quand l’utilisateur sortira un mail du dossier spam, il apprendra que c’est un mail normal. Pour cela, il faut modifier plusieurs fichiers de configuration :

Dans le fichier /etc/dovecot/conf.d/20-imap.conf :

mail_plugins = $mail_plugins imap_sieve

Dans le fichier /etc/dovecot/conf.d/90-sieve.conf, dans la partie plugin :

plugin {
    sieve_plugins = sieve_imapsieve sieve_extprograms
    # Déplacement de n'importe où vers le dossier spam
    imapsieve_mailbox1_name = INBOX.Junk
    imapsieve_mailbox1_causes = COPY
    imapsieve_mailbox1_before = file:/etc/dovecot/sieve/learn-spam.sieve

    # Déplacement du dossier spam vers n'importe quel autre dossier
    imapsieve_mailbox2_name = *
    imapsieve_mailbox2_from = INBOX.Junk
    imapsieve_mailbox2_causes = COPY
    imapsieve_mailbox2_before = file:/etc/dovecot/sieve/learn-ham.sieve

    # Répertoire des scripts
    sieve_pipe_bin_dir = /etc/dovecot/sieve

    # Autoriser l'envoi des eemails à une commande externe
    sieve_global_extensions = +vnd.dovecot.pipe
}

Ensuite, je crée le répertoire contenant les commandes Sieve :

mkdir /etc/dovecot/sieve

Et les deux scripts Sieve d’apprentissage :

Un script pour l’apprentissage du spam : /etc/dovecot/sieve/learn-spam.sieve contenant :

require ["vnd.dovecot.pipe", "copy", "imapsieve"];
pipe :copy "rspamd-learn-spam.sh";

Et un script pour l’opération inverse /etc/dovecot/sieve/learn-ham.sieve contenant :

require ["vnd.dovecot.pipe", "copy", "imapsieve"];
pipe :copy "rspamd-learn-ham.sh";

Il faut maintenant redémarrer Dovecot puis compiler les deux scripts :

systemctl restart dovecot
sievec /etc/dovecot/sieve/learn-ham.sieve
sievec /etc/dovecot/sieve/learn-spam.sieve
chmod u=rw,go= /etc/dovecot/sieve/learn-{spam,ham}.sieve
chown facteur:facteur /etc/dovecot/sieve/learn-{spam,ham}.sieve

Enfin, il reste à créer les deux scripts d’apprentissage pour rspamd :

Le premier /etc/dovecot/sieve/rspamd-learn-spam.sh qui correspond au premier script sieve :

#!/bin/sh
exec /usr/bin/rspamc learn_spam

Et le second /etc/dovecot/sieve/rspamd-learn-ham.sh :

#!/bin/sh
exec /usr/bin/rspamc learn_ham

Et enfin, on fixe les permissions adaptées et on relance Dovecot :

chmod u=rwx,go= /etc/dovecot/sieve/rspamd-learn-{spam,ham}.sh
chown facteur:facteur /etc/dovecot/sieve/rspamd-learn-{spam,ham}.sh
systemctl restart dovecot

Pour en finir avec rspamd, on peut également activer son interface web en ajoutant les lignes suivantes dans le fichier de configuration du site virtuel mail.domaine.tld :

ProxyPass "/rspamd" "http://localhost:11334"
ProxyPassReverse "/rspamd" "http://localhost:11334"

Note : il peut être nécessaire d’activer mod_proxy : a2enmod proxy proxy_http

Pour proteger cette interface, je choisis un mot de passe que je passe à la commande rspamadm pw. Celle-ci me retourne un hash que je vais inscire dans le fichier /etc/rspamd/local.d/worker-controller.inc :

password = "le hash"

Et je redémarre rspamd et apache :

systemctl restart rspamd
systemctl restart apache2

XV. Ajout d’un antivirus

Pour vérifier le contenu des emails, j’utilise l’antivirus ClamAV.

Son installation et le téléchargement initial de signatures de virus de fait avec :

apt install clamav-daemon clamav
systemctl stop clamav-daemon
freshclam
systemctl start clamav-daemon

Remarque : il peut être nécessaire de tuer l’instance de freshclam en cours d’exécution.

Pour que rspamd utilise clamav, il faut créer un fichier /etc/rspamd/override.d/antivirus.conf contenant :

clamav {
    attachments_only = false;
    symbol = "CLAM_VIRUS";
    type = "clamav";
    action = "reject";
    servers = "/var/run/clamav/clamd.ctl";
}

Et relancer rspamd par : systemctl reload rspamd

SaneSecurity fournit une base virale alternative (plus complète que la base officielle), pour l’installer :

wget https://github.com/extremeshok/clamav-unofficial-sigs/archive/master.tar.gz
tar xvzf master.tar.gz
rm master.tar.gz
cd clamav-unofficial-sigs-master
cp clamav-unofficial-sigs.sh /usr/local/sbin/
mkdir /etc/clamav-unofficial-sigs
cp config/os/os.debian.conf /etc/clamav-unofficial-sigs/os.conf
cp config/{master.conf,user.conf} /etc/clamav-unofficial-sigs/

Enfin, éditer le fichier /etc/clamav-unofficial-sigs/user.conf pour activer l’option : user_configuration_complete.

En option on peut configurer automatiquement logrotate et installer les manpages :

/usr/local/sbin/clamav-unofficial-sigs.sh --install-logrotate
/usr/local/sbin/clamav-unofficial-sigs.sh --install-man

Enfin, je copie la configuration de systemd pour permettre les mises à jour et je fais une mise à jour à la main pour vérifier que tout se passe bien :

cp systemd/* /etc/systemd/system/
systemctl daemon-reload
/usr/local/sbin/clamav-unofficial-sigs.sh

Remarque : sur ma config j’ai dû créer manuellement le répertoire /var/lib/clamav-unofficial-sigs/dbs-uh (et rendre clamav.clamav propriétaire).

XVI. Bonnes pratiques pour ne pas être pris pour un spammeur

En plus de toute cette configuration, je veux que mon serveur ne soit pas vu comme un spammeur. Pour cela, il faut respecter quelques règles simples comme le SPF et le DKIM.

XVI.1. SPF

SPF pour Sender Policy Framework est un enregistrement DNS qui décrit le ou les serveurs autorisés à envoyer du mail pour un domaine.

Il n’y a rien à configurer sur le serveur pour le mettre en place, toutes les infos sont dans le DNS.

XVI.2. DKIM

DKIM pour DomainKeys Identified Mail est un mécanisme de signature numérique des mails. Il est basé sur la publication dans le DNS d’une clé cryptographique publique permettant aux clients email de vérifier une signature et sur la configuration des serveurs légitimes du domaine avec la clé privée correspondante pour signer les messages.

La signature DKIM peut être assurée par rspamd, voici comment la mettre en place. Tout d’abord, il faut installer les outils de OpenDKIM pour générer les clés :

apt-get install opendkim-tools

Pour que rspamd utilise automatiquement les clé DKIM, il suffit de les placer dans le répertoire /var/lib/rspamd/dkim donc :

mkdir /var/lib/rspamd/dkim
chown _rspamd:_rspamd /var/lib/rspamd/dkim
cd /var/lib/rspamd/dkim

Pour chaque domaine, il faut créer une clé de signature :

opendkim-genkey -d mondomaine.tld -s v1

L’option -s détermine le sélecteur DKIM, c’est une bonne idée d’avoir une info de version dans le sélecteur car cela permet de changer de clé en cas de besoin sans invalider les emails existants. Le sélecteur est une chaîne arbitraire. Pour construire mes sélecteurs, j’utilise simplement un numéro de version.

Le fichier .txt généré contient l’entrée de DNS à ajouter pour authentifier les mails signés par la clé privée (fichier .private).

Il faut maintenant activer la signature DKIM dans rspamd et lui indiquer quelle clé utiliser pour chaque domaine.

L’activation se fait en créant un fichier /etc/rspamd/local.d/dkim_signing.conf contenant :

path = "/var/lib/rspamd/dkim/$domain.$selector.key";
selector_map = "/etc/rspamd/dkim_selectors.map";

Il faut ensuite renommer le fichier de clé privée :

mv v1.private mondomaine.tld.v1.key

Et créer (ou compléter) le fichier de correspondance /etc/rspamd/dkim_selectors.map

Ce fichier contient une ligne par domaine et indique le sélecteur (et donc la clé) à utiliser :

mondomaine.tld    v1

Remarque : seul l’utilisateur _rspamd doit pouivoir lire les fichiers du répertoire dkim, donc :

chown _rspamd /var/lib/rspamd/dkim/*
chmod u=r,go= /var/lib/rspamd/dkim/*

XVI.3. ARC

ARC pour Authenticated Received Chain est un mécanisme d’authentification des emails qui permet à un serveur intermédiaire (comme un serveur de mailing liste) de retransmettre des messages signés par DKIM sans perdre les bénéfices de ce protocole. ARC va sur-signer le message, attestant ainsi que le message initial était correctement signé.

La mise en place de ARC se fait également avec rspamd en utilisant les mêmes clés que DKIM et se configure dans le fichier /etc/rspamd/local.d/arc.conf :

path = "/var/lib/rspamd/dkim/$domain.$selector.key";
selector_map = "/etc/rspamd/arc_selectors.map";

Et on utilise le même mappage :

ln -s /etc/rspamd/dkim_selectors.conf /etc/rspamd/arc_selectors.conf