Postfix nirvana – Parte I

Questa è la prima parte della guida, e tratta delle impostazioni di base di Postfix. Nella seconda parte verranno affrontati i programmi accessori.

Questo documento, scritto a quattro mani con Manuel, spiega come configurare un server di posta in modo da avere nel proprio sistema utenti, sia reali sia virtuali, che possono accedere tramite interfaccia web alle loro caselle e-mail, con protezione da virus, worm e spam.

Per utente virtuale si intende qualcuno che non ha un account fisico sulla macchina (non c’è alcun suo riferimento nel file /etc/passwd) ed esiste solo per il sistema di posta. La gestione di questi utente avviene tramite interfaccia web e i loro dati sono registrati su un database SQL.

I mezzi scelti per conseguire lo scopo sono:

Per questa installazione ho inoltre utilizzato:

la cui configurazione va però oltre gli scopi di questo howto. Tutti questi software sono stati installati partendo dai pacchetti offerti dalla distribuzione Debian Etch. Le principali fonti di ispirazione sono stati un howto precedentemente scritto da Manuel, Howtoforge, i wiki di Dovecot, Horde, Debian e Debian Administration.

Postfix: configurazione di base

Prima di procedere all’installazione di Postfix occorre assicurarsi che la propria macchina sia FQDN, cioè abbia un nome corretto (per intenderci, al comando hostname deve rispondere qualsiasi cosa che non sia localhost o localhost.localdomain). Per questo occorre impostare il nome macchina e settare il file /etc/hosts correttamente.

I principali file di configurazione sono due: main.cf in cui stanno tutti i parametri della parte MTA e master.cf in cui stanno i parametri del demone, ed entrambi si trovano in /etc/postfix.

Il main.cf ha moltissime opzioni (potete trovare qui un elenco completo); vediamo le più importanti (che vanno modificate rispetto al default):

# questa sezione riguarda le mail 'rimbalzate' :
# si specifica cosa notificare e a quale account

soft_bounce = no
notify_classes = resource, software, bounce, policy, protocol
2bounce_notice_recipient = postmaster

myhostname = nomemacchina.nomedominio
mydomain = nomedominio

# qui si dice a postfix da quali interfacce
# accettare posta

inet_interfaces = all

# myorigin è il dominio che viene aggiunto alle mail inviate
# dagli utenti locali, mentre mydestination è l'elenco dei
# domini che postfix identifica come locali. NON vanno
# elencati qui i domini virtuali.

myorigin = $myhostname
mydestination = $myhostname

# mynetworks è importantissimo: si deve settare in maniera
# corretta altrimenti si può diventare degli open-relay: in
# questa situazione chiunque da internet può usare il nostro
# postfix per inviare posta e si rischia la blacklist
# (e quindi essere di fatto tagliati fuori in partenza)
# un buon test di open-relay sul proprio MTA è questo:
# $telnet relay-test.mail-abuse.org

mynetworks = 127.0.0.0/8, ip.della.rete
relay_domains = $mydestination

# qui abbiamo indicato alcune 'mappe' necessarie per il
# funzionamento dell' MTA. Si noti che hash: indica che
# quella mappa deve essere messa sotto forma di
# database Berkeley (vedremo poi come).

alias_maps = hash:/etc/postfix/aliases
alias_database = hash:/etc/postfix/aliases
sender_canonical_maps = hash:/etc/postfix/sender_canonical

per ora il master.cf non va toccato.

Sono da controllare anche il file aliases e il sender_canonical.

Nel file aliases ci sono i riferimenti ai vari utenti e serve per decidere chi è il destinatario delle mail: va modificato specificando a chi va recapitata la posta di root, solitamente l’utente di ‘manutenzione’ che utilizzate nel vostro sistema (non usate root per queste cose, vero?). Ad ogni modifica del file aliases deve seguire il comando:

# postalias /etc/postfix/aliases

per aggiornare il database aliases, che viene scritto nel file aliases.db.

Attenzione perché può esistere anche un file /etc/aliases: è quello che utilizza sendmail, e per il nostro sistema di posta non serve (ogni modifica a quel file risulta ininfluente).

