Mail sous OpenBSD

Ce wiki a été archivé en 2018.

Le nouveau wiki se trouve à: ressources.labomedia.org

Les fonctionnalités sont désactivées: vous pouvez faire une recherche sur Google site:https://wiki.labomedia.org et découvrir La Labomedia.

De Centre de Ressources Numériques - Labomedia
Aller à : navigation, rechercher

Mise en Place d'un Serveur d'E-Mail

Un serveur d'email est une machine qui réalise la tache de recevoir et d'envoyer des emails pour un nom de domaine. Par exemple, recevoir le courrier électronique envoyé à @labomedia.org et envoyé les courriers sous le nom de @labomedia.org.

Pour pouvoir envoyer des messages, le serveur doit pouvoir contacter d'autre serveur email pour relayer le message. Si on veux pouvoir utiliser un client de messagerie, notre serveur doit à son tour être un relais. Ces échanges sont réalisé avec le protocole smtp.

La réception des messages suit le chemin inverse. Notre serveur est alors le relais en bout de chaîne. Pour que les autres relais sachent où trouver notre serveur, il faut renseigner un champ MX dans le DNS de notre nom de domaine. Une fois le courrier arrivé sur notre machine, il est souvent utile de pouvoir les lire. Pour cela, l'idéal est que notre serveur parle le protocole imap pour pouvoir consulter les messages avec un logiciel comme thunderbird. Alternativement, un site web permettant de remplir cette tache est souvent un gros plus pour l'usabilité de votre service.

Pour résumé, notre serveur dois pouvoir écouter avec le protocole smtp, pouvoir discuter avec d'autres serveur sur ce même protocole, écouter avec le protocole imap et idéalement proposer une interface web pour lire et écrire des messages.

Choix Techniques

Naturellement, cette page de wiki va se concentrer sur une solution pour chacun de éléments du problème. Comme le titre de la page l'indique, je vais utiliser uniquement des composants disponible sous OpenBSD, mais à ma connaissance, ils sont tous disponible aussi sous linux.

Le plus gros morceau, celui qui s'occupera des communications smtp, sera gérer par opensmtpd. L'alternative la plus fréquente sous linux est postfix mais il ne viens pas dans l'installation de base d'OpenBSD et le fichier de configuration est beaucoup plus long.

Dovecot remplira le rôle de serveur imap. Si on veux pouvoir lire nos email avec le protocol pop, c'est aussi dovecot qu'il faudra configurer mais on n'en parleras pas ici. Pour le client web, on présenteras roundcube.

DNS & SSL

Avant de configurer un logiciel, on va s'occuper des prérequis. Comme dit précédemment, si on veux recevoir des mails, il faut qu'un serveur DNS indique où se trouve notre machine. Normalement, les fournisseurs de nom de domaine proposent une interface pour faire ça. Pour tout ce que l'on veut faire, il faut au moins un champ MX et un champ A qui pointe sur le serveur. Si le nom de domaine ne sert pas uniquement pour du mail, il peut être utile de mettre en place un sous-domaine pour le service de webmail. Dans le cas où tout est hébergé sur la même machine, un champ CNAME fera parfaitement l'affaire. Si vous êtes chez gandi, pour le nom de domaine pokematos.com, le résultat devrait ressembler à cela:

DNS Email.png

Les champ A www et CNAME cal ne nous intéresse pas. Le champ MX va indiquer au reste du monde que si on cherche à communiquer avec @pokematos.com, il faut utiliser le serveur répondant à pokematos.com. Ça tombe bien, c'est celui qui est renseigné dans le champ A @, le premier de la liste. Et pour le sous-domaine mail.pokematos.com, même procédé, on indique une redirection avec un champ de type CNAME. Dans la barre d'url, mail.pokematos.com sera affiché mais derrière, ça sera l'ip de pokematos.com. Comme ça, si l'ip du serveur change, il n'y a qu'un seul champ à modifié.

On pourrait s'arrêter là mais il va nous manquer quelque chose pour la suite. Les emails ont un sérieux problème, le spam. Par conséquent, de nombreux serveur de mail refuse d'accepter tout message qu'ils ne considèrent pas de qualité suffisante. Une façon d'avoir des emails de qualité est de chiffrer ses communications avec ssl ou tls et d'utiliser un certificat signer pour ce chiffrement. Heureusement, letsencrypt nous propose aujourd'hui d'avoir gratuitement et simplement un certificat signé.

