How do I use Let's Encrypt certs in qpsmtpd

Thank you so much, Osiris. That was a wonderfully detailed response.

I had tried using the live paths and had still gotten the error, and then tried (temporarily!) changing permissions on that directory, but was still getting the error. Turns out there's a bug in the way the tls plugin verifies its arguments:

unless (-f $cert && -f $key && -f $ca) {
      $self->log(LOGERROR,
                   "Cannot locate cert/key!  Run plugins/tls_cert to generate");

Since the contents of the live directory are symlinks, this test fails. It should really be using "-r" instead. (It should also test each one individually and tell you which file is the problem...)

So, given what you wrote, I put together a small Makefile (below) based on your script. One minor improvement is that I made $QPSMTPD_CONF_DIR/ssl readable only by the qpsmtpd group while still having everything owned by root. Thus, only qpsmtpd can read the key and certificates, and doesn't have permissions to modify them.

While I share your concerns about qpsmtpd being able to read the file, there's no way that the daemon can perform a TLS negotiation without at least having the key in memory, so a security flaw is going to make that key accessible regardless. The only way I see around that is to have a separate process responsible for the negotiations, which gets pretty complicated.

The other idea I am considering is to use a separate key/cert pair for email, which should at least limit the scope of the damage if there is a compromise. That's a project for another day, though.

Thanks again,
Bill

QPSMTPD_CONF_DIR = /etc/qpsmtpd
QPSMTPD_GROUP = qpsmtpd

QPSMTPD_CERTS = $(QPSMTPD_CONF_DIR)/ssl

all: $(QPSMTPD_CERTS)/fullchain.pem $(QPSMTPD_CERTS)/privkey.pem

$(QPSMTPD_CERTS)/%: $(RENEWED_LINEAGE)/% | $(QPSMTPD_CERTS)
        cp $< $@
        chmod go-w,a+r $@

$(QPSMTPD_CERTS):
        mkdir $@
        chgrp $(QPSMTPD_GROUP) $@
        chmod 750 $@
3 Likes