Inhaltsverzeichnis

virtuelle(r) Mailserver unter Postfix 2.11. und CentOS 7

Postfix-Logo 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:

  1. echte Domains $mydestination
    Diese Variante haben wir schon bei der Installation eines sicheren Mailservers mit Postfix unter CentOS 7.x erschlagen.
  2. 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 (Dovecot-IMAP-Server) befasst.
  3. 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, dass eine Domain mehreren dieser Klassen angehört. Also immer nur einer, aber niemals zwei oder gar drei!

Nutzt man $mydestination, so weiss Postfix dass er dafür die hier aufgelistetetn Domains zuständig ist und prüft anhand von local_recipient_maps ob die Empfänger in /etc/aliases oder /etc/passwd zu finden sind. Eine etwaig vorhandene relay_recipient_maps wird Postfix hier nie auswerten!

Hinterlegt die Domains, die Postfix relayen soll hingegen in relay_domains wird dieser die relay_recipient_maps auswerten und an Nachrichten an die definierten next hop bzw. final destinantion weiterleiten!

2. zu relayende Domains

main.cf

Für die individuelle Weiterleitung unserer Nachrichten benutzen wir die beiden Lookup-Tabellen:

  1. transport_maps
  2. relay_domains

Im ersten Schritt erweitern wir nun unsere Postfix-Konfigurationsdatei um folgende Zeilen. Hierzu nutzen wir wie immer den Editor unserer Wahl, so z.B. vim.

 # vim /etc/postfix/main.cf
# Django : 2012-02-06
# Zur Weitergabe der angenommenen Nachrichten an das backend-System (Cyrus-IMAP-Server) verwenden wir
# eine separate Tabelle zur individuellen Weiterleitung. 
relay_domains = btree:/etc/postfix/relay_domains
 
# Lookup-Tabelle zum Aktivieren einer alternativen Mailrouting bei der Zustellung an einen weiteren Mailserver
transport_maps = btree:/etc/postfix/transport_maps, btree:/etc/postfix/relay_domains

Die gerade definierten Lookup-Tabellen legen wir nun als nächstes an.

  1. transport_maps: Lookup-Tabelle zum Aktivieren einer alternativen Mailrouting bei der Zustellung an einen weiteren Mailserver
     # vim /etc/postfix/transport_maps
    # Kapitel 5.2.5 transport-Tabelle: Abweichende Zustellung
    # Lookup-Tabelle zum Aktivieren einer alternativen Mailrouting bei der Zustellung an einen weiteren Mailserver
    # Nach dem Ändern und/oder Erweitern der Tabelle, muß noch mittels  $ postmap /etc/postfix/transport_maps
    # die zugehörige Datenbank erzeugt werden.
    #
    # Alle eMails, die an Subdomains von nausch.org gerichtet sind ("." am Anfang der Zeile!)
    # werden an den/die Mailserver von intra.nausch.org (MX-Records) weitergeleitet. (keine "["-Klammern!)
    #.nausch.org                            smtp:intra.nausch.org
     
    # Mails an backup.nausch.org werden an den Mailserver (A-Record) auf Port 25 mit Namen mail.intra.nausch.org geschickt.
    #backup.nausch.org                      smtp:[mail.intra.nausch.org]:25
  2. relay_domains: Lookup-Tabelle zur Definition der Domänen, für die unser Mailserver Nachricht annehmen soll.
     # vim /etc/postfix/relay_domains
    # Kapitel 12.1 Postfix als eingehendes Mailrelay vor einem anderen Server
    # Lookup-Tabelle zur Definition der Domänen, für die unser Mailserver Nachricht annehmen soll.
    # Nach dem Ändern und/oder Erweitern der Tabelle, muß noch mittels  $ postmap /etc/postfix/relay_domains
    # die zugehörige Datenbank erzeugt werden.
    #
    # Relevant ist erst eimal nur die erste Spalte. Die zweite Spalte dient nur zum Erhalten der Tabellenstruktur und
    # kann daher z.B. als Hinweisfled zum Dokumentieren verwendet werden.
    # Beispiel:
    # omni128.de                    meine eigene Domäne
  3. transport_maps UND relay_domains: Da wir sowieso beide Informationen benötigen können wir auch gleich direkt den jeweiligen Transportweg direkt in der zweiten Spalte der relay_domains-Tabelle hierzu verwenden.
     # vim /etc/postfix/relay_domains
    # Kapitel 12.1 Postfix als eingehendes Mailrelay vor einem anderen Server
    # Lookup-Tabelle zur Definition der Domänenm für die unser Mailserver Nachricht annehmen soll.
    # Nach dem Ändern und/oder Erweitern der Tabelle, muß noch mittels  $ postmap /etc/postfix/relay_domains
    # die zugehörige Datenbank erzeugt werden.
    #
    # Relevanz ost erst eimal nur die erste Spalte. Die zweite Spalte dient nur zum Erhalten der Tabellenstruktur und
    # kann daher z.B. als Hinweisfled zum Dokumentieren verwendet werden.
    # Beispiel:
    # omni128.de                    meine eigene Domäne
    #
    # Da für jede Domäne auch ein Transportweg definiert werden muss, erledigen wir die Definition des selbigen gleich 
    # hier in dieser Tabelle, in dem wir die Spalte zwei hierzu verwenden.
    nausch.org                      lmtp:[imap.intra.nausch.org]:24
    omni128.de                      lmtp:[imap.intra.nausch.org]:24
    wetterstation-pliening.info     lmtp:[imap.intra.nausch.org]:24
    ebersberger-liedersammlung.de   lmtp:[imap.intra.nausch.org]:24

