Summary
FindDNSZoneForHost() in internal/provider/provider.go rejects any host whose domain is listed in the public suffix list, even when a matching zone is explicitly configured in the provider secret.
Root Cause
Lines 150–155 of internal/provider/provider.go:
tld, _ := publicsuffix.PublicSuffix(host)
if host == tld {
return nil, "", fmt.Errorf("%w: %s", ErrNoZoneForHost, originalHost)
}
golang.org/x/net/publicsuffix.PublicSuffix() returns the public suffix of a domain, not just the ICANN TLD. Many real-world domains appear in the public suffix list as privately managed domains (e.g., httpbin.org, github.io, amazonaws.com, azurewebsites.net). For these domains, PublicSuffix(host) returns the host itself, causing the early-exit check host == tld to fire before zone matching is attempted.
Demonstration:
ps, icann := publicsuffix.PublicSuffix("httpbin.org")
// ps = "httpbin.org", icann = false, host == ps → true → rejected
ps, icann = publicsuffix.PublicSuffix("example.com")
// ps = "com", icann = true, host == ps → false → zone matching proceeds
Impact
When using the CoreDNS provider with ZONES=httpbin.org and a DNSRecord with rootHost: httpbin.org, the authoritative record fails reconciliation:
error: "no zone for host: httpbin.org"
The individual DNSRecord succeeds (via the endpoint/delegation provider path), but the authoritative record — which goes through the CoreDNS provider's DNSZoneForHost() directly — hits the public suffix check and fails. This prevents the kuadrant.io/coredns-zone-name label from being added, so the CoreDNS plugin never discovers the record.
This affects any domain in the public suffix list used as both the rootHost and the zone. Subdomains work fine (e.g., simple.k.example.com with zone k.example.com).
Reproduction
# Create provider secret with the domain as the zone
kubectl create secret generic dns-provider-credentials-coredns \
--namespace=dnstest \
--type=kuadrant.io/coredns \
--from-literal=ZONES="httpbin.org"
# Create DNSRecord
kubectl apply -f - <<EOF
apiVersion: kuadrant.io/v1alpha1
kind: DNSRecord
metadata:
name: httpbin-test
namespace: dnstest
spec:
rootHost: httpbin.org
providerRef:
name: dns-provider-credentials-coredns
endpoints:
- dnsName: httpbin.org
recordType: A
recordTTL: 60
targets:
- "10.89.0.17"
EOF
# Wait and check — authoritative record will show DNSProviderError
kubectl get dnsrecord -n dnstest
Suggested Fix
The public suffix check was added to prevent recursion past a useful boundary, but it's too aggressive for privately managed public suffixes. Consider:
- Only checking
icann == true public suffixes (skip privately managed ones)
- Checking the zone list before applying the TLD rejection — if a zone explicitly matches the host, allow it
- Removing the early exit entirely and relying on the recursive subdomain stripping to terminate naturally
Option 2 seems safest — the user has explicitly configured the zone, so it should be respected.
Context
Discovered while investigating DNS-based egress gateway routing for Kuadrant/kuadrant-operator#1847. The use case is mapping external hostnames to an egress gateway's ClusterIP via kuadrant CoreDNS + DNSRecord, where the rootHost IS the external hostname (e.g., httpbin.org).
Summary
FindDNSZoneForHost()ininternal/provider/provider.gorejects any host whose domain is listed in the public suffix list, even when a matching zone is explicitly configured in the provider secret.Root Cause
Lines 150–155 of
internal/provider/provider.go:golang.org/x/net/publicsuffix.PublicSuffix()returns the public suffix of a domain, not just the ICANN TLD. Many real-world domains appear in the public suffix list as privately managed domains (e.g.,httpbin.org,github.io,amazonaws.com,azurewebsites.net). For these domains,PublicSuffix(host)returns the host itself, causing the early-exit checkhost == tldto fire before zone matching is attempted.Demonstration:
Impact
When using the CoreDNS provider with
ZONES=httpbin.organd a DNSRecord withrootHost: httpbin.org, the authoritative record fails reconciliation:The individual DNSRecord succeeds (via the endpoint/delegation provider path), but the authoritative record — which goes through the CoreDNS provider's
DNSZoneForHost()directly — hits the public suffix check and fails. This prevents thekuadrant.io/coredns-zone-namelabel from being added, so the CoreDNS plugin never discovers the record.This affects any domain in the public suffix list used as both the rootHost and the zone. Subdomains work fine (e.g.,
simple.k.example.comwith zonek.example.com).Reproduction
Suggested Fix
The public suffix check was added to prevent recursion past a useful boundary, but it's too aggressive for privately managed public suffixes. Consider:
icann == truepublic suffixes (skip privately managed ones)Option 2 seems safest — the user has explicitly configured the zone, so it should be respected.
Context
Discovered while investigating DNS-based egress gateway routing for Kuadrant/kuadrant-operator#1847. The use case is mapping external hostnames to an egress gateway's ClusterIP via kuadrant CoreDNS + DNSRecord, where the rootHost IS the external hostname (e.g.,
httpbin.org).