---
categories:
- General
- openSUSE
comments: true
date: '2021-10-22 21:04:52+02:00'
disable_share: true
draft: false
featured_image: /images/banner.jpg
omit_header_text: true
tags:
- opensuse
- ldap
- 389-ds
title: Setting up Let's Encrypt certificates for the 389-ds LDAP server
---

In the past months I've set up LDAP at home, to avoid having different user accounts for the services that I run on my home hardware. Rather than the venerable [OpenLDAP](https://www.openldap.org/) I settled for [389 Directory Server](https://directory.fedoraproject.org/), commercially known as Red Hat Directory Server, mainly because I was more familiar with it. Rather than describing how to set that up ([Red Hat's own documentation](https://access.redhat.com/documentation/en-us/red_hat_directory_server/11/html/administration_guide/index) is excellent on that regard), this post will focus on the steps required to enable encryption using [Let's Encrypt](https://letsencrypt.org) certificates.

## The problem

Even the LDAP server (they're actually two, but for the purpose of this post it does not matter) was just operating in my LAN, I wanted to reduce the amount of information going around in clear, including LDAP queries. That meant setting up encryption, of course.

The problem was that Red Hat's docs only cover the "traditional" way of obtaining certificates, that is obtaining a Certificate Authority (CA) certificate, request a server certificate, obtain it and set it up in the server. There is (obviously) no mention of Let's Encrypt *anywhere*. I've found [some](https://gist.github.com/plembo/e69720a116f06c3b73452d4e0a9da0e0) [guides](https://possiblelossofprecision.net/?p=2586), but they were either too complicated (lots of fuzzing around with `certutil`) or they weren't clear for some steps. Hence, this post.

**NOTE**: I've focused on 389-ds version 2.0 and above, which has a different CLI set of commands than the venerable 1.3 series. All of the steps shown here can also be carried out via the [Cockpit](https://cockpit-project.org) Web interface as well, if your distribution carries it (spoiler: openSUSE doesn't).

## Importing the CA

This is arguably one of the most important steps of the process. 389-ds needs also to store the CA for your certificates. As you may (or may not) know, Let's Encrypt's CA certificates are two:

- The actual "root" certificate, by Internet Security Research Group (ISRG);
- An intermediate certificate, signed by the above root, called "R3".

Let's Encrypt certificates, like the one powering this website, are signed by R3. But since you have to follow a "chain of trust", to validate the certificate you follow these steps (excuse me, security people; this is probably a bad semplification):

1. Check the actual certificate (e.g. the one on dennogumi.org)
2. The certificate is signed by "R3", so move up the chain and check the R3 certificate
3. The R3 certificate is signed by the ISRG root certificate, so move up the chain and check the ISRG root
4. The ISRG certificate is trusted by the OS / application using it, so everything stops there.

If any of the steps fails, the whole validation fails.

This long winding explanation is to tell you that 389-ds needs the *whole certificate chain* for its CA (so ISRG root + R3) in order to properly validate the Let's Encrypt certificate you'll use. If you don't do that, chances are that some software which uses the system CA will work (for example `ldapsearch`) but others, like SSSD will fail with "Unknown CA" errors (buried deep into debug logs, so at the practical level they'll just fail and you won't know why).

Let's get to business. Access [the Chain of Trust page](https://letsencrypt.org/certificates/) for Let's Encrypt and download the relevant certificates. I'm not sure if 389-ds supports ECDSA certificates, so I downloaded the RSA ones: ISRG Root X1 and Let's Encrypt R3 (both in PEM format). Put them somewhere in your server. Then, as root, import the two CA certificates into 389-ds (substitute `LDAP_ADDRESS` with the LDAP URI of your server):

```
# ISRG Root

dsconf -v -D "cn=Directory Manager"  LDAP_ADDRESS security ca-certificate \
    add --file /path/to/certificate --name "ISRG"

# Let's Encrypt R3

dsconf -v -D "cn=Directory Manager"  LDAP_ADDRESS security ca-certificate \
    add --file /path/to/certificate --name "R3"
```

**NOTE**: This step may not be necessary if you use Let's Encrypt's "full chain" certificates, but I did not test that.

## Importing the certificates

Then, you have to import a Let's Encrypt certificate, which means you have to obtain one. There are hundreds of guides and clients that can do the job nicely, so I won't cover that part. If you use `certbot`, Let's Encrypt's official client, you will have the certificate and the private key for it in `/etc/letsencrypt/live/YOURDOMAIN/fullchain.pem` and `/etc/letsencrypt/live/YOURDOMAIN/privkey.pem`.

You need to import the private key first (substitute `LDAP_ADDRESS` and `DOMAIN` with the LDAP URI of your server and the Let's Encrypt domain, respectively):

```
dsctl LDAP_ADDRESS tls import-server-key-cert \
    /etc/letsencrypt/live/DOMAIN/fullchain.pem \
        /etc/letsencrypt/live/DOMAIN/privkey.pem
```

Note that you pass the certificate as well as the key to import it (in doubt, [check's Red Hat documentation](https://access.redhat.com/documentation/en-us/red_hat_directory_server/11/html/administration_guide/managing_the_nss_database_used_by_directory_server#installing_a_server_certiticate_using_the_command_line)).

Once the key is done, it is time to import the actual certificate:

```
dsconf -v -D "cn=Directory Manager" LDAP_ADDRESS security certificate add \
    --file /etc/letsencrypt/live/DOMAIN/fullchain.pem \
        --primary-cert \
        --name "LE"
```

`--primary-cert` sets the certificate as the server's primary certificate.

Then, we switch on TLS in the server:

```
dsconf -v -D "cn=Directory Manager" LDAP_ADDRESS config replace \
	nsslapd-securePort=636 nsslapd-security=on
```

And finally, we restart our instance (replace `INSTANCE` with your configured instance name):

```
systemctl restart dirsrv@INSTANCE
```

## Testing everything out

You can use `ldapsearch` to check whether the SSL connection is OK (I've used `Directory Manager`, but you can use any user you want):

```

# STARTTLS

ldapsearch -H ldap://your.ldap.hostname -W -x -D "cn=Directory Manager" -ZZ "search filter here"

# TLS

ldapsearch -H ldaps://your.ldap.hostname -W -x -D "cn=Directory Manager" "search filter here"

```

If everything is OK, you should get a result: otherwise, you'll get an error like "Can't contact the LDAP server".

Alternatively, you can use `openssl`:

```
openssl s_client -connect your.ldap.hostname:636
[...]
---
SSL handshake has read 5188 bytes and written 438 bytes
Verification: OK
```

Don't forget to adjust your applications to connect via `ldaps` rather than `ldap` after everything is done.

## Renewing the certificates

To renew the certificates you repeat the steps outlined above for the certificates (without the CA part, of course). Make sure you always import your private key: if there is a mismatch between it and the certificate, 389-ds will refuse to start.

If you use `certbot` you can use a post-renewal hook to trigger the import of the certificate into 389-ds. [This is what I've been using](https://git.dennogumi.org/einar/scripts/src/branch/master/sysadmin/le_lan_reload_services.sh): bear in mind it's customized to my setup and does a few more things than needed. Also it does only import the certificate, and not the full chain.


## I messed up and 389-ds won't start! What do I do?

You can disable encryption by editing `/etc/dirsrv/slapd-INSTANCE/dse.ldif` and changing `nsslapd-security` to `off`, then start 389-ds again. Then you can review everything and see what went wrong. But if you can, I recommend the Cockpit Web UI: it makes the first-time setup a breeze.

## Wrap up

Importing the certificates is surprisingly simple, but my Internet searches have been frustrating because at least half of what I found was either not applicable, incomplete, or did not work. I hope this small tutorial can be useful for those who want a bit more security in their LDAP setup.
