You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add a CNAME Delegation section to docsource/configuration.md describing
why challenge names are delegated to an isolated validation zone, how the
CnameResolver follows a multi-level CNAME chain to its terminus, how the
DNS provider plugin is selected against the resolved target (enabling
cross-provider delegation), the loop/depth safety guards, and private-zone
resolution via DnsVerificationServer. Update the enrollment flow summary
to include the CNAME resolution step.
Many organizations do not want ACME automation to hold write access to their production DNS zone. The industry-standard pattern is to **delegate just the ACME challenge name** to a separate, isolated validation zone using a `CNAME` record. The plugin supports this transparently.
94
+
95
+
#### Why delegate?
96
+
97
+
A `CNAME` at `_acme-challenge.<domain>` points challenge validation at another zone. ACME automation then only needs write access to that isolated zone — never the production zone. A `CNAME` also cannot coexist with any other record type at the same name (RFC 1034), so the TXT record **must** be created at the CNAME's target, not at the original challenge name.
98
+
99
+
#### How the plugin resolves it
100
+
101
+
Before publishing the challenge record, the plugin runs the `CnameResolver`, which:
102
+
103
+
1. Issues a DNS `CNAME` query for `_acme-challenge.<domain>`.
104
+
2.**Follows the chain to its terminus.** Delegation can be nested multiple levels deep (`A → B → C → …`); the resolver re-queries at each hop and stops only when it reaches a name that has no further `CNAME`. That terminal name is where the TXT record is created.
105
+
3. Returns the original name unchanged when **no**`CNAME` exists — so non-delegated domains behave exactly as before (fully backwards compatible).
106
+
107
+
Safety guards: the resolver detects loops (a name that reappears in the chain) and enforces a maximum depth of **10 hops**, logging a warning and stopping at the last good name rather than looping forever.
108
+
109
+
#### Provider selection follows the delegation
110
+
111
+
The DNS provider plugin is resolved against the **name where the record actually lands**:
112
+
113
+
-**No delegation** → the provider is selected for the certificate domain (e.g. `www.example.com`).
114
+
-**Delegated** → the provider is selected for the **resolved terminal target** (e.g. `abc123.acme-validation.net`).
115
+
116
+
This means a challenge delegated into a zone hosted by a *different* DNS provider is routed to the plugin that owns that zone. Propagation checks and cleanup also operate on the resolved name.
117
+
118
+
> ℹ️ Provider selection uses the AnyCA Gateway's Domain Validation configuration, which matches a configured (optionally wildcard) domain pattern one label at a time. Ensure the **delegation target's zone** is covered by a Domain Validation entry — e.g. a target of `abc123.acme-validation.net` needs a validator whose domain matches `*.acme-validation.net`.
119
+
120
+
#### Example (multi-level delegation across providers)
121
+
122
+
```text
123
+
Cert domain: www.example.com (production zone, e.g. GoDaddy)
Provider plugin selected for: acme-zone.net (the zone that owns val.acme-zone.net)
134
+
TXT record created at: val.acme-zone.net
135
+
ACME CA queries _acme-challenge.www.example.com, follows the CNAMEs, finds the TXT ✅
136
+
```
137
+
138
+
> ℹ️ **Private/internal delegation zones:** set `DnsVerificationServer` to your authoritative DNS server IP. The `CnameResolver` honors it for the CNAME lookups; otherwise public resolvers (Google, Cloudflare, Quad9) are used.
0 commit comments