Automating DNS challenges
We recently announced our new DNS API which we’ve just moved out of beta and into production.
One of the goals of the new API was better support for automating DNS-based challenges, such as those used by Let’s Encrypt to authenticate certificate requests.
DNS-based challenges are needed to obtain wildcard certificates from Let’s Encrypt, and can be a convenient way to get certificates for hostnames that don’t a have publicly accessible web server, but can be tricky to implement due to delays in updating DNS records, and automatic requires having credentials capable of DNS records for your domain stored on your server.
The new API has a number of features to address these issues.
Restricted credentials
The DNS API allows you to create API credentials that are restricted to editing specific records within your domain. Credentials can be restricted by hostname, record type, or both.
For example, you can create credentials that can only edit the _acme-challenge
TXT
record needed for Let’s Encrypt challenges. Access to the DNS API is potentially very sensitive, so it makes sense to limit access as much as possible.
Record verification
Updates made via the API do not become live immediately. There is a delay of up to a minute before they hit our master nameserver, and a potential further delay of a few seconds before the record propagates to our authoritative nameservers. When responding to a DNS-based challenge, you will typically want to ensure that the record is actually live before proceeding with verification.
Our DNS API provides a “verify” feature, that checks that records are live on all authoritative nameservers. For example, a GET
request to the following URL would check that the nameservers have the latest update to the record:
https://api.mythic-beasts.com/dns/v2/zones/example.com/records/_acme-challenge/TXT?verify
This will return a 200
response if the nameservers are up-to-date, and 409
if they are not. This can be used to script a check after updating a record:
#!/bin/sh
ZONE=example.com
RECORD=_acme-challenge
TYPE=TXT
for i in $(seq 1 12); do
RES=$(curl -n https://api.mythic-beasts.com/dns/v2/zones/$ZONE/records/$RECORD/$TYPE?verify -qs -w '%{http_code}' -o /dev/null)
case $RES in
200) echo Records updated
exit 0
;;
409) echo "Not yet updated ($i/12)"
;;
*) echo "Unexpected error: $RES"
exit 1
;;
esac
sleep 10
done
echo Timed out
exit 2
Obtaining certificates the easy way
Our preferred Let’s Encrypt client is the excellent dehydrated, and we maintain a hook script for supporting DNS-based challenges in dehydrated. We haven’t yet updated the hook script to support our new API, but will be doing so soon and will post details here when it’s ready.