aboutsummaryrefslogtreecommitdiff
path: root/content/blog/2022/securing-your-mailserver-with-spf-and-dkim.md
diff options
context:
space:
mode:
Diffstat (limited to 'content/blog/2022/securing-your-mailserver-with-spf-and-dkim.md')
-rw-r--r--content/blog/2022/securing-your-mailserver-with-spf-and-dkim.md264
1 files changed, 264 insertions, 0 deletions
diff --git a/content/blog/2022/securing-your-mailserver-with-spf-and-dkim.md b/content/blog/2022/securing-your-mailserver-with-spf-and-dkim.md
new file mode 100644
index 0000000..592c45b
--- /dev/null
+++ b/content/blog/2022/securing-your-mailserver-with-spf-and-dkim.md
@@ -0,0 +1,264 @@
+---
+title: "Authenticating Your Mailserver With SPF and DKIM"
+date: 2022-09-14T18:52:08+05:30
+---
+
+I recently did a video on setting up an email server, with Postfix for SMTP and
+Dovecot for IMAP, which you can check out [here.](https://odysee.com/@MikunoNaka:d/self-hosting-email-server:0)
+Now this much isn't enough since you want to make sure no one can spoof your domain and/or tamper with the content of your E-mails.
+This is where SPF (Sender Policy Framework) and DKIM (DomainKeys Identified Mail) come to the rescue.
+
+## What are SPF and DKIM?
+
+SPF is used to limit which servers are allowed to send emails from your domain. It protects your domain against domain spoofing.
+Even if you don't use E-mail on your domain, I recommend using SPF to specify that you won't be sending any emails from this particular domain,
+so no one can spoof your domain and pretend to be you while sending emails.
+
+DKIM can be used to sign the emails with a key pair (where the public key is added to your domain's TXT records) so your E-mails' contents cannot be tampered with.
+OpenDKIM is an open source implementation of DKIM, we will be setting up OpenDKIM in this tutorial
+(because I have a natural urge to use anything which has "open" in its name)
+
+### Setting up SPF for outgoing emails on your domain
+
+You need to add a TXT record to your domain containing the SPF syntax. the SPF record should always start with the SPF version number you are using.
+For me it is `v=spf1`. Then, you can add all the SPF "mechanisms" that need to be evaluated in order to identify the E-mail.
+
+Most of the time you just need one or two mechanisms, which are `mx` or `mx:your-domain.tld` and `ip4:your_servers_ipv4` and `ip6:your_servers_ipv6`
+(you don't need all of them, it's kinda overkill)
+
+- `mx` means the email is legit if it comes from a server which is in the MX Records of this domain
+- `mx:your-domain.tld` means the email is legit if it comes from a server which is in the MX Records of your-domain.tld
+- `ip4:ipv4_address` means the email is legit if the sending server has this particular IPv4 address
+- `ip6:ipv6_address` means the email is legit if the sending server has this particular IPv6 address
+
+You can prepend any of these with `-` to *reject* emails which meet this condition (by default it *accepts* the ones passing this condition); You can use `-all` to make sure
+all the other unauthorised emails don't pass the SPF test.
+
+So this is what a valid SPF record would look like:
+
+```
+v=spf1 mx -all
+```
+
+Now I did say using all of these at ones is pretty overkill, but here is what mine looks like:
+
+```
+v=spf1 mx ip4:172.105.59.60 ip6:2400:8904::f03c:93ff:feac:ca67 mx:m.vidhukant.xyz -all
+```
+
+I don't think using many mechanisms is a bad thing, so you can just copy mine and replace the IP4 and IP6 addresses with your server's IP4 and IP6 addresses.
+Which is enough for most usecases. To apply this SPF record just add a TXT record to your root domain. It should look like this:
+
+![SPF Record Screenshot](/images/spf-record-example.png)
+
+**NOTE:** If you are using multiple domains for a single mail server, you should use the exact same SPF record for all the domains.
+If you don't plan to use E-mail with any of your domains, set the SPF record to `v=spf1 -all`.
+ALWAYS add this to your root domain since it tells every receiving server that this domain doesn't
+send E-mails and if you receive one that means it's probably malicious.
+
+[This website](https://www.spf-record.com/syntax) has all of the other info about structuring an SPF record.
+
+### Setting up DKIM (OpenDKIM)
+
+#### Install the necessary packages
+
+``` fish
+apt install opendkim opendkim-tools
+```
+
+#### Configure OpenDKIM
+
+The OpenDKIM config file located at `/etc/opendkim.conf` should look like this:
+
+```
+Syslog yes
+SyslogSuccess yes
+Canonicalization relaxed/simple
+Mode sv
+SubDomains no
+OversignHeaders From
+Socket local:/var/spool/postfix/opendkim/opendkim.sock
+PidFile /var/run/opendkim/opendkim.pid
+AutoRestart yes
+AutoRestartRate 10/1M
+Background yes
+DNSTimeout 5
+SignatureAlgorithm rsa-sha256
+UserID opendkim
+UMask 002
+KeyTable /etc/opendkim/key.table
+SigningTable refile:/etc/opendkim/signing.table
+ExternalIgnoreList /etc/opendkim/trusted.hosts
+InternalHosts /etc/opendkim/trusted.hosts
+TrustAnchorFile /usr/share/dns/root.key
+```
+
+This is what works for me on Debian 11. The data files for OpenDKIM will be stored in `/etc/opendkim/`. If you want to store them anywhere else,
+edit the `KeyTable`, `SigningTable`, `ExternalIgnoreList`, `InternalHosts` parameters in `/etc/opendkim.conf`
+
+#### Setting up the Signing Table
+
+Make a list of all the domains you want to handle E-mails for, and add them to `/etc/opendkim/signing.table` like this:
+
+```
+*@example.tld mail._domainkey.example.tld
+```
+
+Replace both occurances of example.tld to your domain name, and mail to whichever subdomain sends emails. `mail._domainkey.example.tld` would act
+as the DKIM selector for example.tld
+
+If you have any other subdomain set up for the mail server (for example I have `m.vidhukant.xyz` while the standard would be `mail.vidhukant.xyz`),
+replace "mail" with that.
+You can add as many domains you want, But don't add domains which won't be sending emails.
+
+#### Setting up the Key Table
+
+Now edit `/etc/opendkim/key.table` and add lines for each domain like this:
+
+```
+mail._domainkey.example.tld example.tld:mail:/etc/opendkim/keys/example.private
+```
+
+Add one line like this for all the domains added to the signing.table file, replace `mail` and `example.tld` respectively.
+Decide a short name for the private key for this domain, `/etc/opendkim/keys/example.private` in this example holds the private key for `example.tld`
+You should decide different names for each domain you're adding and remember that name, you will need that later.
+
+#### Setting up the Trusted Hosts
+
+Edit the `/etc/opendkim/trusted.hosts` file and add these contents:
+
+```
+127.0.0.1
+::1
+localhost
+hostname
+hostname.example.tld
+*.example.tld
+```
+
+Replace hostname with your server's hostname (defined in `/etc/hostname`), and example.tld with your domain. If you have more than one domain,
+you can append those to the file prepended with a `*.`, just like in `*.example.tld`.
+No need to add another entry for `hostname.example.tld`, just append `*.yourdomain.tld` to the file as many times (for as many domains) you want.
+
+#### Set file permissions
+
+Make sure opendkim user has access to the required files/directories:
+
+``` fish
+chmod u=rw,go=r /etc/opendkim.conf
+chown -R opendkim:opendkim /etc/opendkim
+chmod -R go-rwx /etc/opendkim/keys
+```
+
+#### Generating the keys
+
+Run this command, replacing example.tld with your domain name, and mail with the subdomain for email:
+
+``` fish
+opendkim-genkey -b 2048 -h rsa-sha256 -r -s mail -d example.tld -v
+
+mv /etc/opendkim/mail.private /etc/opendkim/keys/example.private
+mv /etc/opendkim/mail.txt /etc/opendkim/keys/example.txt
+```
+
+Replace "example" in the `example.private` and `example.txt` files with the short name you entered for the domain in the `key.table` file.
+Repeat this step for all the domains if you have multiple of them!
+
+**NOTE:** Never share the contents of the generated ".private" files!
+
+#### Start OpenDKIM
+
+``` fish
+systemctl restart opendkim
+```
+
+#### Add the TXT Records
+
+Read the contents of the TXT file generated by `opendkim-genkey`:
+
+``` fish
+cat /etc/opendkim/keys/example.txt
+```
+
+The output would be something like this:
+
+```
+mail._domainkey IN TXT ( "v=DKIM1; h=sha256; k=rsa; "
+ "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxzNTZydyFiNljq/Md1cXNEqemKDk9CKhZGHSzEH6x0zxtdcv5ROzaytJ4OsatDOdk+Pygkj6Qq9PiLCc3HlWPTcvMEs+M8YvRergTATFNoAmXLXvpbi+DD0oXAsbz2dM/klObY9OSNlJqFpzmGjgRbtSnvCbot8Smg5LreCjmkuHo/sxyynRHGwRHUM6jokm2YGIGATZBIVqtS"
+ "jM418Gtxx9MZUbwcQTlchk1hSQgbXlAAl5tagle3bq/2GwrwrdaghRH750qLjnBQhzdFnH+GjHTmRl2drQ/2zG1L0GlufipZ1UkWulidox2RtIykv2VxDlBYb77G4PAiiJsSar+wIDAQAB" ) ; ----- DKIM key mail for example.tld
+```
+
+Carefully delete everything outside the parenthesis (including the parenthesis) and join all three lines into one.
+Now, remove all the quotes and also the whitespaces between line 2 and 3, so both lines get merged into one, without any space between them.
+
+The result should look like this:
+
+```
+v=DKIM1; h=sha256; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxzNTZydyFiNljq/Md1cXNEqemKDk9CKhZGHSzEH6x0zxtdcv5ROzaytJ4OsatDOdk+Pygkj6Qq9PiLCc3HlWPTcvMEs+M8YvRergTATFNoAmXLXvpbi+DD0oXAsbz2dM/klObY9OSNlJqFpzmGjgRbtSnvCbot8Smg5LreCjmkuHo/sxyynRHGwRHUM6jokm2YGIGATZBIVqtSjM418Gtxx9MZUbwcQTlchk1hSQgbXlAAl5tagle3bq/2GwrwrdaghRH750qLjnBQhzdFnH+GjHTmRl2drQ/2zG1L0GlufipZ1UkWulidox2RtIykv2VxDlBYb77G4PAiiJsSar+wIDAQAB
+```
+
+This is your public key for DKIM.
+
+Now go to your DNS editor, click on Add TXT Record, the hostname should be `mail._domainkey` or whatever the first few characters the original example.txt showed.
+In the value field copy and paste the public key. Make sure there are no errors.
+
+#### Configuring postfix to use OpenDKIM
+
+Set up postfix to process outgoing E-mails with OpenDKIM
+
+``` fish
+postconf -e "milter_default_action = accept"
+postconf -e "milter_protocol = 6"
+postconf -e "smtpd_milters = local:opendkim/opendkim.sock"
+postconf -e "non_smtpd_milters = local:opendkim/opendkim.sock"
+```
+
+Add this to your `/etc/default/opendkim` file to set the socket for postfix
+
+```
+SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"
+```
+
+And then create the socket directory
+
+``` fish
+mkdir /var/spool/postfix/opendkim
+chown opendkim:postfix /var/spool/postfix/opendkim
+```
+
+#### Testing if DKIM is working
+
+Wait for the DNS records to propagate (shouldn't take long!) and send an email with your SMTP server, on the receiving end, your email client should have an option
+to "view source" or "show email headers", open that, you should see a `DKIM-Signature:` field there.
+
+You can now send a test email to a GMail account, and on the GMail web app you can view the email's source.
+It will show detailed information about your DKIM and SPF setup. GMail is by far the best test to verify
+that your authentication mechanisms (SPF, DKIM, etc) are working properly.
+
+## Use DMARC to tell receiving servers how to handle your email
+
+Domain-based Message Authentication, Reporting and Conformance, short for DMARC can be used to specify a set of instructions for the receiving email servers on how
+to handle the email. You can use it to specify which authentication mechanism (SPF, DKIM or both) is in place, what to do with emails which fail authentication
+(you can reject, send, or quarantine them), how to check the `From: ` field of the email. It can also be used by receiving servers to report back to your own server,
+in case any of the checks fail.
+
+All DMARC records start with `v=DMARC1`, and the `p=` field would specify what to do with emails that fail the SPF or the DKIM test. `p=` can have these three values:
+
+- none: do nothing
+- quarantine: quarantine the email (e.g send it to the spam folder)
+- reject: reject the incoming email
+
+It is best to use `p=none` while testing your SPF and DKIM records, after that you can choose between `p=reject` or `p=quarantine`.
+
+You can also optionally use `rua=mailto:your_email` to get DMARC fail reports to your email. Just replace `your_email` with your E-mail.
+You can specify multiple E-mail addresses seperated with a comma.
+
+Here's what an example DMARC record should look like:
+
+```
+v=DMARC1; p=quarantine; rua=mailto:user@example.com
+```
+
+Add this to your domain's TXT records and set the hostname to `_dmarc` and you should be good to go!
+
+Use [this](https://appmaildev.to/en/dkim) DKIM test to test your SPF, DKIM and DMARC configuration.