I finally found a way to sort of securely start using Let’s Encrypt on my servers. One of the reasons I have been hesitant about installing the official client, certbot, is because of some statements made by Theo de Raadt about the security of most clients of the ACME protocol (which is the protocol to talk to Let’s Encrypt). Installing certbot on Ubuntu 16.04 means adding more than 600.000 lines of Python and more than 400.000 lines of C to your installation, and that’s even without counting OpenSSL. Furthermore this code is meant to run periodically as root and touches the network. Oh the horror!
Of course with some extra effort it is possible to run certbot as a dedicated user with minimal privileges. But instead of using a monolithic program, I’d like to focus my energy on a tool that is made with security by design. One that nicely separates all the important parts from each other like code that touches the keys, from code that touches the file system. And code that touches the network, from the complex code that parses the X.509 certificates. Hence, this tutorial will be about installing acme-client (formerly known as letskencrypt), which is made by Kristaps Dzonsons.
Note: the major drawback about the solution presented here, is that you have to watch for updates yourself of both LibreSSL and acme-client. If there is an update to any of those, you have to redo the steps in this tutorial in order to apply the patches. Be warned.
Bring out the tools
First make sure you have a working compiler and package configuration tool installed. Furthermore ensure all required libraries for building the software are available. These tools are only needed in order to compile new versions of the software and are not required for running them.
There are different ways to verify your download, but all involve a trust anchor. Check with the LibreSSL community, like consulting the OpenBSD mirrors and mailing list archives to obtain valid hashes. You ideally do this from different computers using different networks. Never trust a single blog like this one. Furthermore you can Google on the checksums of the files you just downloaded and make sure that they show up at different reputable sites with dates long before now.
Assuming you have a trusted copy of LibreSSL, let’s compile the sources. Because we don’t want to install LibreSSL on the system and mix it up with the installed version of OpenSSL, we’re going to keep it in it’s own directory.
1
2
3
4
5
6
7
8
9
tim@ubuntu:~$ tar zxf libressl-2.5.0.tar.gz
tim@ubuntu:~$ LSSLP=$(pwd)/libressl-2.5.0 # save a pointer to this dir
Now you have a fresh new copy of LibreSSL which is ready to be used. Let’s move on to the final part, compiling acme-client. Luckily, this is not as time consuming as compiling LibreSSL.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
tim@ubuntu:~/libressl-2.5.0$ cd ..
tim@ubuntu:~$ tar zxf acme-client-portable.tgz
tim@ubuntu:~$ cd acme-client-portable-0.1.15/
tim@ubuntu:~/acme-client-portable-0.1.15$ CFLAGS="-I$LSSLP/include" LDFLAGS="-L$LSSLP/ssl/.libs -L$LSSLP/tls/.libs -L$LSSLP/crypto/.libs" make
tim@ubuntu:~/acme-client-portable-0.1.15$ sudo make install
mkdir -p /usr/local/man/man1
mkdir -p /usr/local/bin
install -m 0755 acme-client /usr/local/bin
install -m 0644 acme-client.1 /usr/local/man/man1
Symlink the trust CA store to a location acme-client expects and setup the base directories that will later hold the keys, certificates and chrooted processes.
With the binary in place, we’re ready to start requesting a new certificate. Say we’ve got Nginx running and it serves blog.netsend.nl, which is stored in /var/www/blog.netsend.nl/public/. The document root of your site, in this example /var/www /blog.netsend.nl/public, should contain a .well-known/acme-challenge directory.
acme-client: /etc/ssl/acme/blog.netsend.nl/chain.pem: created
acme-client: /etc/ssl/acme/blog.netsend.nl/cert.pem: created
acme-client: /etc/ssl/acme/blog.netsend.nl/fullchain.pem: created
Now configure your webserver to use the new certificate which is stored in /etc/ssl/acme/blog.netsend.nl/fullchain.pem and the key which is stored in /etc/ssl/acme/private/blog.netsend.nl/privkey.pem. See the documentation of your webserver for specific instructions. In Nginx this would be:
Restart your webserver and see if the new certificate is successfully served. Tip: use https://www.ssllabs.com/ssltest/ to test your SSL configuration.
The last step is to automatically check for renewal via a cronjob, this can be as simple as:
And we’re all set! Now if there is any security update for either LibreSSL or acme-client, fetch the new version, verify your downloads and compile and install the new version.
Please contact me for any suggestions or criticism.
We’re going to mitigate some risks that are inherent when running a server by jailing our nsd authoritative name server into it’s own chroot and making sure it runs with the least privileges possible. This manual is split into two parts. The first part is what it’s all about when it comes to jailing your daemon. Luckily this is not a lot of work because nsd has builtin support for chroots. The second part serves as an example of where to put your zone files and how to include them in your configuration.
We’ll assume you have nsd installed, if not run apt-get install nsd.
Before we lock up the daemon into the jail we have to make sure it has some space where it can write out it’s thoughts. We’ll put the zone files in a different directory just to keep things clear.
Create a new config file in /etc/nsd/nsd.conf.d/local.conf that has pointers to the new writable locations and contains the instructions to chroot and drop privileges.
# echo 'include: /etc/nsd/nsd.conf.d/local.conf' >> /etc/nsd/nsd.conf # service nsd restart
At last pinch a hole in the firewall so it can communicate with the outside world.
1
# ufw allow from any to any port 53
Thanks to the fact that nsd has builtin support for chrooting this is all that comes to it.
2. Setup zone example.com
Now a chrooted authoritative name server without zones doesn’t make any sense, at all. I’ll show you how to link a zone by using an example. Say your name server is located at ns.example.net and it has to answer questions for example.com. Create a zone file for example.com in /etc/nsd/zones/example.com.zone.
1 2 3 4 5 6 7
# cat > /etc/nsd/zones/example.com.zone <<EOF \$ORIGIN example.com. \$TTL 86400 @ IN SOA ns.example.net. hostmaster.example.net. ( 2015033100 24h 2h 3W12h 2h20M ) IN NS ns.example.net. www IN A 203.0.113.2 EOF
Add this zone to the configuration and restart nsd.
Well there you go. The name server at ns.example.net said that www.example.com is located at 203.0.113.2. You’ve chrooted the nsd daemon and setup an example zone. Once you’ve added all your zones you’re done.
Please contact me for any suggestions or criticism.