OpenSMTPD

OpenSMTPD est le serveur de mail développé par OpenBSD. Tout comme OpenSSH, il répond au besoin d'avoir une alternative simple à des solutions existantes. C'est un projet récent, avec une première version stable vieille d'à peine deux ans alors que les deux serveurs de mails les plus utilisé, exim et postfix, sont vieux respectivement de 21 ans et 17 ans. Mais contrairement à ces deux ancêtres, OpenSMTPD peut être configuré en 4 lignes, ce qui est le cas par défaut dans toutes les installations d'OpenBSD.

La syntaxe prend une instruction par ligne. Le premier mot clé indique quel est l'instruction. La ligne est parfois continué par une variable, suivit de mot clé et d'argument. Par exemple, max-message-size est suivit par la taille maximal d'un message alors que limit est suivi d'abord par le système auquel on applique une limites puis des mot clé avec argument précisant le type de limite.

Certificats

OpenSMTPD va chiffrer ses communication à chaque fois que possible. Pour faire les choses proprement, il faut pour utiliser le certificat au nom de notre serveur que l'on générer un peu plus tôt. Pour ce faire, on va utiliser l'instruction pki. Le premier argument est le nom que l'on va associer au certificat, traditionnellement le nom de domaine pour lequel le certificat est valide. Ensuite, différentes propriété seront associé à ce nom à l'aide de mot clé, soit sur une seul ligne soit en plusieurs instructions. Au minimum, il faut indiquer le certificat et la clé privé avec les mot clé certificate et key. Deux autres options sont disponible, ca pour spécifié un certificat de CA et dhparams pour spécifier les paramètres pour Diffie-Hellman.

 pki hostname certificate /etc/ssl/hostname.pem
 pki hostname key /etc/ssl/private/hostname.key

Hey, Listen!

Dans la configuration fournis par défaut, une seul interface est écouté, lo0. C'est très bien pour que le système puisse nous envoyer des emails quand cron fait des bétises, mais c'est pas génial pour recevoir des messages de mémé géraldine. Ici, on va spécifier deux connexion, la première pour les mails venant du monde extérieur et la seconde pour les messages que nos utilisateurs souhaitent voir partir.

Pour écouter le monde extérieur, on utiliser l'instruction listen. Le seul mot clé obligatoire est on suivit d'une interface ou d'une adresse réseau. Le mot clé egress indique que l'on souhaite écouter sur toutes les interfaces. Viennent ensuite 5 mot clé suivant comment on souhaite traiter le chiffrement, 6 si on compte l'absence de mot clé. Ici, on a tls pour indique que l'on accepte que le client lance le chiffrement via STARTTLS et "tls-require verify", qui est un seul mot clé, qui refuse la connexion elle ne commence pas par STARTTLS. Le mot clé pki indique quel certificat on souhaite utiliser pour le chiffrement et auth indique que les clients doivent s'authentifier avec les informations contenant dans la table pour utiliser notre service. Plus d'information sur les tables juste après.

Le dernier mot clé est tag. Il permet de marquer toutes les enveloppes qui rentre par cette connexion. Le problème de cette configuration est que rien n'empêche un méchant bonhomme souhaitant utiliser notre serveur comme plateforme de distribution de spam de se connecter sur la première interface, sur le port smtp. Et on ne peut pas demander à gmail et compagnie de se connecter avec un login et mot de passe. Donc on marque les enveloppes et on refuse de transmettre vers l'extérieur les enveloppes qui sont entré par l'interface de réception.

 listen on egress port smtp tls pki hostname tag mailin
 listen on egress port submission tls-require verify pki hostname auth <table> tag mailout

Tables

Souvent, une valeur dans la configuration peut être un ensemble de valeur. Par exemple, la liste des informations d'authentification ou les domaines que notre serveur accepte de recevoir. Dans ces cas là, OpenSMTPD utilise des tables, qui peuvent être des listes, par exemple pour des adresses réseaux ou des domaines, ou bien des associations comme pour les utilisateurs avec des couples nom d'utilisateur et mot de passe.

