Montage d’un serveur de mail complet (postfix, postgrey, amavisd-new, clamav, spamassassin etc)

Cet article présente la mise en place complète d’un serveur de mails sous Debian mélangeant les composants suivants : postfix, postgrey, amavisd-new, clamav, spamassassin, razor, pyzor, les règles spamassassin de RulesEmporium et enfin procmail pour délivrer dans des boîtes (ou faire suivre sur un autre backend si c’est votre cas).

Ce type d’installation peut tout à fait convenir pour des petites et moyennes entreprises (quelques centaines de personnes), sur un serveur moyennement puissant. Pour faire simple.

Encore une doc sur ce sujet ?

Oui on s’excuse, mais comme d’habitude avec Debian, tout est déjà prêt à fonctionner et pourtant, on trouve généralement des docs de personnes mettant en place l’outil en recompilant les sources, en prenant des fichiers de conf à droite à gauche, en démolissant le beau travail déjà accompli par les packageurs Debian.
Mon approche reste la même : Debian a fait le boulot pour moi, j’en profite.
Au final, cet article est simplement brodée autour du README.Debian de chaque paquet qu’on va installer (surtout amavisd-new) et de quelques autres docs glanées sur le web expliquant tel ou tel paramètre, un peu plus que la doc officielle.
Mais comme rares sont les gens qui lisent les README, mon article devrait quand même intéresser quelques lecteurs, je l’espère.

Ce dont je ne parle pas

Je ne parle pas de l’aspect lecture des mails (en POP, en IMAP, renvoi vers un autre backend (Exchange ?)), mais juste au nettoyage et au blocage amont des spams et virus.
Je pars d’ailleurs d’une machine avec un postfix minimaliste sachant envoyer et recevoir des mails.
Vous pouvez vous reporter à ma doc Debian pour ce cas là, elle décrit en plus de postfix :
– la mise en place de postgrey (voyez l’intérêt ici)
– la mise en place de quelques blocages par blacklists (RBL & co)
– procmail
Je ne parle pas non plus du montage d’un backup MX. Probablement lors d’un prochain article.

Enfin, je colle tous les éléments de ce serveur sur une unique machine physique. Vous pourriez séparer les éléments. A ce moment-là, un peu de raisonnement et une lecture des documentations officielles que je cite me paraît judicieux. Cet article se limiterait alors,pour vous, à comprendre le rôle de chaque morceau, à appréhender la configuration de base et à partir du coup dans la bonne direction.

Comme à mon habitude, je décris aussi quelques bêtises et oublis que j’ai pû rencontrer, ça aidera à débugger et ça explique des choses.

Pré-requis

Etre sur une Debian stable (Lenny) avec le dépôt Debian « volatile » opérationnel (pour les mises à jour de clamav).
Le dépôt « volatile », c’est ça :

moi@srv:~$ cat /etc/apt/sources.list | grep vola
deb http://volatile.debian.org/debian-volatile lenny/volatile main contrib non-free

C’est un dépôt créé pour palier aux problèmes des applications mises à jour constamment (les bases anti-virus par exemple, tout autant que des outils de mssageries instantanées qui voient les protocoles sous-jascents évoluer régulièrement). Si on restait sur le rythme Debian (tous les 2 ans ; bientôt 6 mois), on aurait des applications inutiles.

Rôle de chaque élément

D’abord le schéma qui va bien :

Cheminement du mail
Cheminement du mail

