Mail Security: MTA-STS + Mailcow

Self-hosting e-mail is kind of a challenging task as you have to keep up with all the mechanisms modern mail transport has to offer (e.g. SPF, DKIM, DMARC, DANE etc.). If you don't, the big guys (MS Exchange, Gmail & co.) will start rejecting your mails or marking them as spam and your inboxes will start becoming an easy target for spammers. Mailcow is a cool project that tries to lift most of the weight of hosting your own mail server from your shoulders. Unfortunately, there are still some uncovered subjects. One of them is MTA-STS.

I don't know what SPF, DKIM and DMARC mean.

Skip this part, if you do. Otherwise, bookmark this page, google the terms, implement them as quickly as you can and come back.

MTA-STS explained

MTA-STS stands for Mail Transfer Agent Strict Transport Security and is specified in RFC8461. MTA-STS is the counterpart for DNSSEC/DANE and it aims to force mail servers to communicate via TLS secured connections. This offers multiple benefits:

  1. Enhanced security against routing-based attacks (Spoofing, Cache Poisoning, MITM) even without DNSSEC/DANE as most DNS providers and mail hosters don't fully support DNSSEC/DANE (yet).
  2. Encrypted mail transfer between mail servers to guarantee confidentiality and integrity during mail transport.

Choose: MTA-STS or DNSSEC/DANE

MTA-STS and DNSSEC/DANE can be implemented and used on their own without the other or you can implement both. Both offer the same kind of security for similar problems. Therefore, you have to implement at least one of them. If you don't, attackers can easily reroute your mails to read and modify them.

How to implement MTA-STS policy (for mailcow)

MTA-STS requires two things:

  1. 3 DNS entries for every domain you want to receive mails to or send from
  2. A web server with trusted certificates for every domain you want to receive/send mails to/from that serves a text file

The following guide will show you how you can easily implement both requirements with mailcow. I assume that you have a correctly configured mailcow instance and your mail server has the hostname "mail.example.com".

!!! Make sure to replace every occurrence of mail.example.com with your mail domain !!!

DNS Entries

We start by adding the following 3 DNS entries to the DNS zone of your mail server. The assumption is, that your mail server "mail.example.com" has an A/AAAA record.

CNAME  mta-sts.example.com     mail.example.com
TXT    _mta-sts.example.com    v=STSv1; id=20220324000000Z      
TXT    _smtp._tls.example.com  v=TLSRPTv1; rua=mailto:report@example.com
DNS entries for you mailcow server

Make sure to also replace "report@example.com" with your preferred email for reports.

Afterward, you need to add the following 3 CNAME DNS entries to every one of your domains that use your mailcow server for e-mail.

CNAME  mta-sts.other.com     mail.example.com
CNAME  _mta-sts.other.com    _mta-sts.example.com
CNAME  _smtp._tls.other.com  _smtp._tls.example.com
DNS entries for every domain that uses your mailcow as MTA

mta-sts.txt

Go into your mailcow folder (should be /opt/mailcow-dockerized/). Then go to data/web/.well-known/. Afterward, create a file called mta-sts.txt (touch mta-sts.txt). Open up the file in your favorite editor (e.g. vim or nano) and enter the following content:

version: STSv1
mode: enforce
max_age: 172800
mx: mail.example.com
mx: *.example.com

Example from Google: https://mta-sts.google.com/.well-known/mta-sts.txt

Certificates for every mta-sts.* Domain

Mailcow provides a simple way to automatically issue the right certificates for each of your configured mail domains (inside the mailcow UI).

Go into your mailcow folder (should be /opt/mailcow-dockerized/) and open the mailcow.conf in your favorite editor. Now, scroll till you see ADDITIONAL_SAN and ADDITIONAL_SERVER_NAMES and add mta-sts.* to both variables, like:

# ...

ADDITIONAL_SAN=mta-sts.*

# ...

ADDITIONAL_SERVER_NAMES=mta-sts.*

Save the file and reload the configuration by running docker-compose up -d inside your mailcow folder.

Check if everything works

If everything works, you should now be able to open a link like

https://mta-sts.example.com/.well-known/mta-sts.txt

for every domain you configured in mailcow. If not, the reason for this could be that the DNS entries did not propagate yet. Then, just wait a few hours, run docker-compose restart acme-mailcow in your mailcow folder and try again.

You should also go to checkTLS.com, enter your mail domain, click on "more options", set "check MTA-STS" and hit "Run Test". If everything is ok, it should look like this:

CheckTLS MTASTS Test

This is just the policy

The good news is that you implemented the MTA-STS policy. However, this is just the policy part. Other mail servers will use the policy to force secured transports. Mailcow, though, will not check the MTA-STS policies of other mail servers it tries to contact. There is an open github issue on the mailcow repo about fully implementing MTA-STS checks (see #1809).

References