DNS delegation
DNS delegation, also called DNS aliasing, lets a secondary zone answer the
dns-01 challenge on behalf of the primary one. To get a certificate for
example.com while the validation happens in example.org, create a CNAME
_acme-challenge.example.com pointing at a record in example.org. The ACME
server follows the CNAME and checks the TXT record it ends up at.
Certbot itself knows nothing about such CNAMEs; it always asks the plugin to create
_acme-challenge.<name>. This plugin therefore lets a zone mapping redirect where
that record is actually written.
Typical reasons for delegation:
The primary zone is hosted somewhere without API access, or with a DNS provider that has no certbot plugin.
Security: certbot should not get write access to the primary zone at all, or only to a single record.
The examples below use foo.com as the primary zone and bar.com as the zone
hosted in Azure that certbot writes to.
Redirecting to another zone
Goal: a certificate for test.foo.com. Certbot will ask for the validation record
_acme-challenge.test.foo.com. Without API access to foo.com, create this
CNAME there once, by hand:
_acme-challenge.test.foo.com. CNAME _acme-challenge.test.foo.com.bar.com.
Then map test.foo.com to the bar.com zone by using the zone’s resource
id instead of the resource group’s:
dns_azure_zone1 = test.foo.com:/subscriptions/c135abce-d87d-48df-936c-15596c6968a5/resourceGroups/dns1/providers/Microsoft.Network/dnszones/bar.com
When the plugin is asked to create _acme-challenge.test.foo.com, the target zone
is overridden to bar.com and the record is created there under the full name
_acme-challenge.test.foo.com.bar.com. That is why the CNAME above has to carry
the whole _acme-challenge.test.foo.com prefix in front of bar.com.
Redirecting to a single record
Instead of granting certbot write access to a whole zone, you can point the mapping at one specific TXT record set and grant the DNS Zone Contributor role on that record only.
Again the goal is a certificate for test.foo.com. This time the CNAME can point
at any name, it does not have to contain _acme-challenge:
_acme-challenge.test.foo.com. CNAME test_validation.bar.com.
The mapping names the record set explicitly:
dns_azure_zone1 = test.foo.com:/subscriptions/c135abce-d87d-48df-936c-15596c6968a5/resourceGroups/dns1/providers/Microsoft.Network/dnszones/bar.com/TXT/test_validation
This requires you to create the TXT record test_validation in bar.com up
front with the value -, and to give certbot’s identity write access to it:
az network dns record-set txt add-record \
--resource-group dns1 --zone-name bar.com \
--record-set-name test_validation --value '-'
az role assignment create \
--assignee <identity> \
--role "DNS Zone Contributor" \
--scope /subscriptions/c135abce-d87d-48df-936c-15596c6968a5/resourceGroups/dns1/providers/Microsoft.Network/dnszones/bar.com/TXT/test_validation
Now both the zone and the record name are overridden; the plugin writes the
validation token into test_validation in bar.com, which is exactly where
the ACME server ends up after following the CNAME.
Why the record must exist and is never deleted
Role assignments on an individual record are attached to that resource. If the
plugin deleted the record after validation, the assignment would be gone as well and
the next renewal would fail with an authorization error. For this reason, whenever
a mapping contains a record id, the plugin does not delete the record on cleanup; it
resets its value to - (the value you were told to set initially).
Restricting permissions without delegation
The record-level mapping also works inside the primary zone, for setups that only
want to limit certbot’s permissions and do not need a CNAME. For test.foo.com,
create the TXT record _acme-challenge.test in the foo.com zone with the value
-, assign the role on that record, and map:
dns_azure_zone1 = test.foo.com:/subscriptions/c135abce-d87d-48df-936c-15596c6968a5/resourceGroups/dns1/providers/Microsoft.Network/dnszones/foo.com/TXT/_acme-challenge.test
The zone stays foo.com and the record name is the one certbot would have used
anyway, but now the plugin only ever touches this one record and never deletes it.