1. Postfix reçoit donc la connexion d’un serveur voulant envoyer un mail.
2. Grâce à postgrey, il va filtrer déjà un bon paquet de spams qui n’atteindra pas la suite des composants (et donc pas de charge réseau/cpu inutile).
3. Donc au besoin, le mail revient plus tard, suite à greylisting.
4. Postfix passe le relai à amavisd-new qui orchestre les appels à :
5. ClamAV qui fait ce qu’il a à faire
6. et à spamassassin, lui-même gérant pyzor/razor
7. Retour du mail nettoyé (disons, avec les en-têtes qui vont bien) vesr postfix
8. Postfix livre le mail (dans la boîte de l’utilisateur, au backend, à je ne sais quel autre élément en aval.

Doc officielle, doc complémentaire

Lire /usr/share/doc/amavisd-new/README.postfix.gz est un passage obligé, je trouve. Je me base dessus et je fais certains choix qui pourraient ne pas être les votres. Je n’invente pas grand chose, tout est quasiment dedans.
Si vous êtes sur une installation déjà en production, vous pourriez être intéressés par le paramètre soft_bounce, voyez ici via un :
postfix -e "soft_bounce = yes"

Autre doc intéressante : http://www200.pair.com/mecham/spam/spamfilter20090215.html. A noter : l’auteur n’utilise pas trop le boulot de Debian, donc beaucoup de choses à reparamétrer dans son cas, sans compter les manips à la main : récupérer le fichier de conf X, prendre tel binaire postfix plutôt que celui de la distrib. Bref, pas très Debian-style à mon goût.
Mais au moins il donne une bonne explication de certains paramètres, à vous de voir.
Enfin, cette doc décrit le montage complet d’une Debian, installation, serveur DNS etc. On s’en fout pas mal dans le cas présent. Commencez donc à lire cette doc à partir du mot « postfix anti-spam settings: ». A peu près au milieu.
Vous verrez passer dans les chapitres qui suivent cet endroit quelques paramètres importants sur le comportement des différents outils, les destinataires des notifications de mails vérolés etc, quelques optimisations sur les niveaux de spam acceptables etc. Mon article reprend certaines de ces suggestions et de ma propre expérience.
Cette doc va aussi plus loin : installation de DCC (Distributed Checksum Clearinghouses) et des outils de statistiques. Je n’en parle pas (pour l’instant), on verra avec des articles ultérieurs.

Bon, allez, on installe tout ça.

Installation des logiciels

aptitude install clamav clamav-daemon clamav-freshclam
aptitude install amavisd-new
aptitude install lha arj rar unrar nomarch lzop cabextract razor pyzor p7zip-full pax zip unzip lha zoo

Certains des paquets ici sont discutables, pour les pros du ça-pue-c-est-pas-libre-(tm). Moi je veux simplement analyser un maximum de contenu de mails, pièces jointes en format moins courants y compris.
Les outils type « décompression » serviront à ClamAV pour analyser les contenus de pièces jointes.

Les parties postfix, postgrey, spamassassin et les Maildir sont déjà expliqués dans mes docs/blog à différents endroits.
Deux nuances tout de même :
Je suppose enfin que votre spamassassin est en mode daemon (donc « spamd » tourne) car vous avez mis à 1 le paramètre ENABLED dans /etc/default/spamassassin.
Par rapport à ce que j’explique sur procmail, j’ai opté pour une conf standard pour tous dans /etc/procmailrc plutôt que dans chaque ~/.procmailrc.

Paramétrage de base

Configuration postfix <=> amavis

D’abord, on configure un canal de communication postfix => amavis en mode SMTP et pas LMTP (voir le /usr/share/doc/amavisd-new/README.postfix.gz). J’ajoute à la fin de /etc/postfix/master.cf des lignes suivantes :

amavisfeed unix    -       -       n       -       2     smtp
     -o smtp_data_done_timeout=1200
     -o smtp_send_xforward_command=yes
     -o smtp_tls_note_starttls_offer=no

Le nom « amavisfeed » est libre. Mais c’est le nom du tuyau que vous venez de créer. Il faudra utiliser ce nom plus bas (dans main.cf)

Puis le canal retour (message reinjection), toujours à la fin de /etc/postfix/master.cf :

127.0.0.1:10025 inet n    -       n       -       -     smtpd
     -o content_filter=
     -o smtpd_delay_reject=no
     -o smtpd_client_restrictions=permit_mynetworks,reject
     -o smtpd_helo_restrictions=
     -o smtpd_sender_restrictions=
     -o smtpd_recipient_restrictions=permit_mynetworks,reject
     -o smtpd_data_restrictions=reject_unauth_pipelining
     -o smtpd_end_of_data_restrictions=
     -o smtpd_restriction_classes=
     -o mynetworks=127.0.0.0/8
     -o smtpd_error_sleep_time=0
     -o smtpd_soft_error_limit=1001
     -o smtpd_hard_error_limit=1000
     -o smtpd_client_connection_count_limit=0
     -o smtpd_client_connection_rate_limit=0
     -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks,no_milters
     -o local_header_rewrite_clients=
     -o smtpd_milters=
     -o local_recipient_maps=
     -o relay_recipient_maps=

Enfin, on active le tuyau postfix => amavisd-new pour permettre l’analyse : (pas de tri, on balance tout ; on pourrait restreindre par domaine, adresse émettrice etc). C’est dans /etc/postfix/main.cf :

content_filter=amavisfeed:[127.0.0.1]:10024


Dans cette configuration par défaut, il faut que les ports 10024 et 10025 (localement) soient libres. Les paramètres sont décrits dans la doc en .gz mentionnée ci-dessus. L’idée, en gros, est de créer un autre serveur SMTP, local uniquement sur le port 10024, avec une conf postfix indépendante et vierge – en gros – car on sait que les messages arrivant là seront passés par amavis, donc ils seront propres/nettoyés. Cette seconde instance postfix sera la porte d’entrée pour les retours d’amavisd-new.

Tests des briques de la communication postfix <=> amavisd-new

Là, on peut tenter un /etc/init.d/postfix reload.

Ecoute de amavis

Le 10024 répondait déjà (car c’est le port d’écoute de amavis, lancé depuis qu’on l’a installé) :

# telnet localhost 10024
Trying 127.0.0.1...
Connected to localhost.localdomain.
Escape character is '^]'.
220 [127.0.0.1] ESMTP amavisd-new service ready

Ecoute du 2è postfix (la voie de retour d’amavis)

Le port 10025 ne fonctionne qu’après la conf dans master.cf et un postfix reload :

# telnet localhost 10025
Trying 127.0.0.1...
Connected to localhost.localdomain.
Escape character is '^]'.
220 srv.net ESMTP Postfix (Debian/GNU)

Tests des décodeurs de pièces jointes

On peut voir les « décodeurs » qu’il manque dans /var/log/mail.log.

/var/log/mail.log:Aug 25 17:18:21 srv amavis[28164]: No decoder for       .lha

Dans le cas ci-dessus, on peut conclure que le paquet lha n’est pas installé.
Attention, la doc dit quelque part de se méfier des décodeurs pour analyse des TNEF. Vous risquez de perdre les mails écrits en RTF par Outlook-le-casse-couipied.

Test du retour de mails

On teste un envoi de mail à amavis, et donc le retour :

# telnet localhost 10024
Trying 127.0.0.1...
Connected to localhost.localdomain.
Escape character is '^]'.
220 [127.0.0.1] ESMTP amavisd-new service ready
helo localhost
250 [127.0.0.1]
mail from: <>
250 2.1.0 Sender <> OK
rcpt to: 
250 2.1.5 Recipient  OK
data
354 End data with .
From: virus-tester
To: undisclosed-recipients:;
Subject: amavisd test - simple - no spam test pattern

 This is a simple test message from the amavisd-new test-messages.
.
250 2.0.0 Ok, id=28165-03, from MTA([127.0.0.1]:10025): 250 2.0.0 Ok: queued as 5FD7D9C4057
quit
221 2.0.0 [127.0.0.1] amavisd-new closing transmission channel
Connection closed by foreign host.

Résultats dans /var/log/mail.log (le retour à postfix prend quelques secondes) :

# tail /var/log/mail.log
Aug 27 11:37:43 srv postfix/smtpd[681]: connect from localhost.localdomain[127.0.0.1]
Aug 27 11:37:43 srv postfix/smtpd[681]: 5FD7D9C4057: client=localhost.localdomain[127.0.0.1]
Aug 27 11:37:43 srv postfix/cleanup[683]: 5FD7D9C4057: message-id=<20090827093743.5FD7D9C4057@srv.net>
Aug 27 11:37:43 srv postfix/qmgr[30259]: 5FD7D9C4057: from=<>, size=724, nrcpt=1 (queue active)
Aug 27 11:37:43 srv amavis[28165]: (28165-03) Passed BAD-HEADER, <> -> , quarantine: 5/badh-5kHJ7I-xUr2T, mail_id: 5kHJ7I-xUr2T, Hits: -, size: 175, queued_as: 5FD7D9C4057, 81992 ms
Aug 27 11:38:39 srv postfix/local[684]: 5FD7D9C4057: to=, orig_to=, relay=local, delay=56, delays=0.14/0/0/56, dsn=2.0.0, status=sent (delivered to command: /usr/bin/procmail -a "$EXTENSION")
Aug 27 11:38:39 srv postfix/qmgr[30259]: 5FD7D9C4057: removed

Activation de l’appel amavisd-new <=> ClamAV+Spamassassin

Enlevez les commentaires, c’est tout

C’est expliqué ici : /usr/share/doc/amavisd-new/README.Debian.
Comme d’hab, les fichiers de conf pré-machés par Debian sont très bien et attention à ne pas tenir trop compte de documentation de bidouilleurs qui paramètrent tout ça à la sauce pas-très-Debian.
D’après le README cité ci-dessus, la conf s’active dans /etc/amavis/conf.d/15-content_filter_mode. Il suffit de décommenter les 4 lignes suivantes dans /etc/amavis/conf.d/15-content_filter_mode : (2 pour ClamAV, 2 pour spamassassin)

@bypass_virus_checks_maps = (
   \%bypass_virus_checks, \@bypass_virus_checks_acl, \$bypass_virus_checks_re);
@bypass_spam_checks_maps = (
   \%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re);

En faisant celà, on active la conf définie dans les autres fichiers de /etc/amavis/conf.d/, exemple 15-av_scanners pour les anti-virus. Il s’agit là aussi de modèle de configuration standard de tout un tas d’outils connus (une bonne 15aine d’anti-virus dont NOD32, F-Prot, Grisoft, KAV, du symantec etc). Amavisd-new va donc charger les AV qu’il trouve. De même pour spamassassin.

Petit oubli pour ClamAV

On se paye une erreur :

Aug 27 16:03:09 mon_srv amavis[17143]: (17143-01) (!!)run_av (ClamAV-clamd) FAILED - unexpected , output="/var/lib/amavis/tmp/amavis-20090827T160309-17143/parts: lstat() failed: Permission denied. ERROR\n"
Aug 27 16:03:09 mon_srv amavis[17143]: (17143-01) (!!)ClamAV-clamd av-scanner FAILED: CODE(0x90a9148) unexpected , output="/var/lib/amavis/tmp/amavis-20090827T160309-17143/parts: lstat() failed: Permission denied. ERROR\n" at (eval 86) line 527.
Aug 27 16:03:09 mon_srv amavis[17143]: (17143-01) (!!)WARN: all primary virus scanners failed, considering backups

L’utilisateur clamav doit être dans le groupe amavis, on fait ce qui est dit dans le README.Debian de amavisd-new :

# adduser clamav amavis
Ajout de l'utilisateur « clamav » au groupe « amavis »...
Ajout de l'utilisateur clamav au groupe amavis
Terminé.

Et on contrôle le paramètre suivant dans la conf ClamAV : AllowSupplementaryGroups true. C’est déjà positionné dans le /etc/clamav/clamd.conf fraîchement dépaqueté. Vérifiez tout de même.
Et on redémarre ClamAV évidemment.

On peaufine certains paramètres

Destinataires des alertes

Pensez à bien ajuster les destinataires de « abuse », « postmaster » et « root » de votre serveur. Soit en modifiant les variables comme :

$virus_admin
$banned_admin
$mailfrom_notify_admin OU recip OU spamadmin
$hdrfrom_notify_sender

Soit en étant sûr que ces comptes par défaut (et obligatoires, surtout postmaster) font bien suivre les mails vers une adresse que vous lisez/survolez.

Voyez la doc mentionnée plus haut pour des suggestions à propos des variables $virus_admin & co.

Resctrictions de base de postfix

Je n’en parle pas trop, mais pensez à la conf de base de postfix, notamment votre paramètre smtpd_sender_restrictions dans /etc/postfix/main.cf.
Utilisez un service web quelconque sur Google pour valider que votre serveur n’est pas un open-relay.

Pièces jointes

Dans /etc/amavis/conf.d/20-debian_defaults, je suggère d’élargir la liste des pièces jointes interdites (par extension). Plus besoin de sanitizer, c’est intégré dans amavisd-new. Exemple :

### JACQUES
#  qr'.\.(exe|vbs|pif|scr|bat|cmd|com|cpl)$'i, # banned extension - basic
 qr'.\.(ade|adp|app|bas|bat|chm|cmd|com|cpl|crt|emf|exe|fxp|grp|hlp|hta|
        inf|ins|isp|js|jse|lnk|mda|mdb|mde|mdw|mdt|mdz|msc|msi|msp|mst|
        ops|pcd|pif|prg|reg|scr|sct|shb|shs|vb|vbe|vbs|
        wmf|wsc|wsf|wsh)$'ix,  # banned ext - long