La forme la plus simple est de rentrer les valeur dans le fichier de configuration, directement dans la directive table. Les éléments sont séparé par des virgules, les couple clé/valeur sont séparé par des signes =. C'est ce qu'il y a de plus rapide à faire, les données sont accessible directement dans le fichier de configuration et on peut facilement migrer vers les autres formes.

 # forme 1
 table domains { labomedia.org, radio-campus.org }
 table users { alice = $2b$08$1f4SvI3pbJcJG60M/PHoEOAzCt/ZSVUaSK9lvm7EMwCCoUM1DGUO2 }

La seconde forme consiste à utiliser un fichier, à raison d'une valeur par ligne. Les associations sépare les clé des valeurs avec des espaces ou tabulations. Cela reste une solution simple à mettre en oeuvre tout en évitant de trop faire grandir votre fichier de configuration principal.

 # form 2
 table domains file:/etc/mail/domains
 # /etc/mail/domains
 labomedia.org
 radio-campus.org

La troisième forme prend ses valeurs de la même façon, dans un fichier externe à raison d'une valeur par ligne. Il faut ensuite utiliser l'utilitaire makemap pour créer une version base de donnée du fichier. Ce nouveau fichier se présenteras sous la forme d'un fichier avec l'extension .db à coté. Dans le cas de fichier avec de nombreuses valeurs, on gagne du temps au prix d'une transformation supplémentaire.

 # form 3
 table users db:/etc/mail/users.db
 # /etc/mail/users
 alice    $2b$08$1f4SvI3pbJcJG60M/PHoEOAzCt/ZSVUaSK9lvm7EMwCCoUM1DGUO2

La dernière forme consiste à utiliser une base de donnée sqlite. Il faut alors renseigner un fichier contenant au moins deux directives, dbpath qui indique où se trouve le fichier contenant la base de donnée et une directives pour chaque type de requête que la table supporte, avec la requête en argument. Cette forme semble manquer de documentation mais permet de partager une table avec, par exemple, une installation de dovecot.

 # form 4
 table hostname sqlite:/etc/mail/hostname.conf  
 # /etc/mail/hostname.conf
 dbpath    /var/mail/hostname.db
 query_userinfo    SELECT uid, gid, home FROM users WHERE username = ?;
 query_domain    SELECT domain FROM users where domain = ? LIMIT 1;

Triage

Maintenant que notre serveur écoute le monde extérieur, qu'il sait où sont les certificats et qu'il connait ses tables sur le bout des doigts, il est temps de lui apprendre le bien du mal. Ou plus modestement lui expliquer quel email il va accepter et quel email il va refuser.

Pour cela, on va utiliser une série d'instruction de type accept ou reject. Chacune de ses instructions sera accompagné d'une série de mot clé détaillant la règle. Les mot clés tagged, from, senders, for et recipient sont utiliser préciser quel enveloppe seront affecté. Respectivement, ils filtre sur les tag définit lors des instructions listen, de la source de ma connexion, de l'expéditeur de l'email, du domaine du destinataire et finalement du destinaire.

Ensuite, un dernier mot clé indique que faire du mail. Soit deliver pour indique que le mail va être stocké sur la machine, qui peut être couplé avec userbase pour des utilisateurs virtuel, soit relay pour envoyer l'enveloppe sur un autre serveur de mail.

 accept for local alias <aliases> deliver to mbox
 accept from local for any relay

Si dessus sont les deux règles présentes par défaut sur un système OpenBSD pour le triage. Elle assure le routage des emails locaux, tel que celui envoyé lors de l'installation du système.

La première règle assure la réception des emails à destination de la machine, soit via localhost soit via le nom par défaut. Le manuel de smtpd.conf donne plus de détail à ce sujet. L'argument from n'est pas précisé et sa valeur par défaut est "from local". Seul les connexions local seront donc accepté. Les enveloppes seront délivré dans le fichier mbox pour l'utilisateur correspondant à l'adresse de l'email, après résolution des alias. Les alias par défaut consiste à rediriger la plupart des adresses connu vers root et d'ignorer les utilisateurs qui sont des daemons.

La seconde règle indique simplement que l'on cherche à relayer tout le courrier qui viens de la machine vers l'extérieur. Notre serveur fera de son mieux pour trouver le serveur smtp de l'adresse de destination et lui transmettre l'enveloppe.

 accept from any for domain <domains> userbase <hostname> deliver to maildir
 accept from any tagged mailout sender { @labomedia.org, @radio-campus.org } for any relay

Ici nous avons des règles un peu plus complexe, qui devraient suffire pour un serveur de mail publique. Attention comme toujours à bien adapté les exemples à votre situation et de vérifier que la syntaxe de configuration est toujours correcte.