Il sender_canonical invece serve per tradurre gli account degli utenti locali in indirizzi di posta elettronica. Una volta modificato occorre dare:

# postmap /etc/postfix/sender_canonical

se tutto è ok si può far partire postfix e testarlo con:

# telnet 127.0.0.1 25
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
220  ESMTP Postfix

Amavisd-new, Spamassassin, ClamAV

La configurazione che ho effettuato fino ad ora è sufficiente per un valido, robusto e sicuro sistema di posta. Purtroppo però si sente sempre più l’esigenza di proteggere da virus e spam gli utenti: in prima battuta non ci si pensa, ma se un nostro cliente ha un virus che invia mail a raffica la cosa si ripercuote anche su di noi, sovraccaricando il nostro MTA e rischiando di farlo finire in qualche black-list da cui è poi difficile uscire…

Amavisd-new è una delle versioni demone di amavis-perl; gli aspetti più interessanti sono:
– un’ottima integrazione con postfix
– può utilizzare diversi software antivirus (anche più di uno sulla stessa macchina)
– può invocare direttamente spamd (il demone di spamassassin) e

Sia Spamassassin che ClamAV devono essere costantemente aggiornati per essere efficaci, cosa che non è sempre garantita con i repository di Debian. Per questa ragione è consigliabile scaricarli dai repository di volatile, aggiungendo a /etc/apt/sources.list la riga:

deb http://ftp2.de.debian.org/debian-volatile sarge/volatile main

per installare il tutto eseguo da riga di comando:

# apt-get update
# apt-get install amavisd-new spamassassin clamav clamav-daemon clamav-freshclam zoo unzip bzip2 unzoo nomarch lzop pax

Passo quindi alla configurazione. È necessario abilitare ClamAV e Spamassassin in /etc/amavis/conf.d/15-content_filter_mode, che dovrà avere questo aspetto:

use strict;

# You can modify this file to re-enable SPAM checking
# through spamassassin and to re-enable antivirus checking.

#
# Default antivirus checking mode
# Uncomment the two lines below to enable it back
#

@bypass_virus_checks_maps = (
   \%bypass_virus_checks, \@bypass_virus_checks_acl, \$bypass_virus_checks_re);

#
# Default SPAM checking mode
# Uncomment the two lines below to enable it back
#

@bypass_spam_checks_maps = (
   \%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re);
1;  # ensure a defined return

ed è consigliabile aggiungere la riga

$pax='pax';

nel file /etc/amavis/conf.d/50-user. Normalmente le impostazioni di default contenute in /etc/amavis/conf.d/20-debian_defaults non devono essere modificate. Riavvio i demoni con:

/etc/init.d/amavis restart
/etc/init.d/clamav-daemon restart
/etc/init.d/clamav-freshclam restart

e posso proseguire nella configurazione di Postfix. Per fare in modo che le mail vengano inoltrate al demone di amavisd-new aggiungo le seguenti righe a /etc/postfix/main.cf:

content_filter = amavis:[127.0.0.1]:10024
receive_override_options = no_address_mappings

e poi aggiungo le seguenti in /etc/postfix/master.cf:

amavis unix - - - - 2 smtp
        -o smtp_data_done_timeout=1200
        -o smtp_send_xforward_command=yes

127.0.0.1:10025 inet n - - - - smtpd
        -o content_filter=
        -o local_recipient_maps=
        -o relay_recipient_maps=
        -o smtpd_restriction_classes=
        -o smtpd_client_restrictions=
        -o smtpd_helo_restrictions=
        -o smtpd_sender_restrictions=
        -o smtpd_recipient_restrictions=permit_mynetworks,reject
        -o mynetworks=127.0.0.0/8
        -o strict_rfc821_envelopes=yes
        -o receive_override_options=\
        no_unknown_recipient_checks,no_header_body_checks
        -o smtpd_bind_address=127.0.0.1

Faccio ripartire postfix e con “netstat -tap” vedo Postfix (master) in ascolto sulle porte 25 (smtp) e 10025 e amavisd-new sulla porta 10024. Dopo aver spedito o ricevuto alcune e-mail posso verificare il funzionamento di tutto nei log.

