diff options
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.md | 264 |
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. |