Capitolo 5. Servizi di posta

Si è detto nell'introduzione che uno degli obbiettivi principali da realizzare era la suddivisione delle mailbox (e quindi dei servizi correlati, SMTP, IMAP, webmail) sulle N macchine. Fortunatamente il protocollo SMTP e soprattutto la flessibilità della configurazione di Postfix permettono di implementare quanto voluto senza troppe complicazioni.

La scelta fatta per la configurazione dei servizi SMTP, conseguentemente con le linee guida identificate al Capitolo 1, è stata questa:

  1. assegnare la posta di ciascun utente ad una sola delle N macchine (in modo intercambiabile ma univoco);

  2. avere tutte le N macchine come MX del dominio (o dei domini, che saranno probabilmente più di uno), con eguale probabilità, ed effettuare poi la redirezione interna al server di destinazione finale.

Essendo il database degli utenti replicato su tutte le macchine, ciascun server sa qual'è il server destinatario (finale) di un particolare indirizzo email, ed è quindi possibile costruire le tabelle di transport necessarie.

Flusso delle connessioni SMTP

La figura precedente illustra il percorso seguito, all'interno della nostra rete, dalle mail in arrivo. Anzitutto, il server SMTP remoto sceglie ogni volta casualmente un server MX tra quelli elencati con la stessa priorità, dunque il messaggio arriva su uno qualsiasi dei server. La figura mostra due dei percorsi possibili, corrispondenti al caso in cui il server sia quello che ospita la casella di posta (la destinazione finale della mail) oppure no. Nel primo caso il messaggio non viene ritrasmesso e raggiunge direttamente la maildir dell'utente; nell'altro caso invece viene rimessa in coda, instradata però verso il server di destinazione (attraverso la VPN). In entrambi i casi il messaggio viene sottoposto al controllo antispam un'unica volta.

In relazione al punto 2 qui sopra, si potrebbe considerare che questa soluzione possa non essere la migliore in termini di consumo di banda; e in effetti, facendo un rapido calcolo, in media la probabilità che un messaggio in arrivo su un server non sia destinato lì (e vada quindi ritrasmesso al server finale) è (N-1)/N, che tende a 1 con un certo numero di server[1]. Va però considerato che questa soluzione offre un'elevata resistenza alle interruzioni momentanee di rete, oltre a garantire la suddivisione delle mailbox, il che forse è un vantaggio sufficiente considerato anche che il traffico totale di mail non è particolarmente elevato (le statistiche attuali ci danno una media di 1 messaggio al secondo, con dei picchi di 10 nei momenti di maggiore traffico).

5.1. Configurazione di Postfix

Postfix è configurato, su ciascuna macchina, in modo da accettare la posta in arrivo per tutti gli utenti virtuali, consultando poi una opportuna tabella di transport che gli dirà se consegnare il messaggio localmente, oppure se instradarlo nuovamente verso la macchina di destinatazione finale.

Potendo effettuare l'instradamento finale attraverso la VPN ci si può anche risparmiare un'ulteriore negoziazione SSL tra i server medesimi. Anche la scansione antivirus può essere effettuata solo una volta, al momento della ricezione dall'esterno. Per questo si possono configurare due istanze differenti di smtpd che siano in ascolto sulle due interfacce, esterna e VPN, aggiungendo qualche riga in /etc/postfix/master.cf:

# smtp su interfaccia esterna
192.168.1.1:smtp inet    n   -   -   -   -   smtpd -o opzioni... 
# smtp sulla vpn
172.16.1.1:smtp inet     n   -   -   -   -   smtpd -o opzioni diverse...
    

e differenziando opportunamente le opzioni fornite. Per esempio, se il filtro antispam fosse abilitato in main.cf l'istanza sulla VPN potrebbe avere le seguenti opzioni, per disabilitare la crittazione TLS e il filtro antispam, e non ripetere due volte i controlli sul messaggio:

         -o smtpd_use_tls=no
         -o content_filter= 
         -o local_recipient_maps=
         -o smtpd_helo_restrictions=
         -o smtpd_client_restrictions=
         -o smtpd_sender_restrictions=
         -o smtpd_recipient_restrictions=permit_mynetworks,reject
         -o mynetworks=172.16.0.0/16
    

Un'altra possibilità è quella di avere due istanze di Postfix differenti (e dunque due serie di code differenti) per l'interno e l'esterno, duplicando /etc/postfix e /var/spool/postfix[2]. Lo schema rimane in ogni caso quello di un sistema a due livelli (o tre, se si vuole considerare anche l'antivirus che è un sottosistema SMTP autonomo), con il livello esterno incaricato di gestire la posta entrante e uscente, di effettuare il controllo degli indirizzi validi e dello spam, e di applicare tutti gli eventuali filtri, mentre il livello interno deve occuparsi solamente della delivery finale alla mailbox. La gestione speciale delle code di relay nelle ultime versioni di Postfix dovrebbe però garantire un buon throughput interno anche con un'unica istanza, perfino quando la coda esterna è intasata[3].

5.1.1. Mappe LDAP

Le mappe LDAP devono permettere il riconoscimento di tutti gli utenti virtuali (in local_recipient_maps), il loro instradamento verso il giusto server di replicazione (in transport_maps), infine la delivery alla mailbox corretta (virtual_mailbox_maps) e la risoluzione degli alias (virtual_alias_maps).

Vediamo come sono composte:

ldaptransport

in transport_maps - &(mail=%s)(objectClass=virtualMailUser)(!(host=server1)) -> host

questa mappa funziona perché sono definiti (in master.cf) dei transport SMTP con i nomi delle varie macchine e destinazioni hard-codate. Per esempio, il transport server1, presente su tutte le macchine tranne quella, sarà un transport SMTP con destinazione prefissata (server1-vpn), permettendo customizzazioni specifiche come la regolazione fine della concorrenza, TLS disabilitato, e altre ottimizzazioni. Naturalmente su "server1" le connessioni provenienti dalla VPN non avranno antivirus e antispam abilitati, così il controllo verrà fatto una volta sola.

ldaptransport_server_host = localhost
ldaptransport_server_port = 389
ldaptransport_scope = sub
ldaptransport_bind_dn = "cn=manager, o=anarchy"
ldaptransport_bind = no
ldaptransport_lookup_wildcards = no
ldaptransport_search_base = ou=People, dc=infra, dc=org, o=anarchy
ldaptransport_query_filter = (&(mail=%s)(!(host=amnistia)))
ldaptransport_result_attribute = host
ldaptransport_result_filter = relay:[%s-vpn]
	   

Qui è usata anche l'opzione result_filter, che permette di modificare il risultato della query LDAP dopo averla ricevuta dal server.

ldapmailbox

in virtual_mailbox_maps - &(mail=%s)(host=server1)(objectclass=virtualMailUser)(mailMessageStore=*) -> mailMessageStore

mappa degli indirizzi di posta verso la loro mailbox di destinazione. I path ritornati dalla query sono considerati relativi a /home/mail e generalmente comprendono una directory con il nome del dominio e una con il nome della casella.

ldapmailbox_server_host = localhost
ldapmailbox_server_port = 389
ldapmailbox_scope = sub
ldapmailbox_bind_dn = "cn=manager, o=anarchy"
ldapmailbox_bind = no
ldapmailbox_lookup_wildcards = no
ldapmailbox_search_base = ou=People, dc=infra, dc=org, o=anarchy 
ldapmailbox_query_filter = 
  (&(mail=%s)(objectclass=virtualMailUser)(mailMessageStore=*))
ldapmailbox_result_attribute = mailMessageStore 
	   

ldapalias

in virtual_alias_maps - &(mailAlternateAddress=%s)(objectclass=virtualMailUser) -> mail