ClamAV non ha solitamente bisogno di alcuna impostazione particolare. Il demone freshclam provvederà a tenere sempre aggiornato il database dei virus. Debian durante l’installazione crea già gli utenti e i gruppi necessari. Sarà sufficiente aggiungere l’utente clamav al gruppo amavis e riavviare i demoni con i comandi:

# adduser clamav amavis
# /etc/init.d/amavis restart
# /etc/init.d/clamav-daemon restart
# /etc/init.d/clamav-freshclam restart

Spamassassin è un software scritto in Perl in grado di identificare e bloccare la posta indesiderata (chiamata spam, UCE – unsollicited commercial e-mail oppure anche UBE – unsollicited bulk e-mail) con una buona accuratezza tramite una serie di test euristici sugli headers e sul corpo della mail.

Come impostazioni di base, è richiesto a Spamassassin di raggiungere un punteggio pari a 6.3 per identificare la mail come spam; io ho abbassato la soglia fino a 5 impostando in /etc/spamassassin/local.cf:

required_score           5.0

e fino ad ora non mi è mai capitato che abbia bloccato una mail che non fosse spam, ed ha lasciato passare alcune e-mail che invece lo erano. Ovviamente non si può garantire un’ accuratezza del 100% perché si rischierebbe di stringere troppo i controlli ed avere troppi falsi positivi.

A questo punto per Debian modifico il file /etc/default/spamassassin con:

ENABLED=1

Ed avvio il demone:

# /etc/init.d/spamassassin start

Una delle caratteristiche più utili di Spamassassin sono i filtri “bayesiani” che filtrano le mail sulla base di sequenze di caratteri che compaiono spesso nello spam, e che vengono abilitati in /etc/spamassassin/local.cf dalle righe:

# Enable the Bayes system
use_bayes               1

bayes_path /var/lib/amavis/.spamassassin/bayes

# Enable Bayes auto-learning
bayes_auto_learn              1

la seconda riga dice dove si trova il database, l’indirizzo è quello della configurazione standard di Debian, e l’ultima attiva l’autoapprendimento, che inizierà al riavvio Spamassassin. Per fargli apprendere più velocemente è possibile dargli in pasto delle directory contenenti spam o mail “pulite”, loggandosi come utente amavis e dando i comandi:

sa-learn --spam -C /var/lib/amavis/.spamassassin/ --showdots [directorySPAM]
sa-learn --ham -C /var/lib/amavis/.spamassassin/ --showdots [directoryHAM]

Per tenere le regole sempre aggiornate posso scaricare periodicamente i file configurazione (rules, scores, etc.) inserendo in crontab una riga tipo:

0 4 * * * sa-update && /etc/init.d/spamd restart

È anche possibile aggiungere a Spamassassin moduli come Razor2, Pyzor, DCC, ma questo va un poco oltre lo scopo di questo howto, quindi vi rimando alla documentazione specifica.

Postgrey

I filtri tipo greylist sono uno dei recenti metodi di lotta allo SPAM, e si basano sul fatto che la maggior parte degli spammer inviano i messaggi attraverso server che non gestiscono una coda per la ritrasmissione dei messaggi falliti. Quando una mail viene ricevuta per la prima volta viene registrata la tripletta server/mittente/destinatario e viene respinta con un messaggio 450 di errore temporaneo. I server di cui sopra non riproveranno, mentre un server regolare dovrebbe riprovare l’invio dopo qualche minuto, quando il nostro server, dopo aver verificato la tripletta, lo accetterà. Questo provoca un ritardo nella ricezione di tutte le e-mail, ma evita la ricezione di gran parte dello spam.

Debian mette a disposizione Posgrey, che implementa una greylist in Postfix. L’installazione si esegue come sempre con:

# apt-get install postgrey

dopo l’installazione dovreste avere il demone in ascolto sulla porta 60000, come potete verificare con:

# netstat -anp | grep 60000
tcp        0      0 127.0.0.1:60000         0.0.0.0:*               LISTEN     18478/postgrey.pid

