Aller au contenu | Aller au menu | Aller à la recherche

Un annuaire pour les gouverner tous.......

Aujourd'hui, on va mettre en place un annuaire LDAP, un FusionDirectory en façade pour administrer le contenu du LDAP via une jolie interface Web, on va connecter un serveur mail (SMTP+IMAP+POP), une machine cliente réseau (via PAM) et quelques autres trucs, et on va coller du SSL partout.

Disclaimer, ou pas....

Il y a très très longtemps, dans une galaxie très lointaine, j'aurais commencé ce billet par un gros disclaimer.
Ce disclaimer aurait rappelé que tout est fait par un Vieux Con de Hacker Old School, j'aurais même précisé (tm) pour faire style.

J'aurais rassuré ma sœur sur le fait que ce billet est généreusement saupoudré de liens sur tous les trucs vaguement techniques, et que c'est des liens Wikipedia de préférence, en français si possible, pour avoir des explications simples.

Ensuite, j'aurais probablement fait une nouvelle pseudo liste de trucs qui pourraient arriver si vous tentiez d'appliquer les explications et extraits de configurations (j'aurais probablement même précisé extraits naturels, c'est encore à la mode), mais qui, soyons honnêtes, n'auraient eu que très très très très peu de chances d'arriver, à tel point que j'aurais pu rajouter gagner 2 fois de suite au loto sans même avoir joué dans la liste, sans que les probabilités ne changent grandement.
En réalité, si vous appliquez correctement ces explications sur votre système (c'est à dire matin et soir, en suivant la posologie), l'entropie générée restera probablement très modeste, quoique non nulle. Notez cependant que, si vous appliquez mal les explications, si des trucs ont changé entre temps dans la configuration des logiciels concernés ou si toute autre raison vient à générer un problème, tant pis pour vous.

J'aurais éventuellement détourné des consignes de sécurité d'un truc...... mais j'aurais essayé d'être un minimum original, donc j'aurais dû trouver des consignes de sécurité que je n'ai pas déjà détournées, ce qui m'aurait pris du temps, sans aucune certitude de trouver un truc qui soit utilisable !

J'aurais probablement évité la liste des conditions de sécurité optimales, ayant déjà fait la reprise de la blague de Naheulbeuk avec la liste de courses (ce qui reste le principal intérêt de faire la liste des conditions de sécurité optimales).

Tout ceci aurait pris du temps, lequel temps aurait été définitivement perdu d'après le second principe de la thermodynamique (ou peut être à cause de la dilatation du temps ??). En plus, ça aurait aussi inévitablement augmenté l'entropie globale du système, ce que nous souhaitons tant qu'à faire éviter, comme expliqué au dessus.

Du coup, grande nouveauté dans ce billet technique, il n'y aura donc pas de disclaimer, et nous allons de suite passer au contenu technique susmentionné, sans fioritures ni colifichet, ce qui fera gagner un temps précieux à tout le monde !

Ah, et j'aurais aussi précisé que tout ceci a été réalisé sans qu'aucun animal mignon n'ait été blessé, tué ou mangé, c'est important !

Prérequis techniques

Pour me faire gagner du temps à moi, toutes les instructions supposent que vous les effectuez sur des serveurs Debian (version Stretch au moment de l'écriture de ce billet), et que vous êtes root.

Des serveurs, dans mon cas, puisque pas mal de choses sont réparties sur différentes machines (virtuelles, si vous avez suivi les épisodes précédents), ce qui est plus propre mais pas indispensable. Vous ne verrez donc à peu près jamais de "localhost" ou de "127.0.0.1" (en vrai, il y en a un peu quand même, pour des trucs où ca serait vraiment vraiment bourrin de faire une machine dédiée, mais si vous déployez vos services sur un cluster de raspberry pi, faites vous plaisir !), mais des noms de machines comme "mail" (pour le mail), "ldap" (pour le ldap).... c'est bon, vous avez saisi le principe ? Bien sur, si vous avez un autre découpage, adaptez vous !

Ah, tout ce qui suit part également du principe que vous savez au moins vaguement ce que vous faites, que vous savez comment créer un répertoire, éditer un fichier, que vous saurez prendre de petites initiatives personnelles sur les détails évidents (comme créer des répertoires, par exemple, ou au contraire repérer un changement de répertoire suite à une nouvelle version d'un outil, etc....), bref, que vous avez les notions élémentaires d'administration d'un système Linux en général, et si possible Debian en particulier.

LDAP

Donc, le sujet du jour, c'est un annuaire. Précision importante pour ma sœur: oui, il y a déjà les pages jaunes qui existent, mais là, il n'est pas question de trouver un serrurier à 4h du matin, mais tout simplement de centraliser les informations des utilisateurs du réseau (nom, login, mot de passe et potentiellement d'autres trucs). Nous allons donc utiliser un Annuaire LDAP, et ça tombe bien: il a été conçu pour faire ce boulot !

Point important à garder à l'esprit: LDAP est un protocole, donc, qui explique très bien comment on se connecte, comment on fait des requêtes, etc..... mais qui ne formalise pas beaucoup le contenu. Pour être plus précis, il formalise clairement que le contenu doit respecter les contraintes définies dans des schémas, mais ne fournit que très peu de schémas, pour les cas très simples. Du coup, autant la gestion des groupes d'utilisateurs est par exemple tout à fait normalisée (2 fois, même ..... ok, c'était peut être pas le bon exemple), autant d'autres cas d'usage sont très dépendants des schémas que vous aurez créés ou récupérés.

Mais ..... pourquoi ????

On me demande parfois (pour être exact, pratiquement jamais, sauf quand on apprend que j'ai un LDAP chez moi, et à ce moment là pratiquement tout le temps, en tout cas quand les gens savent ne serait-ce que vaguement ce qu'est un "LDAP". Sinon, en général, on me fait un sourire gêné et on tente plus ou moins subtilement de changer de sujet de discussion) pourquoi j'ai chez moi un LDAP pour moi, ma copine et mon chat (et encore, le chat n'a pas de compte sur mon LDAP). Ma première réponse est souvent "parce que je peux", mais il y en a d'autres, comme "il n'y avait rien d'intéressant à la télé ce soir là".

En réalité, un annuaire LDAP devient (au moins vaguement) pertinent dès que vous commencez à administrer plusieurs ordinateurs (postes de travail, serveurs, etc...) qui vont fournir des services aux mêmes utilisateurs réels: vous pouvez alors regrouper les informations des utilisateurs en question dans le LDAP, et il suffit d'ajouter, modifier ou supprimer dans ce LDAP pour que tous les ordinateurs qui l'utilisent soient au courant. L'exemple le plus flagrant est la centralisation des mots de passe: un utilisateur dispose alors d'un mot de passe unique, utilisable partout sur le réseau, et qui peut être changé à volonté uniquement en changeant le mot de passe du compte LDAP.

Partons donc du principe que nous sommes dans un cas vaguement pertinent (où qu'il n'y a vraiment rien à la télé ce soir, et que votre compte netflix est suspendu à cause du coloc qui a oublié de renouveler l'abonnement), et commençons par la base: l'annuaire lui même !

389

En commençant mes recherches pour une solution complètement gérée par LDAP, j'ai découvert l'existence de 389, une autre implémentation serveur du protocole LDAP (dont le nom fait référence au port réseau par défaut du protocole LDAP, qui est ....... nan, je vous laisse deviner......). La doc semble assez bien faite, plusieurs trucs autour sont proposés, il y a des paquets debian dans les repository de base, bref, j'ai cru quelques instants avoir trouvé une alternative.... et puis j'ai vu les dépendances des paquets en question, avant de découvrir que 389 est implémenté en Java.... c'est peut être un détail pour vous, mais pour moi, ça veut dire beaucoup !

Microsoft Active Directory

Non, là, c'était juste pour déconner ........
Enfin, techniquement parlant, Active Directory (AD pour les intimes ...... je continuerai donc à l'appeler "Active Directory") est vraiment l'implémentation LDAP de Microsoft, mais ......euh...... il n'y avait pas de paquet Debian disponible au moment où j'ai déployé mes nouveaux serveurs, voilà, c'est ça !!!

OpenLDAP

Bref, je suis finalement resté avec un très classique OpenLDAP, qui a quand même évolué depuis les dernières fois qu'on avait fait des trucs ensemble.....
Coté installation, pas de grosses surprises: j'installe d'un bloc le serveur et les outils en ligne de commande pour manipuler:

root@ldap:~ $ apt install slapd ldap-utils

On me demande le mot de passe du compte admin, et l'installation me crée automatiquement une base LDAP, je suppose à partir du domaine de la machine. Un petit dpkg-reconfigure slapd me confirmera que les déductions étaient plutôt pertinentes dans mon cas, même si j'ai changé 2-3 trucs pour le principe.....

LDAPS

Dans le bon vieux temps, j'aurais été éditer /etc/ldap/slapd.conf, ou un truc qui ressemble, pour aller basculer mon serveur LDAP en SSL (et aussi pour changer plein d'autres trucs dans la configuration, en fait). Mais comme je l'ai dit un peu au dessus (et vous pourriez être attentifs, je déteste avoir à me répéter !!), OpenLDAP a évolué depuis le temps, et Slapd en particulier vit sa vie en quasi autarcie, via un truc qu'ils appellent OLC et qu'ils expliquent ici pour les plus curieux.
Bref, il va falloir se mettre à l'ère moderne, et aller configurer Slapd en ligne, via un dif LDAP.

Je pars du principe que vous disposez déjà de votre certificat serveur (comme c'est normalement à usage purement interne, il peut être autosigné, ou dépendre d'une CA privée), qui référence le bon FQDN (genre ldap.mondomaine.com), et qui est réparti ainsi: ldap.cert.pem, ldap.key.pem et ca.pem. Ces 3 fichiers sont stockés dans un endroit de votre disque dur accessible à l'utilisateur openldap, et en particulier le fichier key appartient à cet utilisateur, et a les droits d'accès 0400 (m'est avis que 0600 fonctionne aussi).

Nous allons donc préparer la configuration dans le fichier ldaps.dif suivant:

dn: cn=config
add: olcTLSCACertificateFile
olcTLSCACertificateFile: /chemin/vers/CA.pem

dn: cn=config
add: olcTLSCertificateFile
olcTLSCertificateFile: /chemin/vers/ldap.crt.pem
-
add: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /chemin/vers/ldap.key.pem

dn: cn=config
add: olcTLSVerifyClient
olcTLSVerifyClient: never

Notez bien la petite subtilité au milieu: le - permet d'ajouter 2 entrées en une seule opération. Certains tutoriels sur le net font 4 ajouts distincts, mais mon serveur refusait avec une erreur ldap_modify: Other (e.g., implementation specific) error (80), et ce message dans les logs: TLS: only one of certfile and keyfile specified. Et c'est pas mon genre de forcer les gens programmes sans leur consentement ! Avec le bon ldif, et en ayant respecté les consignes au dessus, tout fonctionne correctement:

root@ldap: $ ldapmodify -Y EXTERNAL -H ldapi:/// -f ldaps.dif

Il ne reste plus qu'à aller éditer /etc/default/slapd en mettant à jour la variable SLAPD_SERVICES:

SLAPD_SERVICES="ldaps:/// ldapi:///"

On a viré l'accès en clair (ldap://), même s'il est possible de faire du StartTLS dessus: je n'ai pas trouvé en 10 secondes de moyen pour obliger le StartTLS en question...... A vous de voir si vous laissez l'accès via socket (ldapi:///).
Un petit service slapd restart plus tard, le serveur n'écoute plus sur le port 389, mais désormais seulement sur le port 636.

Coté clients (c'est à dire toute machine qui va faire à l'occasion des requêtes sur notre serveur LDAP, donc entre autres une partie des autres serveurs dont nous allons nous occuper dans la suite de ce billet), il faut aussi expliquer un peu ce qui se passe. Nous allons déjà poser le fichier ca.pem à un endroit bien accessible (/etc/ssl/certs m'a semblé approprié), et nous assurer qu'il dispose d'accès en lecture pour tout le monde (genre 0644).

Ensuite, nous allons configurer /etc/ldap/ldap.conf:

BASE    dc=mondn,dc=com
URI     ldaps://ldap.mondomaine.com:636

TLS_CACERT      /etc/ssl/certs/ca.pem

Evidemment, vous adapterez les valeurs..... Notez qu'il est important que ldap.mondomaine.com soit le FQDN dans le certificat du serveur (ou alors allez chercher sur le net comment on désactive cette vérification). Et du coup, il est aussi important que votre machine résolve ldap.mondomaine.com vers la bonne IP (via une entrée DNS propre tant qu'à faire, sinon une entrée manuelle dans /etc/hosts, c'est crado, vite fait, pas du tout pratique à maintenir sur un parc important de machines, mais ça fonctionne également), sinon tout va fonctionner nettement moins bien.......
Il y a pas mal d'autres choses configurables dans ce fichier, mais c'est hors propos ici.

Certains clients ou services n'utiliseront pas directement ce fichier de configuration, mais leurs propres paramètres, stockés ailleurs. Dans certains cas, il sera plus pratique d'avoir le certificat de la CA retrouvé automagiquement par SSL lors de la vérification, ce qui est faisable avec la manipulation suivante sur la machine en question:

root@client:~ $ cd /etc/ssl/certs
root@client:/etc/ssl/certs $ ln -s MaCA.pem `openssl x509 -noout -hash -in MaCA.pem`.0

Nous pouvons vérifier que tout fonctionne:

user@client:~ $ ldapsearch -x 
[dump de tout ce qui est lisible sans authentification dans l'annuaire]

Mais... on peut tout lire sans s'authentifier ?

Oui. Enfin, presque, on ne peut pas voir les mots de passe, par exemple, et encore heureux ! Avec les configurations par défaut qui vont être posées d'ici quelques paragraphes, ce n'est pas dramatique, l'essentiel est déjà protégé: un utilisateur ne peut pas changer le mot de passe d'un autre, ne peut pas éditer sa propre fiche LDAP (à part le mot de passe, donc), etc....

Si on veut aller un peu plus loin, on peut tout à fait renforcer les ACLs de slapd. Attention, la suite du billet part cependant du principe que la plupart des informations restent lisibles sans authentification: on évite la création de plusieurs comptes internes avec des droits partiels, et on gagne un peu de réactivité quand un service voudra faire une requête LDAP.

Si vous préférez faire des ACLs qui imposent de s'authentifier pour la moindre lecture, normalement, tous les services permettent cette configuration. Et si pour une raison étrange votre LDAP est joignable depuis le monde entier, blinder vos ACLs devient d'un coup une très très bonne idée !
Dans mon cas, il n'y a qu'une poignée de machines qui peuvent faire des requêtes sur le LDAP, et toutes ces machines sont sous mon seul contrôle (enfin, sauf si un chinois russe de la NSA réussit à en hacker une, bien sur), donc le besoin d'ACLs hyper restrictives n'est pas flagrant.

Réplication LDAP

Si on étudie quand même sérieusement 2 minutes les risques de sécurité, on réalise rapidement que l'annuaire LDAP est vraiment devenu un point critique (ou alors on change de métier. Sauf bien sur si notre métier est "boucher/charcutier", "Responsable RH" ou "Infirmière anesthésiste", par exemple, qu'on lit ce billet un peu en dilettante, et qu'on a étudié sérieusement 2 minutes les risques de sécurité comme ça, juste après avoir lu le début de ma phrase, sans avoir pour autant de suite réalisé que l'annuaire LDAP est vraiment devenu un point critique d'un point de vue sécurité. Dans ce cas, on peut quand même changer de métier, si on étudie sérieusement et depuis bien plus longtemps que 2 minutes l'idée d'une reconversion professionnelle, mais là on est vraiment dans le cas d'une coïncidence extraordinaire qui ne fait pas partie du propos de ce billet... ): quelqu'un qui réussit à avoir accès à ce serveur (le LDAP, suivez, un peu !) peut facilement se créer des droits pour accéder à d'autres trucs. Du coup, on pourrait vouloir protéger un peu ce serveur, en particulier par rapport à certains services qui vont être déployés dans la suite du billet et qui sont publiquement accessibles (donc potentiellement plus facilement attaquables).
Ma première idée pour augmenter le niveau de protection de mon LDAP a été de mettre en place de la réplication de serveur LDAP.

En vrai, il existe plein de raisons qui peuvent justifier la mise en place de réplication:

  • répartition de charge...... dans mon cas, on pourrait presque commencer à deviner un début d'embryon de mauvaise foi......
  • copie du LDAP sur des sites distants. Un serveur dédié qui a un intérêt à avoir accès à au moins une partie des données (pour un MX backup qui filtre un peu, par exemple), on commence presque à avoir un début de vraie raison.....
  • haute disponibilité..... là aussi, chez moi, ce n'est pas tout à fait indispensable, même si ce n'est pas forcément aussi superflu que ça peut en avoir l'air: pendant un éventuel reboot du serveur LDAP, aucun service n'est utilisable.

Bref, dans mon cas, il n'y avait que l'aspect protection du "master" (oui, comme dans d'autres trucs en informatique, le vocabulaire lié à la réplication LDAP est très BDSM......) qui pouvait sérieusement justifier la mise en place de réplication. Et là, horreur: la technique classique de réplication LDAP part du principe que c'est les "slaves" qui viennent se connecter au master pour avoir les infos à jour. Et même s'ils le vouvoient, l'appellent "Maître" et suivent tous ses ordres, d'un point de vue isolation réseau, c'est con.......

En creusant un peu, j'ai quand même trouvé une autre approche plus conforme à mon objectif: les serveurs LDAP esclaves sont dans des catsuit bien fermées niveau réseau, et c'est le Master qui est seul à pouvoir décider de les contacter pour les fouetter leur envoyer les mises à jour du contenu de la base LDAP.
Enfin, en réalité, c'est un peu plus complexe dans la mise en œuvre, du coup j'ai un peu laissé de coté pour l'instant, mais l'idée est tentante !

Ok, et on édite le contenu comment ?

Sur mon ancien serveur, j'éditais le contenu avec des fichiers dif et des appels à ldapmodify. Niveau ergonomie, c'est ....... pas magique.......

On pourrait déjà faire un peu mieux en utilisant un client LDAP graphique, mais il faut toujours connaître les bonnes classes d'objets, se souvenir des syntaxes de plein de champs qu'on va utiliser, etc.....

Nous allons donc utiliser une vraie interface, qui s'occupe de toute la partie interne LDAP pour nous, qui fournit des schémas pour pas mal de cas d'usage, et qui présente les données sous forme construite: Fusion Directory. Fusion Directory fonctionne en PHP, et est donc accessible depuis n'importe quel navigateur web (bon, ok, peut être pas vraiment n'importe quel navigateur.....). Pour vous donner une petite idée, une page d'accueil avec quelques plugins installés ressemble à ça (cliquez pour voir l'image en un peu plus grand, puis râlez sur le fait que vous devez allez cliquer sur "page précédente" pour revenir ici):

Si vous souhaitez répartir les fonctionnalités sur plusieurs serveurs, il peut tout à fait se connecter à un serveur LDAP distant.

Installation de Fusion Directory.

Sur ma Debian Stretch, Fusion Directory n'est pas du tout à jour (moi qui avais choisi Debian Stable justement pour avoir en permanence les toutes dernières versions de tous les programmes........), nous allons donc commencer par rajouter le dépôt (oui, c'est le dépot de Jessie, alors que j'ai bien dit au début du billet qu'on fait tourner Stretch, mais je n'ai pas trouvé de dépot pour Stretch, et en pratique ça fonctionne), et donc avant tout les clés du dépôt en question, mais en évitant les fichiers temporaires:

root@fusion:~ $ apt-key adv --keyserver keys.gnupg.net --recv-key 0xD744D55EACDA69FF
root@fusion:~ $ cat >/etc/apt/sources.list.d/fusion.list <<EOF
deb http://repos.fusiondirectory.org/fusiondirectory-current/debian-jessie jessie main
deb http://repos.fusiondirectory.org/fusiondirectory-extra/debian-jessie jessie main
EOF
root@fusion:~ $ apt update

Edit: Depuis, le dépot de Stretch existe, on va donc uniquement mettre dans fusion.list:

deb http://repos.fusiondirectory.org/fusiondirectory-current/debian-stretch stretch main

Il n'y a apparemment plus de dépot "extra", ce qui n'a pas l'air de poser de problèmes.

Par défaut, l'installation de Fusion Directory va aller chercher apache2, mais comme j'aime faire les choses différemment, il est donc nécessaire de satisfaire explicitement ses petits besoins:

root@fusion:~ $ apt install nginx-light php-fpm fusiondirectory fusiondirectory-schema php-mbstring
[......]
root@fusion:~ $ fusiondirectory-insert-schema

La seconde commande permet d'insérer les schéma de base de Fusion Directory dans l'annuaire LDAP. Il est donc nécessaire qu'une commande ldapmodify sans arguments particuliers exécutée en tant que root sur cette machine autorise l'écriture des schémas dans l'annuaire, ce qui est automatiquement le cas si votre LDAP tourne sur la même machine et que vous avez laissé l'accès au serveur via les sockets (ldapi:///).

Par la suite, pratiquement à chaque fois que nous installerons un plugin pour Fusion Directory, il sera également nécessaire d'installer le (voire les) plugin(s) du module:

root@fusion:~ $ apt install fusiondirectory-plugin-<schema> fusiondirectory-plugin-<schema>-schema 
root@fusion:~ $ fusiondirectory-insert-schema -i /etc/ldap/schema/fusiondirectory/<lebonfichier>.schema

Notez que, pour une raison qui m'échappe un peu, il est nécessaire de pouvoir écrire sur /etc/ldap/schema/fusiondirectory pour que cette commande fonctionne.

nginx et php-fpm

Ok, il ne nous reste plus qu'à avoir un serveur web qui utilise le truc.....

D'abord, d'après le site de FusionDirectory, il faut modifier /etc/php/7.0/fpm/php.ini:

[opcache]
opcache.enable_cli = 0
opcache.memory_consumption = 1024
opcache.max_accelerated_files = 65407
opcache.validate_timestamps = 0
opcache.revalidate_path = On
opcache.error_log = /dev/null
opcache.log_verbosity_level = 1

Ensuite, nous allons créer un fichier de configuration /etc/nginx/sites-available/fusion:

server {
       listen 443 ssl ;
       listen :::443 ssl;

       ssl_certificate         /etc/ssl/private/fusion/fusion.crt.pem ;
       ssl_certificate_key     /etc/ssl/private/fusion/fusion.key.pem ;
       ssl_protocols           TLSv1 TLSv1.1 TLSv1.2;

       root /usr/share/fusiondirectory/html;
       index index.php;

       server_name fusion.mondomaine.com fusion;

       access_log      /var/log/nginx/fusion.access.log;
       error_log       /var/log/nginx/fusion.error.log;

       # pass PHP scripts to FastCGI server
       location ~ \.php$ {
               include snippets/fastcgi-php.conf;

               # With php-fpm (or other unix sockets):
               fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
       }

       location / {
               # First attempt to serve request as file, then
               # as directory, then fall back to displaying a 404.
               try_files $uri $uri/ =404;
       }
}

server {
       listen 80;
       listen :::80;
       server_name fusion.mondomaine.com fusion;
       return 301 https://$host$request_uri;
}

On passe rapidement sur la configuration SSL, et sur la partie http qui fait un redirect sur la version https, tout ceci est assez classique pour Nginx.
La partie configuration PHP est à peine plus intéressante, et au final, le seul point qui retiendra notre attention est le fait que la racine de ce site web est dans /usr/share/fusiondirectory/html.

Il reste juste à créer un lien de ce fichier de configuration dans /etc/nginx/sites-enabled, recharger la configuration de Nginx, et tout devrait fonctionner.

Configuration initiale de FusionDirectory

Cette partie est très simple: vous vous connectez sur le serveur avec votre navigateur web préféré, vous faites la manipulation indiquée pour bien prouver que vous êtes bien l'administrateur autorisé à faire la configuration, puis vous suivez le magicien !

Il ne vous reste plus qu'à vous connecter avec le compte fd-admin fraîchement créé durant l'installation, et vous pouvez commencer à cliquer partout comme un dératé créer vos premiers utilisateurs et serveurs. Dans la suite, nous partirons du principe que vous avez créé vos utilisateurs et serveurs qui vont bien via Fusion Directory, et je ne préciserai que les champs importants pour le truc en cours de configuration.

Arborescence dans FusionDirectory

J'ai rapidement voulu trier un peu mes éléments dans une arborescence. Par exemple, je voulais un ou=mailusers,ou=people,dc=mondomaine,dc=com. Sauf que, quand j'ai créé l'arborescence mailusers en questions, je me suis retrouvé avec l'inverse: ou=people,ou=mailusers,dc=mondomaine,dc=com.

Dans la suite du billet, nous partirons du principe que tout est à plat dans ou=people,dc=mondomaine,dc=com (et pareil pour les services, mais pas dans ou⁼people, forcément....), qui peut donc servir de basedn pour les recherches.

Mais si vous souhaitez ranger, il vous sera nécessaire soit d'élargir votre basedn (non, ce n'est pas forcément aussi pervers que vous pourriez le croire) à dc=mondomaine,dc=com, soit de l'ajuster au bon ou, donc par exemple ou=people,ou=mailusers,dc=mondomaine,dc=com pour la configuration mail, et du coup mettre tous les comptes utilisateurs concernés dans ce sous-arbre.

Bonjour, c'est le facteur !

C'est le gros service niveau complexité de trucs à faire: nous allons configurer un serveur de mails digne des FAIs. Cette partie suppose que vous pouvez effectivement déclarer ce serveur en tant que MX primaire de votre domaine (et que vous savez donc ce que cette phrase veut dire, et comment le faire sans tout casser). Pour être tout à fait exact, cette partie suppose même que vous l'avez fait, soit là, maintenant, tout de suite, si votre domaine est tout neuf, soit tout à la fin juste au moment de la mise en production et après avoir bien vérifié plusieurs fois que tout fonctionne correctement si vous remplacez un autre serveur qui fait déjà ce boulot !

Ici encore, il est tout à fait possible (voire un peu recommandé si vous le pouvez) de faire tourner l'ensemble du service mail sur un serveur distinct. Il est également possible (et assez classe si vous pouvez) de découper encore plus les services sur différentes machines.

Envoyer et recevoir des mails: postfix

SMTP, c'est un peu le bureau de poste des mails: vous donnez un mail au votre (ou à celui le plus proche, souvent celui de votre fournisseur d'accès au net), et il s'occupe de l'envoyer à un autre serveur qui saura quoi en faire (éventuellement le renvoyer lui aussi à un autre serveur). Inversement, quelqu'un dans le monde donne un mail pour vous à son serveur, et à un moment, ce mail finira par être délivré à votre serveur SMTP (parce qu'il est déclaré en tant que MX primaire de votre domaine, donc).

Il serait assez facile de commencer cette partie par un troll un long débat sur le choix du serveur SMTP à utiliser, mais j'ai pris de bonnes résolutions en début de ce billet, et je vais essayer de m'y tenir. Donc, sans plus de suspens, nous utiliserons donc ici Postfix (ce que vous aviez peut être même déjà deviné en lisant le titre de cette section), qui dispose d'une extension LDAP, la vie est quand même parfois bien faite, allons installer tout ce petit monde de suite.
Coté Fusion Directory, d'abord:

root@fusion:~ $ apt install fusiondirectory-plugin-mail* fusiondirectory-plugin-postfix* fusiondirectory-plugin-alias*

Vous penserez à insérer les schémas avec fusiondirectory-insert-schema comme expliqué au dessus. Après avoir redémarré php pour que fusion repère ces nouveaux plugins, vous pourrez ajouter le service "Postfix" à un de vos serveurs, et activer la fonction "mail" pour vos utilisateurs (et configurer leur adresse mails, éventuels alias, etc.... dans l'écran en question, tant qu'à faire....). Dans les 2 cas, les paramètres sont assez explicites pour ne pas trop les détailler ici. Coté service postfix en particulier, si vous avez la curieuse sensation que certains paramètres ne seront pas utilisés, c'est tout à fait normal.

Et du coté du serveur de mail:

root@mail:~ $ apt install postfix postfix-ldap

Selon votre politique de gestion des partitions, vous souhaiterez peut être déplacer /var/spool/postfix ailleurs, et faire un lien symbolique pour éviter les complications. C'est le bon moment.....

La partie LDAP de la configuration va nécessiter plusieurs fichiers, que nous allons tous placer dans un répertoire dédié /etc/postfix/ldap qui sera créé pour l'occasion. Une partie de la configuration sera commune à tous nos fichiers, mais je n'ai malheureusement pas trouvé de syntaxe permettant d'inclure un fichier dans ces fichiers de conf (et oui, j'ai essayé !include). Voici donc une fois pour toutes la partie commune en question, que vous prendrez soin de mettre au début de chacun des fichiers suivants:

server_host     = ldaps://ldap.mondomaine.com:636
bind            = no
search_base     = ou=people,dc=mondomaine,dc=com
scope           = sub
version         = 3

Chaque fichier aura en plus son filtre de recherche et les champs utilisés en réponse:

aliases.cf:
query_filter = (&(gosaMailAlternateAddress=%s)(objectClass=gosaMailAccount)(!(gosaMailDeliveryMode=[*I*])))
result_attribute = mail
boxes.cf:
query_filter = (&(mail=%s)(objectClass=gosaMailAccount)(!(gosaMailDeliveryMode=[*I*])))
result_attribute = mail
forward.cf:
query_filter = (&(|(gosaMailAlternateAddress=%s)(mail=%s))(objectClass=gosaMailAccount)(!(gosaMailDeliveryMode=[*I*])))
result_attribute = mail,gosaMailForwardingAddress
forward-only.cf:
query_filter = (&(|(gosaMailAlternateAddress=%s)(mail=%s))(gosaMailDeliveryMode=[*I*])(objectClass=gosaMailAccount))
result_attribute = gosaMailForwardingAddress

Le forward.cf correspond à un cas assez particulier, dans lequel vous souhaitez livrer le mail en local et le transférer à une autre adresse mail.

Si vous souhaitez carrément avoir une gestion dynamique des domaines que votre postfix doit gérer (en tant que destinataire final), vous pouvez également récupérer la liste des domaines via le ldap, avec le fichier domains.cf suivant:

search_base = ou=systems,dc=zen,dc=inc

query_filter = (&(postfixMyDestinations=%s)(objectClass=fdPostfixServer))
result_attribute = postfixMyDomain

Notez le piège, le search_base est différent ! Bien sur, il vous faudra alors configurer les domaines en question via Fusion Directory.

Il ne reste plus qu'à utiliser ces fichiers de configuration dans /etc/postfix/main.cf:

# LDAP configuration
virtual_alias_maps = proxy:ldap:/etc/postfix/ldap/aliases.cf
          proxy:ldap:/etc/postfix/ldap/forward.cf
          proxy:ldap:/etc/postfix/ldap/forward-only.cf
virtual_mailbox_maps = proxy:ldap:/etc/postfix/ldap/boxes.cf
virtual_mailbox_domains = proxy:ldap:/etc/postfix/ldap/domains.cf

Le préfixe proxy: permet en gros d'optimiser un peu le nombre de connexions et de requêtes entre postfix et le LDAP.

Avant de continuer, et comme il n'est pas encore possible de vérifier que les mails sont correctement livrés, nous allons déjà nous assurer que postfix sait aller récupérer les informations dans le LDAP via nos fichiers de conf:

root@mailserver:~ $ postmap -q monemail@domaine.com ldap:/etc/postfix/ldap/boxes.cf
monemail@domaine.com
root@mailserver:~ $ postmap -q monemail-alias@domaine.com ldap:/etc/postfix/ldap/boxes.cf
root@mailserver:~ $ postmap -q monemail-alias@domaine.com ldap:/etc/postfix/ldap/aliases.cf
monemail@domaine.com
root@mailserver:~ $ postmap -q mailaforwarder@domaine.com ldap:/etc/postfix/ldap/boxes.cf
root@mailserver:~ $ postmap -q mailaforwarder@domaine.com ldap:/etc/postfix/ldap/forward-only.cf
adresseforward@autredomaine.com
root@mailserver:~ $ postmap -q domaine.com ldap:/etc/postfix/ldap/domains.cf
domaine.com

Vous voyez l'idée.....

Root et autres comptes systèmes

Avec cette configuration, absolument rien n'est délivré en local, et les seules adresses mail valides sont dans le LDAP. Du coup, vous devrez très probablement créer des comptes mails ou des alias pour des adresses comme root@domaine.com, postmaster@domaine.com, etc......

Livraison des mails via dovecot

Dans mon cas, le serveur mail est vraiment prévu pour faire ce boulot, et rien d'autre. Donc non seulement il n'est pas nécessaire d'avoir des comptes UNIX correspondant aux comptes mails, mais c'est en fait carrément préférable de ne pas en avoir du tout, et de tout stocker pour un accès IMAP. Nous allons donc livrer tous les mails à dovecot. La configuration simple se fait en ajoutant les lignes suivantes à /etc/postfix/main.cf:

virtual_transport = lmtp:unix:private/dovecot-lmtp
mailbox_transport = lmtp:unix:private/dovecot-lmtp

Cette configuration suppose que le dovecot tourne sur le même serveur, sinon il faudra remplacer le unix:private/dovecot-lmtp par un truc genre inet:imapserver:port. Ah, et a priori, mailbox_transport ne sert à rien dans ce cas très précis de configuration, vu que tous les mails sont censés être virtuels.

Sauf que, plus tard, je vais avoir besoin de retrouver dans mes mails stockés par dovecot un champ X-Original-To (ou n'importe quoi d'autre qui me permet de déterminer l'adresse éventuelle d'alias utilisée, vous verrez pourquoi un peu plus loin), et que je n'ai pas trouvé comment faire rajouter ce champ via lmtp (j'ai même trouvé plusieurs discussions qui disent assez clairement que ce n'est pas possible).

Du coup, le plan B consiste à passer par lda (que je vais aussi utiliser dans un autre cas, donc qu'il faut configurer de toutes façons), et les lignes dans main.cf deviennent:

virtual_transport = dovecot-lda
mailbox_transport = dovecot-lda
dovecot-lda_destination_recipient_limit = 1

Il faut du coup également déclarer ce qu'est dovecot-lda dans master.cf:

dovecot-lda   unix  -       n       n       -       -      pipe
  flags=DROhu user=vmail:vmail argv=/usr/lib/dovecot/deliver -f ${sender} -a ${original_recipient} -d ${user}@${nexthop}

Notez que, pour mon fameux X-Original-To (ou équivalent, donc), au début, je misais tout sur le "-a", qui semble au final ne pas faire grand chose (du coup, vous pouvez tentez sans, moi entre temps je suis en prod, donc je ne touche plus à rien !), alors qu'en fait, c'est le flag O qui, l'air de rien, fait le taf !

Les trucs pas pris en charge par cette configuration

J'ai vu ici et là sur le net des possibilités de gestions de groupes LDAP également dans la configuration postfix, qui se baseraient entre autres sur special_result_attribute. Je n'en ai pas l'usage au final, donc je n'ai pas creusé ce point.

Fusion Directory fournit la possibilité de configurer un mode de réponse automatique. Je n'ai pas creusé non plus.

On pourrait probablement rajouter un outil de gestion propre de mailing lists (sympa, etc....).

Et comme on va le voir plus tard, dans une conf vraiment idéale et super classe, on aurait 2 serveurs SMTP: 1 pour faire le boulot de MX, et l'autre qui accepterait les mails des utilisateurs locaux. Cette conf permettrait du coup d'être très laxiste sur le 2eme serveur (une fois qu'on a quand même bien vérifié que seuls les vrais utilisateurs légitimes peuvent s'en servir) et carrément psychorigide sur la configuration du MX.

La boite aux lettres: Dovecot

Pour vous courriers entrants, dans notre configuration, le boulot de Postfix consiste en gros à les filer au concierge de l'immeuble. C'est ce concierge qui va mettre vos mails dans votre boite aux lettres...... un truc dans le genre, quoi...... Et donc, notre concierge, comme vous l'aurez déjà un peu compris au dessus si vous avez suivi, c'est Dovecot. Là aussi, il y avait d'autres solutions possibles, et je ne vais pas épiloguer des heures sur les raisons de mon choix.

Du coté de Fusion Directory, il existe un plugin fusiondirectory-plugin-dovecot (et sa version schema). Il fait probablement des trucs super dans plein de cas, mais ici, en fait, il ne servira pas. Du coup, rien de spécial à faire sur le serveur de Fusion Directory, puisque nous avons déjà installé le plugin mail.

Coté serveur mail, là, on ne va pas échapper à la configuration de dovecot:

root@mail:~ $ apt install dovecot-imapd dovecot-ldap  dovecot-pop3d dovecot-lmtpd

Si vous souhaitez uniquement fournir IMAP ou POP3, forcément, n'installez que le module correspondant, et n'activez juste pas l'autre dans la configuration.

Un peu de configuration générale

S'il n'existe pas déjà, on va créer un compte utilisateur local UNIX dédié à la gestion des mails sur le serveur qui fait tourner dovecot. Vous pouvez lui mettre un UID assez élevé, genre 5000, 4242, 3872 ou toute autre valeur à votre convenance, qui reste quand même dans la limite valide des UIDs (et tant qu'à faire, tant qu'elle est au dessus de 1000). Et on va lui créer un groupe pour lui, avec les mêmes contraintes. Et on va tous les deux les appeler "vmail", pour "virtual mail", mais si vous préférez l'appeler "facteur", "toto" ou je ne sais quoi d'autre, tant que c'est un nom d'utilisateur UNIX valide et que vous ferez l'effort de remplacer à chaque fois qu'il y a "vmail" dans la suite du billet, c'est comme vous le sentez, et pareil pour le groupe....

La configuration par défaut de dovecot se trouve dans /etc/dovecot (mais quelle surprise !!!), et elle est découpée en petits fichiers thématiques, presque tous dans le sous répertoire conf.d. Il y a beaucoup de trucs dans cette conf, du coup, nous allons lister ici juste les ajouts/changements par fichier. Je n'expliquerai pas ce qui est assez évident.

10-mail.conf

mail_home = /var/mail/%d/%n
mail_location = maildir:/var/mail/%d/%n/Maildir

mail_uid = vmail
mail_gid = vmail

first_valid_uid = <id de vmail>

Si vous n'utilisez pas d'extensions qui vont stocker également des infos pour chaque utilisateur, on peut se passer d'un homeDirectory et déclarer directement un maildir en tant que "racine"... Mais c'est une mauvaise idée
Ici, le répertoire de alice@domaine.com sera du coup /var/mail/domaine.com/alice, si vous ne gérez qu'un seul domaine vous pouvez éventuellement enlever la partie "%d" des arborescences (pensez bien à le faire partout, y compris dans la suite de la conf).

Vous verrez d'autres déclarations de ces home et maildir dans la suite de la conf, parfois avec d'autres tokens (c'est d'ailleurs le gros point sur lequel j'ai trouvé la documentation de Dovecot pas claire du tout)..... Je crois que cette configuration ci suffit, vu qu'elle est globale pour tout le monde, mais j'ai rajouté le mail_home juste avant ma mise en prod, et je n'ai pas pris le temps de re-vérifier tous les cas de figure, du coup, je suis resté dans une conf "ceinture, bretelles et caleçon propre".....

10-master.conf

#Si vous utilisez lmtp
 unix_listener /var/spool/postfix/private/dovecot-lmtp {
   group = postfix
   mode = 0600
   user = postfix
 }

# Si vous utilisez lda
service auth {
  unix_listener auth-userdb {
    mode = 0600
    user = vmail
    group = vmail
  }
}

Selon votre configuration, vous pourriez même avoir besoin des deux !

15-lda.conf

hostname = domaine.com

lda_mailbox_autocreate = yes

lda_mailbox_autosubscribe = yes

protocol lda {
 [........]
 auth_socket_path = auth-userdb
}

LDAP

dovecot-ldap.conf.ext:

uris = ldaps://ldap.domaine.com:636

tls_ca_cert_file = /etc/ssl/certs/MaCA.pem

tls_require_cert = hard

auth_bind = yes

ldap_version = 3

base = ou=people,dc=domaine,dc=com

scope = subtree

user_attrs = homeDirectory=/var/mail/%d/%n,maildir=maildir:/var/mail/%d/%n/Maildir

user_filter = (&(objectClass=gosaMailAccount)(mail=%u)(!(gosaMailDeliveryMode=[*I*])))

pass_attrs = homeDirectory=/var/mail/%d/%n,maildir=maildir:/var/mail/%d/%n/Maildir

pass_filter = (&(objectClass=gosaMailAccount)(mail=%u)(!(gosaMailDeliveryMode=[*I*])))

iterate_attrs = mail=user
iterate_filter = (&(objectClass=gosaMailAccount)(!(gosaMailDeliveryMode=[*I*])))

Ici, seule la véritable adresse mail principale est utilisée, y compris en tant que login. Du coup, quand vos utilisateurs voudront se connecter, leur login sera bien leur adresse mail complète. C'est plus ou moins indispensable pour une configuration multi-domaines, dans laquelle le risque de doublons d'IDs est tout à fait possible (alice@domaine1.com et alice@domaine2.net qui ne sont pas le même utilisateur).

Et on part également du principe qu'un utilisateur qui n'a pas de mails délivrés en local (en pratique, une adresse en forward-only) n'a pas besoin de se connecter directement, d'où le (!(gosaMailDeliveryMode=[*I*])).

10-auth.conf:

#!include auth-system.conf.ext
#!include auth-sql.conf.ext
!include auth-ldap.conf.ext

On désactive auth-system et on active auth-ldap (et on ne touche pas à auth-sql qui s'est juste retrouvé entre les deux dans la conf d'origine).

auth-ldap.conf.ext:

userdb {
 driver = ldap
 args = /etc/dovecot/dovecot-ldap.conf.ext
 
 # Default fields can be used to specify defaults that LDAP may override
 default_fields = homeDirectory=/var/mail/%d/%n,maildir=maildir:/var/mail/%d/%n/Maildir
}

SSL

On a commencé à mettre du SSL partout dans notre réseau, donc autant continuer avec Dovecot, surtout qu'ici, des logins/passwords des utilisateurs vont circuler. Du coup, non seulement on va activer SSL, mais en plus on va le forcer !

10-auth.conf

disable_plaintext_auth = yes

10-master.conf

 inet_listener imaps {
   port = 993
   ssl = yes
 }

 inet_listener pop3s {
   port = 995
   ssl = yes
 }

10-ssl.conf

ssl = required

ssl_cert = </etc/letsencrypt/live/domaine/fullchain.pem
ssl_key = </etc/letsencrypt/live/domaine/privkey.pem

Cette configuration ne désactive pas les services IMAP/POP3 sur les ports par défaut (respectivement 143 et 110), parce que ..... je n'ai pas réussi à les désactiver ! Normalement, le serveur n'autorisera cependant d'authentification sur ces ports qu'après un StartTLS, mais en pratique, j'ai préféré rajouter une règle de filtrage pour bloquer les accès à ces ports (enfin, pour être exact, je n'ai pas mis de règle de filtrage qui autorise les accès sur ces ports......).

Ah, et comme les utilisateurs vont ici potentiellement se connecter depuis plein de trucs différents qu'on ne maîtrise pas, j'ai déployé un certificat let's encrypt. Pour pouvoir gérer automatiquement un tel certificat sur un serveur qui ne fournit pas de service web (ce qui est mon cas ici), on va installer le package certbot, puis exécuter la commande suivante (en supposant que vos utilisateurs accéderont au serveur via le nom de machine mail.domaine.com):

root@mail: ~ $ certbot certonly --standalone --preferred-challenges http -d mail.domaine.com

Dans ce mode, certbot va créer automatiquement un mini serveur web temporaire, le temps de permettre aux serveurs de Let's Encrypt de vérifier qu'on ne bluffe pas, et que mail.domaine.com est effectivement à nous (il faut donc que des requêtes HTTP vers mail.domaine.com arrivent sur cette machine).
Par la suite, certbot sera exécuté à nouveau périodiquement pour renouveler le certificat, il faut juste aller éditer /etc/cron.d/certbot pour lui dire de recharger les services qui utilisent ce certificat en cas de changement, en ajoutant par exemple --renew-hook "service dovecot reload; service postfix reload" à la fin de la ligne.

Sur un système en read-only root, pensez à déplacer /etc/letsencrypt dans /var et faites un lien (/var/lib/letsencrypt existe déjà mais est vide, du coup j'ai préféré ne pas l'utiliser).

Tri des nouveaux mails entrants

Sur mon ancienne configuration, j'avais un .procmailrc (assez bien rempli) dans mon répertoire personnel pour trier les mails selon plein de critères dans différents fichiers de mon répertoire de mails. Sur cette nouvelle configuration, pas de comptes UNIX associés aux utilisateurs mails, nous allons donc utiliser une méthode permettant d'effectuer un boulot similaire à distance, via un protocole normalisé: Sieve, qui va rapidement devenir notre meilleur tamis......

Dovecot gère nativement Sieve et ManageSieve (qui permet donc de modifier ses filtres Sieve à distance), et qui est supporté par pas mal de clients. Il suffit donc d'installer les paquets qui vont bien:

root@mail:~ $ apt install dovecot-managesieved dovecot-sieve

Dans la configuration bien organisée en fichiers de dovecot, c'est donc assez facile d'aller trouver les trucs à changer, dans 20-managesieve.conf (il suffit de décommenter les bonnes lignes, on ne va pas en faire le tour ici), et dans 90-sieve.conf, où il est nécessaire de lui indiquer où stocker la conf sieve:

sieve = file:/var/mail/%d/%n/sieve;active=/var/mail/%d/%n/.dovecot.sieve

En théorie, la conf par défaut devrait suffire ici, vu qu'on a déclaré le homeDirectory, en pratique, ca ne fonctionne pas chez moi, j'ai du louper un truc à un moment......

Il ne reste plus qu'à activer le plugin dans 15-lda.conf et 20-lmtp.conf (si vous utilisez lmtp pour postfix):

mail_plugins = $mail_plugins sieve

Entre autres, je peux donc aller classer les mails qui arrivent via un alias avec l'extrait de configuration sieve suivant:

if address :all :is ["to", "cc", "resent-to", "delivered-to", "X-Original-To"]
        "alias1@domaine.com"
{
        fileinto "alias1";
        stop;
}

Selon le chemin d'arrivée, c'est "delivered-to" et "X-Original-To" qui sont fiables: un mail qu'on reçoit en tant que destinataire caché n'aura pas l'adresse de l'alias dans les autres champs.

D'un point de vue réseau, c'est sur le port TCP 4190, et Manage-Sieve semble prendre en compte la configuration SSL globale, vu qu'il n'annonce que SASL ou StartTLS quand on se connecte dessus.

Importer ses anciens mails

Si vous démarrez un domaine tout neuf et que vous n'avez aucun historique mail à importer, cette section ne vous sera d'aucune utilité. Dans le cas contraire, il y a pas mal de cas possibles, en fonction de l'ancienne méthode de stockage et de la quantité de mails, comptes utilisateurs, etc.... à importer.

Dans mon cas, il y avait un utilisateur à importer (moi, quand je vous dis que j'ai un LDAP surchargé !), disposant d'un gros répertoire de MBoxes (sans vouloir me vanter, et malgré un petit régime de printemps). Après avoir pas mal galéré pour comprendre la syntaxe, j'ai fini par réussir à tout importer avec doveadm import (avec mon répertoire de MBoxes dans /chemin/vers/Mail/):

root@mail:~ $ doveadm import -A mbox:/chemin/vers/Mail/ "" ALL

C'eeeeeest trèèèèèèès loooooooong........
Pour une raison que je n'ai pas trop creusée, une bonne partie des fichiers et répertoires ainsi importés dans le mdir de dovecot appartiennent à root (mais pas tous !), et non à vmail, il faut donc faire un gros

root@mail: ~ $ chown -R vmail.vmail /var/mail/domaine.com/user

(plus simple, vu que pas mal de répertoires commencent par un ., et quitte à être vraiment bourrin, on peut même le faire sur tout /var/mail, en fait....), sinon votre MUA pourra voir les répertoires, mais ne pourra pas lire les mails dedans, ce qui est quand même un peu l'idée de départ.....

Quitte à faire de la manip à la main, on peut directement convertir les mbox en mdir, qui est le format utilisé par dovecot pour gérer les répertoires d'utilisateurs (vu qu'on l'a configuré comme ça......):

root@mail:~ $ mb2md -s /home/user/Mail -d /var/mail/domaine/user
root@mail:~ $ chown -R vmail.vmail /var/mail/domaine/user

C'est au passage beaucoup plus rapide que doveadm, mais je n'ai pas du tout regardé si le contenu potentiellement déjà existant de /var/mail/domaine/user est préservé ou pas !

Si vous avez un maildir à importer, les 2 techniques sont pratiquement les mêmes: précisez à doveadm que vous avez un maildir et pas un répertoire de mboxes, ou importez directement votre maildir sans passer par la case mb2md (vous n'auriez pas touché 20 000€ de toutes façons.......).

Si vos anciens mails sont déjà sur un serveur IMAP, imapsync semble avoir bonne presse, mais je vous dis ca en me basant uniquement sur quelques rapides infos vues sur le net alors que je cherchais autre chose !
Dans ce cas, vous pouvez aussi lire la section suivante, là, maintenant, de suite.....

Récupération automatique de mails d'un autre compte

J'ai quelques comptes dans d'autres domaines que je veux consulter via mon MUA et via mon compte principal. Du coup, j'ai besoin d'un logiciel qui va automatiquement vérifier régulièrement si j'ai de nouveaux mails dans ces boites distantes, et si c'est le cas, il va les rapatrier sur mon adresse principale.
Là, on est plus dans l'exception: la plupart des comptes utilisateurs de mon serveur de mail n'auront pas ce genre de besoins, et comme j'ai également besoin de manipuler directement des mots de passes, cette partie de la configuration sera donc faite complètement en dehors du LDAP, et nécessitera de se connecter en root sur le serveur de mail pour tout changement ultérieur.

Dans mon ancienne configuration, avec des mbox tout à plat dans des répertoires d'utilisateurs UNIX, j'utilisais fetchmail. Avec les utilisateurs virtuels et Dovecot, mes premières recherches m'ont indiqué que le cas était un peu plus complexe (fetchmail délivre des mails locaux, à la base), et qu'une autre solution plus ou moins équivalente gère facilement le fait de filer les mails à un autre truc qui va s'occuper de les délivrer: Getmail.
Du coup, c'est parti pour une installation et configuration de getmail (précisément getmail4, vu que la dernière version à l'heure actuelle est getmail5 et qu'on est sur Debian Stable.....):

root@mail:~ $ apt install getmail4

Comme les utilisateurs de mails n'ont pas de comptes UNIX locaux sur le serveur, il faut décider arbitrairement où poser les fichiers de configuration (à priori 1 par compte distant). /root/.getmail, /etc/getmail ou ailleurs, à vous de voir. On partira sur /etc/getmail pour l'exemple, voyons le contenu d'un de ces fichiers:

[retriever]
type = SimplePOP3SSLRetriever
server = pop.provider.fr
username = login@provider.fr
password = secret

[destination]
type = MDA_external
path = /usr/lib/dovecot/deliver
arguments = ("-e", "-d", "mymail@domaine.com")
user = root
group = root
allow_root_commands = true

[options]
read_all = true
delete = true
delivered_to = true
# do not add a Received: header field
received = false

La première partie se passe de commentaires, et est facilement adaptable (IMAP, POP, SSL ou pas). La 3eme, à vous de voir vos options. Reste la seconde partie qui nous intéresse:

  • on veut faire délivrer les mails à dovecot, donc via /usr/lib/dovecot/deliver (c'est le lda de tout à l'heure).
  • -e, c'est pour que dovecot retourne une erreur à l'exécution si nécessaire, au lieu de faire un mail de retour à l'expéditeur.
  • -d mymail@domaine.com sert à indiquer à dovecot quel est l'utilisateur de destination réel, vu qu'il ne correspondra pas à l'utilisateur qui exécute getmail (root).
  • user et group devraient être positionnés à vmail. Sauf que je n'ai pas réussi à faire fonctionner getmail avec cette conf, et que le seul moyen que j'ai trouvé était de faire tourner en tant que root....
  • allow_root_commands = true vu qu'il n'aime pas tourner en tant que root par défaut. Il y a probablement moyen de faire plus propre.

Getmail réclame également un répertoire de configuration/data. Soit vous créez simplement un /root/.getmail (son répertoire par défaut pour l'utilisateur root), soit vous lui précisez un répertoire avec --getmaildir (attention, ce répertoire doit être accessible en écriture).

On fait une vérification à la main pour s'assurer que les mails sont récupérés, et il ne reste plus qu'à automatiser l'exécution de getmail. LA technique classique reste via cron, avec un /etc/cron.d/getmail dans ce genre:

SHELL=/bin/sh

*/10 * * * * root /usr/bin/getmail --rcfile /etc/getmail/mail1@providera.fr --rcfile /etc/getmail/mail2@provider2.com

Ici, on exécute cette commande toutes les 10 minutes. Vous pouvez également faire plusieurs entrées, pour aller récupérer le premier compte souvent, et le second genre une fois par jour seulement.

Il semble également possible de faire fonctionner getmail en tant que service, je n'ai pas testé.

Autoriser les envois de mails pour les utilisateurs authentifiés distants

En théorie, n'importe qui peut envoyer des mails de son adresse @domaine.fr depuis n'importe où, tant qu'il dispose d'un relai SMTP un minimum conciliant. Typiquement, le SMTP "sortant" de votre FAI (celui qui n'est accessible que depuis l'intérieur du réseau de votre FAI) est probablement assez conciliant. En pratique, on peut avoir plusieurs raisons de vouloir fournir à nos utilisateurs légitimes un relai SMTP pour qu'ils envoient des mails depuis leur adresse de notre domaine, même si ces utilisateurs sont actuellement en vadrouille à l'extérieur du réseau.
Par contre, on ne veut pas forcément pour autant devenir un relai à SPAM de notoriété mondiale, il va donc nous falloir une solution pour permettre à nos utilisateurs légitimes de s'authentifier, et ne faire relai sortant que pour ces utilisateurs authentifiés.

SASL

Coté SMTP, Postfix gère cette possibilité d'authentification. Par contre, d'après mes quelques recherches, il semble ne pas être capable de se connecter directement au serveur d'authentification (dans notre cas, le LDAP) pour valider les utilisateurs, et se repose sur le protocole SASL, et du coup sur "le truc derrière qui gère". Dovecot gère (et donc, comme c'est Dovecot qui gère, on utilisera le même login / password que pour IMAPS ou POP3S).

Coté postfix, dans main.cf:

smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_tls_auth_only = yes

Le dernier paramètre interdit une authentification non chiffrée (avant le StartTLS).... Bon, ok, du coup, on va aussi configurer Postfix pour qu'il permette le StartTLS:

# TLS parameters
smtpd_tls_cert_file=/etc/letsencrypt/live/mail.domaine.com/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/mail.domaine.com/privkey.pem
smtpd_use_tls=yes
smtpd_tls_CApath = /etc/ssl/certs
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtpd_tls_security_level = may

Le "May" en security level est assez important, vu que, comme on est MX primaire du domaine, on doit aussi accepter les connexions SMTP entrantes classiques, pour pouvoir recevoir des mails de n'importe quel relai dans le monde qui ne connaît pas forcément StartTLS.

On ajoutera également permit_sasl_authenticated juste après chaque fois où on a déjà permit_mynetworks dans les restrictions. Par exemple:

# avant:
smtpd_relay_restrictions = permit_mynetworks 
              defer_unauth_destination
# après:
smtpd_relay_restrictions = permit_mynetworks
             permit_sasl_authenticated
             defer_unauth_destination

Bon, là, en vrai, c'est la valeur par défaut d'origine de smtpd_relay_restrictions, mais au moins vous avez un exemple simple.....

Coté dovecot, on donne la possibilité à postfix de venir demander des authentifications, dans 10-master.conf:

 unix_listener /var/spool/postfix/private/auth {
   mode = 0666
 }

Et voilà, un utilisateur authentifié depuis un endroit qui n'est pas dans my_networks peut désormais envoyer des mails via notre SMTP.... et c'est peut être un peu trop souple dans ce cas: après tout, l'utilisateur est censé pouvoir envoyer des mails depuis sonemail@domaine.com, voire depuis sonalias@domaine.com, mais pas forcément depuis monemail@domaine.com ou sonemail@unautredomaine.fr (ou, dans le dernier cas, pas via notre SMTP).

Par contre, un ordinateur de mon réseau local devra pouvoir envoyer des mails depuis www@domaine.com (par exemple). Et n'importe qui du reste du monde a le droit de m'envoyer des mails à une adresse valide chez moi, mais n'a pas le droit d'envoyer autre chose via mon serveur...... La solution est dans une bonne configuration de la vérification de l'émetteur:

smtpd_sender_restrictions = 
       reject_authenticated_sender_login_mismatch
       permit_mynetworks 
       permit_sasl_authenticated 
       reject_non_fqdn_sender 
       reject_unknown_sender_domain

smtpd_sender_login_maps = ldap:/etc/postfix/ldap/senders.cf

Et la partie spécifique du senders.cf est:

query_filter = (&(|(gosaMailAlternateAddress=%s)(mail=%s))(objectClass=gosaMailAccount))
result_attribute = mail

C'est assez subtil: si on est authentifié, on doit passer par la vérification de login, quel que soit le réseau d'où on vient. Sinon, si on est sur un réseau de "mynetworks", alors on fait ce qu'on veut. Et dans les autres cas, on subit les vérifications classiques.
On pourrait utiliser directement reject_sender_login_mismatch, ce qui forcerait la vérification également pour les utilisateurs non authentifiés. Dans mon cas, j'ai pas mal de machines locales qui émettent des mails depuis root@mondomaine.com, et comme j'ai rattaché cette adresse à mon adresse principale, je ne peux pas forcer cette vérification. Il y aurait probablement des moyens détournés de s'en sortir, peut être en passant par un compte intermédiaire de "forward only" pour ces adresses, et en changeant le filtre en un truc genre:

query_filter = (&(|(gosaMailAlternateAddress=%s)(mail=%s))(objectClass=gosaMailAccount)(!(gosaMailDeliveryMode=*I*)))

Submission

Comme je viens de le dire à l'instant, ca n'est pas forcément simple de gérer proprement tous les cas pour un serveur qui doit faire à la fois MX primaire (donc accepter les mails entrants depuis n'importe où dans le monde) et relai SMTP pour les mails sortants. Enfin, quand on souhaite ne pas être une grosse passerelle à spams.....

Une des approches possibles est l'utilisation du protocole Submission, qui est en fait à peu près le protocole SMTP mais sur un autre port, qui est censé être réservé à un usage de relai pour les utilisateurs locaux.

Pour le mettre en œuvre, c'est presque aussi simple que d'aller décommenter les lignes correspondantes dans master.cf, sauf que, à ce que j'ai lu sur le net, l'implémentation Postfix fait qu'il n'est pas possible pour autant d'avoir un process vraiment distinct pour les mails entrants et pour les mails en relai.

Du coup, pas de submission pour moi pour l'instant, et une bonne raison de plus pour mettre en place dans un futur proche un relai SMTP dédié, ce qui me permettrait en prime de mettre en place du Postscreen sur le MX.....

Pas de publicité, merci !

Vous, je sais pas, moi j'en ai un peu marre d'avoir dans ma boite aux lettres tous les matins une tonne de prospectus pour me vanter la promo du cassoulet en boite dans le supermarché du coin, et je ne vous parlerai même pas des appels chez moi pour me proposer une super assurance, un forfait téléphonique à la tarification ultra compétitive, etc..... bon, ok, là je viens de vous en parler un peu, disons donc que je ne vous en parlerai même pas plus que ce que je viens de dire.....

Pour mes mails, c'est pareil, et on va donc déployer tout un arsenal pour réduire au maximum les pourriels.

Vérifications de base dans postfix

Les spammeurs ont tendance à envoyer en masse, et le plus vite possible. Ils profitent du coup souvent d'un certain laxisme dans les serveurs pour gagner du temps et jeter le spam sans se préoccuper de respecter complètement la norme. Au contraire, un vrai serveur SMTP est censé respecter complètement cette norme, nous allons donc commencer par ce qui est simple à vérifier, et à configurer dans /etc/postfix/main.cf.

D'abord, nous allons obliger les adresses des mails (MAIL FROM et RCPT TO) à respecter un minimum les normes:

strict_rfc821_envelopes = yes

Ensuite, nous allons exiger un minimum de politesse de la part de notre correspondant (ce qui nous permettra au passage de forcer certaines validations plus tard):

smtpd_helo_required = yes

Et nous allons enfin considérer qu'un expéditeur doit avoir une adresse mail qui est censée être à peu près valide, et correspondre à un domaine qui existe vraiment:

smtpd_sender_restrictions = reject_unknown_sender_domain, reject_non_fqdn_sender

Selon les configurations de vos clients légitimes, vous souhaiterez peut être cette version, qui n'applique pas cette restriction aux machines de votre LAN (en supposant que vous avez mis à jour mynetworks), ou aux utilisateurs authentifiés par SASL:

smtpd_sender_restrictions = permit_mynetworks permit_sasl_authenticated 
                reject_non_fqdn_sender reject_unknown_sender_domain

Notez que la plupart de ces configurations pourraient casser des scripts internes un peu bourrins qui envoient des mails légitimes à la sauvage, ou qui envoient des mails avec un domaine non renseigné (ce qui peut aussi être légitime dans certains cas de mails locaux).

Il y a en théorie plusieurs autres options intéressantes, qui sont très efficaces pour stopper les spammeurs, comme:

smtpd_helo_restrictions = permit_mynetworks 
            reject_invalid_hostname
            reject_unknown_hostname 
smtpd_client_restrictions = permit_mynetworks
             reject_unknown_client_hostname

Sauf que plein de serveurs de mails légitimes sont mal configurés, et seraient donc refoulés avec ces vérifications activées....

Il existe également sur les versions assez récentes de Postfix une extension Postscreen, dont l'idée est sympa, mais qui annonce clairement qu'il ne doit pas être déployé sur des serveurs directement utilisés par des MUAs. Comme c'est actuellement le cas de ma conf, je mets l'idée de coté pour l'instant.

Vous pouvez me rappeler la semaine prochaine ?

Première approche pour se protéger un peu des spammeurs, le greylisting. Le principe est assez simple: quand un serveur veut vous envoyer un mail, vous commencez par lui répondre "là je peux pas j'ai aquaponey, reviens plus tard". L'idée est qu'un logiciel de spam ne reviendra pas (il fait dans le bête et rapide, donc n'implémente pas les trucs comme la gestion de file d'attente), alors qu'un vrai serveur, si (et malheureusement, les centres d'appels téléphoniques aussi......). Alors, bien sur, jusque là, la technique est très très facile à mettre en œuvre, mais présente un très léger défaut: ceux qui reviennent vraiment, on veut pouvoir les reconnaître, et cette fois réellement prendre en charge leur mail ! Il nous faut donc un gestionnaire de greylist. Sur mon ancienne implémentation, j'avais simplement déployé postgrey, qui est très simple à déployer et à configurer. Cette fois ci, comme je veux également déployer d'autres techniques, j'ai regardé plusieurs solutions (en me limitant à ce qui est dans les dépots debian, pour des raisons de maintenance), et j'en ai trouvé certaines qui gèrent également d'autres techniques antispam:

  • MtPolicyd semble complet, mais embarque beaucoup, beaucoup de dépendances à l'installation, et la gestion des listes blanches ne semble être possible que par une base SQL. Probablement très bien pour un usage très intensif, mais un peu overkill dans mon cas.....
  • Gross a l'air léger, gère aussi le RBL (que j'explique après), n'embarque pratiquement aucune dépendance, mais la doc laisse carrément à désirer.
  • Postfix embarque directement un service de greylisting, mais ils disent eux même qu'il s'agit d'un serveur "simplifié"..... pas très encourageant, et surtout, le script en question n'était pas installé sur ma Debian, donc je ne considère pas cette option comme disponible.
  • Bley propose du greylisting intelligent. Mais il embarque pas mal de dépendances aussi (quoique nettement moins que MtPolicyd), dont quelques unes qui ne m'emballent pas du tout (des trucs SQL) sur mon serveur de mails.

Bref, au final, j'en suis pour l'instant revenu à Postgrey, qui tire lui aussi quelques dépendances, mais à peu près exclusivement des librairies, disons que c'est moins pire...... C'est parti pour une installation et une configuration express:

 root@mailserver:~ $ apt install postgrey

Et dans /etc/postfix/main.cf:

smtpd_recipient_restrictions = 
     permit_my_networks
 .....
     reject_unauth_destination,
 .....
     check_policy_service inet:127.0.0.1:10023,
 .....

Comme le greylisting se base sur l'IP, on pourrait le faire dès la connexion du client. Mais Postgrey tient une base à jour par rapport à IP Client / Emetteur / Destinataire, donc on doit le mettre ici. Et c'est du coup important de le mettre APRES reject_unauth_destination. On recharge la conf de postfix, et zou !

Vous disposez accessoirement désormais d'un répertoire /etc/postgrey qui contient 2 fichiers de whitelists. Vous pouvez ajouter vos propres entrées de whitelist via les versions .local de ces fichiers.

Délit de sale gueule IP

Seconde technique pour se protéger des spams: repérer des spammeurs connus quand ils essaient de vous envoyer des mails. Ca s'appelle du RBL, il y a des listes publiquement accessibles plus ou moins performantes disponibles. Le choix de la liste en question est assez important: trop laxiste, la liste ne sert pas à grand chose. Trop stricte, elle pourrait refuser des expéditeurs légitimes !

Comme c'est un test uniquement sur l'IP du client, on va le tester tant qu'à faire au bon endroit:

smtpd_client_restrictions = 
       permit_mynetworks
       permit_sasl_authenticated
       reject_rbl_client zen.spamhaus.org
       permit

Là, on utilise la RBL de chez Spamhaus, qui est assez réputée.

On pourrait rajouter d'autres tests RBL (comme reject_rhsbl_client pour le nom de machine du client), mais l'IP, c'est déjà pas mal.

Point important à noter: les versions récentes de Postfix font tous les tests (smtpd_*_restrictions) après le RCPT TO (mais dans l'ordre logique, quand même). Du coup, même lors de l'évaluation de smtpd_client_restrictions, on peut autoriser les clients authentifiés par SASL.

Expéditeurs légitimes

Le principe du SPF est au contraire de pouvoir vérifier qui est légitimement censé pouvoir émettre des mails d'un domaine donné, via un enregistrement spécifique dans la zone DNS du domaine en question. Sur le papier, l'idée est carrément super. En pratique, c'est plus compliqué.....

D'abord, tous les domaines n'ont pas renseigné l'extension SPF en question. Ensuite, il est parfois à peu près légitime d'envoyer des mails d'un domaine sans passer par leurs serveurs officiels (par exemple pour vos adresses mails fournies par votre FAI, mais quand vous êtes ailleurs). Pour ce dernier cas, l'enregistrement SPF du domaine est censé préciser si on doit s'y attendre ou pas.

root@mail:~ $ apt install postfix-policyd-spf-python  # existe aussi en perl

On doit ajouter un truc à la main dans /etc/postfix/master.cf:

policyd-spf  unix  -       n       n       -       0       spawn
    user=policyd-spf argv=/usr/bin/policyd-spf

Et dans main.cf, on va rajouter la vérification de cette policy au niveau de smtpd_sender_restrictions, vu qu'il s'agit d'un test sur l'émetteur (notez que la plupart des docs sur le net le placent dans smtpd_recipient_restrictions):

smtpd_sender_restrictions =
    ...
    check_policy_service unix:private/policyd-spf,
    ...

(On le mettra vers la fin, après toutes les vérifications sur le fait que le domaine existe vraiment, etc...).

Petit avantage annexe: si votre domaine SPF est configuré de façon assez restrictive (c'est à dire qui finit par "-all" pour dire que toute source non listée n'est vraiment pas censée envoyer de mails de ce domaine, ce qui est le cas de ma conf SPF), un spammeur qui essaie de vous envoyer des mails avec une adresse d’expéditeur dans votre domaine (ce qui est assez fréquent) se fera refouler par cette configuration !

Ah, à un moment, vous risquez de vous retrouver à éditer /etc/postfix-policyd-spf-python/policyd-spf.conf. J'ai perdu un temps fou dans mes tests en croyant que TestOnly = 1 signifiait qu'on était en mode test, alors que non, ca veut dire qu'on est en mode prod (donc bloquant).............

Les vrais utilisateurs UNIX locaux

Avant de passer des heures à vouloir mettre en place un serveur de mail, j'étais donc aussi parti dans l'idée de gérer mes utilisateurs UNIX locaux avec Fusion Directory, si vous vous souvenez (et si vous ne vous souvenez pas, il se trouve que moi, je m'en souviens, malgré ma mémoire fluctuante).

Le truc le plus difficile ici sera de choisir entre libpam-ldap et libpam-ldapd (notez la différence: un 'd' à la fin du 2eme......). J'ai choisi libpam-ldapd, qui semble plus récent, mieux documenté (et qui, surtout, a un 'd' en plus à la fin !!!), mais l'essentiel de la conf risque d'être assez proche avec libpam-ldap.
Donc, c'est parti pour l'installation:

root@workstation:~ $ apt install libnss-ldapd

Vous devriez vous retrouver avec également libpam-ldapd et nslcd d'installés dans la foulée. Durant cette installation, on vous demandera pour quels services on veut pouvoir gérer via LDAP, choisissez passwd, group et shadow.

Renseignez /etc/ldap/ldap.conf si ce n'est pas déjà fait. En fait, renseignez le avant d'installer les paquets, vu que du coup à peu près toute la conf sera correctement pré-renseignée....
Editez /etc/nslcd.conf pour y mettre également les informations de votre serveur LDAP, mettez à jour le tls_cacertfile si nécessaire, redémarrez nslcd et nscd.
Pas de binddn ou bindpw ici: root local ne pourra donc pas forcer le changement d'un mot de passe, ce qui est bien dans notre cas. Un user peut changer son mot de passe.
/etc/pam.d est déjà fourni dans un état fonctionnel pour LDAP.

Il ne vous reste plus qu'à tester que tout fonctionne.

Pour pousser un peu plus loin la conf, ca serait très classe d'utiliser des trucs comme autodir ou libpam-mklocaluser pour créer à la volée les répertoires des nouveaux utilisateurs lors de la première connexion. Sauf que ca nécessite d'avoir les droits d'écriture dans le /home du NFS depuis n'importe quelle station client NFS. Comme je crée vraiment très très peu d'utilisateurs UNIX dans mon cas, j'ai donc mis cette option de coté.

Autofs

On peut bien sur monter le /home NFS "en dur". Pour plein de raisons (dont "j'ai eu à une époque des galères dont je ne me souviens plus bien"), je ne fais plus trop ça, et j'utilise autofs. En théorie, bonne nouvelle, il existe un plugin pour configurer autofs.

En pratique, je n'ai vraiment que /home à configurer, du coup, j'en suis resté à une configuration manuelle.

Config manuelle openbar

Autofs supporte un montage à la volée, il suffit de configurer comme suit:

  • /etc/autofs.conf: forcer NFS version 4
  • /etc/auto.master: activer la ligne /net -hosts
  • service autofs restart

Avec cette conf, si quelqu'un essaie d'accéder à /net/a/b, autofs va automatiquement tenter de monter le partage b sur le serveur a.
Il ne vous reste alors qu'à avoir le lien suivant pour que ca fonctionne pour votre /home:

root@client:/$ ls -ld home
lrwxrwxrwx 1 root root <date> home -> net/serveurnfs/home

Config manuelle restrictive

Sauf que, avec une telle conf openbar, n'importe quel utilisateur peut tenter un montage d'autres points sur d'autres serveurs. Comme je ne suis pas fan de l'idée, je vais préférer une configuration restrictive:

  • dans /etc/auto.master, mettez une ligne /net/serveurnfs /etc/auto.serveurnfs
  • créez un /etc/auto.serveurnfs, et mettez uniquement: home serveurnfs:/home
  • service autofs restart

Et créez le même lien que dans la solution openbar:

root@client:/$ ls -ld home
lrwxrwxrwx 1 root root <date> home -> net/serveurnfs/home

Les trucs que j'ai laissé tomber.....

Dans mon plan initial, on gérait d'autres trucs avec Fusion Directory et le LDAP......

DNS

Il existe un plugin pour gérer le DNS, et même une doc chez Fusion Directory qui explique comment faire. Mais j'ai du louper un truc dans l'explication, et j'ai fini par laisser tomber pour l'instant.

J'ai également repéré à un moment bind9-dyndb-ldap, mais là aussi, manque de doc, de compréhension, de temps, de motivation (oui, ok, j'ai depuis très longtemps un petit script qui me génère automatiquement la zone DNS, la zone reverse et la conf DHCP à partir d'un CSV rapide à éditer.....).

DHCP

Comme pour le DNS, on devrait pouvoir gérer le DHCP par Fusion Directory, et il y a de la doc pour la configuration du plugin et pour la configuration du serveur DHCP.
Et comme pour le DNS, je n'ai pas réussi à faire fonctionner le truc, et j'ai lâché l'affaire pour l'instant.

Utilisateurs Samba

Non, là, en vrai, je n'ai pas laissé tomber, je n'ai même pas regardé......
(note pour ma soeur: non, je ne dénigre pas certains styles de musique et de danse assez sympas, là il s'agit d'autre chose qui ne me concerne pas)

FusionDirectory et restrictions ssh

L'idée est pas mal. En pratique, j'ai déjà des accès ssh par clés ssh uniquement, et un utilisateur légitime chez moi qui sait générer ses clés et les poser au bon endroit a le droit de faire du ssh sur toutes les machines clientes qui embarquent le /home NFS....

Ajouter un commentaire

Le code HTML est affiché comme du texte et les adresses web sont automatiquement transformées.

Fil des commentaires de ce billet