content/blog/mail_server_alpine_postfix_dovecot_tutorial.md: write spf/dkim section
This commit is contained in:
parent
109052b512
commit
1c9757a78f
1 changed files with 284 additions and 0 deletions
|
@ -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.
|
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: -->
|
<!-- FOOTNOTES: -->
|
||||||
|
|
||||||
[^server_trust]: This is only true to the extent that your server is not compromised. You could say there's an order of
|
[^server_trust]: This is only true to the extent that your server is not compromised. You could say there's an order of
|
||||||
|
|
Loading…
Reference in a new issue