Skip to content

feat: Manage private DNS contexts and resolver access - #233

Merged
scotwells merged 30 commits into
feat/internal-dns-delivery-contractsfrom
feat/internal-dns-context-access
Oct 22, 2026
Merged

scotwells merged 30 commits into
feat/internal-dns-delivery-contractsfrom
feat/internal-dns-context-access

Conversation

@scotwells

@scotwells scotwells commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Create managed private zones under their DNS context. Product services discover the assigned zone and domain through context status. DNS reserves query destinations and manages downstream versions; network services supplies private connectivity. Applied access persists until confirmed withdrawal.

An established context keeps ownership when another context requests the same consumer identity. Integration-selected destinations must be unicast addresses outside the regional resolver pool, preventing overlap with another context's allocated address.

Test plan

  • Ownership and allocation regression tests fail without the fixes
  • Control-plane and platform package tests
  • CI: API and controller tests
  • CI: Lint and generated manifests
  • CI: Container packaging
  • CI: Repository end-to-end tests

Stacked on #232. Architecture: #229.

Related: datum-cloud/enhancements#921

@scotwells
scotwells force-pushed the feat/internal-dns-context-access branch 2 times, most recently from 6ef901d to c546005 Compare October 9, 2026 01:33
@scotwells
scotwells added this pull request to stack #240 October 9, 2026 02:17
@scotwells
scotwells force-pushed the feat/internal-dns-context-access branch from abd287d to db527d6 Compare October 12, 2026 17:09
@scotwells
scotwells force-pushed the feat/internal-dns-context-access branch from db527d6 to f321ac6 Compare October 12, 2026 17:21
@scotwells
scotwells force-pushed the feat/internal-dns-context-access branch from f321ac6 to 2a91264 Compare October 12, 2026 21:17
@scotwells
scotwells force-pushed the feat/internal-dns-context-access branch 2 times, most recently from 9c2f22c to bf43ed8 Compare October 12, 2026 22:07
@scotwells
scotwells force-pushed the feat/internal-dns-context-access branch from bf43ed8 to 10a428b Compare October 12, 2026 22:16
ecv
ecv previously approved these changes Oct 22, 2026

@ecv ecv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving. Context lookups are namespace-scoped and UID-pinned, and withdrawal and shard selection filter on project UID, so I found no cross-tenant path. The reconciler is wired and given RBAC in #238. Follow-ups are in #261: destination claims that are never released and share no key space with generated addresses, and duplicate consumerID ownership decided by name order rather than age.

@scotwells
scotwells dismissed ecv’s stale review October 22, 2026 02:02

The merge-base changed after approval.

ecv
ecv previously approved these changes Oct 22, 2026

@ecv ecv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-approving at ae2a3d6. The new commits reject non-routable destinations, refuse addresses in the regional prefix or with a regional claim, and give consumerID ownership to the oldest context. Claim release and the DNSResolverBinding watch are still open, and #261 tracks them along with a zoned-address gap in ClaimDestination.

scotwells and others added 2 commits October 22, 2026 09:30
The parent branch removed `DNSZoneAssociationSpec.Managed`. The context reconciler already marks the managed association with its controller owner reference and the managed label, so it no longer sets the flag.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
scotwells and others added 3 commits October 22, 2026 10:19
…l-dns-context-access

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…l-dns-context-access

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kevwilliams
kevwilliams previously approved these changes Oct 22, 2026

@kevwilliams kevwilliams left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified destination claims refuse the regional resolver pool and other contexts' addresses, and duplicate consumer IDs keep the older context.

ecv
ecv previously approved these changes Oct 22, 2026

@ecv ecv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve at 9a52cea. Since my last approval at ae2a3d6, the only change in this PR's own files is 2513558, which stops setting the removed DNSZoneAssociation managed flag. Everything else came in from the base branch through merges. I found no path that lets one project resolve another project's private zones. go build ./..., go vet ./internal/internaldns/... and the tests for the three touched packages pass locally, and CI is green. The envtest case skips locally, so I relied on CI for it.

Earlier findings at head

