DNS Configurations and CNAME Delegation
In the last article, I explained how to create a DNS Provider Configuration document and use it to request certificates for your servers or domain from an ACME provider (like LetsEncrypt) using a dns-01 challenge. But what if your DNS Provider doesn’t have an API? What if you don’t get access to your DNS Provider, because the administration is with a different department? What if your organisation doesn’t have the skills to create a DNS Configuration for your DNS Provider? That’s when CNAME Delegation comes to the rescue.
What is CNAME Delegation?
When the ACME Provider checks your challenge token in DNS (see the last article), it will check for a DNS TXT record with the name “_acme-challenge.<hostname>.<domain>”. However, before it checks for a DNS TXT record, it will first check if a CNAME record for this name exists. A CNAME is an alias. Usually, CNAME records are used to give an A-record for something like vm00004564 a more readable name. In this case, the CNAME can refer the ACME provider to a completely different domain. Like a free domain that’s hosted at deSEC.
In your DNS this will look like this:
So I have a host, demohub.martdj.nl, for which I want to request a certificate. The TXT record with the validation token would have as name “_acme-challenge.demohub.martdj.nl”, but instead of creating such a TXT record, I have created a CNAME record for this. The CNAME record makes LetsEncrypt look for a TXT record with the name validation in the DNS domain martdj.dedyn.io. This TXT record I can create with the DNS Configuration from the last article… with some small adjustments.
Adjusting deSec’s DNS Configuration for CNAME Delegation
In the DNS Configuration from my previous post, the name of the TXT record is determined by the variable param_DnsTxtName as in:
@Left(param_DnsTxtName;"." + cfg_DnsZone)
We want to replace this value, with the correct value for the TXT record name, but only if we use CNAME delegation. The DNS Provider document contains a special field, Custom value (cfg_CustomValue), which we can use for that. The above formula then becomes:
@if(cfg_CustomValue="";@Left(param_DnsTxtName;"." + cfg_DnsZone);cfg_CustomValue)
If the custom value field of the DNS Provider contains a value, this value will be used as the name of the DNS TXT record. Otherwise, the default _acme-challenge.<hostname> will be used. You can find the new version of the deSec DNS Configuration here. It can be used as a drop-in replacement of the version of the previous post, as the behaviour is the same if you don’t enter a custom value.
Creating your DNS Provider document for CNAME Delegation
As an example, I want to create a certificate for demohub.martdj.nl, using my DNS Configuration for deSEC. As shown above, I created a CNAME from demohub.martdj.nl to validation.martdj.dedyn.io. Then the DNS Provider would look like this:
The Registered domain determines that CertMgr will use this DNS Provider for certifying certificates for the martdj.nl domain. As DNS zone it still lists martdj.dedyn.io as that’s the DNS zone in which the TXT record will be created. The Custom value simply contains the value that I entered in my CNAME record in martdj.nl’s DNS.
This way, I can create a certificate for any hostname in the martdj.nl domain, as long as I’ve created a CNAME record in martdj.nl’s DNS for the acme-challenge of this hostname. If I create a CNAME record pointing _acme-challenge to validation.martdj.dedyn.io, I can even create a wildcard certificate *.martdj.nl this way!
Using CNAME delegation, you can use the awesome feature of DNS Configurations, without ever doing any programming yourself. You just need to create a free deSEC account, import the deSEC DNS Configuration .dxl in your certstore, create a DNS Provider with the right credentials and values and create a CNAME record for any hostname you wish to request a certificate for. This can include wildcard certificates!
There is one downside. You add an extra party to the process and if there are any problems with recertifying your certificates, and you’re not around, you’d better written very good documentation, as for most people this won’t be intuitive to troubleshoot.