content/blog/mail_server_alpine_postfix_dovecot_tutorial.md: write spf/dkim section

This commit is contained in:
revsuine 2024-11-21 03:32:47 +00:00
parent 109052b512
commit 1c9757a78f
Signed by: revsuine
GPG key ID: 3F257B68F5BC9339

View file

@ -782,6 +782,290 @@ With our setup, we are also able to use STARTTLS on port 143 (incoming) and 587
You should be able to send and receive emails as normal now.
# Set up SPF, DKIM, and DMARC
<abbr title="Sender Policy Framework">SPF</abbr>, <abbr title="DomainKeys Identified Mail">DKIM</abbr>, and <abbr
title="Domain-based Message Authentication, Reporting and Conformance">DMARC</abbr> records are TXT DNS records that
protect against people spoofing your domain. Having correctly configured SPF, DKIM, and DMARC records helps your mail
avoid getting caught by spam filters.
SPF records indicate which hosts or IP addresses are allowed to send email from your domain.
DKIM digitally signs emails with a private key to verify that they came from your server. If someone else without your
private key sends email from your domain, they wouldn't be able to produce a valid DKIM signature. DKIM public keys are
published in TXT DNS records, so that any other mail server can verify a signature of an email from your domain.
DMARC records state that your domain uses SPF and DKIM, and that emails sent from your domain should pass SPF and DKIM
checks.
## Sender Policy Framework
Add a TXT record for your root domain with the contents `v=spf1 mx ~all`, like:
```dns
revsuine.xyz. 900 IN TXT "v=spf1 mx ~all"
```
In your DNS manager, you would enter:
<!-- html table so that header can be column not row -->
<table>
<tr>
<th>Name</th>
<td><code>@</code></td>
</tr>
<tr>
<th>Type</th>
<td><code>TXT</code></td>
</tr>
<tr>
<th>TTL</th>
<td>Default (mine is 900)</td>
</tr>
<tr>
<th>TXT data</th>
<td><code>v=spf1 mx ~all</code></td>
</tr>
</table>
This is assuming you're sending emails from `domain.com` instead of, e.g. `sub.domain.com`. If your email addresses are
like `user@sub.domain.com`, you would use `sub` as the name in the DNS record instead of `@`, which denotes the apex
domain. The same applies for all the DNS records in this section.
Breaking down the TXT data:
<!-- html table bc the last cell is quite long in contents and markdown requires one cell to all be on one line -->
<table>
<tr>
<th>Part</th>
<th>Explanation</th>
</tr>
<tr>
<td><code>v=spf1</code></td>
<td>This is an SPF record, and the SPF record version is SPF1.</td>
</tr>
<tr>
<td><code>mx</code></td>
<td>All hosts listed in MX records are allowed to send emails from this domain.</td>
</tr>
<tr>
<td><code>~all</code></td>
<td>
Emails from your domain should only come from hosts specified by your SPF record. Can also be
<code>+all</code>, <code>-all</code>, <code>?all</code>, but those are rarely used. <code>-all</code> means
that emails not from SPF-approved hosts should be rejected; however, this option can cause valid emails to
be rejected if the recipient has multiple SMTP servers, and an email is relayed from one of their SMTP
servers to another, for instance if one SMTP server goes down and they have a backup server.
</td>
</tr>
</table>
## DomainKeys Identified Mail
### Configure OpenDKIM
OpenDKIM is an open-source implementation of DKIM signing and authentication. You can install it with:
# apk add opendkim opendkim-utils
You may also want `opendkim-doc` for documentation.
Add the `postfix` user to the `opendkim` group:
# adduser postfix opendkim
Edit your OpenDKIM config file at `/etc/opendkim/opendkim.conf`. Ensure the following is present (`Canonicalization` is
likely already there, so just change and uncomment things, and add lines where necessary):
```conf
Canonicalization relaxed/simple
Mode sv
SubDomains no
AutoRestart yes
AutoRestartRate 10/1M
Background yes
DNSTimeout 5
SignatureAlgorithm rsa-sha256
```
Add the following to the config file:
```conf
# OpenDKIM user
# Remember to add user postfix to group opendkim
UserID opendkim
# Map domains in From addresses to keys used to sign messages
KeyTable refile:/etc/opendkim/key.table
SigningTable refile:/etc/opendkim/signing.table
# Hosts to ignore when verifying signatures
ExternalIgnoreList /etc/opendkim/trusted.hosts
# A set of internal hosts whose mail should be signed
InternalHosts /etc/opendkim/trusted.hosts
```
Create a directory for OpenDKIM's keys at `/etc/opendkim/keys/`, and ensure the directory is owned by `opendkim` and
that no one else has read or write access to the keys directory:
# mkdir /etc/opendkim/keys
# chown -R opendkim:opendkim /etc/opendkim
# chmod go-rw /etc/opendkim/keys
Create `/etc/opendkim/signing.table` and set its contents to the following:
```
*@domain.com default._domainkey.domain.com
*@*.domain.com default._domainkey.domain.com
```
This tells OpenDKIM to use your domain's private key to sign any emails originating from `domain.com` and its
subdomains. Replace `domain.com` with your domain.
Now create `/etc/opendkim/key.table` and set its contents to:
```
default._domainkey.domain.com domain.com:default:/etc/opendkim/keys/domain.com/default.private
```
Replacing `domain.com` with your domain. This tells OpenDKIM where your private key is stored.
Create `/etc/opendkim/trusted.hosts` and set its contents to
```
127.0.0.1
localhost
.domain.com
```
Similarly, replace `domain.com` with your domain.
### Generate your keys
Create a directory for your domain's keys at `/etc/opendkim/keys/domain.com`. Use `opendkim-genkey` to generate your
keys:
# opendkim-genkey -b 2048 -d domain.com -D /etc/opendkim/keys/domain.com -s default -v
Replace `domain.com` with your domain.
Set the owner and permissions of the private key so that only `opendkim` has read and write access to it:
# chown opendkim:opendkim /etc/opendkim/keys/domain.com/default.private
# chmod 600 /etc/opendkim/keys/domain.com/default.private
### Publish your public key in your DNS records
Look at your public key:
# cat /etc/opendkim/keys/domain.com/default.txt
You'll see something like this:
```
default._domainkey IN TXT ( "v=DKIM1; k=rsa; "
"p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu7QJxihVsEGhsZBLMxGKCVecIhjINp/zMGH0ExHN5QelxRIKdAHpJ33cZUBEsL0H27/4E8BK9RZ4AOaDMHfIGJ9FybyyD+gHhvKFFHzyts0QpkwLV+3bApsMqSR4ZsSzt3pZvRhQrXaoUds+9CyQBuEGx16PcA2O04/vWlvWhwStJrZWWHDYl2PX3QHfFFSsJaTsiFMwnMECvg"
"a6TdBTcsbcHwfedkoeMv5RQFlKisqCEiJkUYbJaczDA88fcZm21eGW8HiCSwq3324ExfWSwPGVsXAn1Blq/oKklpjXQIwwrphglK//G6AF7M3AAfqBdCvUbkAjs28fJwGqiVxaCwIDAQAB" ) ; ----- DKIM key default for revsuine.xyz
```
This is what your DNS record should look like. Copy **everything between the brackets** and add it to your DNS record:
<!-- using html table for above reasons of line breaks... -->
<table>
<tr>
<th>Name</th>
<td><code>default._domainkey</code></td>
</tr>
<tr>
<th>Type</th>
<td><code>TXT</code></td>
</tr>
<tr>
<th>TTL</th>
<td>Default value (mine is 900)</td>
</tr>
<tr>
<th>TXT data</th>
<td>
What you copied from between the brackets, <em>with all double quotes and extra whitespace (beyond a single
space character) removed</em>
</td>
</tr>
</table>
So with the above public key, my DNS record is
```dns
default._domainkey.revsuine.xyz. 900 IN TXT (
"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQ"
"EFAAOCAQ8AMIIBCgKCAQEAu7QJxihVsEGhsZBLMx"
"GKCVecIhjINp/zMGH0ExHN5QelxRIKdAHpJ33cZU"
"BEsL0H27/4E8BK9RZ4AOaDMHfIGJ9FybyyD+gHhv"
"KFFHzyts0QpkwLV+3bApsMqSR4ZsSzt3pZvRhQrX"
"aoUds+9CyQBuEGx16PcA2O04/vWlvWhwStJrZWWH"
"DYl2PX3QHfFFSsJaTsiFMwnMECvg a6TdBTcsbcH"
"wfedkoeMv5RQFlKisqCEiJkUYbJaczDA88fcZm21"
"eGW8HiCSwq3324ExfWSwPGVsXAn1Blq/oKklpjXQ"
"IwwrphglK//G6AF7M3AAfqBdCvUbkAjs28fJwGqi"
"VxaCwIDAQAB"
)
```
and what I entered into the data field of my DNS manager when adding the record was
```
v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu7QJxihVsEGhsZBLMxGKCVecIhjINp/zMGH0ExHN5QelxRIKdAHpJ33cZUBEsL0H27/4E8BK9RZ4AOaDMHfIGJ9FybyyD+gHhvKFFHzyts0QpkwLV+3bApsMqSR4ZsSzt3pZvRhQrXaoUds+9CyQBuEGx16PcA2O04/vWlvWhwStJrZWWHDYl2PX3QHfFFSsJaTsiFMwnMECvg a6TdBTcsbcHwfedkoeMv5RQFlKisqCEiJkUYbJaczDA88fcZm21eGW8HiCSwq3324ExfWSwPGVsXAn1Blq/oKklpjXQIwwrphglK//G6AF7M3AAfqBdCvUbkAjs28fJwGqiVxaCwIDAQAB
```
You can now test your DKIM key with:
# opendkim-testkey -d domain.com -s default -vvv
Don't worry about
```
opendkim-testkey: key not secure
```
This just means that DNSSEC isn't enabled for your domain name.
### Use OpenDKIM with Postfix
You can use a Unix socket for this, but I couldn't get the Unix socket to work, so I'll show you how to connect Postfix
to OpenDKIM using a TCP/IP socket on port 8891 instead.
Edit your OpenDKIM config `/etc/opendkim/opendkim.conf`, and ensure that the following line is present:
```conf
Socket inet:8891@localhost
```
Also make sure there are no other uncommented `Socket` lines.
Now configure Postfix at `/etc/postfix/main.cf`, and add the following lines:
```conf
milter_default_action = accept
milter_protocol = 6
smtpd_milters = inet:127.0.0.1:8891
non_smtpd_milters = $smtpd_milters
```
This uses the Milter extension, which is something that can be used to process mail; in this case, to add headers to
emails relating to DKIM.
<!-- TODO DMARC section here -->
### Test SPF, DKIM, and DMARC
You can use [mail-tester.com](https://www.mail-tester.com/) and send an email from your domain to check that SPF, DKIM,
and DMARC are all working for your server.
<!-- FOOTNOTES: -->
[^server_trust]: This is only true to the extent that your server is not compromised. You could say there's an order of