master.conf

In der /etc/postfix/master.cf ist für die Zustellung an unseren Cyrus-IMAP-Server mit dem Zustellprotokoll lmtp bereits alles vorbereitet.

 # vim /etc/postfix/master.cf
...
local     unix  -       n       n       -       -       local
...

3. virtuelle Domains

main.cf

In der /etc/postfix/main.cf geben wir nun an, dass für die Annahme und Weiterleitung von Nachrichten, die beiden Tabellen/Datenbaken virtual_alias_domains und virtual_alias_maps verwendet werden sollen.

 virtual_alias_domains = hash:/etc/postfix/virtual_alias_domains
 virtual_alias_maps = hash:/etc/postfix/virtual_alias_maps

Den Defaultwert $mydestination für relay_domains löschen wir

 relay_domains =

Anschließend geben wir unserem Postfix die beiden zusätzlichen Tabellen bekannt, in dem wir ihn einmal durchstarten.

 # service postfix restart

virtual_alias_domains

In der virtual_alias_domains geben wir an, für welche virtuellen Domains Nachrichten angenommen werden sollen.

wetter.nausch.org               blaablubb
#
omni128.de                      meine_erste_Domain
#
wetterstation-pliening.info     erste_Info_Domain

In der ersten Spalte der Tabelle tragen wir nun unsere zusätzlichen Domänen ein, die zweite Spalte ist ein Bemerkungsfeld mit wahlfreiem Inhalt (wird nicht ausgewertet).

virtual_alias_maps

In der virtual_alias_maps erfolgt nun die Zuordnung (mappings) der eMailadressen.

@omni128.de                             @nausch.org
admin@wetterstation-pliening.info       michael@nausch.org
@wetterstation-pliening.info            @nausch.org

Folgende Definitionen haben wir festgelegt:

Nach Änderungen an den beiden vorgenannten virtual_tables, müssen diese noch mittels postmap in das hash-Format konvertiert werden.

 # postmap /etc/postfix/virtual_alias_domains && postmap /etc/postfix/virtual_alias_maps
# ll virtual_*
-rw-r--r-- 1 root root   772 28. Nov 09:47 virtual_alias_domains
-rw-r--r-- 1 root root 12288  2. Dez 20:59 virtual_alias_domains.db
-rw-r--r-- 1 root root  1109 28. Nov 11:29 virtual_alias_maps
-rw-r--r-- 1 root root 12288  2. Dez 20:59 virtual_alias_maps.db

Voila! Schon nimmt unser MX die Nachrichten den neuen virtuellen Domains an und stellt diese in die betreffenden Userpostfächer.

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.10.1 unter CentOS 7.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

Die Konfiguration, oder genauer gesagt die Aktivierung der Empfängervalidierung erfolgt über die Option reject_unverified_recipient in der /etc/postfix/main.cf.

Dort aktivieren wir den in der Grundkonfiguration unserers Restrictions-Regelwerk vorbereiteten Eintrag reject_unverified_recipient.

...
 
################################################################################
## SMTP RECIPIENT RESTRICTIONS
#
# Django : 2014-10-29 - Schutz unserer Empfänger mit Hilfe der Recipient 
#          Restrictions 
# default: smtpd_recipient_restrictions =
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

Links