DEV Community

onyxcross5743
onyxcross5743

Posted on

DNS Zones and Records: Why Zone Identifiers Make Operations Auditable

Short answer: A zone identifier selects the authority, and a record identifier selects one object inside it; record operations need both so retries cannot mutate a same-named record in the wrong DNS zone.

For an e-commerce platform, the expensive part of custom-domain DNS is rarely the number of records. It is retaining enough identity and history to prove which customer-owned zone produced a change, while platform-owned zones can be reconciled from one controlled inventory. A zone identifier is the stable boundary; a record identifier is the address of one mutable object inside it. Treating those two values as interchangeable is how a retry deletes the wrong hostname or an audit trail loses its subject.

What does a zone ID identify that a record name cannot?

A DNS name is a lookup key, not an ownership claim. shop.example can exist in several authoritative zones, and the same relative name can have several record types. The zone ID binds an operation to the authority that owns the data. The record ID then binds it to one row within that authority. This is the same separation a ledger uses between an account and a posting: a human-readable label helps operators, while an immutable identifier makes reconciliation deterministic.

The distinction matters in the application scenario. A customer may delegate store.customer.tld to the platform, while the platform also operates customer.tld for its own storefronts. A request that says “delete www” is underspecified. A request that says “delete record r_1842 in zone z_77” is testable, retryable, and reviewable.

Names are hints.

IDs are contracts.

Where does the bill come from, and what should retention preserve?

The dominant operational cost is usually retention and review of change evidence, not DNS query volume. Keeping every raw provider response forever creates a large, low-signal archive; keeping only the final record set makes it impossible to explain an accidental change. I retain the zone and record identifiers, actor, request id, previous value, new value, and timestamp for each mutation, then expire raw payloads on a documented schedule. That is a deliberate loss: reconstructing an old provider-specific response becomes harder, but the audit facts remain compact and portable.

For a customer-owned zone, the platform should store the delegation it requested and the observation it received, with a status such as pending, active, or revoked. For a platform-owned zone, it can treat the authoritative inventory as its source of truth and reconcile desired state against it. The retention policy is therefore part of the ownership decision: customer-owned workflows need evidence of external coordination, while platform-owned workflows need evidence of internal convergence.

An idempotent mutation records its intent before making the external call. A simplified Go shape looks like this:

type RecordCommand struct {
    ZoneID       string
    RecordID     string
    RequestID    string
    ExpectedETag string
    Value        string
}

func apply(ctx context.Context, c RecordCommand, dns DNSClient, audit AuditLog) error {
    if audit.Seen(ctx, c.RequestID) {
        return nil
    }
    current, err := dns.GetRecord(ctx, c.ZoneID, c.RecordID)
    if err != nil {
        return err
    }
    if c.ExpectedETag != "" && current.ETag != c.ExpectedETag {
        return ErrConflict
    }
    if err := dns.SetRecord(ctx, c.ZoneID, c.RecordID, c.Value); err != nil {
        return err
    }
    return audit.Append(ctx, c.RequestID, c.ZoneID, c.RecordID, current.Value, c.Value)
}
Enter fullscreen mode Exit fullscreen mode

The exactly-once mindset is aspirational at the network boundary; a timeout can occur after the provider accepted the write. The durable request ID and subsequent read-back are what make the workflow effectively once in the application. Never infer success from a client timeout, and never retry a delete by name alone. This adds a read and an audit write to every mutation, so a latency-sensitive health-check path is the wrong place to reuse this workflow.

Timeouts happen.

How should customer-owned and platform-owned zones differ?

The boundary changes failure handling more than it changes DNS syntax. In a customer-owned zone, verification may require observing a TXT token and waiting for authoritative nameservers to agree. The platform cannot assume it can roll back a record it does not control. It should expose a pending state, poll with bounded backoff, and make revocation explicit.

In a platform-owned zone, the service can apply a desired-state loop: list records by zone ID, compare normalized values, and submit narrowly scoped updates. The loop must still honor record IDs because names can collide across types, and a concurrent operator may replace a record between list and update. An ETag or equivalent version check turns that race into a visible conflict instead of silent overwrite. The trade-off is operational complexity: desired-state reconciliation is safer for many stores, but a small team may prefer a manual approval queue until it can operate conflict metrics and replay tooling.

DMARC illustrates why record identity and policy semantics must stay separate. A TXT record at _dmarc carries a policy document whose meaning is defined by RFC 7489; the record ID identifies where that document is stored, not whether the policy is safe for a particular merchant. Validation, authorization, and DNS mutation are three different checks.

Which tests catch the identifier bugs early?

I test the state machine with two zones containing identical relative names, two record types at the same name, a repeated request ID, and a stale ETag. The expected result is boring: each operation touches one intended record, retries produce no second audit event, and conflicts remain visible. Integration tests then verify read-after-write and the provider's pagination behavior; they should not rely on an undocumented ordering of records.

Observability should carry zone_id, record_id, request_id, ownership mode, and outcome as structured fields. Logs may redact TXT values because they can contain verification tokens. Metrics can count reconciliation lag and conflict rates without retaining customer content. Access controls should make zone ownership a policy decision, not a string comparison in a handler.

The practical rule is concise: resolve the zone first, resolve the record second, and persist both identities with the intent and result. That ordering gives customer-owned and platform-owned workflows a common audit vocabulary without pretending they have the same authority.

Further reading

Top comments (0)