###

# qr'.\.(mim|b64|bhx|hqx|xxe|uu|uue)$'i,  # banned extension - WinZip vulnerab.

  qr'^\.(exe-ms)$',                       # banned file(1) types
# qr'^\.(exe|lha|tnef|cab|dll)$',         # banned file(1) types
### JACQUES
  qr'^\.(exe|lha|cab|dll)$', # OK pour TNEF, merci outlook
###

Comportement lors de détection de spam

EDIT 08/10/2009. Quelques variables importantes à positionner (écraser par rapport à la conf par défaut) :

[...]
serveur:/etc/amavis/conf.d# cat 50-user
$final_spam_destiny = D_DISCARD; # pour eviter de renvoyer des notifications inutiles a des zombies
$sa_tag_level_deflt  = undef; # pour toujours avoir le tag dans les headers, même si c'est pas du spam
$sa_tag2_level_deflt = 5.0; # d'habitude je mets 5, na !
$sa_kill_level_deflt = 12.0; # d'experience, a 10 on est deja bien bien sur que c'est du spam
[...]

Enfin, j’avais oublié un point important, la variable « @local_domains_acl ». Elle défini la liste des domaines sur lesquels spamassassin va intervenir. Les domaines non listés ici ne sont tout simplement pas pris en compte, donc pas analysés, donc pas « flaggés »…
Je ne l’avais pas vu au début car avec un seul domaine qui est le nom de la machine etc, tout va bien avec le choix par défaut de Debian dans 05-domain_id:@local_domains_acl = ( ".$mydomain" );.
Là où ça se complique, c’est quand vous gérez plusieurs domaines, suivant comment votre bousin est défini. Par exemple avec des domaines virtuels, gérés en base de données, c’est mort (prochain article à venir sur la gestion de domaines et d’utilisateurs virtuels).
J’ai donc forcé cette variable dans le fichier /etc/amavis/conf.d/50-user :

