Automating Let's Encrypt certificates further / 2018-07-08

2018-07-08 Automating Let's Encrypt certificates further 4 months ago
Encrypt all the things meme Over two years ago I started using Let's Encrypt certificates. Recently I wanted to automate this a step further and found dehydrated automated certificate renewal which helps a lot in automating certificate renewal with minimal hassle.

First thing I fixed was http-based verification. The webserver has been set up to make all .well-known/acme-challenge directories end up in one place on the filesystem and it turns out this works great with dehydrated.

I created a separate user for dehydrated, gave that user write permissions for the /home/httpd/html/.well-known/acme-challenge directory. It also needs write access to /etc/dehydrated for its own state. I changed /etc/dehydrated/config with:
CHALLENGETYPE="http-01"
WELLKNOWN="/home/httpd/html/.well-known/acme-challenge"
Now it was possible to request certificates based on a .csr file. I used this to get a new certificate for the home webserver, and it turned out to be easier than the previous setup based on letsencrypt-nosudo.

But dehydrated makes more automation possible. It can generate new private keys and certificates automatically, but that's not the exact setup I wanted. I like re-using existing .csr files so the private keys of services don't change unless they need to, but with different private keys for different services. So after some designing I set up a directory for dehydrated with .csr and .crt files to make it request a new .crt when the old .crt was 30 or more days old. Some shell programming to auto-renew certificates with the .csr available:
#!/bin/sh

cd $HOME

# time to renew
find httprenewable -name \*crt -mtime +30 |
while read -r crt
do
	csr=${crt%.crt}.csr
	if [ -f $csr ]; then
		echo Would renew $csr to $crt
		./dehydrated/dehydrated -s $csr > tmp/certificate.crt
		if [ $? -eq 0 ]; then
			cp tmp/certificate.crt $crt
			rm tmp/certificate.crt
		fi
	else
		echo WARNING: $crt without $csr
	fi
done

find httprenewable -name \*crt -mtime +60 |
while read -r crt
do
	echo WARNING: certificate $crt is over 60 days old
done
The next logical step is to automatically install the new certificates and signal the service to load the new certificate. With a bit of defensive programming: make sure the certificate matches the private key of the service before the certificate is installed. This is where make is good, checking prerequisites and only taking action when needed.

This also has to run as root since it needs to restart services and read private key files.
#!/usr/bin/make -f

ALL: /etc/mail/tls/sendmail-server.crt /etc/mail/tls/sendmail-client.crt /etc/apache2/ssl/server.crt

/etc/mail/tls/sendmail-server.crt: /home/dehydrated/dnsrenewable/felsenstein-sendmail-server.crt
        /usr/local/bin/checkcert /etc/mail/tls/sendmail-common.key $^
        cp $^ $@
        service sendmail reload

/etc/mail/tls/sendmail-client.crt: /home/dehydrated/dnsrenewable/felsenstein-sendmail-client.crt
        /usr/local/bin/checkcert /etc/mail/tls/sendmail-common.key $^
        cp $^ $@
        service sendmail reload

/etc/apache2/ssl/server.crt: /home/dehydrated/dnsrenewable/felsenstein-apache.crt
        /usr/local/bin/checkcert /etc/apache2/ssl/server.key $^
        cp $^ $@
        apache2ctl configtest && apache2ctl graceful
The /usr/local/bin/checkcert is based on Certificate Key Matcher - Check whether your private key matches your SSL certificate.:
#!/bin/sh

set -e

if [ \! -f "$1" ]; then
        exit 1
fi
if [ \! -f "$2" ]; then
        exit 1
fi

# check ssl private key 1 with ssl pem encoded x509 certificate 2 public key

SUMPRIVPUBKEY=`openssl pkey -in $1 -pubout -outform pem | sha256sum`
SUMCERTPUBKEY=`openssl x509 -in $2 -noout -pubkey -outform pem | sha256sum`

if [ "${SUMPRIVPUBKEY}" = "${SUMCERTPUBKEY}" ]; then
        exit 0
else
        exit 1
fi
The Makefile runs twice a week, same as the certificate renewal job.

As visible in the Makefile it's now possible to maintain valid certificates for all kinds of services, as long as (in this case) HTTP verification is possible. The good price of Let's Encrypt certificates, together with automating the procedures until keeping existing certificates is no work at all makes it possible to have valid certificates for lots of things. This includes the sendmail client and server certificate. Now a lot more mail has the verify=OK message in the headers.

As you can imagine this approach only works for services where I can use http-based verification, although I use this for certain services that happen to run on a system that also runs the http server but not exactly for the name that I want the certificate for since the _default_ virtualhost also serves up the right .well-known/acme-challenge directory.

Tags: , , , ,

, reachable as koos+website@idefix.net. PGP encrypted e-mail preferred.

PGP key 5BA9 368B E6F3 34E4 local copy PGP key 5BA9 368B E6F3 34E4 via keyservers pgp key statistics for 0x5BA9368BE6F334E4 Koos van den Hout
RSS
Other webprojects: Camp Wireless, wireless Internet access at campsites, The Virtual Bookcase, book reviews
This page generated in 0.004495 seconds.