Using LetsEncrypt with KumoMTA

  • March 12, 2024

Handling email over TLS-encrypted connections has become the default, and KumoMTA supports TLS for all messages in and out of the system.  There are 3 ways to get a TLS certificate needed for this channel security.

  • 1) Create a self-signed certificate - These are often rejected by receivers as “untrusted”
  • 2) Purchase a commercial certificate - These can be very expensive
  • 3) Use a LetsEncrypt free but valid certificate - These are “free,” but you have to go through some steps to get one.
  •  

This blog will explain how I generate these for my demo servers.  Your deployment may be different, so it is best to start by looking at the LetsEncrypt site and the CertBot instructions. If you are reading this to get a certificate for KumoMTA, then you are definitely doing it with shell access. If you want to follow through the instructions on CertBot, select “OTHER” for the “Software” and choose your OS from the next dropdown list.  I deploy on Ubuntu 22, but select Ubuntu 20 here because it is “close enough”.

I will install a host-specific (not wildcard) certificate on an Ubuntu 22 instance.  If you also use Ubuntu 22 and want a certificate for a specific host, then this should track perfectly.  If not, adjust accordingly based on the links above. You can install KumoMTA before or after this - it does not matter.

The easiest way to accomplish this is to use the HTTP challenge method.  If you do not want to open port 80 inbound, then your other option is to use DNS-01 challenge explained further below.

Doing it

In this example, I will build a certificate for a domain demo.mydomain.com.  Be sure to substitute your OWN domain if you are following this example. Ensure your domain for this server is resolvable in DNS, which will be required for sending any email from it anyway. Also, ensure port 80 is open bidirectionally so you can contact the certificate service, and it can look for a challenge key. You are likely not running a web server on your MTA, but CertBot will “fake” the existence of a web server temporarily with the process below.  

Remove any old version:   sudo apt-get remove certbot

Install certbot:  sudo snap install --classic certbot

Make it accessible to the system :  sudo ln -s /snap/bin/certbot /usr/bin/certbot

Generate a cert with this and answer the questions: sudo certbot certonly --standalone

If you did everything correctly above, it should look something like this (with your domain, obviously):

----------------------------------------------------
Successfully received certificate.

Certificate is saved at: /etc/letsencrypt/live/demo.mydomain.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/demo.mydomain.com/privkey.pem
This certificate expires on 2024-05-30.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the
background.

----------------------------------------------------

Now, you can add directives to use the certificate with KumoMTA. You can copy these out of the LetsEncrypt managed directory and put them into a KumoMTA local file, or you can leave them where they are, but in either case, you need to ensure the kumod user can access them. If you leave them in the LetsEncrypt directory, then you need to
sudo chgrp kumod /etc/letsencrypt/archive
and
sudo chmod 750 /etc/letsencrypt/archive 

This allows the kumod group (and its only user) to access the certificate files directly. If you move the files to another directory, ensure that they have 644 permissions (-rw-r--r--) and are accessible by the kumod user. Note that I specified the "archive" directory above and not the "live" directory referred to below.  This is because the "live" directly contains symlinks to the actual files in the "archive" directory, and THOSE are the permissions that need to be altered.

You can also modify the post hook for the renewal to do this automatically on every renewal:

certbot renew --post-hook 'chgrp kumod /etc/letsencrypt/archive;sudo chmod 750 /etc/letsencrypt/archive' 


Now you can use these in the listeners:

  kumo.start_esmtp_listener {
   listen = '0.0.0.0:25',
     tls_private_key = "/etc/letsencrypt/live/demo.mydomain.com/privkey.pem",
     tls_certificate = "/etc/letsencrypt/live/demo.mydomain.com/fullchain.pem",
  }

 kumo.start_http_listener {
   listen = '127.0.0.1:8000',
     tls_private_key = "/etc/letsencrypt/live/demo.mydomain.com/privkey.pem",
     tls_certificate = "/etc/letsencrypt/live/demo.mydomain.com/fullchain.pem",
 
 }

What if you can’t/won’t open port 80 inbound?

The other way to authenticate the challenge is to use DNS-01. You can satisfy the security challenge with DNS if you follow the instructions for your DNS provider here:
https://eff-certbot.readthedocs.io/en/latest/using.html#dns-plugins

I use Route53, so I created an AWS policy based on the instructions here: https://certbot-dns-route53.readthedocs.io/en/stable/  

At a high level, an AWS admin can create a Policy that is basically a copy/paste of the sample in the link above.  Then it is modified to change the Resource ARN for your hosted zone.  After you have the needed credentials, store them in an appropriate place as per the documentation link above. When that is complete and tested, you can move on with the steps shown in the WILDCARD side of the CertBot instructions.

Support OpenSource

CertBot is Free and OpenSource software. If you like Certbot, please consider supporting their work by:

* Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate

* Donating to EFF:                    https://eff.org/donate-le