Renew DANE TLSA records for SMTP.
This commit is contained in:
parent
3f2e0cfdd8
commit
6e1c5bc28e
212
content/posts/2024/dane-tlsa-record-for-letsencrypt/index.md
Normal file
212
content/posts/2024/dane-tlsa-record-for-letsencrypt/index.md
Normal file
@ -0,0 +1,212 @@
|
||||
---
|
||||
title: "How to create or renew a TLSA record for DANE with certificates from Let's Encrypt"
|
||||
slug: create-or-renew-tlsa-records
|
||||
description: >
|
||||
I had to renew my TLSA records for DNS-based Authentication of Named Entities (DANE)
|
||||
on my server that uses SSL certificates from Let's Encrypt.
|
||||
date: 2024-10-03T09:26:58Z
|
||||
draft: false
|
||||
# ShowLastmod: true
|
||||
toc: true
|
||||
scrolltotop: true
|
||||
tags:
|
||||
- server
|
||||
- certificate
|
||||
---
|
||||
|
||||
I have been operating my own mail server for some 10+ years. Recently, some
|
||||
e-mails that others attempted to send to me any my family would not longer be
|
||||
delivered. This is a very unfortunate situation, because most people will not
|
||||
make a second attempt (e.g., with a different recipient address), leave alone
|
||||
provide you with an error message. However, luckily, this morning (Reunification
|
||||
Day in Germany!), I received this screenshot:
|
||||
|
||||
{{< figure src="outlook-error.jpg"
|
||||
alt="(German) screenshot of an e-mail delivery error due to an invalid TLSA record"
|
||||
caption="(German) screenshot of an e-mail delivery error due to an invalid TLSA record">}}
|
||||
|
||||
And then it was all clear to me. The resource records (RR) in my domain-name
|
||||
system (DNS) configuration that configure [DNS-based Authentication of Named
|
||||
Entities (DANE)][dane] were no longer valid. I use certificates issued by Let's
|
||||
Encrypt, and evidently their chain of trust had changed so that the trust
|
||||
anchors that I had written into my DNS records were no longer valid.
|
||||
|
||||
Correctly setting up TLSA records for DANE is everything but trivial. After some
|
||||
trial and error, I found the following resource most useful:
|
||||
|
||||
<https://dnssec-stats.ant.isi.edu/~viktor/x3hosts.html>
|
||||
|
||||
Key points:
|
||||
|
||||
- When using TLSA RR in the form `2 1 1 ...`, i.e., declaring that the payload
|
||||
(`...`) of the record is the digest of a "trust anchor", be aware that this
|
||||
must be the `SHA256` digest of the _public key_ of your trust anchor.
|
||||
- Let's Encrypt's `certbot` tool places three files on your server: `cert.pem`,
|
||||
`chain.pem` and `fullchain.pem`, where `cert.pem` is the mail server's
|
||||
certificate, `chain.pem` is the trust chain _excluding the root CA_ and
|
||||
`fullchain.pem` is `cert.pem` + `chain.pem`. The important bit here is that
|
||||
**none of these certificate files contain the root CA**!
|
||||
- As a consequence, do not use a digest of Let's Encrypt's root CAs in your TLSA
|
||||
record, _unless_ you want to add that root CA to the certificate files on your
|
||||
server (don't).
|
||||
- Configure TLSA records for _all_ intermediate CAs, e.g., R10-R14.
|
||||
|
||||
Interstingly and embarassingly, the Information Sciences Institute (ISI) on
|
||||
their page linked to above has a list of mail servers that still use a TLSA
|
||||
record with a _retired_ CA from Let's Encrypt -- and that list contains
|
||||
`bovender.de' :-/ I guess it's about time to fix that!
|
||||
|
||||
## Let's Eencrypt's chains of trust
|
||||
|
||||
Let's Encrypt's chains of trust are described here:
|
||||
|
||||
<https://letsencrypt.org/certificates/>
|
||||
|
||||
For the reasons mentioned above, we are not interested in the root CAs (ISRG
|
||||
Root X1 and ISRG Root X2). Instead, we want to use the digests of the public
|
||||
keys of the subordinate (intermediate) CAs. At the time of writing (2024-10),
|
||||
Let's Encrypt lists four active intermediate CAs:
|
||||
|
||||
- E5 and E6 for certificates with ECDSA public keys
|
||||
- R10 and R11 for certificates with RSA public keys
|
||||
|
||||
To find out which of the two algorithms (ECDSA and RSA) was used to generate
|
||||
your mail server's certificate, SSH into your server, navigate to
|
||||
`/etc/letsencrypt/live/<mailserver-certificate-name>` as root and issue:
|
||||
|
||||
```text
|
||||
$ openssl x509 -in cert.pem -noout -text
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number:
|
||||
03:d3:73:ef:60:97:31:88:bc:e5:31:99:f3:00:d5:b0:c1:92
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
Issuer: C = US, O = Let's Encrypt, CN = R11
|
||||
Validity
|
||||
Not Before: Sep 24 22:37:51 2024 GMT
|
||||
Not After : Dec 23 22:37:50 2024 GMT
|
||||
Subject: CN = bovender.de
|
||||
Subject Public Key Info:
|
||||
# ...
|
||||
```
|
||||
|
||||
Thus, my mail server's current (!) certificate was issued by **R11**.
|
||||
|
||||
This may be different in the future. For example, currently my web server's certificate uses the ECDSA algorithm:
|
||||
|
||||
```text
|
||||
$ cd ../bovender/
|
||||
$ openssl x509 -in cert.pem -noout -text
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number:
|
||||
04:22:00:17:8a:ed:51:09:56:15:62:2e:b5:85:49:70:05:ac
|
||||
Signature Algorithm: ecdsa-with-SHA384
|
||||
Issuer: C = US, O = Let's Encrypt, CN = E6
|
||||
Validity
|
||||
Not Before: Aug 19 11:34:11 2024 GMT
|
||||
Not After : Nov 17 11:34:10 2024 GMT
|
||||
Subject: CN = bovender.de
|
||||
```
|
||||
|
||||
This certificate was issued by the **E6** intermediate CA.
|
||||
|
||||
An alternative way to find out more about a web server's SSL certificate is to
|
||||
use `curl`:
|
||||
|
||||
```plain
|
||||
$ curl -I --write-out '%{certs}' https://bovender.de
|
||||
HTTP/2 301
|
||||
server: nginx/1.27.1
|
||||
date: Thu, 03 Oct 2024 09:25:05 GMT
|
||||
content-type: text/html
|
||||
content-length: 169
|
||||
location: https://www.bovender.de/
|
||||
strict-transport-security: max-age=63072000; includeSubDomains; preload
|
||||
|
||||
# ...
|
||||
|
||||
Subject:C = US, O = Let's Encrypt, CN = E6
|
||||
Issuer:C = US, O = Internet Security Research Group, CN = ISRG Root X1
|
||||
|
||||
# ...
|
||||
|
||||
-----END CERTIFICATE-----
|
||||
```
|
||||
|
||||
E6 again (surprise!).
|
||||
|
||||
The key type that `certbot` uses to renew certificates is contained in
|
||||
`/etc/letsencrypt/renewal/<mailserver-certificate-name>.conf`:
|
||||
|
||||
```plain
|
||||
$ cat mail.conf
|
||||
# renew_before_expiry = 30 days
|
||||
version = 2.11.0
|
||||
archive_dir = /etc/letsencrypt/archive/mail
|
||||
cert = /etc/letsencrypt/live/mail/cert.pem
|
||||
privkey = /etc/letsencrypt/live/mail/privkey.pem
|
||||
chain = /etc/letsencrypt/live/mail/chain.pem
|
||||
fullchain = /etc/letsencrypt/live/mail/fullchain.pem
|
||||
|
||||
# Options used in the renewal process
|
||||
[renewalparams]
|
||||
account = [REDACTED]
|
||||
authenticator = webroot
|
||||
server = https://acme-v02.api.letsencrypt.org/directory
|
||||
key_type = rsa
|
||||
# ...
|
||||
```
|
||||
|
||||
The line `key_type` declares that RSA be used for my mail server's certificate.
|
||||
|
||||
## Setting up TLSA RRs in your DNS zone
|
||||
|
||||
As advised by [ISI.edu][isi], it is best practive to have TLSA records for all
|
||||
possible intermediate CAs as you will never know which intermediate CA will be
|
||||
the next to issue a renewed certificate. This is even more important if you have
|
||||
a cron job set up to automatically renew certificates that are about to expire.
|
||||
|
||||
For the record (pun intended), here are my `_25._tcp` entries. Everything after
|
||||
the pound sign (`#`) MUST NOT be included in the record, of course.
|
||||
|
||||
```plain
|
||||
2 1 1 2bbad93ab5c79279ec121507f272cbe0c6647a3aae52e22f388afab426b4adba # R10
|
||||
2 1 1 6ddac18698f7f1f7e1c69b9bce420d974ac6f94ca8b2c761701623f99c767dc7 # R11
|
||||
```
|
||||
|
||||
Following the advice by "~viktor" on [ISI.edu][isi], I have left only those two
|
||||
records in my DNS zone that represent currently used intermediate CAs (R10 and
|
||||
R11). I know that `certbot` will not issue ECDSA certificates for my mail server
|
||||
because the configuration file (see above) contains the line `key_type=RSA`. My
|
||||
web server has an ECDSA certificate, but I currently see no use for DANE for my
|
||||
web server as [Chrome and Firefox do not support it][dane].
|
||||
|
||||
## Verify the validity of the TLSA record
|
||||
|
||||
To test the DANE works as expected, try one of these sites:
|
||||
|
||||
- <https://www.mailhardener.com/tools/dane-validator?domain=bovender.de>
|
||||
- <https://dane.sys4.de/smtp/bovender.de>
|
||||
- <https://www.nslookup.io/domains/bovender.de/dns-records/tlsa/>
|
||||
|
||||
Place this into your DNS records and wait for the updated records to propagate
|
||||
worldwide.
|
||||
|
||||
## "Die Moral von der Geschicht"
|
||||
|
||||
"The moral of the story":
|
||||
|
||||
- Server administration was, is, and will always be complicated.
|
||||
- Always mistrust yourself.
|
||||
- Regularly verify that everything works as expected, especially
|
||||
security-related stuff.
|
||||
- If something does not work, spend more time researching on the world wide web.
|
||||
I came across the [ISI.edu][isi] page only after several hours and is was far
|
||||
more useful for me than all the websites and blog and forum posts that I had
|
||||
previously read.
|
||||
|
||||
[dane]: https://en.wikipedia.org/wiki/DNS-based_Authentication_of_Named_Entities
|
||||
[isi]: https://dnssec-stats.ant.isi.edu/~viktor/x3hosts.html
|
Binary file not shown.
After Width: | Height: | Size: 441 KiB |
Loading…
Reference in New Issue
Block a user