Using Let’s Encrypt with a Chef-managed server

In November 2014 it was announced, that Mozilla and the EFF (among others) were working on a project called Let’s Encrypt, which aimed at increasing the use of HTTPS encrypted connections. The plan was to set up a new CA that would issue free certificates and provide a client to automate the process of obtaining and installing a certificate on a web server. This way, both financial and technological barriers to offering secure connections would be lowered. Let’s Encrypt is officially run by the Internet Security Research Group (ISRG). In December 2015 the project entered public beta and has since then issued over 250.000 certificates

This blog and a number of other websites that I host have been served over HTTPS for a while. Although I know enough about webservers and certificates to set it up myself, I also know the hassle involved. Let’s Encrypt therefore not only appealed to me philosophically. Finally, during the christmas holidays, I managed to find some time to get the transition to Let’s Encrypt started. While the process itself was supposed to be easy, I had a specific topic to address: my server is not set up manually, it is managed using Chef (see here and here). I had to find a way to integrate Let’s Encrypt into my automated server setup. Here’s what I came up with.


The tasks

Before diving into chef details I want to list the tasks that had to be accomplished to fully automate the integration of Let’s Encrypt into my server setup.

  • Install Let’s Encrypt
  • Create HTTPS Certificates
  • Update webserver HTTPS configuration
  • Automatically renew certificates

These tasks needed to be represented in my Chef cookbooks, so let’s look at how I achieved that.


The solution

Currently, Let’s Encrypt is in public beta and the folks at the ISRG provide enough documentation to enable users to get started. The installation process involves cloning a git repository and then run a bash script (./letsencrypt-auto) to request a certificate. Let’s Encrypt can automatically configure webservers with the new certificates but in my case this would interfere with the rest of my server automation. There’s some options that can be used to configure the client. Here’s the structure of my cookbook, I’m providing links to some of the files for your reference:

attributes/default.rb
recipes/apache2.rb
recipes/default.rb
templates/001-default-vhost-ssl.conf.erb
templates/renew-certificate.sh.erb
Berksfile
metadata.rb

recipes/default.rb
In the default recipe I create required directories, the values of which are configured in the cookbook’s attributes.
Then, most importantly the git repository for LE is cloned to the server. I’m using a specific tag mainly because I want to avoid errors that could happen when the code in the repository changes. I will manually update the revision to use when appropriate.

After that, a script is put on the server that will create and renew the certificate.

Then the recipe for the webserver configuration is included.

At the end of the recipe, I’m defining a cron job that will initiate certificate renewal in the morning of every first day of a month.

recipes/apache2.rb

Here, the basic HTTPS configuration is enabled in the webserver by first linking the ssl module to the mods-enabled folder and then creating a new configuration file in the sites-available/ folder from a cookbook template before linking it to the sites-enabled folder.

templates/001-default-vhost-ssl.conf.erb

This file contains the apache2 ssl configuration. I’m using the SSL settings that Let’s Encrypt recommends. Apache loads site configuration in alphabetical order. My default HTTP configuration, which is configured in the webserver cookbook, starts with 000-, naming the HTTPS configuration 001- will ensure that it is loaded after the default HTTP configuration.

templates/renew-certificate.sh.erb

This template is used to create a script on the server. It uses attributes that have been defined in the cookbook (e.g. domain names that should be included in the certificate). I’m using the certonly plugin to tell the client to not configure a webserver. The client can use different methods for domain authentication and I’m using the –webroot –webroot-path option. It’s noteworthy that you can define a webroot-path for every domain that you use with Let’s Encrypt.

You can also use –standalone, then the client will start its own webserver. However, this means that you have to stop your own webserver before running the LE client (and restarting it afterwards).


The conclusion

The cookbook explained above is my first attempt to integrate Let’s Encrypt in my Chef managed server. There’s certainly still a few areas that I’m not completely satisfied with, but for now it works. Once Let’s Encrypt finishes the beta phase I will see if there’s changes that need to be applied. I’m hoping that Let’s Encrypt will provide a packaged version of their client through apt-get, this would simplify the installation process.

In my opinion Let’s Encrypt is a huge improvement. It shows what can be done in terms of usability and enables the use of HTTPS especially for non-experts. It will be interesting to see how this changes the market of certificate vendors, both in terms of usability and in terms of certificate pricing.

UPDATE (Feb. 8th):

Since writing this post, I have changed my approach a little: Initially I have managed the data folder, where Let’s Encrypt stores its files (private key, certificates, etc.) in the cookbook. I’ve removed that, since LE will recreate it when it’s not there. There might be some rate limits that could present a problem here, but I didn’t hit any until now.

The next thing to integrate into my approach will be domain name validation through a DNS challenge, which Let’s Encrypt enabled since I posted this. That is, once the functionality is enabled in the ACME client.

2 thoughts on “Using Let’s Encrypt with a Chef-managed server

Leave a Reply