Finding Status Evidence
Duplicate consumerID goes to the older context, not the earlier name Fixed context_reconciler.go:114-128 sorts by creationTimestamp then UID; TestNewContextCannotDisplaceExistingConsumerOwner covers it
Destination claims accept loopback, link-local and multicast Fixed allocator.go:51 requires IsGlobalUnicast
Destination can equal another context's regional address Fixed allocator.go:55-69 refuses the regional prefix and any existing dns-address-claim-*; tests at allocator_test.go:80,102
Zoned or IPv4-mapped destination Closed by the API destinationAddress is isIP(self) and immutable (internaldns_project_types.go:95,103), and isIP rejects zones
Destination claims never released Open, tracked in #261 allocator.go:45-48 keeps claims on purpose. Because the destination is immutable, each new access binding leaks one claim, rather than each edit
DNSResolverBinding not watched Open, tracked in #261 reconciler.go:118-124; serving acknowledgements are seen only on the LeaseDuration/2 requeue

Blocking

None.

Non-blocking

  • confirmAccessWithdrawal treats reason InvalidManagedDomain as terminal (context_reconciler.go:427), but nothing sets that reason. An invalid ManagedDomainSuffix is reported as InvalidIdentity with the message "consumerID is required" (context_reconciler.go:131-152). Withdrawal behaves the same either way, but the condition misleads whoever reads it. Set InvalidManagedDomain in that branch.
  • A transient error from ClaimDestination is folded into valid = false (context_reconciler.go:279). The access binding then flips to Accepted=False / AccessRejected until the next requeue. Serving is safe, because confirmAccessWithdrawal keeps the binding when the spec still matches. Return API errors and keep InvalidOrStaleAccess for genuine refusals.
  • ResolveNaming accepts any Ready context (naming.go:40-44). A context with managedNamespace.enabled: false is Ready at context_reconciler.go:139, so the canonical name gets an empty DNSZoneRef. If the context was once enabled, it gets the stale ref, because Status.ManagedNamespace is never cleared. The function also skips the ObservedGeneration check that resolverContextReady makes. No caller exists in this PR, so fix this before one lands.
  • ClaimDestination's second parameter is named accessUID, but the call at context_reconciler.go:279 passes the context UID. The behavior is fine, since the claim belongs to the context. Rename the parameter so the owner key reads correctly.
  • Reconcile falls back to req.Namespace when ProjectNamespace is empty (reconciler.go:99-102). It then writes bindings for that namespace under the configured ProjectUID. That is safe only with one project per control plane. Require ProjectNamespace, or say in the code that this is the deployment assumption.

Comment thread internal/internaldns/controlplane/context_reconciler.go
Comment thread internal/internaldns/controlplane/context_reconciler.go Outdated
Comment thread internal/internaldns/controlplane/naming.go
scotwells and others added 2 commits October 22, 2026 14:39
…laims

A resolver context rejected for an invalid managed domain suffix now reports `InvalidManagedDomain` with a message saying the suffix is not a valid DNS name, instead of `InvalidIdentity` and "consumerID is required". The access binding withdrawal path already treated that reason as terminal.

The allocator now wraps every merit-based refusal of a service destination in `model.ErrDestinationRefused`. The access reconciler rejects the binding only for that error and returns any other error, so a transient API failure is retried instead of flipping an accepted binding to `AccessRejected` until the next requeue.

`ResolveNaming` now requires the context's Ready condition to match its current generation and its managed namespace to carry a zone UID, so a context without a managed namespace, or with a stale one, yields no canonical name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@scotwells
scotwells dismissed stale reviews from ecv and kevwilliams via a489e2d October 22, 2026 19:55
@scotwells
scotwells requested a review from ecv October 22, 2026 19:56
ecv
ecv previously approved these changes Oct 22, 2026

@ecv ecv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-approving at a489e2d. An invalid suffix now reports InvalidManagedDomain. Only model.ErrDestinationRefused rejects a binding, so a transient API error retries instead of flipping an accepted binding to AccessRejected. ResolveNaming now requires a current Ready context with a managed zone UID.

@scotwells
scotwells dismissed ecv’s stale review October 22, 2026 20:37

The merge-base changed after approval.

@scotwells
scotwells requested a review from ecv October 22, 2026 20:37

@ecv ecv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-approving. The head is unchanged; only the base moved after the parent merged.

@scotwells
scotwells merged commit 9b4e245 into main Oct 22, 2026
18 checks passed
@scotwells
scotwells deleted the feat/internal-dns-context-access branch October 22, 2026 20:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants