Automating DNS-challenge based LetsEncrypt certificates with AWS Route 53

John Rix
4 min readDec 16, 2019

Due to my current web hosting arrangements and various use of Docker, Apache, Nginx and other, I prefer using DNS-challenges when generating new certificates via LetsEncrypt. The downside of this is that I was manually re-generating my certificates every 60 days or so, as they were approaching their expiry dates.

The array of certificates I am managing has been progressively growing over time also, to the point where time pressures finally forced me to investigate properly automating the certificate renewals.

Preliminary Investigations

A couple of mis-guided Google searches on LetsEncrypt APIs later and I was reminded that the certbot command provides convenient Pre- and Post-Validation Hooks that can be used to set up and tear down the necessary DNS TXT record entries for the ACME protocol to verify ownership of the domain(s) in question. Great! I next went digging into AWS’ Route 53 (my chosen DNS provider’s) API documentation to verify methods were available to achieve the necessary. Naturally, they are there, and well documented.

Of course, I then came to my senses (again) and figured somebody is sure to have solved this problem already as well though. Sure enough…

Aha!

Enter certbot-dns-route53. This is in fact one of a range of available DNS Plugins for certbot (something I would have already known if I had RTFM properly on certbot). With these plugins, you don’t even need to utilise the pre/post validation hook options of certbot. In the case of certbot-dns-route53, once you ensure appropriate permissions are authorised, using the plugin is as simple as adding the --dns-route53 option to the certbot command:

$ sudo certbot certonly --dns-route53 -d example.com

Installation

This is where things got a little murky, and I almost gave up at one point.

As you may be aware, there are a few ways to install and operate the certbot command. Unfortunately, depending upon your own environment and the installation you opt for (or have been saddled with), you will likely have a differing and potentially quite old version of certbot available to you. Furthermore, suggesting the DNS plugin installation documentation was obtuse would be generous. There is nothing at all about it mentioned on the ReadTheDocs page linked above, while the GitHub page for the plugin has a Setup section whose instructions essentially boil down to ‘Install this package.’ Sigh.

After a range of attempts to get it working, and running into different errors, I found the following (quite straightforward) approach got me over the line (for reference, I’m using Ubuntu 18.04):

$ sudo add-apt-repository ppa:certbot/certbot
$ sudo apt-get install certbot python3-certbot-dns-route53

Important note: I did find I had to undo some earlier failed installation attempts before the above would work properly (see that GitHub issue link just above).

AWS Permissions Setup

The plugin documentation outlines the specific AWS permissions needed for it to work correctly:

  • route53:ListHostedZones
  • route53:GetChange
  • route53:ChangeResourceRecordSets

Create an appropriate policy containing these permissions. For the route53:ChangeResourceRecordSets permission, you can either grant this permission to a specific hosted zone as exemplified in the plugin documentation, or simply to all zones in your account. Example of the latter below:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"route53:GetChange",
"route53:ListHostedZones",
"route53:ChangeResourceRecordSets"
],
"Resource": "*"
}
]
}

You then need to assign this Policy to a Role.

Next, the plugin documentation instructs you to deploy AWS user credentials (for a user assigned the aforementioned Role) to your environment, either using environment variables or a credentials configuration file. However, if you are operating on an EC2 instance, you can instead assign the Policy to a (new or existing) Role created specifically for EC2 and grant that Role directly to the EC2 instance instead. That way, there is no messing around with credential files or the likes.

Operation

As suggested above, generation of certificates using the plugin is quite trivial:

$ sudo certbot certonly --dns-route53 -d example.com

You are also provided an extra optional command line argument to allow time for DNS propagation of the TXT records before proceeding with the validation step:

$ sudo certbot certonly --dns-route53 --dns-route53-propagation-seconds 30 -d example.com

Automatic renewal of your existing certificates is of course equally straight-forward. Just add a root crontab entry along the following lines (adjusting to your desired schedule!):

00 3 * * 1 /usr/bin/certbot renew --dns-route53 --dns-route53-propagation-seconds 30

In Summary

If you can get past the installation pitfalls of the certbot-dns-route53 plugin, it provides a nice clean solution for fully automating the management of your LetsEncrypt certificates in an AWS environment using Route 53.

Would love to hear others experiences in the comments!

--

--