Dovecot, Anbindung an einen Frontend-Mailserver (Postfix-SMTP-Server)
1. LMTP
In der Regel werden wir hinter unserem eigentlichen SMTP-Mailserver ein Backend System, eben unser Dovecot-Server, bereithalten, von welchem unsere User ihre elektronische Post abholen. Damit unser Mailserver Postfix, der die Nachrichten von fremden Mailserver annimmt, bewertet und prüft, auch an unser internes Postoffice weiterleiten kann, sind noch Ergänzungen an der Konfiguration des Postfix-Mailservers notwendig.
Egal ob nun unsere beiden Mailserverkomponenten auf getrennten Hosts oder auf einem Host laufen, der Konfigurationsaufwand für LMTP ist dabei fast identisch.
Dovecot (LMTP)
Konfiguration
Zur Anbindung des MUA1) Dovecot an unseren MTA2) Postfix nutzen wir das Protokoll LMTP. In der Konfigurationsdatei /etc/dovecot/conf.d/10-master.conf sind im Abschnitt service lmtp bereits verschiedene Dovecot-Listener enthalten.
Statt der vorbereiteten Variante über einen Unix-Datei-Socket, werden wir aber einen TCP/IP-Socket verwenden. Zum einen gibt es dabei keine großen Probleme in chroot-Umgebungen, bzw. können wir so recht einfach und schnell, den IMAP-Server von einem all-in-one-Host auf mehrere Maschinen aufteilen. Hierzu werden wir den LMTP-Port 24 auf eine eigene IP-Adresse binden, die der Postfix-Mailserver dann exclusiv ansprechen darf. Damit der LMTP-Port nicht von anderen Maschinen aus erreichbar ist, werden wir mit einer geeigneten firewalld-Regel, den Zugriff streng reglemetieren.
Als erstes werden wir nun die nötige LMTP-Konfiguration in der 10-master.conf festlegen.
# vim /etc/dovecot/conf.d/10-master.conf
- /etc/dovecot/conf.d/10-master.conf
... service lmtp { unix_listener lmtp { #mode = 0666 } # Create inet listener only if you can't use the above UNIX socket #inet_listener lmtp { # Avoid making LMTP visible for the entire internet #address = #port = #} # Django : 2014-07-22 # Einlieferung der Nachrichten via LMTP inet_listener lmtp { address = 10.0.0.70 port = 24 } } ...
Aktivierung
Zum Aktivieren unserer Konfigurationsänderung führen wir einen reload des dovecot-Daemons durch.
# systemctl reload dovecot.service
Der Reload wurde im maillog dokumentiert. Bei Bedarf können wir den Status unseres Dovecot_Servers abfragen.
# systemctl status dovecot.service
dovecot.service - Dovecot IMAP/POP3 email server Loaded: loaded (/usr/lib/systemd/system/dovecot.service; enabled) Active: active (running) since Tue 2014-07-22 21:35:37 CEST; 24h ago Process: 23610 ExecReload=/bin/kill -HUP $MAINPID (code=exited, status=0/SUCCESS) Main PID: 22063 (dovecot) CGroup: /system.slice/dovecot.service ├─22063 /usr/sbin/dovecot -F ├─22065 dovecot/anvil [0 connections] ├─23613 dovecot/log └─23615 dovecot/config Jul 23 21:32:16 vml000070.dmz.nausch.org dovecot[23587]: imap-login: Login: user=<michael@nausch.org>, method=PLAIN, rip=10.0.0.20, mpid=23601, TLS, TLSv1 with ciphe...YQAKAAAU> Jul 23 21:47:21 vml000070.dmz.nausch.org systemd[1]: Reloading Dovecot IMAP/POP3 email server. Jul 23 21:47:21 vml000070.dmz.nausch.org dovecot[22063]: master: Warning: SIGHUP received - reloading configuration Jul 23 21:47:21 vml000070.dmz.nausch.org systemd[1]: Reloaded Dovecot IMAP/POP3 email server. Jul 23 21:47:21 vml000070.dmz.nausch.org dovecot[23587]: imap: Server shutting down. in=548 out=1966 Hint: Some lines were ellipsized, use -l to show in full.
Mit dem Befehl netstat überprüfen wir nun als nächstes, ob unser Port auf der richtigen Adresse gebunden ist.
# netstat -tulpen
Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State User Inode PID/Program name tcp 0 0 10.0.0.70:993 0.0.0.0:* LISTEN 0 80047 22063/dovecot tcp 0 0 10.0.0.70:995 0.0.0.0:* LISTEN 0 80010 22063/dovecot tcp 0 0 10.0.0.70:3659 0.0.0.0:* LISTEN 0 80092 22063/dovecot tcp 0 0 10.0.0.70:110 0.0.0.0:* LISTEN 0 80009 22063/dovecot tcp 0 0 10.0.0.70:143 0.0.0.0:* LISTEN 0 80046 22063/dovecot tcp 0 0 10.0.0.70:24 0.0.0.0:* LISTEN 0 93699 22063/dovecot
Verbindungstest
Somit können wir einen ersten Verbindungstest zu unserem LMTP-Port durchführen.
# telnet 10.0.0.70 24
Unser Dovecot-Server akzeptiert die Verbindung und gibt das Server-Greeting aus.
Trying 10.0.0.70... Connected to 10.0.0.70. Escape character is '^]'. 220 imap.nausch.org Dovecot ready.
Mit dem LMTP-Kommando quit loggen wir uns aus und beenden die Verbindung:
quit
Der Server Bestätigt den Befehl mit einem 2xx-Code und beendet die Verbindung.
221 2.0.0 OK Connection closed by foreign host.
Paketfilterregel
Damit nun nicht jeder fremde Host sich mit dem LMTP-Port verbinden kann, regeln wir den Zugriff über eine Firewall-Regel so, dass nur der vorgeschaltete MTA Postfix-Mailserver sich mit unserem Dovecot-Server auf Port 24 verbinden kann.
Unter CentOS 7 wird als Standard-Firewall die dynamische firewalld verwendet. Ein großer Vorteil der dynamischen Paketfilterregeln ist unter anderem, dass zur Aktivierung der neuen Firewall-Regel(n) nicht der Daemon durchgestartet werden muss und somit alle aktiven Verbiundungen kurz getrennt werden. Sondern unsere Änderungen können on-the-fly aktiviert oder auch wieder deaktiviert werden.
In unserem Konfigurationsbeispiel hat unser Postfix-Server die IP-Adresse 10.0.0.80 und unser Dovecot-Server die 10.0.0.70. Wir brauchen also eine Firewall-Definition, die ausschließlich Verbindungen von der Source-IP 10.0.0.80 auf die Destination-IP 10.0.0.70 auf Port 24 gestattet.
Mit Hilfe des Programms firewall-cmd legen wir nun eine permanente Regel in der Zone public, dies entspricht in unserem Beispiel das Netzwerk-Interface eth0 mit der IP 10.0.0.70 an. Als Source-IP geben wir die IP-Adresse unseres Postfix-Servers also die 10.0.0.80 an. Genug der Vorrede, mit nachfolgendem Befehl wird diese restriktive Regel angelegt.
# firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="10.0.0.80/32" port protocol="tcp" port="24" destination address="10.0.0.70/32" accept"
Zum Aktivieren brauchen wir nun nur einen reload des Firewall-Daemon vornehmen.
# firewall-cmd --reload
Fragen wir nun den Regelsatz unserer iptables-basieten Firewall ab, finden wir in der Chain IN_public_allow unsere aktive Regel.
# iptables -nvL
... Chain IN_public_allow (1 references) pkts bytes target prot opt in out source destination 0 0 ACCEPT tcp -- * * 10.0.0.80 10.0.0.70 tcp dpt:24 ctstate NEW ...
abschließender Test
Somit steht einem abschließenden Test nun nichts mehr im Wege. Als erstes versuchen wir vom Postfix-server aus eine LMTP-Verbindung herzustellen.
$ telnet 10.0.0.70 24
Trying 10.0.0.70... Connected to 10.0.0.70. Escape character is '^]'. 220 imap.nausch.org Dovecot ready. quit 221 2.0.0 OK Connection closed by foreign host.
Die Verbindung wurde im Maillog entsprechend dokumentiert:
# tail -n2 /var/log/maillog
Jul 23 22:18:16 vml000070 dovecot: lmtp(24316): Connect from 10.0.0.80 Jul 23 22:18:18 vml000070 dovecot: lmtp(24316): Disconnect from 10.0.0.80: Successful quit
Ein Verbindungsaufbau von einem anderen Netzwerk-Host wird hingegen von der Firewall erfolgreich weggeblockt.
# telnet 10.0.0.70 24
Trying 10.0.0.70... telnet: connect to address 10.0.0.70: No route to host
Postfix (LMTP)
Da unser Mailserver nicht nur für die Hauptdomäne nausch.org eMails annehmen soll, sondern auch für die anderen (sub)Domains, erweiteren wir unsere Postfix-Konfiguration um ein paar Optionen.
Postfix nimmt immer dann Post außerhalb unseres $mynetworks an, wenn er sich zuständig fühlt. Hierzu kennt Postfix drei Klassen von Domains:
- echte Domains $mydestination
Diese Variante haben wir schon bei der Installation eines sicheren Mailservers mit Postfix unter CentOS 6.x erschlagen. - zu relayende Domains $relay_domains
Mit diese Variante haben wir uns bereits bei der Anbingung unseres Mailservers an ein Backend-Mailgateway im Kapitel Anbindung an einem Backend-Mailserver (Cyrus-IMAP-Server) befasst. - virtuelle Domains $virtual_alias_domains
Eine alternative Einbindung virtueller Domains ist die Verwendung von virtual_alias_domains und virtual_alias_maps
Wichtig: Dabei ist es logisch ausgeschlossen, daß eine Domain mehreren dieser Klassen angehört. Also immer nur einer, aber niemals zwei oder gar drei!
Da wir unsere Maildomänen und Nutzerkonten mit Hilfe von Postfixadmin zur Verwaltung des Dovecot-IMAP-Server unter CentOS 7.x nutzen, werden wir die Option 3, also $virtual_alias_domains verwenden.
Konfiguration
In der Postfix-Konfigurationsdatei /etc/postfix/main.cf definieren wir also die nötigen Optionen zur Nutzung der virtuelle Mailboxen.
Für den Transport definieren wir nun den virtual_transport in Richtung Dovecot-Server, in unserem Konfigurationsbeispiel der Host mit der IP-adresse 10.0.0.70.
# vim /etc/postfix/main.cf
- /etc/postfix/main.cf
... # Django : 2013-02-07 # virtuelle Mailboxen virtual_mailbox_domains = proxy:mysql:/etc/postfix/mysql_virtual_domains_maps.cf virtual_alias_maps = proxy:mysql:/etc/postfix/mysql_virtual_alias_maps.cf, proxy:mysql:/etc/postfix/mysql_virtual_alias_domain_maps.cf, proxy:mysql:/etc/postfix/mysql_virtual_alias_domain_catchall_maps.cf virtual_mailbox_maps = proxy:mysql:/etc/postfix/mysql_virtual_mailbox_maps.cf, proxy:mysql:/etc/postfix/mysql_virtual_alias_domain_mailbox_maps.cf virtual_transport = lmtp:[10.0.0.70]:24 ...
Aktivierung
Zum aktivieren unserer Konfigurationsänderung führen wir nun einen Reload unseres Postfix-Mailservers durch.
# systemctl reload postfix.service
Im Maillog unseres Servers wird dieser Reload entsprechend dokumentiert.
# tail -n2 /var/log/maillog
Jul 23 23:30:21 vml000070 postfix/postfix-script[24353]: refreshing the Postfix mail system
Jul 23 23:30:21 vml000070 postfix/master[2578]: reload -- version 2.10.1, configuration /etc/postfix
Der Reload wurde im maillog dokumentiert. Bei Bedarf können wir den Status unseres Dovecot_Servers abfragen.
# postfix.service - Postfix Mail Transport Agent
Loaded: loaded (/usr/lib/systemd/system/postfix.service; enabled) Active: active (running) since Mon 2014-07-21 15:28:29 CEST; 2 days ago Process: 24347 ExecReload=/usr/sbin/postfix reload (code=exited, status=0/SUCCESS) Main PID: 2578 (master) CGroup: /system.slice/postfix.service ├─ 2578 /usr/libexec/postfix/master -w ├─24358 qmgr -l -t unix -u └─24359 pickup -l -t unix -u Jul 21 15:28:29 vml000070.dmz.nausch.org postfix/master[2578]: daemon started -- version 2.10.1, configuration /etc/postfix Jul 21 15:28:29 vml000070.dmz.nausch.org systemd[1]: Started Postfix Mail Transport Agent. Jul 23 23:30:21 vml000070.dmz.nausch.org systemd[1]: Reloading Postfix Mail Transport Agent. Jul 23 23:30:21 vml000070.dmz.nausch.org postfix/postfix-script[24353]: refreshing the Postfix mail system Jul 23 23:30:21 vml000070.dmz.nausch.org postfix/master[2578]: reload -- version 2.10.1, configuration /etc/postfix Jul 23 23:30:21 vml000070.dmz.nausch.org systemd[1]: Reloaded Postfix Mail Transport Agent.
Dynamische Empfänger-Verifizierung
Im vorgenannten Konfigurationsbeispiel werden für alle Empfänger Nachrichten angenommen, die in der statischen Lookup-Tabelle gelistet ist. Was ist nun aber, wenn das Backend-System wiederum die Annahme einer weitergeleiteten Nachricht verweigert? Richtig, unser Mailserver würde diese als Bounce zurück zum Absender schicken. Dies wollen wir eben sowenig, wie den zusätzlichen Pflegeaufwand für die richtige und aktuelle relay_recipients-Tabelle!
Wir werden daher einfach die Entscheidung, ob nun eine Nachricht angenommen werden soll, oder nicht, an das Backendsystem delegieren.
Den notwendigen Konfogurationseintrag finden wir bereits in der Hauptkonfigurationsdatei von unserem Postfix 2.6.6 unter CentOS 6.x.
# grep verify /etc/postfix/master.cf
verify unix - - n - 1 verify
Postfix wird mit Hilfe des Moduls verify versuchen, noch während der Annahme der Bachricht von einem fremden Mailserver, beim Backend-System in Erfahrung zu bringen, ob dieses die Nachricht auch abnehmen würde. Ist dies der Fall, reicht Postfix die Nachricht an das Backend weiter. Anderenfalls wird die Annahme der Nachricht verweigert. Damit nun der Mailserver nicht jedesmal nachfragen muss, werden wir ihm hierzu eine kleine Datenbanktabelle spendieren, die auch nach einen Neustart des Servers zur Verfügung stehen kann.
Konfiguration
Als erstes legen wir nun das entsprechende Verzeichnis an und schenke es dem Nutzer Postfix.
# mkdir /var/spool/postfix/data
# chown postfix.root /var/spool/postfix/data
# chmod 700 /var/spool/postfix/data
Als nächstes definieren wir noch die entsprechende Datenbank, bzw. den Ort wo Postfix diese Datenbank abspeichern wird. Hierzu tragen wir in die Konfigurationsdatei main.cf folgenden Eintrag nach.
# vim /etc/postfix/main.cf
# Postfix-eigene verify-Datenbank für die dynamische (Kapitel 12.2.2 Dynamische Empfänger-Verifizierung) # Empfänger-Überprüfung nutzen address_verify_map = btree:/var/spool/postfix/data/verify
Ferner aktivieren wir noch den in der Grundkonfiguration unserers Restrictions-Regelwerk vorbereiteten Eintrag reject_unverified_recipient,.
# # Django : 2012-02-06 # Schutz durch Restrictions für unser SOHO # smtpd_recipient_restrictions = # Postmaster, abuse und andere aufgaben- oder funktionsgebundene E-Mail-Adressen (Role-Accounts) whitelisten check_recipient_access btree:/etc/postfix/access_recipient-rfc, # Black- und Whitelisting (Kapitel 8.2.3 White- und Blacklisting) check_client_access cidr:/etc/postfix/access_client, check_helo_access btree:/etc/postfix/access_helo, check_sender_access btree:/etc/postfix/access_sender, check_recipient_access btree:/etc/postfix/access_recipient, # Unsauberer eMails nicht annehmen (Kapitel 8.2.4 Anforderungen an Mailadressen) reject_non_fqdn_sender, reject_non_fqdn_recipient, reject_unknown_sender_domain, reject_unknown_recipient_domain, # Unsere eigenen Nutzer zulassen-/erlauben (Kapitel 8.2.2 Relaying erlauben und verbieten) permit_sasl_authenticated, permit_mynetworks, # RBL überprüfen (Kapitel 10.11 Realtime Blackhole Lists) reject_rbl_client zen.spamhaus.org, reject_rbl_client ix.dnsbl.manitu.net, reject_rbl_client bl.spamcop.net, reject_rbl_client dnsbl.njabl.org, reject_rhsbl_client multi.uribl.com, # Dynamische Prüfung auf existente Relay-Empfänger (Kapitel 12.2.2 Dynamische Empfänger-Verifizierung) reject_unverified_recipient, # Backupserver (MX) erlauben # permit_mx_backup, # alles andere an relaying verbieten (Kapitel 8.2.2 Relaying erlauben und verbieten) reject_unauth_destination, # Zu guter Letzt alles durchlassen, was bis jetzt noch nicht beanstandet wurde permit
Die Pflege der verify-Datenbank übernimmt dabei Postfix selbst, trägt neue Adressen ein und löscht auch regelmäßig alte Einträge - kurz und gut, der Postfix betreibt also eine Art Brutpflege. Da wir keine Änderungen an weiteren Parametern vorgenommen hatten, greifen hier die Default-Werte.
# postconf address_verify_positive_refresh_time
address_verify_positive_refresh_time = 7d
Nach Ablauf der sieben Tage wird das verify-Modul eine bereits bekannte und positiv gekennzeichnete eMailadresse erneuit beim Zielserver anfragen und die Aktualität des Datensatzes überprüfen.
# postconf address_verify_positive_expire_time
address_verify_positive_expire_time = 31d
Erst nach Ablauf von 31 Tagen wird eine bekannte und positive Adresse aus der Datenbank entfernt. Da aber bereits nach 7 Tagen eine Überprüfung der Adresse stattfindet, werden „gute Adressen“ quasi nie gelöscht sondern stehen sofort zur Verfügung!
# postconf address_verify_negative_refresh_time
address_verify_negative_refresh_time = 3h
Nach drei Stunden wird das verify-Modul eine noch nicht existente gecachte Empfänger-Adresse beim Zielserver erneut anfragen.
# postconf address_verify_negative_expire_time
address_verify_negative_expire_time = 3d
Nicht existierende Empfängeradressen werden maximal drei Tage vorgehalten und dann gelöscht.
# postconf address_verify_sender
address_verify_sender = $double_bounce_sender
# postconf double_bounce_sender
double_bounce_sender = double-bounce
Dieser Parameter legt fest, mit welchem Envelope-From die Anfragen an den Zielserver gerichtet werden sollen.
automatische Pflege
Erreicht nun eine Kontaktanfrage von einem fremden Mailserver, also einem Server, der nicht in $mynetworks definiert ist, kann man im Logfile des Mailservers sehr schön beobachten, wie Postfix die Adressen überprüft.
# tail -f /var/log/maillog
... Jun 4 22:11:20 vml000080 postfix/smtpd[13738]: connect from unknown[192.168.10.45] Jun 4 22:12:06 vml000080 postfix/cleanup[13743]: 55C673A: message-id=<20120604201206.55C673A@mx1.nausch.org> Jun 4 22:12:06 vml000080 postfix/qmgr[13643]: 55C673A: from=<double-bounce@nausch.org>, size=253, nrcpt=1 (queue active) Jun 4 22:12:06 vml000080 postfix/lmtp[13744]: 55C673A: to=<django@nausch.org>, relay=10.0.0.70[10.0.0.70]:24, delay=0.08, delays=0.04/0.01/0.02/0.01, dsn=2.1.5, status=deliverable (250 2.1.5 ok) Jun 4 22:12:06 vml000080 postfix/qmgr[13643]: 55C673A: removed Jun 4 22:12:09 vml000080 postfix/smtpd[13738]: 563E13A: client=unknown[192.168.10.45] Jun 4 22:12:17 vml000080 postfix/smtpd[13738]: disconnect from unknown[192.168.10.45] ...
Das Beispiel zeigt einen erfolgreichen Überprüfungsversuch status=deliverable (250 2.1.5 ok) ).
Wir im Gegensatz versucht an einen nicht existierenden Empfänger eine Nachricht zuzustellen, erfolgt hier der Vermerk status=undeliverable .
... Jun 4 22:26:07 vml000080 postfix/smtpd[13753]: connect from unknown[192.168.10.45] Jun 4 22:26:37 vml000080 postfix/cleanup[13760]: F0DAC3A: message-id=<20120604202637.F0DAC3A@mx1.nausch.org> Jun 4 22:26:38 vml000080 postfix/qmgr[13643]: F0DAC3A: from=<double-bounce@nausch.org>, size=253, nrcpt=1 (queue active) Jun 4 22:26:38 vml000080 postfix/lmtp[13761]: F0DAC3A: to=<peer.heinlein@nausch.org>, relay=10.0.0.70[10.0.0.70]:24, delay=0.08, delays=0.04/0.01/0.01/0.01, dsn=5.1.1, status=undeliverable (host 10.0.0.70[10.0.0.70] said: 550-Mailbox unknown. Either there is no mailbox associated with this 550-name or you do not have authorization to see it. 550 5.1.1 User unknown (in reply to RCPT TO command)) Jun 4 22:26:38 vml000080 postfix/qmgr[13643]: F0DAC3A: removed Jun 4 22:26:40 vml000080 postfix/smtpd[13753]: NOQUEUE: reject: RCPT from unknown[192.168.10.45]: 450 4.1.1 <peer.heinlein@nausch.org>: Recipient address rejected: unverified address: host 10.0.0.70[10.0.0.70] said: 550-Mailbox unknown. Either there is no mailbox associated with this 550-name or you do not have authorization to see it. 550 5.1.1 User unknown (in reply to RCPT TO command); from=<swat@nausch.org> to=<peer.heinlein@nausch.org> proto=SMTP helo=<ich> Jun 4 22:26:49 vml000080 postfix/smtpd[13753]: disconnect from unknown[192.168.10.45] ...
Einträge suchen/anzeigen
Werfen wir nun einen Blick in die verify-Datenbank von Postfix können wir für beide Beispiele die entsprechenden Einträge finden.
# postmap -s btree:/var/spool/postfix/data/verify
django@nausch.org 0:0:1338840726:250 2.1.5 ok peer.heinlein@nausch.org 2:0:1338841598:host 10.0.0.70[10.0.0.70] said: 550-Mailbox unknown. Either there is no mailbox associated with this 550-name or you do not have authorization to see it. 550 5.1.1 User unknown (in reply to RCPT TO command)
manuell Einträge löschen
Wollen wir, warum auch immer, einen Eintrag der verify-Datenbank manuell entfernen, greifen wir auch auf den Befehl postmap zurück.
# postmap -d peer.heinlein@nausch.org /var/spool/postfix/data/verify
LMTP-Einlieferungstests
Da nun alle Konfigurationen erfolgreich abgeschlossen sind, können wir uns nunmehr an den finalen Test unserer LMTP-Konfiguration wagen. Auch hier verwenden wir den gewohnten Test via telnet von berechtigten SMTP-Host aus. Die Eingaben am testenden Client sind in der Farbe blau und die Rückmeldungen unseres Dovecot-Servers in der Farbe hellgrau gekennzeichnet. Die Ausgaben des Befehls telnet sind in der Farbe schwarz eingefärbt.
$ telnet 10.0.0.70 24 Trying 10.0.0.70... Connected to 10.0.0.70. Escape character is '^]'. 220 imap.nausch.org Dovecot ready. LHLO vml000080.dmz.nausch.org 250-imap.nausch.org 250-8BITMIME 250-ENHANCEDSTATUSCODES 250 PIPELINING mail from:<django@nausch.org> 250 2.1.0 OK rcpt to:<michael@nausch.org> 250 2.1.0 OK DATA 354 OK From: django@nausch.org To: michael@nausch.org Subj: finaler LMTP-Einlieferungstest Date: 2014-07-23 23:42 Ahoi, das ist eine Testmail, eingeliefert via telnet imap-server auf Port 24 . 250 2.0.0UYNyIuTM0FM+YgAAOs1BfA Saved quit 221 2.0.0 OK Connection closed by foreign host.
Je nach Einstellungen bei der Konfigurationsoption mail_debug beim Log-Level in der /etc/dovecot/conf.d/10-logging.conf wird die erfolgreiche Annahme im Maillog mehr oder weniger ausführlich ausfallen.
# doveconf mail_debug
mail_debug = no
# tail -n 3 /var/log/maillog
Jul 24 09:13:50 vml000070 dovecot: lmtp(24916): Connect from 10.0.0.80 Jul 24 09:16:41 vml000070 dovecot: lmtp(24916, michael@nausch.org): GoSmFy6y0FNUYQAAOs1BfA: msgid=unspecified: saved mail to INBOX Jul 24 09:16:44 vml000070 dovecot: lmtp(24916): Disconnect from 10.0.0.80: Successful quit
Bei aktiviertem mail_debug wird es dann schon wesentlich umfangreicher.
# tail -f /var/log/maillog
Jul 24 11:07:48 vml000070 dovecot: lmtp(25150): Debug: none: root=, index=, indexpvt=, control=, inbox=, alt= Jul 24 11:07:48 vml000070 dovecot: lmtp(25150): Connect from 10.0.0.80 Jul 24 11:08:03 vml000070 dovecot: lmtp(25150): Debug: Loading modules from directory: /usr/lib64/dovecot Jul 24 11:08:03 vml000070 dovecot: lmtp(25150): Debug: Module loaded: /usr/lib64/dovecot/lib10_quota_plugin.so Jul 24 11:08:03 vml000070 dovecot: lmtp(25150): Debug: Module loaded: /usr/lib64/dovecot/lib90_sieve_plugin.so Jul 24 11:08:03 vml000070 dovecot: lmtp(25150): Debug: auth input: michael@nausch.org home=/var/spool/mail/vmail/nausch.org/michael/ uid=97 gid=12 quota_rule=*:bytes=5120000000 Jul 24 11:08:03 vml000070 dovecot: lmtp(25150): Debug: Added userdb setting: plugin/quota_rule=*:bytes=5120000000 Jul 24 11:08:12 vml000070 dovecot: lmtp(25150, michael@nausch.org): Debug: Effective uid=97, gid=12, home=/var/spool/mail/vmail/nausch.org/michael/ Jul 24 11:08:12 vml000070 dovecot: lmtp(25150, michael@nausch.org): Debug: quota: No quota setting - plugin disabled Jul 24 11:08:12 vml000070 dovecot: lmtp(25150, michael@nausch.org): Debug: Namespace inbox: type=private, prefix=, sep=, inbox=yes, hidden=no, list=yes, subscriptions=yes location=maildir:/var/spool/mail/vmail/nausch.org/michael Jul 24 11:08:12 vml000070 dovecot: lmtp(25150, michael@nausch.org): Debug: maildir++: root=/var/spool/mail/vmail/nausch.org/michael, index=, indexpvt=, control=, inbox=/var/spool/mail/vmail/nausch.org/michael, alt= Jul 24 11:08:12 vml000070 dovecot: lmtp(25150, michael@nausch.org): Debug: Namespace : /var/spool/mail/vmail/nausch.org/michael doesn't exist yet, using default permissions Jul 24 11:08:12 vml000070 dovecot: lmtp(25150, michael@nausch.org): Debug: Namespace : Using permissions from /var/spool/mail/vmail/nausch.org/michael: mode=0700 gid=default Jul 24 11:08:12 vml000070 dovecot: lmtp(25150, michael@nausch.org): Debug: sieve: Pigeonhole version 0.4.2 initializing Jul 24 11:08:12 vml000070 dovecot: lmtp(25150, michael@nausch.org): Debug: sieve: include: sieve_global_dir is not set; it is currently not possible to include `:global' scripts. Jul 24 11:08:12 vml000070 dovecot: lmtp(25150, michael@nausch.org): Debug: UYNyIuTM0FM+YgAAOs1BfA: sieve: script file /var/spool/mail/vmail/nausch.org/michael//.dovecot.sieve not found Jul 24 11:08:12 vml000070 dovecot: lmtp(25150, michael@nausch.org): Debug: UYNyIuTM0FM+YgAAOs1BfA: sieve: user's script ~/.dovecot.sieve doesn't exist (trying default script location instead) Jul 24 11:08:12 vml000070 dovecot: lmtp(25150, michael@nausch.org): Debug: UYNyIuTM0FM+YgAAOs1BfA: sieve: no default script configured for user Jul 24 11:08:12 vml000070 dovecot: lmtp(25150, michael@nausch.org): Debug: UYNyIuTM0FM+YgAAOs1BfA: sieve: user has no valid location for a personal script Jul 24 11:08:12 vml000070 dovecot: lmtp(25150, michael@nausch.org): Debug: UYNyIuTM0FM+YgAAOs1BfA: sieve: no scripts to execute: reverting to default delivery. Jul 24 11:08:12 vml000070 dovecot: lmtp(25150, michael@nausch.org): UYNyIuTM0FM+YgAAOs1BfA: msgid=unspecified: saved mail to INBOX Jul 24 11:08:15 vml000070 dovecot: lmtp(25150): Disconnect from 10.0.0.80: Successful quit
Auf unserem Festplatten wurde die eMail auch entsprechend abgespeichert.
/var/spool/mail/vmail/nausch.org └── michael ├── cur ├── dovecot.index.cache ├── dovecot.index.log ├── dovecot-uidlist ├── dovecot-uidvalidity ├── dovecot-uidvalidity.53d0ccfc ├── new │ └── 1406192892.M100007P25150.vml000070.dmz.nausch.org,S=437,W=450 └── tmp
# cat /var/spool/mail/vmail/nausch.org/michael/new/1406192892.M100007P25150.vml000070.dmz.nausch.org\,S\=437\,W\=450
Return-Path: <django@nausch.org> Delivered-To: <michael@nausch.org> Received: from vml000080.dmz.nausch.org ([10.0.0.80]) by imap.nausch.org (Dovecot) with LMTP id UYNyIuTM0FM+YgAAOs1BfA for <michael@nausch.org>; Thu, 24 Jul 2014 11:08:05 +0200 From: django@nausch.org To: michael@nausch.org Subj: finaler LMTP-Einlieferungstest Date: 2014-07-23 23:42 Ahoi, das ist eine Testmail, eingeliefert via telnet imap-server auf Port 24
2. SASL
Damit unsere Mailbox-Inhaber auch von extern aus Ihre eMails bei unserem Postfix-Mailserver abliefern können, benötigen wir einen Mechanismus, der den Clients erlaub sich beim SMTP-Server anzumelden. Postfix bietet hierzu das Framework SASL3) zur Authentifizierung an. Somit brauchen wir uns keine großen Gedanken machen, welche Authentifikationsmechanismen wir bei unserem Postfix-Server konfigurieren müssen.
Dovecot
Konfiguration
Die Konfiguration auf Seiten des Dovecot-Servers ist denkbar einfach, ist die grundlegende Konfiguration ja schon in der Datei /etc/dovecot/conf.d/10-master.conf vorbereitet.
# vim /etc/dovecot/conf.d/10-master.conf
... service auth { # auth_socket_path points to this userdb socket by default. It's typically # used by dovecot-lda, doveadm, possibly imap process, etc. Users that have # full permissions to this socket are able to get a list of all usernames and # get the results of everyone's userdb lookups. # # The default 0666 mode allows anyone to connect to the socket, but the # userdb lookups will succeed only if the userdb returns an "uid" field that # matches the caller process's UID. Also if caller's uid or gid matches the # socket's uid or gid the lookup succeeds. Anything else causes a failure. # # To give the caller full permissions to lookup all users, set the mode to # something else than 0666 and Dovecot lets the kernel enforce the # permissions (e.g. 0777 allows everyone full permissions). unix_listener auth-userdb { #mode = 0666 #user = #group = } # Postfix smtp-auth #unix_listener /var/spool/postfix/private/auth { # mode = 0666 #} # Auth process is run as this user. #user = $default_internal_user # Django : 2014-05-23 # default: unset # Authentifizierungsport 3659 für Postfix Frontend-Mailserver definiert inet_listener { address = 10.0.0.70 port = 3659 } } ...
Zum Aktivieren unserer Einstellungsänderungen führen wir einen Reload unseres Dovecot-Daemon durch.
# systemctl reload dovecot
Fragen wir nun die offenen Ports von Dovecot ab, finden wir auch unseren SASL-Port 3569.
# netstat -tulpen | grep dovecot
tcp 0 0 10.0.0.70:4190 0.0.0.0:* LISTEN 0 126663 13526/dovecot tcp 0 0 10.0.0.70:993 0.0.0.0:* LISTEN 0 126726 13526/dovecot tcp 0 0 10.0.0.70:995 0.0.0.0:* LISTEN 0 126689 13526/dovecot tcp 0 0 10.0.0.70:3659 0.0.0.0:* LISTEN 0 129217 13526/dovecot tcp 0 0 10.0.0.70:110 0.0.0.0:* LISTEN 0 126688 13526/dovecot tcp 0 0 10.0.0.70:143 0.0.0.0:* LISTEN 0 126725 13526/dovecot tcp 0 0 10.0.0.70:10000 0.0.0.0:* LISTEN 0 126788 13526/dovecot tcp 0 0 10.0.0.70:24 0.0.0.0:* LISTEN 0 126698 13526/dovecot
Paketfilter / Firewall
Damit nun nicht jeder fremde Host sich mit dem SASL-Port verbinden kann, regeln wir den Zugriff über eine Firewall-Regel so, dass nur der vorgeschaltete MTA Postfix-Mailserver sich mit unserem Dovecot-Server auf Port 3569 verbinden kann.
Unter CentOS 7 wird als Standard-Firewall die dynamische firewalld verwendet. Ein großer Vorteil der dynamischen Paketfilterregeln ist unter anderem, dass zur Aktivierung der neuen Firewall-Regel(n) nicht der Daemon durchgestartet werden muss und somit alle aktiven Verbiundungen kurz getrennt werden. Sondern unsere Änderungen können on-the-fly aktiviert oder auch wieder deaktiviert werden.
In unserem Konfigurationsbeispiel hat unser Postfix-Server die IP-Adresse 10.0.0.80 und unser Dovecot-Server die 10.0.0.70. Wir brauchen also eine Firewall-Definition, die ausschließlich Verbindungen von der Source-IP 10.0.0.80 auf die Destination-IP 10.0.0.70 auf Port 3569 gestattet.
Mit Hilfe des Programms firewall-cmd legen wir nun eine permanente Regel in der Zone public, dies entspricht in unserem Beispiel das Netzwerk-Interface eth0 mit der IP 10.0.0.70 an. Als Source-IP geben wir die IP-Adresse unseres Postfix-Servers also die 10.0.0.80 an. Genug der Vorrede, mit nachfolgendem Befehl wird diese restriktive Regel angelegt.
# firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="10.0.0.80/32" port protocol="tcp" port="3569" destination address="10.0.0.70/32" accept"
Zum Aktivieren brauchen wir nun nur einen reload des Firewall-Daemon vornehmen.
# firewall-cmd --reload
Fragen wir nun den Regelsatz unserer iptables-basieten Firewall ab, finden wir in der Chain IN_public_allow unsere aktive Regel.
# iptables -nvL IN_public_allow
Chain IN_public_allow (1 references) pkts bytes target prot opt in out source destination 0 0 ACCEPT tcp -- * * 10.0.0.80 10.0.0.70 tcp dpt:3569 ctstate NEW 0 0 ACCEPT tcp -- * * 10.0.0.80 10.0.0.70 tcp dpt:10000 ctstate NEW 0 0 ACCEPT tcp -- * * 10.0.0.80 10.0.0.70 tcp dpt:24 ctstate NEW 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 ctstate NEW 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:110 ctstate NEW 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:143 ctstate NEW 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:995 ctstate NEW 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:993 ctstate NEW
Postfix
Auch der Konfigurationsaufwand auf Seiten von Postfix hält sich in überschaubaren Grenzen.
Konfiguration
Zum Aktivieren der SASL-Autentifikation gegen unseren Dovecot-Server tragen wir die folgenden Zeilen in der Postfix-konfigurationsdatei /etc/postfix/main.cf nach
# vim /etc/postfix/main.cf
... # Django : 2012-10-09 # SMTP-Auth (SASL) # Enable SASL authentication in the Postfix SMTP server. By default, the Postfix SMTP server # does not use authentication. smtpd_sasl_auth_enable = yes # The SASL plug-in type that the Postfix SMTP server should use for authentication. The available # types are and dovecot. smtpd_sasl_type = dovecot # Implementation-specific information that the Postfix SMTP server passes through to the SASL # plug-in implementation that is selected with smtpd_sasl_type. Typically this specifies the # name of a configuration file or rendezvous point. smtpd_sasl_path = inet:10.0.0.70:3659 # Postfix SMTP server SASL security options; as of Postfix 2.3 the list of available features # depends on the SASL server implementation that is selected with smtpd_sasl_type. The following # security features are defined for the cyrus server SASL implementation: # Restrict what authentication mechanisms the Postfix SMTP server will offer to the client. # The list of available authentication mechanisms is system dependent. Specify zero or more of # the following: # noplaintext # Disallow methods that use plaintext passwords. # noactive # Disallow methods subject to active (non-dictionary) attack. # nodictionary # Disallow methods subject to passive (dictionary) attack. # noanonymous # Disallow methods that allow anonymous authentication. # forward_secrecy # Only allow methods that support forward secrecy (Dovecot only). # mutual_auth # Only allow methods that provide mutual authentication # (not available with Cyrus SASL version 1). # # By default, the Postfix SMTP server accepts plaintext passwords but not anonymous logins. # # Warning: it appears that clients try authentication methods in the order as advertised by the # server (e.g., PLAIN ANONYMOUS CRAM-MD5) which means that if you disable plaintext passwords, # clients will log in anonymously, even when they should be able to use CRAM-MD5. So, if you # disable plaintext logins, disable anonymous logins too. Postfix treats anonymous login as no # authentication. smtpd_sasl_security_options = noanonymous # The name of the Postfix SMTP server's local SASL authentication realm. # By default, the local authentication realm name is the null string. smtpd_sasl_local_domain = $mydomain # The SASL authentication security options that the Postfix SMTP server uses for TLS encrypted # SMTP sessions. smtpd_sasl_tls_security_options = $smtpd_sasl_security_options # Enable inter-operability with remote SMTP clients that implement an obsolete version of the # AUTH command (RFC 4954). Examples of such clients are MicroSoft Outlook Express version 4 # and MicroSoft Exchange version 5.0. broken_sasl_auth_clients = yes ...
Ein Restart unseres Postfix-Servers aktiviert unsere Konfigurationsanpassungen.
# systemctl restart postfix
SASL-Anmeldetest
Melden wir uns nun via telnet auf Port 25 bei unserem Postfix-Server an werden uns nach Eingabe des EHLO die Authentifizierungsmöglichkeiten (gegen unseren Dovecot-SASL-Port 3569) angezeigt.
Bei Test vsind die Eingaben am testenden Client in der Farbe blau und die Rückmeldungen unseres Dovecot-Servers in der Farbe hellgrau gekennzeichnet. Die Ausgaben des Befehls telnet sind in der Farbe schwarz eingefärbt.
Wir bauen also eine Verbindung zu unserem Postfix-Server zum SMTP 25 auf und setzen dann den Befehl EHLO ab, damit uns der SMTP-server seine Authentifizierungsoptionen anzeigt.
$ telnet 10.0.0.80 25 Trying 10.0.0.80... Connected to 10.0.0.80. Escape character is '^]'. 220 mx01.nausch.org ESMTP Postfix EHLO test 250-mx01.nausch.org 250-PIPELINING 250-SIZE 52428800 250-ETRN 250-STARTTLS 250-AUTH PLAIN LOGIN DIGEST-MD5 CRAM-MD5 250-AUTH=PLAIN LOGIN DIGEST-MD5 CRAM-MD5 250-ENHANCEDSTATUSCODES 250 8BITMIME quit 221 2.0.0 Bye Connection closed by foreign host.
Melden wir uns nun über unseren Mailclient an, typischerweise passiert das jeweils vor dem Versand von ausgehenden Nachrichten, sehen wir diese Anmeldungen auch im Maillog unseres Postfix-Servers
# less /var/log/maillog
Aug 10 10:56:29 vml000080 postfix/smtpd[20787]: A46D975: client=vml000020.dmz.nausch.org[10.0.0.20], sasl_method=LOGIN, sasl_username=django@nausch.org
Auf seiten unseres Dovecot-Servers passiert natürlich wesentlich mehr, da ja dort die Authentifizierungsanfrage des Postfix-Servers angenommen und bearbeitet wird. Im Detail bedeutet dies, dass der Dovecot-Server eine passdb-Anfrage gegen unsere MySQL-Datenbank macht und das Ergebnis OK an den postfix-Frontend-Server zurückmeldet.
# less /var/log/maillog
Aug 10 10:56:29 vml000070 dovecot: auth: Debug: auth client connected (pid=0) Aug 10 10:56:29 vml000070 dovecot: auth: Debug: client in: AUTH#0111#011LOGIN#011service=smtp#011nologin#011lip=10.0.0.80#011rip=10.0.0.20#011secured Aug 10 10:56:29 vml000070 dovecot: auth: Debug: client passdb out: CONT#0111#011VXNlcm5hbWU6 Aug 10 10:56:29 vml000070 dovecot: auth: Debug: client in: CONT#0111#011bWljaGFlbEBuYXVzY2gub3Jn (previous base64 data may contain sensitive data) Aug 10 10:56:29 vml000070 dovecot: auth: Debug: client passdb out: CONT#0111#011UGFzc3dvcmQ6 Aug 10 10:56:29 vml000070 dovecot: auth: Debug: client in: CONT#0111#011RGQ0bWRkMyE= (previous base64 data may contain sensitive data) Aug 10 10:56:29 vml000070 dovecot: auth: Debug: sql(michael@nausch.org,10.0.0.20): cache expired Aug 10 10:56:29 vml000070 dovecot: auth-worker(6830): Debug: Loading modules from directory: /usr/lib64/dovecot/auth Aug 10 10:56:29 vml000070 dovecot: auth-worker(6830): Debug: Module loaded: /usr/lib64/dovecot/auth/libdriver_mysql.so Aug 10 10:56:29 vml000070 dovecot: auth-worker(6830): Debug: Module loaded: /usr/lib64/dovecot/auth/libdriver_sqlite.so Aug 10 10:56:29 vml000070 dovecot: auth-worker(6830): Debug: sql(michael@nausch.org,10.0.0.20): query: SELECT username AS user, password FROM mailbox WHERE username = 'michael@nausch.org' AND active = '1' Aug 10 10:56:29 vml000070 dovecot: auth: Debug: client passdb out: OK#0111#011user=michael@nausch.org#011