Files
my-vault/00_Inbox/Clippings/2024/02/OpenDKIM on Postfix with virtual domains [rigacci.org].md
T

150 lines
7.5 KiB
Markdown
Raw Normal View History

2026-01-05 13:03:55 +08:00
---
page-title: "OpenDKIM on Postfix with virtual domains [rigacci.org]"
url: https://rigacci.org/wiki/doku.php/doc/appunti/linux/sa/postfix_opendkim
date: "2024-02-02 07:49:12"
---
### ****Table of Contents
## OpenDKIM on Postfix with virtual domains
In this tutorial we will install **[OpenDKIM](http://www.opendkim.org/ "http://www.opendkim.org/")** on a GNU/Linux mail server based on **Debian 11 Buster**. The mail service is provided by **Postfix** configured for virtual domains using **virtual\_alias\_domains**.
apt install opendkim opendkim-tools
In Debian 11 Bullseye the service is controlled (enable, start, stop, etc.) by Systemd:
systemctl status opendkim.service
Because Postfix is running into a chroot, it cannot access the `/run/opendkim/opendkim.sock` Unix socket to communicate with opendkim, so we change the `Socket` option into **/etc/opendkim.conf** and make the daemon to be listening on port **127.0.0.1:8891/TCP**:
Socket inet:8891@localhost
The same daemon is used both for signing and verifying. Signing is performed when the client connecting to the MUA is authenticated and the **From:** address matches the domains to be signed (see the command line option **\-d** or the **SigningTable** option of the `/etc/opendkim.conf` configuration file), verifying is performed in other cases.
## Create the keys in /etc/dkimkeys/
The canonical directory to keep the keys is **/etc/dkimkeys/**. For each domain we can have more than one key (e.g. when a key is to be renewed, etc.), so each key is identified by the **domain name** and by an arbitrary **selector**; it is a common practice to use the current year as the selector.
We create one subdirectory for each virtual domain:
DOMAIN\='rigacci.org'
SELECTOR\='2022'
mkdir /etc/dkimkeys/"$DOMAIN"
chown opendkim:opendkim /etc/dkimkeys/"$DOMAIN"
chmod 700 /etc/dkimkeys/"$DOMAIN"
sudo \-u opendkim opendkim-genkey \-D /etc/dkimkeys/"$DOMAIN" \-d "$DOMAIN" \-s "$SELECTOR"
This will create two files:
- **/etc/dkimkeys/$DOMAIN/$SELECTOR.private** - The RSA private key.
- **/etc/dkimkeys/$DOMAIN/$SELECTOR.txt** - The public key, already in TXT format to be inserted into the DNS zone.
## Add the private key in /etc/dkimkeys/keytable
It is necessary to tell OpenDKIM what is the private key to use when it wants to sign a mail from a domain. We must add one line for each domain into **/etc/dkimkeys/keytable**:
\[SELECTOR\].\_domainkey.\[DOMAIN\] \[DOMAIN\]:\[SELECTOR\]:/etc/dkimkeys/\[DOMAIN\]/\[SELECTOR\].private
## Add the public key into the DNS zone
Now it is necessary to publish the public key into the DNS. Just copy and paste the .txt file into the zone file:
2022.\_domainkey IN TXT ( "v=DKIM1; h=sha256; k=rsa; "
"p=MIIBIjANBgkqhkiG9w0BAQ..."
"W0CdtxNd+xRgCopJCp93CLiD..." ) ; ----- DKIM key 2022 for rigacci.org
## Add the domain (or single sender) to be signed
Into the file **/etc/dkimkeys/signingtable** we declare that mails originating from that domain must be signed:
\*@\[DOMAIN\] \[SELECTOR\].\_domainkey.\[DOMAIN\]
**NOTICE**: The use of the wildcard (to indicate all the senders from a domain) is possibile if *signingtable* is declared with **refile** (regular expression file) into the configuration file. Otherwise you have to specify every single sender address where signing is to be applied.
Remember to reload OpenDKIM after changing the **signingtable**:
systemctl reload opendkim.service
## Configure OpenDKIM
Into the **/etc/opendkim.conf** file we inform OpenDKIM to look into a **KeyTable** to find keys and into a **SigningTable** to know which domains require signing. The service will listen on port **8891/TCP** (should use *Unix domain socket* instead? Better performances? More painfull because Postfix runs in chroot).
\# We use virtual domains, so we use KeyTable and SigningTable
KeyTable file:/etc/dkimkeys/keytable
SigningTable refile:/etc/dkimkeys/signingtable
# Match a list of hosts whose messages will be signed.
# By default, only localhost is considered as internal host.
#InternalHosts refile:/etc/dkimkeys/trustedhosts
# Socket for the MTA connection (required).
Socket inet:8891@localhost
**NOTICE**: **refile** means that the file contains regular expressions (e.g. asterisk wildcard to indicate all the mail addresses into a domain).
## Test the OpenDKIM configuration
Reload the DNS Bind service and test that OpenDKIM can properly use the keys (it is not necessary to reload the OpenDKIM service):
\# opendkim-testkey -v -v
opendkim-testkey: using default configfile /etc/opendkim.conf
opendkim-testkey: record 0 for '2022.\_domainkey.rigacci.org' retrieved
opendkim-testkey: checking key '2022.\_domainkey.rigacci.org'
opendkim-testkey: key 2022.\_domainkey.rigacci.org not secure
opendkim-testkey: 1 keys checked; 1 pass, 0 fail
## Signing message test
cat message.txt \\
| opendkim-testmsg \-d "$DOMAIN" \-k "/etc/dkimkeys/$DOMAIN/$SELECTOR.private" \-s "$SELECTOR.$DOMAIN"
## Configure Postfix
Message signing with OpenDKIM is performed as a **milter** (mail filter) in Postfix; milters are declared into the **/etc/postfix/main.cf** configuration file.
Using the **non\_smtpd\_milters** directive we may add DKIM for locally generated mails, i.e. local submissions via sendmail command line, submissions to the **qmqpd**, ([Quick Mail Queuing Protocol](https://en.wikipedia.org/wiki/Quick%20Mail%20Queuing%20Protocol "https://en.wikipedia.org/wiki/Quick Mail Queuing Protocol") daemomn), re-injected mails. More generally we may apply DKIM signature for all the messages received by the SMTP daemon, using the **smtpd\_milters** directive.
Using custom settings in **/etc/postfix/master.cf**, you can declare specific milters for messages received from your users over the **submission** protocol only (port **587/TCP**). In this snippet of `master.cf` we use a custom **mua\_milters** directive:
submission inet n - y - - smtpd
-o syslog\_name=postfix/submission
-o smtpd\_tls\_security\_level=encrypt
-o smtpd\_sasl\_auth\_enable=yes
-o smtpd\_tls\_auth\_only=yes
-o smtpd\_client\_restrictions=permit\_sasl\_authenticated,reject
-o smtpd\_milters=$mua\_milters
-o smtpd\_sender\_restrictions=$mua\_sender\_restrictions
-o smtpd\_relay\_restrictions=$mua\_relay\_restrictions
Having done this, we define the custom **mua\_milters** directive in `main.cf` to apply SpamAssassin and DKIM filtering on sumbitted messages:
\# Locally generated mails (e.g. from command line Mutt) are filtered with OpenDKIM.
non\_smtpd\_milters = inet:localhost:8891
# Mails received via SMTP protocol are filtered with OpenDKIM;
# messages created using SoGO webmail go through this milter.
smtpd\_milters = inet:localhost:8891
# Filters applied (as smtpd\_milters) to messages received via SUMBISSION/587;
mua\_milters =
unix:spamass/spamass.sock,
inet:localhost:8891
Another important Postfix setting is **milter\_default\_action**, the default is **tempfail** which means that if the milter does not respond, the message will be held into the queue and retried later. Other settings can be **accept** or **reject**:
milter\_default\_action = tempfail
## Logging
When a message passes through the OpenDKIM filter, you get the following line into **mail.log**:
opendkim\[983999\]: 37FDD7D659: DKIM-Signature field added (s=2022, d=rigacci.org)
If a message does not match any entry in **/etc/dkimkeys/signingtable**, it will not be signed; the log is:
opendkim\[983999\]: 4778D7D610: no signing table match for 'testmail@rigacci.org'
opendkim\[983999\]: 4778D7D610: no signature data
## Web References