Let’s Encrypt, Firewalls and Route 53

May 19, 2017

Let’s Encrypt, the free and automated certificate authority is revolutionising the way that SSL/TLS certificates are obtained and managed, shifting away from expensive and manual traditional methods to a sleek and cost free process.

This article discusses how to install and automatically renew an LE certificate on a RHEL based server using DNS-01 validation against TXT records in Amazon’s Route 53.

So What’s the Problem?

Searching for installation instructions on Google will return a lot of articles explaining how to install and automatically renew an LE certificate using the Certbot Acme client. By default, Certbot will attempt to perform validation challenges against the server that the (sub)domain’s DNS address resolves to. This method works great if the servers are exposed to the internet, however if the servers are locked down behind a Firewall, the challenge will always fail.

The natural reaction, at least for myself, was to start searching for documentation on the Let’s Encrypt website regarding their IP range so that I could whitelist it on our Firewalls. However, I quickly found posts on the LE forums from LE/Certbot engineers stating that they do not want to announce specific addresses for security reasons and that the currently used addresses are subject to change.

The solution…

Thankfully, there are available tools to help us validate LE certificates without the challenge taking place on the server that the DNS address for the certificate you’re generating resolves to.

In this example I’m going to be using a combination of shell script Acme client Dehydrated and the Ruby based Route 53 DNS-01 Hook

Step 1: Export your AWS credentials to allow the scripts to generate a TXT record in Route 53. (Make sure that you add these into your servers bash profile to ensure that the details persist)

export AWS_REGION="region goes here"
export AWS_ACCESS_KEY_ID=“access_key_goes_here”
export AWS_SECRET_ACCESS_KEY="secret_key_goes_here"

Step 2: Create a dehydrated directory.

mkdir /etc/dehydrated

Step 3: Pull down the default configuration file.

cd /etc/dehydrated && curl -O 
https://raw.githubusercontent.com/lukas2511/dehydrated/master/docs/examples/config

Step 4: Clone the Dehydrated Repo

git clone 
https://github.com/lukas2511/dehydrated.git

Step 5: Clone the Route 53 Ruby hook

cd dehydrated && curl -O
https://gist.githubusercontent.com/joshgarnett/02920846fea35f738d3370fd991bb0e0/raw/5412ee600278acf843832cd918455b8e6d50ba5c/lets-encrypt-route53.rb

Step 6: Ensure that the ruby hook is executable

chmod +x lets-encrypt-route53.rb

Step 7: Install the AWS-SDK gem

gem install aws-sdk

Step 8: Register and accept terms

./dehydrated --register --accept-terms

Step 9: Initiate certificate generation (Replace example.com with your own domain)

./dehydrated --cron --domain example.com --hook ./lets-encrypt-route53.rb --challenge dns-01

Step 10: Add the same command to a cron/systemd job. Your web server might need to reload its configuration when a new certificate is created so don’t forget to add that to your scheduled task.

For example on nginx…

cd /etc/dehydrated/dehydrated && ./dehydrated --cron --domain example.com --hook ./lets-encrypt-route53.rb --challenge dns-01 && service nginx reload

That’s it you’re done! Now just configure your webserver to use the generated certificate/key and your days of manually renewing and paying for certificates are over.

Ta best!