Email Server With Postfix Dovecot and MailScanner (Part 4 - SPF DKIM and DMARC)

Both SPF and DKIM has two parts: One is the DNS records for SPF/DKIM serve the purpose of setting your own policy for others to check. The other is to check if the incoming mail message is in accordance with the SPF/DKIM that is set by the admins of the domain from which the message was sent.

SPF

DNS txt record

Add a txt record to DNS server:

@ TXT 300 v=spf1 a ip4:11.22.33.44/32 include:mydomain.com ~all

Test it by sending an email to check-auth@verifier.port25.com and will get a report back.

SPF on Postfix

To prevent sender address forgery, we setup The Sender Policy Framework (SPF) on the postfix. When there is an incoming email, postfix will check the SPF record.

yum install perl-Mail-SPF perl-Sys-Hostname-Long

cd /usr/local/src
wget https://launchpad.net/postfix-policyd-spf-perl/trunk/release2.010/+download/postfix-policyd-spf-perl-2.010.tar.gz
tar zvxf postfix-policyd-spf-perl-2.010.tar.gz
cd postfix-policyd-spf-perl-2.010
cp postfix-policyd-spf-perl /usr/local/sbin/.

Then edit /etc/postfix/master.cf and add the following stanza at the end:

[...]
policy unix - n n - - spawn
user=nobody argv=/usr/bin/perl /usr/local/sbin/postfix-policyd-spf-perl

(The leading spaces before user=nobody ... are important so that Postfix knows that this line belongs to the previous one!)

Then open /etc/postfix/main.cf and search for the smtpd_recipient_restrictions directive. You should have reject_unauth_destination in that directive, and right after reject_unauth_destination you add check_policy_service unix:private/policy like this:

smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination, check_policy_service unix:private/policy
policy_time_limit = 3600

Restart MailScanner, send an email from gmail to gao@mydomain.com, in header:

Received-SPF: pass (gmail.com ... _spf.google.com: Sender is authorized to use 'gao@gmail.com' in 'mfrom' identity (mechanism 'include:_netblocks.google.com' matched)) receiver=szeta; identity=mailfrom; envelope-from="gao@gmail.com"; helo=mail-pa0-f48.google.com; client-ip=209.85.220.48

DKIM

OpenDKIM

Install OpenDKIM

yum install opendkim

Generate keys for signing
You need to generate a private and a public key for each of the domains for which you wish to sign mail. The private key is stored away on your server, while the public key gets published in your domain’s DNS records so that receiving mail servers can verify your DKIM-signed mail.
You need decide now what the name of your selector is going to be. A selector is a unique keyword that is associated with both keys (public and private), included in all the signatures, and published in your DNS records. For simplicity, I use the word szeta as my default selector.

mkdir -p /etc/opendkim/keys/mydomain.com
/usr/sbin/opendkim-genkey -D /etc/opendkim/keys/mydomain.com/ -d mydomain.com -s szeta

Now we have two files for each domain(the text file is the public key).

chown -R opendkim:opendkim /etc/opendkim/keys/*

Edit four configuration files:

  1. /etc/opendkim.conf (I created a new file)

    ##
    ## opendkim.conf -- configuration file for OpenDKIM filter
    ##
    AutoRestart Yes
    AutoRestartRate 10/1h
    Canonicalization relaxed/simple
    ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
    InternalHosts refile:/etc/opendkim/TrustedHosts
    KeyTable refile:/etc/opendkim/KeyTable
    LogWhy Yes
    Mode sv
    PidFile /var/run/opendkim/opendkim.pid
    SignatureAlgorithm rsa-sha256
    SigningTable refile:/etc/opendkim/SigningTable
    Socket inet:8891@localhost
    Syslog Yes
    SyslogSuccess Yes
    TemporaryDirectory /var/tmp
    UMask 022
    UserID opendkim:opendkim
  2. /etc/opendkim/KeyTable

    szeta._domainkey.mydomain.com mydomain.com:szeta:/etc/opendkim/keys/mydomain.com/szeta
  3. /etc/opendkim/SigningTable

    *@mydomain.com szeta._domainkey.mydomain.com
  4. /etc/opendkim/TrustedHosts

    127.0.0.1
    ::1
    localhost

Now enable OpenDKIM in Postfix, edit /etc/postfix/main.cf, add

smtpd_milters = inet:127.0.0.1:8891
non_smtpd_milters = $smtpd_milters
milter_default_action = accept

Now start services

systemctl enable opendkim
systemctl start opendkim
systemctl restart MailScanner

DNS txt record

Now that the mail server is signing outgoing mail and verifying incoming mail, you’ll need to put some information in your DNS records to tell other mail servers how your keys are set up, and provide the public key for them to check that your mail is properly signed.

Use the public key created above to add a DNS TEXT record to mydomain.com.

Check:

$ dig szeta._domainkey.mydomain.com TXT +noall +answer 

szeta._domainkey.mydomain.com. 3599 IN TXT "v=DKIM1\; k=rsa\; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDGYaonAHWmVitTa9p4QRmtjobBRyWflXwCa3akQ87aJ2iT8bg/25/t7dwzOq4nRS9CoW6vu9gVPBS6hWIumRoWFwYfwgUXGWCxMQLr6Nc7wuKnqPOoA6/JTa0s1o0QWiY18k1Rsh8p4/oRQilCEVjvdezRxsIigIEGUlEn9a+xqwIDAQAB"

Test

Restart MailScanner then send email to check-auth@verifier.port25.com then read the report, also analyse header as well.

DMARC

A DMARC policy allows a sender to indicate that their emails are protected by SPF and/or DKIM, and give instruction if neither of those authentication methods passes. Please be sure you have a DKIM and SPF set before using DMARC.

To enable DMARC, just add a TXT DNS record. Host name is _dmarc and text value is v=DMARC1; p=none ;rua=mailto:postmaster@mydomain.com

To check:

# dig _dmarc.mydomain.com TXT +noall +answer 
_dmarc.mydomain.com. 7207 IN TXT "v=DMARC1\;p=none\;rua=mailto:postmaster@mydomain.com"

Test mail server

A final test for the email server can be done at https://www.mail-tester.com/. I got a score of 10/10! -:)


Quick links: