Phase 5: DKIM/DMARC/SPF
Phase 5: DKIM/DMARC/SPF Authentication
Objective
Install OpenDKIM and OpenDMARC as postfix milters. Configure DKIM signing for outbound mail, DKIM/DMARC verification for inbound mail, and SPF checking. After this phase, every message carries Authentication-Results headers — the same headers Abnormal Security reads via M365 Graph API.
Concepts
| Term | Meaning |
|---|---|
Milter |
Mail filter — a plugin interface for postfix/sendmail. Milters inspect and modify messages during SMTP transaction. |
DKIM Signing |
Outbound: hash message body + selected headers, sign with private key, add |
DKIM Verification |
Inbound: extract |
DMARC Alignment |
The |
Authentication-Results |
Header added by the receiving MTA summarizing SPF, DKIM, and DMARC verdicts. This is what Abnormal reads. |
OpenDKIM Installation
sudo dnf install -y opendkim opendkim-tools
sudo systemctl enable opendkim
Generate DKIM Key Pair
sudo mkdir -p /etc/opendkim/keys
sudo opendkim-genkey -s default -d inside.domusdigitalis.dev -D /etc/opendkim/keys/
sudo chown opendkim:opendkim /etc/opendkim/keys/default.private
# View public key (this goes in DNS — Phase 4)
cat /etc/opendkim/keys/default.txt
OpenDKIM Configuration
sudo tee /etc/opendkim.conf <<'EOF'
Syslog yes
Mode sv
Canonicalization relaxed/simple
Domain inside.domusdigitalis.dev
Selector default
KeyFile /etc/opendkim/keys/default.private
Socket inet:8891@localhost
SigningTable refile:/etc/opendkim/signing.table
KeyTable /etc/opendkim/key.table
InternalHosts /etc/opendkim/trusted.hosts
EOF
# Signing table
echo "*@inside.domusdigitalis.dev default._domainkey.inside.domusdigitalis.dev" | sudo tee /etc/opendkim/signing.table
# Key table
echo "default._domainkey.inside.domusdigitalis.dev inside.domusdigitalis.dev:default:/etc/opendkim/keys/default.private" | sudo tee /etc/opendkim/key.table
# Trusted hosts
sudo tee /etc/opendkim/trusted.hosts <<EOF
127.0.0.1
::1
10.50.1.91
10.50.1.0/24
EOF
OpenDMARC Installation
sudo dnf install -y opendmarc
sudo systemctl enable opendmarc
OpenDMARC Configuration
sudo tee /etc/opendmarc.conf <<'EOF'
Socket inet:8893@localhost
AuthservID mail-01.inside.domusdigitalis.dev
RejectFailures false
SPFSelfValidate true
HistoryFile /var/run/opendmarc/opendmarc.dat
EOF
SPF Verification
sudo dnf install -y pypolicyd-spf
Add to postfix main.cf:
sudo postconf -e "policy-spf_time_limit = 3600s"
Add to master.cf:
# Append SPF policy service
echo "policy-spf unix - n n - - spawn
user=nobody argv=/usr/libexec/postfix/policyd-spf" | sudo tee -a /etc/postfix/master.cf
Connect Milters to Postfix
sudo postconf -e "milter_default_action = accept"
sudo postconf -e "milter_protocol = 6"
sudo postconf -e "smtpd_milters = inet:localhost:8891, inet:localhost:8893"
sudo postconf -e "non_smtpd_milters = inet:localhost:8891"
sudo postconf -e "smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination, check_policy_service unix:private/policy-spf"
Restart All Services
sudo systemctl restart opendkim opendmarc postfix
sudo systemctl status opendkim opendmarc postfix
Test Authentication Headers
# Send a test message
echo "Subject: Auth test from Phase 5
This is a test of DKIM signing and authentication." | sendmail -v evan@inside.domusdigitalis.dev
# Inspect headers on delivered message
# Look for: DKIM-Signature, Authentication-Results (spf, dkim, dmarc)
head -50 ~/Maildir/new/$(ls -t ~/Maildir/new/ | head -1)
Expected headers:
Authentication-Results: mail-01.inside.domusdigitalis.dev;
dkim=pass header.d=inside.domusdigitalis.dev;
spf=pass smtp.mailfrom=inside.domusdigitalis.dev;
dmarc=pass header.from=inside.domusdigitalis.dev
DKIM-Signature: v=1; a=rsa-sha256; d=inside.domusdigitalis.dev; s=default; ...
Verification Checklist
-
OpenDKIM running:
systemctl is-active opendkim -
OpenDMARC running:
systemctl is-active opendmarc -
DKIM key in DNS:
dig @10.50.1.90 TXT default._domainkey.inside.domusdigitalis.dev +short -
Outbound mail has
DKIM-Signatureheader -
Delivered mail has
Authentication-Resultsheader with spf, dkim, dmarc verdicts -
opendkim-testkey -d inside.domusdigitalis.dev -s default -vvvpasses