mappa degli alias locali verso l'indirizzo email di destinazione finale.

ldapalias_bind_dn = cn=manager,o=anarchy
ldapalias_bind = no
ldapalias_search_base = ou=People, dc=infra, dc=org, o=anarchy 
ldapalias_query_filter = 
  (&(mailAlternateAddress=%s)(objectclass=virtualMailUser))
ldapalias_result_attribute = mail
ldapalias_lookup_wildcards = no
	   

5.1.2. Antispam/Antivirus

I servizi antispam sono molto semplici per il momento, anche se piuttosto efficaci. Su tutte le macchine che ricevono la posta è installato Postgrey, un sistema di greylisting: ogni messaggio che arriva per la prima volta (caratterizzato dalla tripletta server smtp / mittente / destinatario) viene respinto con un errore temporaneo che permane per 60 secondi. Dopo N messaggi consegnati con successo per una particolare tripletta, questa viene inserita nella whitelist così da evitare ulteriori controlli per un certo lasso di tempo. Per i server SMTP normali questo errore temporaneo non rappresenta un problema, il messaggio viene messo in coda e la consegna viene tentata di nuovo dopo poco tempo. Il meccanismo funziona perché la stragrande maggioranza dei virus e dei meccanismi usati dagli spammer non utilizzano un vero server SMTP e non hanno la possibilità di mantenere messaggi in coda, dunque generalmente non riprovano la consegna una seconda volta. Certo, dal punto di vista dell'utente questo significa che la consegna dei messaggi non è "immediata" ma richiede più tempo (si parla comunque di minuti), in ogni caso ci pare un buon compromesso, vista l'efficacia del greylisting.

Postgrey è installato come policy_service nell'istanza di Postfix che accetta posta dall'esterno (sull'IP pubblico):

  smtpd_recipient_restrictions = ...,
                    check_policy_service inet:127.0.0.1:60000,
                    ...
	

È da diverso tempo che usiamo Postgrey e non abbiamo riscontrato problemi di sorta, anzi, come protezione antispam è risultata (per il momento) molto efficace. È utile in ogni caso controllare /etc/postfix/whitelist_clients, ed eventualmente inserirvi i server di posta con cui si comunica più frequentemente, sia per velocizzare le consegne che per impedire che il database temporaneo di Postgrey cresca troppo di dimensione.

In aggiunta a questo, il meccanismo principale antispam è amavis-ng, che utilizziamo con la scansione antivirus disabilitata (che è eccessivamente pesante sulla CPU delle macchine, dato il traffico gestito) e che dunque è usato solamente come wrapper SMTP per il modulo di analisi di SpamAssassin. Si compensa parzialmente alla mancanza dell'antivirus con una serie di espressioni regolari da controllare nel corpo dei messaggi, implementate direttamente dentro Postfix in mime_header_checks e body_checks: queste regexp sono mantenute regolarmente da www.securitysage.com e contengono fingerprint dei virus più comuni, come anche molte altre regole utili per respingere buona parte dello spam prima ancora di dover inoltrare il messaggio ad Amavis.

Amavis è installato come content_filter nell'istanza di Postfix che accetta la posta dall'esterno (sull'IP pubblico), ed è configurato per inoltrare i messaggi approvati con successo al server di back-end (quello in ascolto su localhost).

Note

[1]

Si consiglia, come ulteriore elemento di riflessione, la lettura dell'articolo High Capacity Email (disponibile presso http://www.vergenet.net/linux/mail_farm/), che contiene anche utili considerazioni sulle misure migliori per ridistribuire il carico sui server pesando opportunamente mailbox con alto e basso traffico.

[2]

A questo proposito si può leggere la trattazione completa svolta su http://advosys.ca/papers/postfix-instance.html, e la documentazione ufficiale (per Postfix 2.1) presso http://www.postfix.org/FILTER_README.html

[3]

Si veda la discussione presente su http://www.postfix.org/ADDRESS_CLASS_README.html