SPF Milter ist eine Milter-Anwendung zur Verifizierung von E-Mail-Absendern mittels des Sender-Policy-Framework-Protokolls. In einen milterfähigen Mailserver integriert setzt sie die im DNS veröffentlichte SPF-Policy gegenüber Clients durch.
SPF Milter setzt die Vorgaben der SPF-Spezifikation [RFC 7208] wortgetreu um.
Die Verifizierung wird stets in der von der Spezifikation empfohlenen Folge
durchgeführt: Erst wird optional die HELO identity (der mittels SMTP-Befehl
HELO
angegebene Domainname) des Clients überprüft. Führt dieser Schritt nicht
zu einem Ergebnis, dann wird seine MAIL FROM identity (der mittels SMTP-Befehl
MAIL FROM
angegebene Absender) überprüft. Das so ermittelte endgültige
Resultat wird dann vom Milter in geeigneter Weise behandelt, entweder indem mit
einem SMTP-Fehler geantwortet wird, oder indem das Resultat in den Kopfteil der
Nachricht geschrieben wird.
Innerhalb des von der Spezifikation gesetzten Rahmens bietet SPF Milter flexible Konfigurationsmöglichkeiten. Konfigurationsparameter für den Verifikationsablauf, die Behandlung des Resultats, SMTP-Antwort, Header und so weiter decken eine Bandbreite von Anwendungsszenarien ab. Konfiguration kann im laufenden Betrieb angepasst werden, ohne dass ein Neustart nötig ist.
Was die Implementierung angeht, ist SPF Milter im Wesentlichen nicht mehr als eine Konfigurationsmaske, die über eine in das Milter-Protokoll integrierte SPF-Bibliothek gelegt ist. Die SPF-Implementierung besorgt [viaspf], die dazugehörige DNS-Implementierung besorgt [domain]. Wir erachten diese Komponenten als eine solide Basis für SPF-Milter-Software.
SPF Milter ist ein [Rust]-Projekt. Es kann wie üblich mit Cargo kompiliert und/oder installiert werden. Das folgende Kommando etwa lädt und installiert die neuste Version von [crates.io]:
cargo install --locked spf-milter
Als Milter-Anwendung benötigt SPF Milter die C-Bibliothek libmilter. Unter
Debian und Ubuntu beispielsweise muss das Paket libmilter-dev
installiert
werden, unter Red Hat (und Klonen) das Paket sendmail-milter-devel
.
Bei der Kompilierung wird das Programm pkg-config
verwendet, um die
Milter-Bibliothek zu lokalisieren. Fehlen auf einer Distro die
pkg-config-Metadaten für libmilter, kann die in diesem Projekt vorhandene Datei
milter.pc
Hilfe bieten: Dazu milter.pc
bearbeiten und mit dem Pfad zu
libmilter versehen, und milter.pc
in einem Verzeichnis ablegen. Unter Red Hat
zum Beispiel muss milter.pc
folgendes enthalten:
prefix=/usr
libdir=${prefix}/lib64
Dann beliebige Cargo-Befehle mit obigem Verzeichnis auf dem pkg-config-Pfad
ausführen. Das Kompilieren des spf-milter
-Programms geht dann so:
PKG_CONFIG_PATH=/path/to/dir cargo build
Die Bibliothek [domain] benötigt die Bibliothek OpenSSL. Unter Debian und Ubuntu
muss das Paket libssl-dev
installiert werden, unter Red Hat das Paket
openssl-devel
.
Nach der Kompilierung erfolgt die Installation durch Kopieren von spf-milter
nach /usr/sbin
; spf-milter.service
nach /etc/systemd/system
;
spf-milter.conf
nach /etc
. Der Service lässt sich dann mit dem Kommando
systemctl enable --now spf-milter
starten.
Die man pages können ebenso durch Kopieren installiert werden:
cp spf-milter.8 /usr/local/share/man/man8/
cp spf-milter.conf.5 /usr/local/share/man/man5/
mandb
Als Mindestanforderung für Rust gilt Version 1.46.0.
Fürs Kompilieren aus dem Quellcode gelten die obengenannten Anforderungen.
Ausserdem ist für das Ausführen der Integrationstests das Programm miltertest
notwendig. (miltertest
ist Teil der Software [OpenDKIM].)
Der Standardpfad für die Konfigurationsdatei kann zur Kompilierzeit
überschrieben werden, indem die Umgebungsvariable SPF_MILTER_CONFIG_FILE
definiert wird.
Nach der Installation kann SPF Milter auf der Kommandozeile als spf-milter
aufgerufen werden. SPF Milter liest Konfigurationseinstellungen aus dem File
/etc/spf-milter.conf
. Darin muss mindestens der Parameter socket
eingestellt
werden. Die Beispielkonfiguration spf-milter.conf
zeigt wie das geht.
Beim Aufruf von spf-milter
startet der Milter im Vordergrund. Er kann mit
einem Signal oder mittels Tastenkombination Steuerung-C heruntergefahren werden.
Soll SPF Milter als Dienst betrieben werden, empfiehlt sich als Vorlage der im
Projekt vorhandene systemd-Service spf-milter.service
. Diese Datei nach Bedarf
anpassen (zum Beispiel User
und UMask
beifügen), in /etc/systemd/system
installieren und dann den Service aktivieren und starten.
Statusmeldungen schreibt SPF Milter standardmässig ins Syslog. Neben Fehlermeldungen und Warnungen wird für jede überprüfte Identität das Verifizierungsergebnis in das Log geschrieben.
Die Konfiguration von SPF Milter erfolgt in erster Linie über
Konfigurationsparameter, die in der Datei /etc/spf-milter.conf
hinterlegt
werden. Alle Parameter haben sinnvolle Standardwerte, mit Ausnahme des
Parameters socket
, der zwingend angegeben werden muss.
Als Referenz ist die man page spf-milter.conf(5) massgebend. (Die man page
lässt sich auch ohne Installation ansehen mit: man ./spf-milter.conf.5
)
Konfiguration kann im laufenden Betrieb vom File neu geladen werden, indem das
Signal SIGUSR1
an den Milter-Prozess gesandt wird. Einzelheiten dazu stehen in
der man page.
Für jene, die SPF Milter zum ersten Mal verwenden, bietet der folgende Abschnitt eine kurze praktische Einführung und Übersicht über die wichtigsten Konfigurationsparameter.
Nehmen wir uns zwei Minuten Zeit um zum ersten Mal SPF Milter aufzusetzen.
Der erste Schritt ist, das Socket des Milters, wohin sich der MTA verbinden
wird, auszuwählen und einzurichten. Dazu dient der Parameter socket
. Als
Wert muss eine Socket-Spezifikation in einem von zwei Formaten stehen:
inet:port@host
oder
inet6:port@host
für ein TCP-Socketunix:path
für ein UNIX-Domain-SocketSo muss das im Konfigurationsfile ausschauen:
```
socket = inet:3000@localhost ```
Zur Erinnerung: Die Konfigurationseinstellungen gehören ins File
/etc/spf-milter.conf
. Die Syntax ist wie oben gezeigt und in der man page
dokumentiert. Dabei nicht vergessen, den Milter mit dem MTA zu integrieren. Mit
[Postfix] etwa heisst das, das Socket in /etc/postfix/main.cf
anzugeben:
smtpd_milters = inet:localhost:3000
Diese Dinge eingestellt, den Milter aufgestartet und die Postfix-Konfiguration neu geladen, beginnt SPF Milter sogleich eintreffende Nachrichten zu verarbeiten.
Verschiedene Aspekte der Verarbeitung können angepasst werden. Die wichtigste
konfigurierbare Facette des Verifikationsablaufs ist, ob die HELO identity
überprüft wird oder nicht. Dazu dient der Boole’sche Parameter
verify_helo
:
```
verify_helo = yes ```
Verifikation der HELO identity einschalten bedeutet nicht Verifikation der MAIL FROM identity ausschalten. Vielmehr wird so die HELO identity zusätzlich vor der MAIL FROM identity überprüft. Sofern die HELO identity überhaupt berücksichtigt werden soll, kann es von Vorteil sein, diese Option eingeschaltet zu lassen. Denn, wie in Abschnitt 2.3 von RFC 7208 ausgeführt, ist die HELO identity gewöhnlich simpler als die komplexere MAIL FROM identity, und ist oft mit einer weniger aufwändigen SPF-Policy verknüpft, die mit weniger DNS-Abfragen auskommt.
Absender mit einem negativen Autorisierungsresultat oder einem Fehlerresultat
können vom Milter auf SMTP-Ebene mit einer temporären oder permanenten
Fehlerantwort abgewiesen werden. Die abzuweisenden SPF-Resultate werden mit dem
Parameter reject_results
deklariert:
```
reject_results = fail, temperror, permerror ```
Die SPF-Resultate werden mit Kommas getrennt aufgelistet. Im obigen Beispiel würden Absender mit Resultat fail abgewiesen, Absender mit Resultat softfail jedoch angenommen.
Bei angenommenen, also nicht abgewiesenen Absendern wird das Resultat in eine
neue Headerzeile ihrer Nachricht geschrieben. Die Art der Headerzeile kann
ebenfalls konfiguriert werden, und zwar mittels Parameter header
. Zur
Auswahl stehen die Header-Typen Received-SPF
und Authentication-Results
.
Beispiel:
```
header = Received-SPF ```
Und damit seid ihr gerüstet fürs selbständige Experimentieren.
Beim Experimentieren mit der Konfiguration ist jeweils kein Neustart nötig, es genügt, dem Milter das Neuladen-Signal zu schicken. Dieses Feature sowie viele weitere Einstellungen sind in der man page spf-milter.conf(5) erklärt.
Zu Vertiefung wollen wir uns in diesem Abschnitt zwei geläufige Anwendungsfälle genauer ansehen: „Standard“-SPF und SPF als Teil von DMARC.
Der RFC-konforme Standardanwendungsfall für SPF-Verifikation wird von den
Standardeinstellungen von SPF Milter gut abgedeckt. Es genügt also, den
Pflichtparameter socket
einzustellen und alle anderen Parameter auf der
Defaulteinstellung zu belassen, um diesen Anwendungsfall einzurichten.
/etc/spf-milter.conf
:
socket = inet:3000@localhost
Gehen wir nun das Standardverhalten der Reihe nach durch.
Als erstes verifiziert SPF Milter die HELO identity (verify_helo=yes
). Wenn
das Ergebnis dieses Tests weder in die Menge der abzuweisenden noch der
„definitiven“ HELO-Resultate fällt, wird als nächstes die MAIL FROM identity
verifiziert. Die genannten Mengeneinstellungen, reject_helo_results
und
definitive_helo_results
, erlauben es, genau festzulegen, aufgrund welcher
HELO-Resultate die Verifizierung der MAIL FROM identity ausgelassen oder
übersprungen werden kann. Standardmässig wird sowohl für die HELO wie für die
MAIL FROM identity derselbe Satz Resultate abgewiesen, und kein HELO-Resultat
zählt als „definitiv“.
Aus dem HELO- oder MAIL-FROM-Test resultiert ein finales Ergebnis. Dieses wird
dann vom Milter gemäss den Empfehlungen von RFC 7208 in eine Antwort umgesetzt:
Die Resultate fail, temperror und permerror werden mit einer permanenten
beziehungsweise temporären SMTP-Fehlerantwort abgewiesen, alle anderen Resultate
werden in einer Headerzeile der Nachricht hinzugefügt. Die Menge der
abzuweisenden Resultate ist mittels der Parameter reject_results
und
reject_helo_results
konfigurierbar. Ebenso können Statuscode und Text der
SMTP-Antwort für jedes SPF-Resultat ajustiert werden.
Für den Header wird standardmässig eine Headerzeile vom Typ Received-SPF
generiert. Der Header-Typ lässt sich mit dem Parameter header
anpassen
(header=Received-SPF
). Beide in RFC 7208 definierten Header-Typen sind
„Standard“, dienen aber verschiedenen Zwecken: Received-SPF codiert
vollständig die Eingabeparameter und Informationen zum SPF-Resultat,
Authentication-Results hingegen dient nur der Übermittlung des Resultats. Hier
und generell ist es das Bestreben von SPF Milter, die Spezifikationen genau zu
befolgen, insbesondere RFC 7208 und 8601, sowie die dort referenzierten. Im
Zweifelsfall also die RFCs lesen!
softfail
wie ein negatives Autorisierungsresultat behandeln. Unter
besonders restriktiven Bedingungen kann das Resultat softfail
wie fail
behandelt, also abgewiesen werden. Um dies zu implementieren, genügt es,
softfail
zu den abzuweisenden Resultaten hinzuzufügen.
/etc/spf-milter.conf
:
reject_results = fail, softfail, temperror, permerror
Mehr Informationen im Header. SPF Milter unterstützt beide spezifizierten
Header-Typen. Es können nicht nur der eine oder der andere, sondern auch beide
gleichzeitig verwendet werden. Die Konfiguration erfolgt über den Parameter
header
. Zusätzlich sorgt include_all_results
dafür, dass die Resultate aller
verifizierten Identitäten aufgezeichnet werden (HELO und MAIL FROM).
/etc/spf-milter.conf
:
header = Received-SPF, Authentication-Results
include_all_results = yes
SPF kann auch als Teil einer DMARC-Verifikation genutzt werden. Domain-based Message Authentication, Reporting, and Conformance (DMARC) ist in [RFC 7489] spezifiziert. Da DMARC das Resultat, das die SPF-Komponente produziert, als Eingabe für seinen eigenen Validierungsprozess verwendet, sind einige Anpassungen an der Standardkonfiguration vorzunehmen.
/etc/spf-milter.conf
:
socket = inet:3000@localhost
verify_helo = no
reject_results =
header = Authentication-Results
Erstens ist bei DMARC nur die MAIL FROM identity von Belang, die HELO
identity spielt keine Rolle. Daher sollte dieser Schritt übersprungen werden,
indem verify_helo
deaktiviert wird.
Zweitens liegt es nahe, Absender nicht gleich nach der SPF-Verifikation
abzuweisen, da eine solche Entscheidung ja an die nachfolgende DMARC-Komponente
delegiert werden soll (je nach dem kann diese Anforderung aber auch anders
gelöst werden). In der obigen Konfiguration werden dank der Einstellung
reject_results=
(die leere Menge) keine Abweisungen mit SMTP-Fehlerantwort
getätigt. Der Milter schreibt alle Resultate nur in den Header.
Drittens wird mit dem Parameter header
der Typ der Headerzeile von
Received-SPF
zu Authentication-Results
abgeändert, da dies der Header ist,
mit dem DMARC arbeitet. Der Authentication-Results-Header wurde allgemein zur
Transportierung des Authentisierungsstatus für spätere maschinelle Verarbeitung
entworfen. Spezifiziert wurde er jüngst in [RFC 8601].
Fehlende Autorisierung der HELO identity frühzeitig abweisen. Mit ein
wenig Fantasie lässt sich von der HELO identity auch in einem DMARC-Szenario
Gebrauch machen: Ein Absender mit nicht autorisierter HELO identity führt
bestimmt nichts Gutes im Schilde und darf abgewiesen werden. Zur Implementierung
dieser Anforderung fügen wir nur fail
den für die HELO identity
abzuweisenden Resultaten hinzu. In allem Übrigen verhält sich diese
Konfiguration wie die oben.
/etc/spf-milter.conf
:
verify_helo = yes
reject_helo_results = fail
reject_results =
Jeder Beitrag ist willkommen. Bitte ein Ticket auf dem Issue-Tracker aufmachen, sei es für Fragen, Anregungen, Bugs, Features, Dokumentation, Übersetzungen usw. Um das Projekt langfristig am Leben zu erhalten, kann ich Interessierten auch Commit-Rechte geben.
Bitte neue Features zuerst diskutieren, bevor ihr sie implementiert. Wir glauben, dass die Implementierung verhältnismässig oft das einfachere ist, die meiste Zeit braucht das Design und die Motivation eines Features. Genaue und fehlerresistente Implementierung der RFCs ist im Vergleich mit ähnlicher Software eine der herausragenden Leistungen von SPF Milter – immer die RFCs zu Rate ziehen!
Dieses Projekt wird als freie Software unter einer GPL-Lizenz entwickelt. Wir bitten, diese Entscheidung zu respektieren.
Copyright © 2020–2021 David Bürgin
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.