Per fare in modo che Postfix usi il demone bisogna aggiungere la seguente riga in /etc/postfix/main.cf, sotto a “smtpd_recipient_restrictions”:

check_policy_service inet:127.0.0.1:60000

Controllando il log dovreste vedere il tutto funzionare.

Postfix e i suoi controlli anti-UCE

Postfix prevede la possibilità di effettuare un certo numero di test sulle mail in transito: è possibile controllare gli headers e il corpo del messaggio, mittenti e i destinatari, parti mime ed allegati. Lo svantaggio è che tutto questo causa un forte appesantimento del sistema di posta, e l’accuratezza non è molto elevata (c’è il rischio di avere molti falsi positivi e falsi negativi).

Nel main.cf possiamo specificare questi controlli (che sono una piccola parte rispetto a quelli disponibili):

# vengono specificate le tavole con cui confrontare le mail
# in transito. Se sul vostro sistema è installato pcre è
# consigliabile utilizzare questo al posto delle regexp per
# questioni di velocità.
#header_checks = regexp:/etc/postfix/header_checks
#body_checks = regexp:/etc/postfix/body_checks
header_checks = pcre:/etc/postfix/header_checks
body_checks = pcre:/etc/postfix/body_checks

# si controlla la parte mime degli headers del messaggio
#mime_header_checks = regexp:/etc/postfix/mime_header_checks
mime_header_checks = pcre:/etc/postfix/mime_header_checks

# si richiede che chi si collega al nostro server smtp
# invii un helo/ehlo (alcuni spammer non lo fanno...)
smtpd_helo_required = yes

# il controllo lo si può fare sul mittente, sul destinatario
# o sul recipient (che è l'ultimo ad essere specificato
# nella mail) è preferibile fare il controllo sul recipient e
# non sul sender per poter avere il maggior numero di
# informazioni sulla mail che viene bloccata e’ anche
# possibile inserire, tra i vari server che mantengono le
# black-list, la riga reject_rbl_client dnsbl.sorbs.net,
# Il problema e’ che in questo database sono elencati
# alcuni server smtp italiani molto usati, tra i quali quello
# di libero ed alcuni di telecom italia...
#smtpd_client_restrictions =
#smtpd_sender_restrictions =
smtpd_recipient_restrictions =  permit_mynetworks,
                                check_sender_access hash:/etc/postfix/access,
                                check_recipient_access hash:/etc/postfix/access,
                                check_client_access hash:/etc/postfix/access,
                                reject_invalid_hostname,
                                reject_non_fqdn_sender,
                                reject_unknown_sender_domain,
                                reject_unauth_destination,
                                reject_rhsbl_client blackhole.securitysage.com,
                                reject_rhsbl_sender blackhole.securitysage.com,
                                reject_rbl_client bl.spamcop.net,
                                reject_rbl_client l1.spews.dnsbl.sorbs.net,
                                reject_rbl_client dul.spews.dnsbl.sorbs.net,
                                reject_rbl_client sbl-xbl.spamhaus.org,
                                reject_rbl_client combined.njabl.org

# non è esattamente un controllo anti-UCE, ma se ci sono
# utenti non più attivi che ricevono e-mail valide può essere
# utile avvisare il mittente che l’indirizzo non è più
# valido, ed eventualmente comunicare il nuovo indirizzo.
relocated_maps = hash:/etc/postfix/relocated

Vediamo più da vicino queste mappe (e come si compilano): alcune sono di tipo hash ed altre di tipo pcre (o regexp). Per quelle di tipo hash occorre dare il comando postmap prima di riavviare postfix per aggiornare il database, mentre per le altre basta solamente riavviare il demone postfix.

/etc/postfix/body_checks (pcre o regexp)

la forma in cui devono essere messe le regole è:

/pattern/      AZIONE	MOTIVAZIONE

Tra pattern, azione e motivazione ci deve essere almeno uno spazio; per questioni di chiarezza visiva mi piace impaginare il file utilizzando vari [tab] in maniera da avere tutto incolonnato.

Un esempio di body_checks è:

# il testo che vogliamo intercettare va messo tra / /, e può
# contenere spazi. La clausola REJECT indica il rifiuto del
# messaggio (ce ne sono altre: OK, WARN, ecc..)
# [A10] è un codice univoco che utilizzo io per capire quale
# testo ha causato il rifiuto del messaggio (utile ad
# esempio per testare le regole) il mittente riceverà in
# questo caso un messaggio di bounce con la motivazione:
# [A10] Your email had spam-like body contents.
# Si può leggere il file sample-pcre-body.cf.

/sono spammer/ 	REJECT [A10] Your email had spam-like body contents.

si può anche andare sul complicato utilizzando le espressioni regolari:

# così io impedisco il recapito di mail con allegati dei file aventi
# estensioni che fanno supporre  la presenza di virus; come visto
# prima si può mettere un testo dopo il reject che spiega la
# motivazione e suggerisce di zippare l'allegato per poterlo inviare.

/name=".*\.(com|exe|bat|cmd)"/            REJECT [1] Filetype not permitted, please ZIP them
/name=".*\.(hta|vb[esx]|wsf|wsh|js|jse)"/ REJECT [2] Filetype not permitted, please ZIP them
/name=".*\.(shb|shs|lnk|chm|pif|scr)"/    REJECT [3] Possible virus attachment
/^TVqQAAMAAAAEAAAA\/\/8AALgAAAAAAAAAQAAA/ REJECT [4] Possible virus attachment

/etc/postfix/header_checks (pcre o regexp)

la forma è la medesima di body_ckecks, ma in questo caso dobbiamo specificare gli headers:

# si lavora ad esempio sul programma con cui è stata creata
# la mail, sul soggetto, ma ci si può sbizzarrire...

/^X-Mailer: Floodgate/  REJECT [A19] Spam-like header contents.
/^Subject: .*Super Viagra/  	REJECT [B09] Spam-like Subject.

# possiamo anche bloccare mittenti e destinatari, in modo molto
# similare a quel che fa /etc/postfix/access
# per maggiori informazioni si veda il file sample-pcre-header.cf

/^From:.*utente@dominio*$/      	REJECT This account sends spam.
/^To:.*utente@dominio.locale*$/ 	REJECT This account isn't active.

/etc/postfix/mime_header_checks (pcre o regexp)

è una tavola specifica per le estensioni mime, che possono sfuggire ai controlli sul body e sugli headers; la sintassi è del tutto simile ai due file precedenti.
Io utilizzo clausole molto simili a questa:

# blocco i file .pif (e allo stesso modo qualsiasi file con
# estensione pericolosa).

/name=[^>]*\.pif/ 			REJECT Files .pif may contain viruses.

/etc/postfix/access (hash)

Come detto, serve specificamente per intercettare mittenti o destinatari indesiderati.
La sintassi prevede 3 categorie su cui effettuare i confronti: un utente ben determinato, un certo utente di qualsiasi dominio o tutti gli utenti di un certo dominio.

Ad esempio:

# occorre specificare il codice e la risposta che postfix restituisce
# al mittente. Nei primi due casi andiamo in match su indirizzi e-mail
# completi nel terzo esempio il confronto lo si fa sull’utente e nel
# quarto sul dominio per altre informazioni man 5 access
# oppure sample-pcre-access.cf

utente1@dominio1  			550 You are a spammer!
pippo@dominio2				550 This account is no longer active
utente@      				550 Your email comes from a blacklisted address
dominio      				550 Your email comes from a blacklisted domain

Il file access e’ anche importante per effettuare delle whitelist sugli indirizzi da accettare, anche se provengono da utenti, domini o indirizzi IP elencati in qualche black-list.

In particolare dobbiamo, nel rispetto delle RFC, accettare qualsiasi cosa indirizzato alla casella postmaster ed eventualmente alla abuse.

Quindi inseriamo:

postmaster@miodominio		OK
abuse@miodominio		OK

Se qualche nostro utente vuole ricevere posta da utenti in BL, possiamo elencare qui i mittenti specifici o l’intero dominio di appartenenza:

utente@dominioinbl		OK
dominioinbl			OK

Continua...