====== Add DKIM and DMARC support to Proxmox Mail Gateway ======
[[https://www.proxmox.com/en/proxmox-mail-gateway|Proxmox Mail Gateway]] is a great email filtering solution, but it lacks DKIM and DMARC support. This how-to explains how to add them. And also how to configure ports 465 and 587 for authenticated clients.
===== Enable authenticated ports =====
This is needed if you want your external clients to be able to relay emails through PMG. Ports 465 and 587 will be equivalent to the 26 one, but with encryption (either STARTTLS or SSL in Wrapper mode). I'll use AD to auth my user, but it could be another LDAP server
* Install SASL daemon
apt install sasl2-bin libsasl2-modules-ldap
* Add postfix to the sasl group
usermod -a -G sasl postfix
* Configure the SASL daemon
cat <<_EOF > /etc/default/saslauthd
START=yes
DESC="SASL Authentication Daemon"
NAME="saslauthd"
MECHANISMS="ldap"
MECH_OPTIONS=""
OPTIONS="-c -m /var/run/saslauthd"
_EOF
cat <<_EOF > /etc/postfix/sasl/smtpd.conf
pwcheck_method: saslauthd
mech_list: plain login
_EOF
cat << _EOF > /etc/saslauthd.conf
ldap_servers: ldap://dc1.domain.tld ldap://dc2.domain.tld
ldap_start_tls: yes
ldap_tls_check_peer: yes
ldap_tls_cacert_file: /etc/ssl/certs/ca-certificates.crt
ldap_search_base: DC=domain,DC=tld
ldap_filter: (&(|(memberOf=CN=Mail,OU=Groups,DC=domain,DC=tld)(sAMAccountName=smtp))(objectClass=user)(|(userPrincipalName=%u@domain.tld)(sAMAccountName=%u)))
ldap_bind_dn: CN=Proxmox Mail Gateway,OU=Apps,DC=doman,DC=tld
ldap_password: SuperSecretPassw0rd
_EOF
You need to adjust the addresses of your servers, the search base, the filter, the bind dn and its password of course
* Now start the sasl auth daemon
systemctl enable saslauthd
systemctl restart saslauthd
Note that auth is not enabled yet, postfix must be configured for this, we'll do it later, when enabling dkim and dmarc
===== Configure DKIM =====
We'll use the opendkim project for this. And we'll use two separated instances
* One responsible for signing outgoing email
* The other responsible for DKIM signature verification for inbound emails
* Install packages
apt install opendkim opendkim-tools
* Configuration for the //verifier// instance
mkdir /etc/opendkim
cat <<_EOF > /etc/opendkim/verifier.conf
Syslog yes
LogResults yes
LogWhy yes
SyslogSuccess yes
UMask 007
Mode v
AllowSHA1Only yes
AlwaysAddARHeader yes
Socket local:/var/run/opendkim/verifier.sock
PidFile /var/run/opendkim/verifier.pid
TrustAnchorFile /usr/share/dns/root.key
UserID opendkim
Background no
Nameservers 10.99.2.1
_EOF
Replace 10.99.2.1 with the DNS server you want to use, or remove the line to let opendkim resolv itself. You should use a local, recursive, caching resolver
* Configuration of the //signer// instance
cat <<_EOF > /etc/opendkim/signer.conf
Syslog yes
LogResults yes
LogWhy yes
SyslogSuccess yes
UMask 007
KeyTable /etc/opendkim/keytable
SigningTable /etc/opendkim/signingtable
Mode s
InternalHosts 0.0.0.0/0
Socket local:/var/run/opendkim/signer.sock
PidFile /var/run/opendkim/signer.pid
TrustAnchorFile /usr/share/dns/root.key
UserID opendkim
Background no
Nameservers 10.99.2.1
_EOF
cat <<_EOF > /etc/opendkim/signingtable
# Add one line per domain you want to sign when email are being sent.
# You can use different keys if needed
# Or just use a wildcard to sign everything with the same key
* default
_EOF
cat <<_EOF > /etc/opendkim/keytable
default %:default:/etc/opendkim/keys/default/default.private
_EOF
* Create the keys
mkdir -p /etc/opendkim/keys/default
chown opendkim /etc/opendkim/{keys,keys/default}
chmod 700 /etc/opendkim/{keys,keys/default}
opendkim-genkey -D /etc/opendkim/keys/default/ -s default }}
Replace 10.99.2.1 with the DNS server you want to use, or remove the line to let opendkim resolv itself. You should use a local, recursive, caching resolver
In this example, every outbound emails will be signed, and the same key will be used for all of them. You can configure different key though.
* Create systemd unit for both opendkim instances
cat <<_EOF > /etc/systemd/system/opendkim-signer.service
[Unit]
Description=OpenDKIM DomainKeys Identified Mail (DKIM) Milter - signer
Documentation=man:opendkim(8) man:opendkim.conf(5) man:opendkim-genkey(8) man:opendkim-genzone(8) man:opendkim-testadsp(8) man:opendkim-testkey http://www.opendkim.org/docs.html
After=network.target nss-lookup.target
[Service]
Type=simple
UMask=0007
ExecStart=/usr/sbin/opendkim -x /etc/opendkim/signer.conf
User=opendkim
Group=opendkim
MemoryLimit=50M
PrivateTmp=yes
PrivateDevices=yes
ProtectSystem=full
ProtectHome=yes
NoNewPrivileges=yes
Restart=on-failure
ExecReload=/bin/kill -USR1 $MAINPID
[Install]
WantedBy=multi-user.target
_EOF
cat <<_EOF > /etc/systemd/system/opendkim-verifier.service
[Unit]
Description=OpenDKIM DomainKeys Identified Mail (DKIM) Milter - verifier
Documentation=man:opendkim(8) man:opendkim.conf(5) man:opendkim-genkey(8) man:opendkim-genzone(8) man:opendkim-testadsp(8) man:opendkim-testkey http://www.opendkim.org/docs.html
After=network.target nss-lookup.target
[Service]
Type=simple
UMask=0007
ExecStart=/usr/sbin/opendkim -x /etc/opendkim/verifier.conf
User=opendkim
Group=opendkim
MemoryLimit=50M
PrivateTmp=yes
PrivateDevices=yes
ProtectSystem=full
ProtectHome=yes
NoNewPrivileges=yes
Restart=on-failure
ExecReload=/bin/kill -USR1 $MAINPID
[Install]
WantedBy=multi-user.target
_EOF
systemctl daemon-reload
* Start and enable the daemons
systemctl stop opendkim
systemctl disable opendkim
systemctl enable opendkim-signer
systemctl start opendkim-signer
systemctl enable opendkim-verifier
systemctl start opendkim-verifier
===== Configure DMARC =====
DMARC is a policy framework sitting on top of SPF and DKIM. This time, we only need one instance to filter incoming emails
* Install opendmarc
apt install opendmarc
* Configure dmarc
cat <<_EOF > /etc/opendmarc.conf
Background false
IgnoreAuthenticatedClients true
IgnoreHosts /etc/pmg/mynetworks
PidFile /var/run/opendmarc/opendmarc.pid
PublicSuffixList /usr/share/publicsuffix/
Syslog true
RejectFailures true
UMask 007
Socket local:/var/run/opendmarc/opendmarc.sock
HistoryFile /var/run/opendmarc/history.dat
_EOF
* Start and enable the service
systemctl enable opendmarc
systemctl start opendmarc
Storing and sending DMARC report can be done, but you need a mysql server. I'll leave it out of scope for this how-to, though, reporting is an important piece of DMARC
===== Configure postfix to use all this =====
Now, we just have to copy master.cf template and adjust it to make use of the new features
mkdir /etc/pmg/templates
cp -a /var/lib/pmg/templates/master.cf.in /etc/pmg/templates/
Edit **/etc/pmg/templates/master.cf.in** and apply this patch
-o smtpd_helo_restrictions=
-o smtpd_client_restrictions=
-o smtpd_sender_restrictions=
+ -o smtpd_milters=unix:/var/run/opendkim/signer.sock
[% pmg.mail.ext_port %] inet n - - - 1 postscreen
@@ -91,6 +23,25 @@
-o receive_override_options=no_address_mappings
-o smtpd_discard_ehlo_keywords=silent-discard,dsn
-o mynetworks=127.0.0.0/8,[% postfix.int_ip %]
+ -o smtpd_milters=unix:/var/run/opendkim/verifier.sock,unix:/var/run/opendmarc/opendmarc.sock
+
+submission inet n - - - 100 smtpd
+ -o content_filter=scan:127.0.0.1:10023
+ -o smtpd_enforce_tls=yes
+ -o smtpd_sasl_auth_enable=yes
+ -o smtpd_client_restrictions=permit_sasl_authenticated,reject
+ -o smtpd_recipient_restrictions=reject_unknown_recipient_domain
+ -o smtpd_sender_restrictions=
+ -o smtpd_helo_restrictions=
+ -o smtpd_milters=unix:/var/run/opendkim/signer.sock
+
+smtps inet n - - - 100 smtpd
+ -o content_filter=scan:127.0.0.1:10023
+ -o smtpd_tls_wrappermode=yes
+ -o smtpd_sasl_auth_enable=yes
+ -o smtpd_client_restrictions=permit_sasl_authenticated,reject
+ -o smtpd_recipient_restrictions=reject_unknown_recipient_domain
+ -o smtpd_sender_restrictions=
+ -o smtpd_helo_restrictions=
+ -o smtpd_milters=unix:/var/run/opendkim/signer.sock
127.0.0.1:10025 inet n - n - - smtpd
-o content_filter=
You can see we just add smtpd_milters for inbound and outbound. And we add two new listeners on 465 (smtps) and 587 (submission), with settings equivalent to the listener on port 26