Core's reverse-zone lifecycle assumes that one NetworkPrefix owns each reverse zone because network_prefixes_prefix_excl prevents overlap. Once separate VPCs can reuse a prefix, zone creation, zone deletion, and PTR lookup cannot use that site-wide ownership assumption.
Current state
crates/api-db/src/dns/mod.rs documents its reliance on the global NetworkPrefix exclusion.
- NetworkSegment lifecycle creates and removes reverse DNS state.
- PTR lookup can find records by address without a tenant/VPC view.
- The MVP does not include tenant split-horizon DNS.
General idea
- Serialize create/delete operations that affect the same reverse-zone name with the existing shared mutation lock or a focused PostgreSQL advisory lock.
- Make live reverse-zone identity unique and reusable when two active prefixes need the same zone.
- Delete a reverse zone only after no active prefix still needs it.
- Where the address-only lookup finds multiple live owners, return no PTR record rather than selecting one tenant's name. Preserve the current gRPC
NotFound to DNS NXDOMAIN behavior; there is no trusted VPC discriminator on today's DNS request path.
- Keep forward records and unique-address behavior unchanged.
- Avoid building a new general prefix-to-zone ownership subsystem unless the database model proves the simpler reference check cannot be made race-free.
Acceptance criteria
- Creating equal eligible prefixes concurrently does not create duplicate live reverse-zone rows or fail nondeterministically.
- Deleting one prefix does not remove reverse DNS state still needed by another prefix.
- An ambiguous address-only PTR query returns no PTR data through the current authoritative-negative
NXDOMAIN behavior and never returns a cross-VPC record.
- Existing unique-prefix create/delete and PTR behavior remains compatible.
- Concurrency, shared-zone lifecycle, ambiguous lookup, and rollback tests are included.
Not in this issue
- Tenant-specific DNS views exposed through a public API.
- A new trusted VPC-scoped DNS request contract or strict
NOERROR/NODATA response handling.
- Forward-DNS redesign.
- Global prefix-constraint removal.
Likely areas
crates/api-db/src/dns/mod.rs
crates/api-db/src/dns/domain.rs and resource_record.rs
crates/api-core/src/handlers/dns.rs
- NetworkSegment lifecycle code
crates/api-core/src/tests/dns.rs and database DNS tests
Split trigger
Keep this M while existing records plus a lock/reference check can implement shared-zone lifecycle and address-only no-answer behavior. If a trusted VPC-scoped DNS contract or a new public DNS view is required later, size that separately rather than pulling it into this safety fix.
Planning
- Size: M
- Risk: Critical
- Best fit: Senior Rust/database engineer with DNS review
Dependencies
Part of #3883.
Core's reverse-zone lifecycle assumes that one NetworkPrefix owns each reverse zone because
network_prefixes_prefix_exclprevents overlap. Once separate VPCs can reuse a prefix, zone creation, zone deletion, and PTR lookup cannot use that site-wide ownership assumption.Current state
crates/api-db/src/dns/mod.rsdocuments its reliance on the global NetworkPrefix exclusion.General idea
NotFoundto DNSNXDOMAINbehavior; there is no trusted VPC discriminator on today's DNS request path.Acceptance criteria
NXDOMAINbehavior and never returns a cross-VPC record.Not in this issue
NOERROR/NODATA response handling.Likely areas
crates/api-db/src/dns/mod.rscrates/api-db/src/dns/domain.rsandresource_record.rscrates/api-core/src/handlers/dns.rscrates/api-core/src/tests/dns.rsand database DNS testsSplit trigger
Keep this M while existing records plus a lock/reference check can implement shared-zone lifecycle and address-only no-answer behavior. If a trusted VPC-scoped DNS contract or a new public DNS view is required later, size that separately rather than pulling it into this safety fix.
Planning
Dependencies
Part of #3883.