Let's Encrypt Proxy DNS Authentication

reading time ( words)

Certain use cases preclude DNS dynamic updates to a zone for technical, policy or other reasons. This post explains a simple way to enable automatic DNS-based authorization for Let’s Encrypt certificates – and perhaps for other vendors’ – by way of delegating the authorization challenge to a trusted DNS zone.

In the example below, we want to automatically issue or renew a wildcard certificate for athena.pics but unfortunately no dynamic updates can be made under that domain. If you want to request wildcard certificates with Let’s Encrypt, this obstacle will need addressing.

By provisioning a simple CNAME record pointing to a domain name where dynamic updates can be made, the dns-01 authentication can complete and the certificate can be issued or renewed automatically.

The CNAME record can be added at any time, and left there for as long as desired. For our example, athena.pics will trust proxy.lem.click for its ACME authorizations. The new DNS record would look like this, in the athena.pics DNS zone:

$ORIGIN athena.pics.
_acme-challenge.athena.pics. 60 IN CNAME _acme-challenge.proxy.lem.click.

This is an explicit trust relationship. Anyone with the ability to add records to _acme-challenge.proxy.lem.click will be able to request certificates on behalf of athena.pics.

With this CNAME record in place, requesting the TXT record through your plain old resolver will ultimately fetch the TXT records that would complete the authorization. All you need to do is add the TXT record with the authorization challenge under _acme-challenge.proxy.lem.click. The example below uses dynamic updates to accomplish this:

nsupdate -k ~/mykey.conf
> update add _acme-challenge.proxy.lem.click. 1 IN TXT your-challenge-here
> send
> ^D

Querying a recursive resolver would now show the TXT record we added in the previous step because the CNAME will be traversed:

dig txt _acme-challenge.athena.pics @8.8.8.8
    ⋮
;; ANSWER SECTION:
_acme-challenge.athena.pics. 0	IN	CNAME	_acme-challenge.proxy.lem.click.
_acme-challenge.proxy.lem.click. 0 IN	TXT	"your-challenge-here"
    ⋮

Let’s Encrypt will perform a similar lookup, ultimately finding the challenges at the expected location.

The latest version of my nsupdate-hook script makes this process easy. For the example above to work, all you would need to do is set CHALLENGE_DOMAIN to proxy.lem.click in your shell or crontab file.