AWS API Gateway
Amazon Web Service’s scalable API offering: API Gateway is an execellent way to create simple APIs that charge by-the-request. One pain point though is that by default, your API is available via an ugly auto-generated URL such as:
https://4ittmt4ei7.execute-api.us-east-1.amazonaws.com/dev/
There is an option to manually upload an SSL certificate to enable a custom domain but its tedious and well, manual.

Well that just won’t do.
Unfortunantly, as of this writing, API Gateway can’t be connected to Cloudfront - this is how one would apply a custom domain name to an S3 bucket, for example. Here’s a write-up on how Cloudfront works to secure an S3 bucket: Building a Blog Part 5 - Securing an S3 Website.
Lets Encrypt to the rescue!
No matter! We can solve this problem using Let’s Encrypt and Route 53. Route 53 (AWS’s DNS service) provides an API for creating DNS records (TXT, ALIAS, etc). Using a DNS-challange, we can use Let’s Encrypt to validate our custom domain name (configured with Route 53). I wrote a python script that runs as a plugin on top of Dehydrated (previously known as letsencrypt.sh), an implementation of Let’s Encrypt that runs as a shell script.
ACME API Gateway
This hook uses Route 53 to get certificates for securing an Amazon API Gateway. This allows for secure and custom domains for your API.
Clone Dehydrated
git clone https://github.com/lukas2511/dehydrated.git
Checkout
cd dehydrated
git clone https://github.com/mikeblum/acme-api-gateway.git
Setup
cd into acme-api-gateway:
cd acme-api-gateway
Add the AWS keys (strongly recommend creating an IAM role for this) so we can update the Route53 DNS records for this domain.
vi .env
#!/bin/bash
export AWS_ACCESS_KEY=########################
export AWS_SECRET_ACCESS_KEY=#################
source ./env
Create a virtualenv:
virtualenv env
source ./env/bin/activate
Install dependencies
pip install -r requirements.txt
- tldextract
- dnspython
- boto3
- route53
Get Certificates
./dehydrated --cron --force --domain {{ domain }} --hook acme-api-gateway/hooks/hook.py --challenge dns-01
This will automatically verify and deploy your custom domain and make it available in API Gateway.
Output looks like this:
Processing {{ your domain }}
+ Checking domain name(s) of existing cert... unchanged.
+ Checking expire date of existing cert...
+ Valid till Feb 11 20:48:00 2017 GMT (Longer than 30 days). Ignoring because renew was forced!
+ Signing domains...
+ Generating private key...
+ Generating signing request...
+ Requesting challenge for {{ your domain }}...
deploy_challenge
{{ your domain }}
IQYeRiF-3MIymB_PwFHIXAhPPicaiks6ec1uHgdi-aE
removing DNS challenge
creating TXT record for letsencrypt challenge
modified: True
+ Responding to challenge for {{ your domain }}...
clean_challenge
{{ your domain }}
IQYeRiF-3MIymB_PwFHIXAhPPicaiks6ec1uHgdi-aE
removing DNS challenge
removing old TXT record for letsencrypt challenge
+ Challenge is valid!
+ Requesting certificate...
+ Checking certificate...
+ Done!
+ Creating fullchain.pem...
deploy_cert
deploying certificates to API Gateway
renewing domain name ({{ your domain }}) in API Gateway
Create Alias record from {{ your domain }} to dqux49yhycipr.cloudfront.net
+ Done!
When you check your AWS API Gateway panel, you’ll find your validated domain available to attach to any deployed API in your account:

This script now gives us one-click automated certificate deployments for our API Gateways.
Note, since a Let’s Encrypt certificate expires every 90 days, you’ll want to re-run this script periodically.
Cheers!