Hier werden die Unterschiede zwischen zwei Versionen gezeigt.
Nächste Überarbeitung | Vorherige Überarbeitung | ||
fortgeschrittene:postfix-opendkim [2022/09/18 20:58] ingo_wichmann angelegt |
fortgeschrittene:postfix-opendkim [2022/12/24 11:30] (aktuell) ingo_wichmann [opendkim konfigurieren] |
||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
- | TODO: noch nicht fertig | + | ====== OpenDKIM ====== |
+ | ===== Pakete ===== | ||
+ | * Debian (11): ''opendkim'', zum Testen zusätzlich: ''opendkim-tools miltertest'' | ||
+ | ===== dkim Schlüsselpaar erzeugen ===== | ||
+ | mkdir /etc/opendkim | ||
+ | cd /etc/opendkim | ||
+ | opendkim-genkey -d linuxhotel.de | ||
+ | (( Alternativ kann man den Selector z.B. mit ''-s 2022'' auf einen selbst gewählten Wert setzen. Übliche Werte sind der hostname (nicht der fqdn) oder das Jahr. Läßt man das wie hier weg, dann wird "default" genommen. )) | ||
- | Pakete: | + | ===== öffentlichen Schlüssel der DNS-Zone hinzufügen ===== |
- | opendkim | + | cat default.txt >> /var/cache/bind/master/linuxhotel.de |
- | zum Testen zusätzlich: | + | |
- | opendkim-tools miltertest | + | |
- | + | ||
- | + | ||
- | cd /etc/dkimkeys | + | |
- | sudo -u opendkim opendkim-genkey -s brahma20220917 -d taikonet.de | + | |
- | (( man kann den Selector (-s brahma20220917) auch weglassen, dann wird "default" genommen. Übliche Werte sind der hostname (nicht der fqdn) oder das Jahr )) | + | |
- | chgrp opendkim brahma20220917.private | + | |
- | chmod g+r brahma20220917.private | + | |
- | cat brahma20220917.txt >> /var/cache/bind/master/ingo-wichmann.de | + | |
DKIM Keys werden selten ausgetauscht. TTL kann in der Regel länger sein als andere, z.B. auf 1D (1 Tag) anpassen. Auf der anderen Seite: zum Testen mit "t=y;" kann auch eine kürzere TTL praktisch sein. | DKIM Keys werden selten ausgetauscht. TTL kann in der Regel länger sein als andere, z.B. auf 1D (1 Tag) anpassen. Auf der anderen Seite: zum Testen mit "t=y;" kann auch eine kürzere TTL praktisch sein. | ||
- | vim /var/cache/bind/master/ingo-wichmann.de | + | vim /var/cache/bind/master/linuxhotel.de |
- | named-checkzone -D ingo-wichmann.de /var/cache/bind/master/ingo-wichmann.de | grep _domainkey | + | named-checkzone -D linuxhotel.de /var/cache/bind/master/linuxhotel.de | grep _domainkey |
- | -><file> | + | ->${selector}._domainkey.${domain} |
- | brahma20220917._domainkey.ingo-wichmann.de. 86400 IN TXT "v=DKIM1; h=sha256; k=rsa; " "p=MIIB.... | + | <file> |
+ | default._domainkey.linuxhotel.de. 86400 IN TXT "v=DKIM1; h=sha256; k=rsa; " "p=MIIB.... | ||
</file> | </file> | ||
- | ${selector}._domainkey.${domain} | + | rndc reload linuxhotel.de |
- | rndc reload ingo-wichmann.de | + | |
journalctl -fu named.service | journalctl -fu named.service | ||
- | dig @127.0.0.1 brahma20220917._domainkey.ingo-wichmann.de txt | + | |
+ | ==== DNS-Eintrag prüfen ==== | ||
+ | dig @127.0.0.1 default._domainkey.linuxhotel.de txt | ||
-> DKIM Record Check (gibt es eine Alternative zu https://www.dmarcanalyzer.com/dkim/dkim-checker ?) | -> DKIM Record Check (gibt es eine Alternative zu https://www.dmarcanalyzer.com/dkim/dkim-checker ?) | ||
- | sudo -u opendkim -g opendkim opendkim-testkey -d ingo-wichmann.de -s brahma20220917 -k brahma20220917.private -vv | + | opendkim-testkey -d linuxhotel.de -s default -k default.private -vv |
- | -> "brahma20220917.private: WARNING: unsafe permissions" ist meiner Meinung nach hier irreführend. Das kann man mit chown opendkim brahma20220917.private && chmod g-r brahma20220917.private fixen, aber dadurch gibt man dem opendkim-Prozess Owner- und Schreibrechte an der Datei. Nicht besser. | + | -> "key not secure" bedeutet, dass die DNS Antwortwort nicht mit DNSSEC validiert werden konnte (fehlendes AD flag in der Ausgabe von ''dig'') - DKIM funktioniert aber auch ohne DNSSEC. Aber natürlich ist es mit DNSSEC besser. |
- | -> "key not secure" bedeutet, dass die DNS Antwortwort nicht mit DNSSEC validiert werden konnte (fehlendes AD flag) - DKIM funktioniert aber auch ohne DNSSEC. Aber natürlich ist es mit DNSSEC besser. | + | ===== opendkim konfigurieren ===== |
+ | Verzeichnis für Unix-Socket anlegen: | ||
+ | mkdir /var/spool/postfix/opendkim | ||
+ | chgrp opendkim /var/spool/postfix/opendkim | ||
+ | chmod o-rwx /var/spool/postfix/opendkim | ||
<file txt /etc/opendkim.conf> | <file txt /etc/opendkim.conf> | ||
- | Domain ingo-wichmann.de | + | Domain linuxhotel.de |
- | # können auch mehrere Domains sein, kann auch eine Dateiname einer Datei sein, die mehere Domains enthält. | + | # können auch mehrere Domains sein, kann auch ein Pfad zu einer Datei sein, die mehrere Domains enthält. |
- | Selector brahma20220917 | + | # Selector 2022 |
# wenn man nichts einstellt, dann "default" | # wenn man nichts einstellt, dann "default" | ||
- | KeyFile /etc/dkimkeys/brahma20220917.private | + | KeyFile /etc/opendkim/default.private |
+ | |||
+ | Socket local:/var/spool/postfix/opendkim/opendkim.sock | ||
+ | # Postfix smtpd läuft im chroot, daher muss der Socket da hin | ||
InternalHosts 127.0.0.0/8, | InternalHosts 127.0.0.0/8, | ||
- | # hier alle IP-Adressen von SMTP-Clients, die über diesen MTA versenden. | + | # hier alle IP-Adressen von unauthentifizierten SMTP-Clients, die über diesen MTA versenden. SASL-authentifizierte SMTP-Clients werden unabhängig von Ihrer IP-Adresse signiert. |
+ | </file> | ||
+ | Die [[https://wiki.debian.org/opendkim#DNS_resolution|opendkim-Version in Debian macht DNS-Anfragen selbst]], und nutzt nicht die Einstellungen aus ''/etc/nsswitch.conf'' und ''/etc/resolv.conf''. Wenn opendkim die selben Nameserver nutzen soll, dann muss man die mit ''Nameservers ...'' angeben. | ||
- | #KeyTable refile:/etc/opendkim/KeyTable | + | Syntax testen: |
- | #SigningTable refile:/etc/opendkim/SigningTable | + | opendkim -n |
- | </file> | + | |
- | mkdir /var/spool/postfix/opendkim | + | opendkim neu starten: |
- | chgrp opendkim /var/spool/postfix/opendkim | + | systemctl restart opendkim.service |
- | chmod g-rwx /var/spool/postfix/opendkim | + | |
- | chmod o-rwx /var/spool/postfix/opendkim | + | |
- | Testen: | + | ==== opendkim testen ==== |
<file txt test.eml> | <file txt test.eml> | ||
- | To: iw@example.com | + | To: test@example.com |
Subject: Testing DKIM | Subject: Testing DKIM | ||
Date: Wed, 29 Jan 2014 17:34:00 +0000 (UTC) | Date: Wed, 29 Jan 2014 17:34:00 +0000 (UTC) | ||
- | From: iw@ingo-wichmann.de | + | From: nutzer@linuxhotel.de |
hello dkim | hello dkim | ||
</file> | </file> | ||
- | sudo -u opendkim opendkim-testmsg -d ingo-wichmann.de -k /etc/dkimkeys/brahma20220917.private -s brahma20220917 < test.eml | + | opendkim-testmsg -d linuxhotel.de -k /etc/opendkim/default.private -s default < test.eml |
<code lua opendkim-testmilter.lua> | <code lua opendkim-testmilter.lua> | ||
- | -- socket = "local:/var/spool/postfix/opendkim/opendkim.sock" | + | -- usage: |
- | -- host = "localhost" | + | -- miltertest -s opendkim-testmilter.lua -D socket=local:/var/spool/postfix/opendkim/opendkim.sock -D host=localhost -D ip=127.0.0.1 -D from=test@linuxhotel.de |
- | -- ip = "127.0.0.1" | + | |
- | -- from = "test@ingo-wichmann.de" | + | -- TODO: auth_type |
- | -- to = "none@example.com" | + | |
- | -- date = "Wed, 29 Jan 2014 17:34:00 +0000 (UTC)" | + | |
- | -- subject = "Testing DKIM" | + | |
conn = mt.connect(socket) | conn = mt.connect(socket) | ||
Zeile 85: | Zeile 87: | ||
error "mt.conninfo() failed" | error "mt.conninfo() failed" | ||
else | else | ||
- | msg = "send connection info - host: " .. host .. "ip: " .. ip | + | msg = "send connection info - host: " .. host .. ", ip: " .. ip |
- | print("send connection info") | + | print(msg) |
end | end | ||
print("") | print("") | ||
print("send envelope macros and sender data") | print("send envelope macros and sender data") | ||
-- mt.helo() is called implicitly | -- mt.helo() is called implicitly | ||
+ | -- TODO: auth_type | ||
mt.macro(conn, SMFIC_MAIL, "i", "test-id") | mt.macro(conn, SMFIC_MAIL, "i", "test-id") | ||
if mt.mailfrom(conn, from) ~= nil then | if mt.mailfrom(conn, from) ~= nil then | ||
Zeile 100: | Zeile 103: | ||
if mt.getreply(conn) ~= SMFIR_CONTINUE then | if mt.getreply(conn) ~= SMFIR_CONTINUE then | ||
error "mt.mailfrom() unexpected reply" | error "mt.mailfrom() unexpected reply" | ||
- | end | ||
- | if mt.rcptto(conn, to) ~= nil then | ||
- | error "mt.rcptto() failed" | ||
- | else | ||
- | msg = "send rcptto " .. to | ||
- | print(msg) | ||
- | end | ||
- | if mt.getreply(conn) ~= SMFIR_CONTINUE then | ||
- | error "mt.rcptto() unexpected reply" | ||
end | end | ||
print("") | print("") | ||
Zeile 117: | Zeile 111: | ||
msg = "send From: " .. from | msg = "send From: " .. from | ||
print(msg) | print(msg) | ||
- | end | ||
- | if mt.header(conn, "To", to) ~= nil then | ||
- | error "mt.header(To) failed" | ||
- | else | ||
- | msg = "send To: " .. to | ||
- | print(msg) | ||
- | end | ||
- | if mt.getreply(conn) ~= SMFIR_CONTINUE then | ||
- | error "mt.header(From) unexpected reply" | ||
- | end | ||
- | -- if mt.header(conn, "Date", date) ~= nil then | ||
- | -- error "mt.header(Date) failed" | ||
- | -- else | ||
- | -- msg = "send Date: " .. date | ||
- | -- print(msg) | ||
- | -- end | ||
- | if mt.getreply(conn) ~= SMFIR_CONTINUE then | ||
- | error "mt.header(Date) unexpected reply" | ||
- | end | ||
- | if mt.header(conn, "Subject", "Signing test") ~= nil then | ||
- | error "mt.header(Subject) failed" | ||
- | else | ||
- | msg = "send Subject: " .. subject | ||
- | print(msg) | ||
- | end | ||
- | if mt.getreply(conn) ~= SMFIR_CONTINUE then | ||
- | error "mt.header(Subject) unexpected reply" | ||
end | end | ||
-- send EOH | -- send EOH | ||
Zeile 152: | Zeile 119: | ||
error "mt.eoh() unexpected reply" | error "mt.eoh() unexpected reply" | ||
end | end | ||
- | print("send body") | ||
- | if mt.bodystring(conn, "This is a test!\r\n") ~= nil then | ||
- | error "mt.bodystring() failed" | ||
- | end | ||
- | -- if mt.getreply(conn) ~= SMFIR_CONTINUE then | ||
- | -- error "mt.bodystring() unexpected reply" | ||
- | -- end | ||
- | -- end of message; let the filter react | ||
if mt.eom(conn) ~= nil then | if mt.eom(conn) ~= nil then | ||
error "mt.eom() failed" | error "mt.eom() failed" | ||
Zeile 180: | Zeile 139: | ||
-- wrap it up! | -- wrap it up! | ||
- | mt.disconnect(conn) | + | mt.disconnect(conn)</code> |
- | </code> | + | miltertest -s opendkim-testmilter.lua -D socket=local:/var/spool/postfix/opendkim/opendkim.sock -D host=localhost -D ip=127.0.0.1 -D from=test@linuxhotel.de |
- | miltertest -s opendkim-testmilter.lua -D socket=local:/var/spool/postfix/opendkim/opendkim.sock -D host=localhost -D ip=127.0.0.1 -D from=test@ingo-wichmann.de -D to=none@example.com -D subject="Testing DKIM" | + | |
+ | ====== Postfix ====== | ||
+ | (( | ||
+ | Wenn wir opendkim bzw. unserer obigen Konfiguration nicht vertrauen: | ||
+ | postconf -e 'milter_default_action = accept' | ||
+ | postconf -e 'soft_bounce = yes' | ||
+ | Ich würde das nur einschalten, wenn es tatsächlich Ärger mit dem opendkim-Milter gibt. | ||
+ | Im Regelbetrieb sollten beide Einstellungen wieder auf ihren Default zurückgesetzt werden. | ||
+ | )) | ||
+ | |||
+ | Postfix Zugriffsrechte auf den opendkim-Socket geben: | ||
+ | gpasswd -a postfix opendkim | ||
+ | Postfix soll den opendkim-Milter nutzen: | ||
+ | postconf -e 'smtpd_milters = unix:opendkim/opendkim.sock' | ||
+ | postconf -e 'non_smtpd_milters = unix:opendkim/opendkim.sock' | ||
Doku: | Doku: | ||
https://www.mailhardener.com/kb/dkim | https://www.mailhardener.com/kb/dkim | ||
https://datacadamia.com/marketing/email/postfix/opendkim | https://datacadamia.com/marketing/email/postfix/opendkim |