@local_domains_acl = ( ".maboite.fr", "un.autre.alias.net" );

A noter que là, je prends en charge les éventuels sous-domaines « toto.maboite.fr » (c’est voulu, grâce au point devant « maboite ») et uniquement « un.autre.alias.net », mais pas un domaine de mails qui s’appellerait « encore.un.autre.alias.net ». Pigé ?

Quarantaine

Où doivent aller les mails vérolés ? Par défaut, je suggère de ne rien toucher au paramètre $virus_quarantine_to, ainsi les mails vérolés vont dans une arborescence de /var/lib/amavis/virusmails. Jetez-y un oeil une fois des tests de détection effectués (voir ci-dessous, dernier chapitre).
Et documentez vous sur amavisd-release.

Décodeurs, suite et fin

Dans /etc/amavis/conf.d/01-debian, jouez avec les variables $unrar et autres qui vous intéressent (oui oui, unrar c’est pas libre, tout ça, installez le paquet vrms). Il vous faut les applications correspondantes. Voyez le log /var/log/mail.log pour savoir ce qu’il manque par rapport à votre conf.

spamassassin

If you use spamassassin with the Bayes database system, you should make sure
that the spamassassin configuration option « bayes_auto_expire 0 » is set in
spamassassin configure files. This disables the automatic expiration of tokens
which causes problems for amavisd-new when activated. The amavisd-new package
includes cron jobs that take care of syncing and expiring the token database
frequently.

