AWS API Gateway + Let’s Encrypt SSL certs

Set up an API Gateway custom domain using a free SSL certificate

Marc Richards
Quote, Unquote Serverless
6 min readJan 26, 2017

--

A match made…until something better comes along

If you want to use a custom domain name with AWS API Gateway, you need to upload your own SSL certificate. For some bizarre reason, in January 2017, AWS still doesn’t allow you to use certs created with their own Certificate Manager service. One can only hope that they will resolve that soon, but until then Let’s Encrypt provides the best alternative for getting a free SSL certificate to use with API Gateway.

There is a lot of info out there on how to use Let’s Encrypt with your own web server, but most of the tools and blog posts don’t really apply to the “serverless” scenario that you get with API Gateway. The default domain verification method used by most Let’s Encrypt compatible tools is to serve a special file over HTTP, but that presents a chicken and egg problem for API Gateway, since you need the SSL Certificate first before you can create the custom domain.

Luckily there is a DNS based verification method as well, and after trying a couple different tools, I found what seems to be the simplest cross-platform way to get a DNS verified Let’s Encrypt SSL certificate issued. This post will walk you through the steps that I used to get my cert for API Gateway, but the same steps should apply for any situation where you need to get a cert using DNS verification instead of HTTP verification (e.g. for an internal tool or appliance that isn’t exposed to the internet).

TL;DR Version

  1. Download the Google acme client binary from their GitHub page
  2. acme reg -gen -accept mailto:username@domain.com
  3. openssl genrsa -out api.mydomain.com.key 2048
  4. acme cert -k api.mydomain.com.key -dns=true api.mydomain.com

You will be prompted to add a specific TXT record to your domain’s DNS entries to verify ownership. After that, your certificate will be generated and downloaded to the folder where you executed the commands.

Full Version

First I tried Certbot, which is considered to be the official Let’s Encrypt client, but unfortunately it doesn’t run on Windows, it requires a lot of dependencies on Linux, and it displayed a big “WARNING: THIS IS NOT COMPATIBLE AND MIGHT BREAK THINGS” message when I tried to run it on my Amazon Linux EC2 instance. So back to the drawing board.

Fortunately Let’s Encrypt allows you use any of a list of available ACME compatible clients, but most of the clients that I looked at failed at least one of the following tests:

  1. Created by a developer/company that I trust
  2. Considered production ready by the developer
  3. Works on Windows or Amazon Linux (ideally both)
  4. Has as few dependencies as possible
  5. Supports DNS based verification

Google’s acme client provides a simple, cross-platform statically-linked binary that has no dependencies. It is written in Go, but Google provides pre-built, platform specific executables so that you don’t need to have Go installed. It meets all of my criteria.

Step 1: Download the google/acme client binary

Binary releases are available on Github for Windows, Linux (x86 & ARM), and MacOS. A SHA1 checksum file is available on the page as well so you can double check the signature to make sure that your binary was not corrupted. You can put the binary in the folder where you want to generate your certificate for simplicity sake or add it to your PATH.

Step 2: Register an account with Let’s Encrypt

The next step is to register an account with Let’s Encrypt from the command line. This will create a Let’s encrypt account key (not to be confused with your certificate’s private key) and a config file in the default config directory (~/.config/acme or the Windows equivalent). You can read about what each option does by typing “acme help reg”. Your email address will not be verified, so be sure to double check it. It is where your expiration notices will be sent. Also be mindful not to accidentally omit the mailto:.

acme reg -gen -accept mailto:username@domain.com

Step 3: Generate a private key for your certificate

While acme itself has no dependencies, the process still has one indirect dependency. Though Google’s acme client can generate a private key for you, currently they automatically use the ECDSA signature algorithm and there is no option to specify otherwise (I opened an issue). At present AWS API Gateway only supports 2048 bit RSA certs so I had to use openssl to generate my private key. The good news is that openssl is installed by default on most Linux boxes including AWS EC2 instances. Note that you don’t need to generate a CSR (Certificate Signing Request), just a private key. Make sure that you put the generated key in to your working folder.

openssl genrsa -out api.mydomain.com.key 2048

Step 4: Request a certificate from Let’s Encrypt using DNS verification instead of HTTP

One of the more important conditions for me was that I could verify my domain ownership using DNS instead of HTTP. AWS API Gateway requires an SSL certificate in order for you to set up a custom domain (chicken and egg problem). Alternatively I could have hosted a verification file on S3 and pointed my DNS at S3 for verification before pointing it back at API Gateway, but it is much easier for me to just set a TXT record once and be done with it. The “acme cert” command below issues a request for a new certificate based on the private key that you just created, using DNS verification.

acme cert -k api.mydomain.com.key -dns=true api.mydomain.com

After running the command you will be prompted with the instructions e.g. Add a TXT record for _acme-challenge.api.domain.com with the value “somelongrandomstring” and press enter after it has propagated.

You can usually add the DNS TXT record via the web console of the service provider that manages DNS for your domain. After you have made the change you can use this free DNS lookup tool from Google to see if your update has started propagating. Once that is confirmed, hit Enter and a PEM certificate named api.mydomain.com.crt should be created right there in the directory beside the private key. Note that the acme client will automatically bundle your certificate and the Let’s Encrypt Intermediate certificate into the same file. Your certificate is the first one in the file.

The acme client will also return a URL where you can download the certificate, but you can just ignore that if you like. FYI the downloadable version is a binary DER encoded cert.

Free DNS hosting

If your current DNS host doesn’t allow you to set TXT records then it is probably time to switch. Cloudflare is actually an awesome free option that most people don’t even consider. If you set up your domain under their free plan, but configure it not to route requests through their network, they are basically just a free, reliable DNS hosting service with a great interface.

Try not to lose your account key

One last thing to note, once you have completed the verification process for a given sub-domain you do not need to go through the same process again to issue a new certificate as long as you are still using the same Let’s Encrypt account key (not to be confused with your certificate’s private key). So make sure you keep your account.key and config file safe. They are in the config directory (~/.config/acme).

Renewing your certificate

The process to “renew” your certificate is really just to issue a new cert with a later expiration date. If you are using the same account key as before then there is no verification step. You can just run the command below in the directory that contains your certificate’s private key

acme cert -k api.mydomain.com.key api.mydomain.com

--

--