Configure OpenDKIM with Postfix on Debian

Configure OpenDKIM with Postfix on Debian

DKIM (DomainKeys Identified Mail) is an email authentication protocol that allows recipients to verify that an email message truly came from the domain that it claims to have come from. Because spam often contains counterfeit headers, this type of authentication is required. DKIM uses public-key cryptography to enable senders to electronically sign valid emails in a way that recipients can verify. DKIM also protects mail from tampering, providing nearly end-to-end integrity from the signature to the validating Mail Transfer Agent (MTA).

Further reading: Explanation DKIM (DomainKeys Identified Mail) in all details

Further reading: What is email envelope and email header

Install OpenDKIM

apt-get install opendkim opendkim-tools

Configure OpenDKIM

Our goal is configure OpenDKIM for two domains: example1.com and example2.com.

Let's start with the main configuration file /etc/opendkim.conf

Clear the content of this file and append the following lines to the end of the conf file (each parameter is explained below). Optionally, you can choose a custom port number for the Socket. Make sure that it's not used by a different application.

/etc/opendkim.conf
AutoRestart             true
AutoRestartRate         10/1h
UMask                   002
Syslog                  true
SyslogSuccess           true
LogResults              true
LogWhy                  true

Canonicalization        relaxed/simple

MTA                     file:/etc/opendkim/mta.table
ExternalIgnoreList      refile:/etc/opendkim/TrustedHosts
InternalHosts           refile:/etc/opendkim/TrustedHosts
KeyTable                refile:/etc/opendkim/key.table
SigningTable            refile:/etc/opendkim/signing.table

Mode                    s
PidFile                 /run/opendkim/opendkim.pid
SignatureAlgorithm      rsa-sha256

UserID                  opendkim:opendkim
Socket                  inet:8887@localhost

Parameter Description
Domain default (none), Specify for which domain(s) signing should be done. No default; must be specified for signing. We configure domain with KeyTable and SigningTable
AutoRestart auto restart the filter on failures
AutoRestartRate specifies the filter's maximum restart rate, if restarts begin to happen faster than this rate, the filter will terminate; 10/1h - 10 restarts/hour are allowed at most
UMask gives all access permissions to the user group defined by UserID and allows other users to read and execute files, in this case it will allow the creation and modification of a Pid file.
Syslog these parameter enable logging via calls to syslog
SyslogSuccess Log success activity to syslog?
LogWhy If logging is enabled (see Syslog below), issues very detailed logging about the logic behind the filter's decision to either sign a message or verify it.
Canonicalization defines the canonicalization methods used at message signing, the simple method allows almost no modification while the relaxed one tolerates minor changes such as whitespace replacement; relaxed/simple - the message header will be processed with the relaxed algorithm and the body with the simple one
MTA A set of MTA names (a la the sendmail(8) DaemonPortOptions Name parameter ) whose mail should be signed by this filter. There is no default, meaning MTA name is not considered when making the sign-verify decision.
ExternalIgnoreList specifies the external hosts that can send mail through the server as one of the signing domains without credentials
InternalHosts defines a list of internal hosts whose mail should not be verified but signed instead. Identifies a set internal hosts whose mail should be signed rather than verified. Entries in this data set follow the same form as those of the PeerList option below. If not specified, the default of "127.0.0.1" is applied. Naturally, providing a value here overrides the default, so if mail from 127.0.0.1 should be signed, the list provided here should include that address explicitly.
KeyTable Maps key names to signing keys. In simple terms, this tells OpenDKIM where to find your kyes. If present, overrides any KeyFile directive. Require SigningTable enabled.
SigningTable lists the signatures to apply to a message based on the address found in the From: header field. The value of the lookup should return the name of a key found in the KeyTable that should be used to sign the message.
Mode declares operating modes; s for sing, v for verify, or sv for both sign and verify
PidFile the path to the Pid file which contains the process identification number
SignatureAlgorithm selects the signing algorithm to use when creating signatures
UserID the opendkim process runs under this user and group
Socket the milter will listen on the socket specified here, Posfix will send messages to opendkim for signing and verification through this socket; 8887@localhost defines a TCP socket that listens on localhost, port 8887
SignHeaders Specifies the set of header fields that should be included when generating signatures. If the list omits any header field that is mandated by the DKIM specification, those fields are implicitly added. By default, those fields listed in the DKIM specification as "SHOULD" be signed (RFC6376, Section 5.4) will be signed by the filter. See the OmitHeaders configuration option for more information about the format and interpretation of this field.
OmitHeaders Specifies a set of header fields that should be omitted when generating signatures. If an entry in the list names any header field that is mandated by the DKIM specification, the entry is ignored. A set of header fields is listed in the DKIM specification (RFC6376, Section 5.4) as "SHOULD NOT" be signed; the default list for this parameter contains those fields (Return-Path, Received, Comments, Keywords, Bcc, Resent-Bcc and DKIM-Signature). To omit no headers, simply use the string "." (or any string that will match no header field names). Specifying a list with this parameter replaces the default entirely, unless one entry is "" in which case the list is interpreted as a delta to the default; for example, ",+foobar" will use the entire default list plus the name "foobar", while "*,-Bcc" would use the entire default list except for the "Bcc" entry.