Je ne mesure pas trop l’impact, à vrai dire, mais je suppose qu’il vaut mieux le faire, donc ajoutez bayes_auto_expire 0 dans la conf /etc/spamassassin/local.cf.

Mise à jour de l’anti-virus

Le programme freshclam est planifié automatiquement lors de l’installation de ClamAV. Vous pouvez contrôler sa bonne exécution (il tourne une fois par heure) dans :

srv:/etc# tail /var/log/clamav/freshclam.log
Received signal: wake up
ClamAV update process started at Thu Sep 10 15:25:18 2009
main.cvd is up to date (version: 51, sigs: 545035, f-level: 42, builder: sven)
daily.cld is up to date (version: 9791, sigs: 77548, f-level: 43, builder: guitar)
--------------------------------------
Received signal: wake up
ClamAV update process started at Thu Sep 10 16:25:18 2009
main.cvd is up to date (version: 51, sigs: 545035, f-level: 42, builder: sven)
daily.cld is up to date (version: 9791, sigs: 77548, f-level: 43, builder: guitar)
--------------------------------------

Testez avec EICAR

EICAR est un virus inoffensif. Essayez de vous envoyer des mails avec différentes pièces jointes fournies ici : http://securite-informatique.info/virus/eicar/. Vous validerez ainsi la réaction de votre serveur.
J’ai eu une erreur dans le mail.info lors de la détection du virus. Le serveur tente d’informer l’admin des virus, mais avec une légère erreur de syntaxe sur l’expéditeur :

Sep 21 15:33:37 ns305192 postfix/smtpd[20381]: warning: Illegal address syntax from localhost.localdomain[127.0.0.1] in MAIL command: 

J’ai alors modifié la liste des expéditeurs de mails d’alertes. Dans le fichier /etc/amavis/conf.d/50-user :

$mailfrom_notify_admin='postmaster@chezmoi.fr';
$mailfrom_notify_recip='postmaster@chezmoi.fr';
$mailfrom_notify_spamadmin='postmaster@chezmoi.fr';
$mailfrom_to_quarantine='postmaster@chezmoi.fr';

J’ai trouvé la liste de toutes les adresses émettrices d’alertes sur ce site : http://www.radical-spam.org/documentations/amavisd-new.html. Il y a de belles explications sur les modèles de mails et d’autres trucs. Bref, à survoler.
Je n’ai pas trouvé comme pour postfix une commande permettant de voir les variables en mémoire d’amavisd-new. Si ça existe, je suis preneur.



Voilà. Je crois qu’une fois tout ceci fait, votre serveur est paré à en prendre plein la tête.
Pensez à des outils genre mailgraph, surveillez vos logs, surtout au début.

14 comments

  1. Ping : Nicolas Hennion (nicolargo) 's status on Tuesday, 22-Sep-09 11:12:20 UTC - Identi.ca
  2. Ping : Julien [Esprit-Libre] (espritlibre) 's status on Tuesday, 22-Sep-09 11:16:33 UTC - Identi.ca
  3. hello,
    c’est possible d’avoir une version pdf pour ce genre d’article s’il te plait ?
    merci d’avance 😉

    (bah oui, internet n’est pas partout, mais j’aime bien avoir de la lecture ^^)

  4. Une impression vers une imprimante virtuelle PDF ne ferait-elle pas l’affaire ?
    Ça doit être natif sur un ubuntu et possible sur Windows avec pdfcreator
    quant a un CSS qui va bien de mon coté pour bien présenter la page, désole je fais le minimum syndical en CSS :/

  5. Modification du chapitre « Comportement lors de détection de spam » ; j’ai oublié un détail qui faisait que spamassassin n’en fout pas une ramée si on ne lui indique pas clairement la liste des domaines qu’il doit gérer.

    J’ai vu ça en refaisant quelques tests et en prévision d’un prochain article où je mélangerai les domaines virtuels (en MySQL) et les domaines « normaux », dirais-je.

    => Variable @local_domains_acl

  6. J’ajouterai qu’un p’tit SQLGrey est pas mal, surtout lorsque l’on utilise plusieurs serveurs « en front ». Aprés, pour clamAv, bien faire attention de prendre la version Clamd (daemon) et pas ClamAv (la version Perl) super gourmande en ressource.. Ah oui, j’oubliais.. Excellent article. 😉

  7. Merci pour les explications éclairées.

    Dans la partie : Installation des logiciels
    deux fois le paquet lha dans la troisième commande aptitude install

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.