150 lines
7.5 KiB
Markdown
150 lines
7.5 KiB
Markdown
---
|
||
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 |