====== 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