In case you haven’t heard, Let’s Encrypt now supports wildcard certificates as a feature of the new ACME v2 protocol. However, current client support is still somewhat limited, as the Let’s Encrypt CA requires domain validation via DNS-01 challenge. To further complicate things, DNS-01 requires programmatic access to your nameservers. But let’s assume you are already using Route53 and you’re looking for the simplest way to begin issuing wildcard certificates for your hosted zones. You’ll need an up-to-date ACME client, such as the latest version of Certbot. Chances are your server distro is not that bleeding-edge. That’s where Docker comes in.

Let’s take a look at how to quickly set up a Docker container for Certbot to issue wildcard certificates via Let’s Encrypt.

What You’ll Need

You’ll need a few things to get started:

  • A domain name set up to use Amazon Route53 nameservers.
  • A set of AWS credentials configured with the appropriate Route53 permissions (details below).
  • A functioning Docker instance on your web server.

Create the Docker Script

Let’s start by creating a working directory for our Docker image:

$ mkdir ~/certbot-docker
$ cd ~/certbot-docker

Now throw the following code into a file named ~/certbot-docker/certbot-docker.sh:

#!/bin/sh

sudo docker run -it --rm --name certbot \
--env AWS_CONFIG_FILE=/etc/aws-config \
-v "${PWD}/aws-config:/etc/aws-config" \
-v "/etc/letsencrypt:/etc/letsencrypt" \
-v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
certbot/dns-route53 certonly --server https://acme-v02.api.letsencrypt.org/directory

Notice the part where it mentions the file ${PWD}/aws-config. Next we need to create that file using your AWS API credentials.

Provide Your AWS API Credentials

The ~/certbot-docker/aws-config file should look like this:

[default]
aws_access_key_id=XXXXXXXXXXXXXXXXXXXX
aws_secret_access_key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

If you haven’t set up the API credentials yet, login to the AWS IAM console and create a group with the following policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "VisualEditor0",
      "Effect": "Allow",
      "Action": [
        "route53:GetChange",
        "route53:ListHostedZones"
      ],
      "Resource": "*"
    },
    {
      "Sid": "VisualEditor1",
      "Effect": "Allow",
      "Action": "route53:ChangeResourceRecordSets",
      "Resource": "arn:aws:route53:::hostedzone/*"
    }
  ]
}

Special thanks to the author of this forum post for pointing me in the right direction.