Let’s Encrypt with Salt Stack
SSL, need I say more? It can be a pain to manage technically, a pain to manage for a business, confusing for beginners and sometimes the more experienced developers among us. Let’s Encrypt are a free automated open certificate authority, aiming to end all of that by making SSL free and simple to use — with a few commands you can encrypt your website traffic.
So, let’s get started.
A couple of caveats
I lied, we aren't getting started just yet as there are a couple of things to bear in mind first.
- Let’s Encrypt is still in beta so do consider that before you roll this out to all your production boxes ;)
- As far as I can tell, Let’s Encrypt will work best with single server domains, so no Load Balancers, if you run a Load Balancer through HAProxy or the like you might be able to do something there. EC2 ELBs make things a little bit trickier, Let’s Encrypt does have beta support for DNS verification so that might be worth looking at but is beyond the scope of this article.
- I won’t be covering Salt Stack basics, they have some great tutorials and documentation on their site so do take a look if you are not familiar.
- All the code examples use Salt’s Stateconf renderer which gives some nice sugar on top of Salts default YAML formatted states, I highly recommend it, you can read up on it here.
For now we will just work with a single box serving a single domain as an example.
Installation of Let’s Encrypt
There are a few ways to install Let’s Encrypt:
- OS Package (apt, yum, apk etc)
- Pip (Python package manager)
- Git (Directly from a git clone)
If you are lucky enough to run a linux distribution with rolling updates or are running at the bleeding edge this is the simplest way to install Let’s Encrypt. At time of writing there is no official Ubuntu PPA for <= 14.04 LTS, however you’ll be able to apt install on Ubuntu 16.04 LTS.
The next best method is to use pip, this does need a lot more cruft since there are package dependencies required, the example here is on Ubuntu 14.04 LTS. Note we also need to manually update some Python level packages since Let’s Encrypts ships with out of date versions required for the tool to function correctly (oddly):
Finally the manual git version, I don’t recommend this method since this will rely on the letsencrypt-auto tool which will attempt to install itself and dependencies onto your system. It’s basically a giant bash script, if you are cool with that it’s well documented on their GitHub Page and I suggest you look at the script before using it, so I’m not going to cover that here.
Let’s Encrypt does not have a configuration directory or file per se but you can pass configuration file paths as arguments. These files can contain things like the RSA key size you wish to use, the domain(s) you want SSL certs for, and what sort of authenticator you wish to use (we will get that later). For now let’s just create a directory for convenience:
I’ve also created a “webroot” directory, this is where Let’s Encrypt will store it’s temporary files for domain verification.
Let’s Encrypt has to verify that you do truly own your domain for which we want a certificate, otherwise anyone could create certificates for any domain and that would be a very bad thing indeed.
We will be using the “webroot” authenticator which will, upon a signing request, call a defined url on port 80 for the domain you wish to sign. This will usually be http://your.domain.com/.well-known/acme-challenge. Provided Let’s Encrypt can access this and everything is OK you’ll be granted your certificate.
I recommend you read up more about the internal workings of Let’s Encrypt here.
Automatic Certification Generation
Ok, so we’ve got the basics — Let’s Encrypt is installed. Now it’s time to get to crux of the matter — certificate generation.
First we need a web server. For this example, I’m using Nginx.
Now we just need our domain configuration for Let’s Encrypt and Nginx:
It’s important to check for the existence of your certificate path since in the first run you won’t have any certificates and including the SSL server block in the Nginx configuration will prevent Nginx from starting. This is why on line 9 of the Nginx configuration we perform such a check.
We now have everything in place, let’s add a final state to our domain sls that will call the Let’s Encrypt command line interface to generate our certificate:
And thats it! Again we check to make sure we don’t have any certificates and if we don’t we will generate them with Let’s Encrypt.
The command we use will automatically accept Let’s Encrypts Terms of Service, points to our configuration file and tells Let’s Encrypt we only want a certificate (the certonly bit at the end).
Provided you have glued all the bits together correctly the following will happen in this order:
- Install Let’s Encrypt CLI tool and configuration directories
- Install Nginx
- Create our Let’s Encrypt and Nginx configurations for our domain
- Use the Let’s Encrypt CLI tool to generate our certs
- Regenerates our domains Nginx configuration with SSL enabled
- Reload Nginx
The certificates created by Let’s Encrypt last for 90 days, So it’s important you renew them regularly. Fortunately this is a simple process we can automate with a bash script and a cron job.
Just add the following to your domain.sls and you’ll be all set:
Here we will run a bash script on the 28th day of every month which will renew our certificate with Let’s Encrypt and reload the Nginx configuration.
(taken from https://www.nginx.com/blog/free-certificates-lets-encrypt-and-nginx/)
You now have a free automated SSL certificate serving your web site.