source: opendkim.conf man page

Create OpenDKIM files from config

Create file /etc/opendkim/TrustedHosts with this content:

/etc/opendkim/TrustedHosts
127.0.0.1

Create file /etc/opendkim/mta.table with this content:

/etc/opendkim/mta.table
mta.example.com

Create OpenDKIM signing table

This file is used for declaring the domains/email addresses and their selectors.

Create opendkim base directory and /etc/opendkim/signing.table file:

mkdir /etc/opendkim
touch /etc/opendkim/signing.table
/etc/opendkim/signing.table
*@example1.com    mail._domainkey.example1.com
*@example2.com    mail._domainkey.example2.com

The syntax of SigningTable is:

*@domain.com    selector._domainkey.domain.com

Create OpenDKIM key table

Create file /etc/opendkim/key.table.

touch /etc/opendkim/key.table

A key table contains each selector/domain pair and the path to their private key.

Edit file /etc/opendkim/key.table:

/etc/opendkim/key.table
mail._domainkey.example1.com    example1.com:mail:/etc/opendkim/keys/example1.com/mail.private
mail._domainkey.example2.com    example2.com:mail:/etc/opendkim/keys/example2.com/mail.private

The syntax of KeyTable is:

selector._domainkey.domain.com    domain.com:selector:/full_path_to_dir_in_key.table/selector.private

Generate OpenDKIM public and private keys

Change to the opendkim directory and create a separate folders for the domains to hold the keys:

cd /etc/opendkim
mkdir keys
mkdir keys/example1.com
mkdir keys/example2.com

Generate keys using opendkim-genkey tool for domain example1.com:

~] opendkim-genkey -b 2048 -s mail -d example1.com -D /etc/opendkim/keys/example1.com/ -v
opendkim-genkey: generating private key
opendkim-genkey: private key written to mail.private
opendkim-genkey: extracting public key
opendkim-genkey: DNS TXT record written to mail.txt

and for domain example2.com:

~] opendkim-genkey -b 2048 -s mail -d example2.com -D /etc/opendkim/keys/example2.com/ -v
opendkim-genkey: generating private key
opendkim-genkey: private key written to mail.private
opendkim-genkey: extracting public key
opendkim-genkey: DNS TXT record written to mail.txt

verify content of key files directories:

~] ls -o /etc/opendkim/keys/example1.com/
-rw------- 1 root 1675  7. dec 15.28 mail.private
-rw------- 1 root  512  7. dec 15.28 mail.txt
~] ls -o /etc/opendkim/keys/example2.com/
-rw------- 1 root 1679  7. dec 15.30 mail.private
-rw------- 1 root  512  7. dec 15.30 mail.txt

restart OpenDKIM daemon:

~] systemctl restart opendkim

check status opendkim daemon:

~] systemctl status opendkim
● opendkim.service - OpenDKIM Milter
     Loaded: loaded (/lib/systemd/system/opendkim.service; enabled; preset: enabled)
     Active: active (running) since Fri 2024-04-12 16:48:26 CEST; 46s ago
       Docs: man:opendkim(8)
             man:opendkim.conf(5)
             man:opendkim-lua(3)
             man:opendkim-genkey(8)
             man:opendkim-genzone(8)
             man:opendkim-testkey(8)
             http://www.opendkim.org/docs.html
    Process: 175917 ExecStart=/usr/sbin/opendkim (code=exited, status=0/SUCCESS)
   Main PID: 175919 (opendkim)
      Tasks: 7 (limit: 4653)
     Memory: 2.2M
        CPU: 24ms
     CGroup: /system.slice/opendkim.service
             ├─175919 /usr/sbin/opendkim
             └─175920 /usr/sbin/opendkim

Apr 12 16:48:26 mailout1 systemd[1]: Starting opendkim.service - OpenDKIM Milter...
Apr 12 16:48:26 mailout1 systemd[1]: opendkim.service: Can't open PID file /run/opendkim/opendkim.pid (yet?) after start: No such file or directory
Apr 12 16:48:26 mailout1 opendkim[175920]: OpenDKIM Filter v2.11.0 starting
Apr 12 16:48:26 mailout1 systemd[1]: Started opendkim.service - OpenDKIM Milter.

Check OpenDKIM listen on inet port 8887:

~] netstat -lnp | grep 8887
tcp        0      0 127.0.0.1:8887          0.0.0.0:*               LISTEN      175920/opendkim

Publish Your DKIM Public Key in DNS Records

Display the public key:

~] cat /etc/opendkim/keys/example1.com/mail.txt 
mail._domainkey IN      TXT     ( "v=DKIM1; h=sha256; k=rsa; "
          "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv7LKyl/k5QwPSSJwfH91S9ORmPNsPnezvBISsdQ4RGYU4E7NrGT7+8oZ7Zihtwr3LaFt8VN2+wj7lxgcGg7p800EmHSJRCgMHQQrEA2dWGHy0xp4U4mWl0diuTp85DCpmHUulv/ZwQbwP9L2pPuZP2D63LKpc1YPmHjmAtcDda2uPOuvoa6gwYZrYPOh05SBBCgZfweeehV7+r"
          "Nys0SwcpIhqVGANt2vRCHqi2Uhz+AkuUFbb8JvjNSUDxF74MYN58Xu2ibWvXa8kXQQTB7X1q1dnWJZt5kvOyVhD16WpZm3gaXBcFxUICzSLQYEhre25w5k+T1XC1AQZL8yPdyugwIDAQAB" )  ; ----- DKIM key mail for example1.com

In your DNS manager, create a TXT record, enter mail._domainkey in the name field. Then go back to the terminal window, copy everything between the parentheses and paste it into the value field of the DNS record. You need to delete all double quotes and white spaces in the value field. If you don’t delete them, then the key test in the next step will probably fail.

Your TXT dns record for mail._domainkey for example1.com domain:

v=DKIM1; h=sha256; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv7LKyl/k5QwPSSJwfH91S9ORmPNsPnezvBISsdQ4RGYU4E7NrGT7+8oZ7Zihtwr3LaFt8VN2+wj7lxgcGg7p800EmHSJRCgMHQQrEA2dWGHy0xp4U4mWl0diuTp85DCpmHUulv/ZwQbwP9L2pPuZP2D63LKpc1YPmHjmAtcDda2uPOuvoa6gwYZrYPOh05SBBCgZfweeehV7+rNys0SwcpIhqVGANt2vRCHqi2Uhz+AkuUFbb8JvjNSUDxF74MYN58Xu2ibWvXa8kXQQTB7X1q1dnWJZt5kvOyVhD16WpZm3gaXBcFxUICzSLQYEhre25w5k+T1XC1AQZL8yPdyugwIDAQAB

test DNS record:

~] dig txt mail._domainkey.example1.com
;; ANSWER SECTION:
mail._domainkey.sherlog.eu. 120 IN      TXT     "v=DKIM1; h=sha256; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv7LKyl/k5QwPSSJwfH91S9ORmPNsPnezvBISsdQ4RGYU4E7NrGT7+8oZ7Zihtwr3LaFt8VN2+wj7lxgcGg7p800EmHSJRCgMHQQrEA2dWGHy0xp4U4mWl0diuTp85DCpmHUulv/ZwQbwP9L2pPuZP2D63LKpc1YPmHjmAtcDda2uPOuvoa6gwYZ" "rYPOh05SBBCgZfweeehV7+rNys0SwcpIhqVGANt2vRCHqi2Uhz+AkuUFbb8JvjNSUDxF74MYN58Xu2ibWvXa8kXQQTB7X1q1dnWJZt5kvOyVhD16WpZm3gaXBcFxUICzSLQYEhre25w5k+T1XC1AQZL8yPdyugwIDAQAB"

Test DKIM Key

Enter the following command on Debian server to test your key.

~] opendkim-testkey -d example1.com -s mail -vvv
opendkim-testkey: using default configfile /etc/opendkim.conf
opendkim-testkey: checking key 'mail._domainkey.example1.com'
opendkim-testkey: key not secure
opendkim-testkey: key OK

If everything is OK, you will see Key OK in the command output.

If you see Key not secure in the command output, don’t panic. This is because DNSSEC isn’t enabled on your domain name. DNSSEC is a security standard for secure DNS query. Most domain names haven’t enabled DNSSEC. There’s absolutely no need to worry about Key not secure. You can continue to follow this guide.

Note that your DKIM record may need some time to propagate to the Internet. Depending on the domain registrar you use, your DNS record might be propagated instantly, or it might take up to 24 hours to propagate. You can go to https://mxtoolbox.com/dkim.aspx , enter mail as the selector and enter your domain name to check DKIM record propagation.

Connect Postfix to OpenDKIM

Next, we add the service (now available on port 8887) to the milters listed for the all Postfix smtp/25 services in the file /etc/postfix/master.cf:

42
43
44
45
46
47
48
49
50
192.168.0.223:smtp       inet    n       -       n       -       -       smtpd
 -o mail_name=postfix/smtpd/smtpd25
 -o strict_rfc821_envelopes=yes
 -o smtpd_tls_security_level=may
 -o smtpd_sasl_auth_enable=yes
 -o smtpd_sender_restrictions=reject_non_fqdn_sender,permit_sasl_authenticated,permit_mynetworks,reject
 -o smtpd_recipient_restrictions=permit_sasl_authenticated,permit_mynetworks,reject
 -o smtpd_milters=inet:127.0.0.1:8887
 -o content_filter=spam

restart postfix service:

~] systemctl restart postfix

Resources

SUBSCRIBE FOR NEW ARTICLES

@
comments powered by Disqus