La première règle met en place des compte virtuel pour un ensemble de domaine définit par une table. Si on utilise les tables donnés en exemple un peu plus haut, <domains> correspond aux valeurs contenu dans un fichier et <hostname> prend ses valeurs dans une base de donnée sqlite. Au niveau du triage, on accepte tout le courrier entrant à conditions que le domaine de destination soit connu. L'idée est de bien générer un message de bounce pour signifier à l'expéditeur que son message s'est perdu. Pour la réception, userbase prend une table de type Userinfo qui associe un utilisateur à un triplet UID, GID et dossier personnel. UID et GID doivent correspondre à un numéro d'utilisateur et de groupe existant sur le système, qui peuvent être commun pour l'ensemble des utilisateurs virtuels. Le dossier personnel quand à lui va servir à stocker les messages, il est donc préférable qu'il soit unique. Dans le cas d'une table dans l'une des trois premières, le triplet se donne sous la forme d'une chaîne de caractères avec les champs séparé par des signes deux points, par exemple `alice 1000:10:/home/alice`. Les messages seront stocké dans un dossier maildir, dans ce dossier personnel.

La seconde règle s'occupe des messages sortant. Elle restreint les possibilités d'envoie de messages deux deux façon. D'abord, seul les messages avec la marque mailout sont autorisé à être transmis. Ça force les utilisateurs à passer par l'interface smtp avec authentification et limite le risque de se voir transformer en plateforme tournante pour le spam. L'autre limite est au niveau des adresses email d'expédition autorisé. Le but est là aussi de limiter le spam, dans le cas où un de nos utilisateurs aurait sa machine infecté par un super virus capable d'utiliser sa connexion smtp à notre machine. Au moins, les seuls spam qu'on enverra seront à notre nom. Au niveau du traitement, une fois le triage réalisé, on se contente de transmettre le message. Comme avec la règle par défaut, c'est OpenSMTPD qui s'occupe de trouver à qui transmettre le message.

Dovecot

Nos emails sont stocké maintenant stocké sur le serveur. Pour les lire, il nous faut avoir accès au fichiers où ils sont stocké et d'un programme capable de les lires, nommé un MTA ou un acronyme similaire dont j'ai oublié la signification. Si on avait un accès à la machine, ce programme pourrait être thunderbird ou mutt. Mais ce n'est pas vraiment notre cas ici. On va donc utiliser un programme qui sait lire un fichier mbox et qui sait parler imap. Ainsi, on pourra utiliser thunderbird qui ira demander au serveur nos emails. Sur le serveur, c'est ce programme qui va répondre aux demande de notre MUA.

Dovecot est un programme qui peut remplir ce boulot. Il sait lire les mails dans un fichier mbox ou un dossier maildir et il sait parler les protocoles imap et pop3. Il faut cependant le configurer. Tout les fichiers de configurations sont dans /etc/dovecot, le principal est dovecont.conf qui va inclure tout les fichiers .conf dans conf.d.

Utilisateurs

Les utilisateurs servent deux objectifs pour dovecot. Assurer l'authentification pour ne pas distribuer le courrier à tout le monde et obtenir les informations sur où est le courrier et comment y accéder.

Leur informations de configuration sont éparpillé sur plusieurs fichiers. Le point d'entré est conf.d/10-auth.conf, avec la plupart des options concernant l'authentification des utilisateurs. Il y a deux points intéressant. L'option auth_failure_delay est un compromis entre le confort d'utilisation et les robots qui essai toutes les combinaisons de mot de passe. À la fin du fichier, il faut inclure un fichier qui va renseigner comment sont stocké les utilisateurs. On va se concentrer sur sqlite, donc ça sera auth-sql.conf.ext.

 # userdb statique
 userdb {
   driver = static
   args = uid=vmail gid=vmail home=/var/vmail/%u
 }

Ce nouveau fichier va renseigner deux tables, passdb et userdb. Elles vont respectivement donner les informations d'authentification et les informations pour lire les messages. Cela implique deux faire deux requêtes SQL. Il y a deux solutions si l'on souhaite éviter cela. La première, dans le cas d'utilisateur virtuel, est de préciser une table statique pour userdb, comme dans l'exemple au dessus. La seconde consiste à retourner les valeurs pour les deux requêtes dans passdb et de renseigner prefetch comme driver pour userdb. La suite de cette explication va se baser sur cette hypothèse. Du coté de passdb, il faut spécifier sql comme driver et le chemin vers le fichier contenant la configuration pour sql, à savoir /etc/dovecot/dovecot-sql.conf.ext.

Ce dernier fichier va contenir les informations de connexions. Dans notre cas, on va utiliser sqlite comme driver, un chemin vers le fichier contenant la base de donnée et BLF-CRYPT comme schéma de stockage pour les mot de passe. Il faut ensuite spécifier l'option password_query, qui est chargé de récupérer le mot de passe stocké dans la base de donnée. Comme on a utilisé prefetch pour récupérer les donnés des utilisateurs, il faut aussi récupérer ces données dans cette requête. Au total, cela fait 6 champs à récupérer. Pour passdb, les colonnes username, domain et password doivent être récupéré. Pour userdb, ce sont les colonnes userdb_uid, userdb_gid et userdb_home. Il n'est cependant pas nécessaire que la table SQL possède des colonnes avec ces noms là. Il n'est même pas nécessaire que les données existent dans la table. Cette requête correspond à la demande:

 password_query = \
   SELECT username, domain, password, \
     uid as userdb_uid, 5000 as userdb_gid, "/var/vmail/%d/%n" AS userdb_home \
   FROM users WHERE username = '%n' AND domain = '%d'

Les deux exemples de configuration utilisent des marqueurs de la forme %x. Ces marqueurs sont utilisés par dovecot qui va les remplacer par des valeurs plus approprié. %u sera remplacé par le nom d'utilisateur, autrement dit tout ce qui se trouve à gauche du signe @ dans l'email. %d sera remplacé par le domaine, tout ce qui est à droite. Pour finir, %u est l'adresse email en entier.

IMAP

La première chose à faire est de renseigner les protocoles que l'on souhaite utiliser. Pour cela, on renseigne l'option protocols dans dovecot.conf. Elle prend une liste de valeur séparé par des espaces. Les valeurs qui nous intéressent sont imap et imaps. La première utiliser le port standard avec un passage à une connexion chiffrée via STARTTLS alors que la seconde chiffre immédiatement la connexion. Les options de chiffrements sont dans le fichier conf.d/10-ssl.conf. La plus importante se nomme simplement ssl et prend trois valeurs, no pour désactivé, yes laisse le choix à l'utilisateur et required impose l'usage du chiffrement. Dans le cas du protocole imap, dovecot refuseras de connecter un client avant qu'il utiliser STARTTLS. Les deux premières valeurs interagissent avec disable_plaintext_auth du fichier 10-auth.conf. Dans sa valeur par défaut, yes, dovecot refuseras que l'utilisateur se connecte en envoyant son mot de passe si la connexion n'est pas chiffré. Les autres options concernant le chiffrement qui nous intéresse sont ssl_cert et ssl_key et éventuellement ssl_key_password. Ces options ne prennent pas de chemin vers des fichiers mais bien l'intégralité d'un certificat, sa clé privé et le mot de passe de la clé. Cependant, si une valeur est préfixé par le symbole <, dovecot utilisera la valeur du fichier à l'emplacement spécifié par la valeur. Il n'est pas nécessaire de donner des droits particuliers à ces fichiers, simplement le droit de lecture pour l'utilisateur root.

Si l'on souhaite changer les options spécifique à imap, il faut se tourner vers le fichier conf.d/20-imap.conf et modifier dans le bloc protocol imap { ... }. L'option la plus intéressante est mail_plugins qui permet de définir des comportements supplémentaire, comme par exemple la suppression automatique des messages après un certain nombre de jour. Pour changer le port, il faut modifier le fichier conf.d/10-master.conf. Dans le bloc service imap-login, chaque bloc inet_listener définit comment dovecot va écouter les connexion imap et imaps.

Il ne reste plus qu'a définir les différentes boites disponibles pour l'adresse mail. Pour cela, direction conf.d/15-mailboxes.conf. Chaque boite de réception est définit sous la forme d'un bloc mailbox dans un bloc namespace. Une option "auto = subscribe" dans le bloc va forcer la création d'un dossier correspondant et l'option special_use permet de marquer des boites avec des fonctionnalités prédéfinie. Les plus importantes sont \Drafts, \Junk, \Trash et \Sent.

Roundcube