Skip to content

Stale hostname CNAME/ALIAS not reaped on hostname removal — breaks resolution (SERVFAIL) #283

Description

@ecv

Summary

When a custom hostname is removed from an HTTPProxy/Gateway (or its proxy binding is torn down), the DNS record the platform created for it (a CNAME for non-apex, ALIAS for apex, pointing at the proxy's *.datumproxy.net canonical name) can be left behind. The stale record then points at a canonical name that no longer exists — so the hostname fails to resolve (authoritative SERVFAIL) and can block a later resource from re-claiming it.

Warning

Confirmed via DNS, with live customer impact. Originally filed against the HTTPProxy-delete path — that path's cleanup is present and fixed since NSO v0.17.0 (prod v0.24.3). The live gap is on hostname/binding removal: the customer-hostname record survives after its proxy canonical is gone. Only formal step left is confirming the upstream proxy no longer lists the hostname (see Open question).

How the records flow (where reap must happen)

  1. Upstream (project control plane)gateway_dns_controller creates a per-hostname DNSRecordSet, Gateway-owned. On hostname removal it should be reaped by the label-based garbageCollectDNSRecordSets (diff desired-vs-existing, delete stale).
  2. Downstream projection (host cluster, ns-<uid>) — a mirrored copy owned by the DNSZone + an anchor ConfigMap. GC'd only when its upstream is deleted (anchor cascade). Anchor-ownership here is by design, not the bug.
  3. PowerDNSdns-operator writes/removes the RRset and resolves ALIAS targets at query time; a live CR ⟹ the RRset is kept. If the ALIAS target is NXDOMAIN, PowerDNS returns SERVFAIL for the name.

Reaping a removed hostname therefore depends entirely on step 1 (upstream garbageCollectDNSRecordSets).

Evidence (prod — customer AB1889, ab.dk, project ab-generic-1qnl3i)

  • Downstream DNSRecordSet ab-website-g2rfww-9f7feda5 = ALIAS www.ab.dk → loneliness-snake-9nkbf.datumproxy.net; Programmed=True, Accepted=True, created 2026-07-12, still present days later. Anchor present ⟹ upstream DNSRecordSet still exists.
  • The proxy hostname was moved www.ab.dk → bare ab.dk (see infra#3407), yet the www.ab.dk record persists.

DNS confirmation (queried this session)

  • www.ab.dkSERVFAIL, authoritatively, on both ns1/ns2.datumdomains.net.
  • Cause: the ALIAS target loneliness-snake-9nkbf.datumproxy.netNXDOMAIN (confirmed on 8.8.4.4, 1.1.1.1, and authoritative) — the proxy canonical was torn down.
  • Control: sibling media.ab.dk (ALIAS → a live proxy canonical) → NOERROR; datumproxy.net zone is healthy. So the zone/operator are fine — only www's target is dead.
  • User impact: www.ab.dk is unresolvable for any resolver without a cached positive (ALIAS TTL 300s); stale caches mask it intermittently.

Net: the proxy binding/canonical for www.ab.dk was removed but its customer-hostname ALIAS was not reaped → the reap gap, now breaking resolution.

Open question (formal final confirmation)

Pull the upstream HTTPProxy ab-website-g2rfww spec.hostnames from PCP ab-generic-1qnl3i:

  • www.ab.dk removed (expected, given the canonical is gone) → confirms garbageCollectDNSRecordSets isn't reaping on hostname removal → NSO bug.
  • www.ab.dk still listed → the record is intentional but its target is dead — a different failure (canonical not maintained), still a bug.

Test-coverage gap (fold into the fix)

  • garbageCollectDNSRecordSets is unit-tested in isolation (gateway_dns_controller_test.go:771,845), but no test drives the full create → remove-hostname reconcile round-trip.
  • Gateway-delete finalizer cleanup (cleanupDNSRecordSets, gateway_controller.go:1676) and the HTTPProxy-delete DNS cascade are untested.
  • No chainsaw e2e references DNSRecordSet at all.
  • The fix should add: hostname-removal reap (upstream + projected downstream), Gateway-delete, and HTTPProxy-delete cases — asserting the record is gone and the hostname stops resolving.

Related

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions