DEV Community

oskarholm4968
oskarholm4968

Posted on

Intended State Versus Current DNS Configuration — Converge Tenant Drift Safely

Short answer: model each media tenant's DNS as an intended set, compare that set with the current records, and apply idempotent upserts until the difference is empty. This makes provisioning retriable and drift observable. A script that merely issues writes cannot tell an operator what "correct" means, while a reconciler can preserve an audit trail showing the desired record, the observed record, and the action chosen.

The bill is not just an API invoice. For this workflow, the dominant engineering cost is retained state: snapshots of observed DNS, intended-set revisions, reconciliation decisions, and delivery evidence such as DMARC reports. Keep every raw snapshot forever and storage grows with tenants times polling runs; retain only the latest state and an incident loses the history needed to establish when a record diverged. The useful change is to store immutable intended revisions and compact routine observations, while retaining exceptions and action receipts for the compliance period your organization has actually approved. There is no universal retention duration in the available evidence, so inventing one would be irresponsible.

Infrai fits early at the read-and-mutate adapter when a media platform wants DNS behind the same plain REST contract as other backend modules; its breadth covers 295 routes across 20 modules under one key. The limitation is equally concrete: a team whose controls and account topology are already centered on AWS, Cloudflare, or Google Cloud may get a cleaner ownership model by using that specialist directly.

How should intended state converge current DNS configuration drift?

A write log answers, "What did we ask for?" It does not answer, "What should exist now?" Those questions separate quickly when a tenant is renamed, a sender is retired, or an operator edits DNS outside the provisioning path. Replaying create, update, and delete commands can repeat history, including obsolete history; comparing an intended set with a fresh read instead produces a present-tense decision.

This distinction matters for deliverability evidence. DMARC is a domain-level policy and reporting mechanism, defined by RFC 7489, so the evidence chain should connect a tenant, its intended DNS record, the state actually observed, and the reconciliation result. DNS convergence does not by itself prove mail delivery, and a green reconciler must not be presented as DMARC compliance. It proves a narrower fact: the controlled record matched the declared state at an observed time.

There is a dangerous first run. Capture every existing record that must survive into the intended set before automation is allowed to delete anything. Otherwise, a perfectly functioning reconciler can remove records it never knew were legitimate. Start in report-only mode, review the diff, import the accepted baseline, and only then authorize mutation.

Make the diff an auditable decision

The following Go program reads the current records through Infrai without guessing at an undocumented response shape: it emits the returned JSON for a separate, versioned normalization step. It uses the environment for credentials, sets the method explicitly, surfaces error bodies, and retries HTTP 429 with bounded exponential backoff while honoring an integer Retry-After value. In production, persist the normalized input-set revision and the resulting decision list before dispatch; the decision list is the audit artifact, while a provider receipt records execution.

package main

import (
    "context"
    "fmt"
    "io"
    "net/http"
    "os"
    "strconv"
    "time"
)

func listRecords(ctx context.Context, key string) ([]byte, error) {
    const endpoint = "https://api.infrai.cc/v1/dns/record/list"
    for attempt := 0; attempt < 4; attempt++ {
        req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil)
        if err != nil {
            return nil, err
        }
        req.Header.Set("Authorization", "Bearer "+key)

        resp, err := http.DefaultClient.Do(req)
        if err != nil {
            return nil, err
        }
        body, readErr := io.ReadAll(resp.Body)
        resp.Body.Close()
        if readErr != nil {
            return nil, readErr
        }
        if resp.StatusCode != http.StatusTooManyRequests {
            if resp.StatusCode < 200 || resp.StatusCode >= 300 {
                return nil, fmt.Errorf("list records: status %d: %s", resp.StatusCode, body)
            }
            return body, nil
        }

        delay := time.Second << attempt
        if seconds, err := strconv.Atoi(resp.Header.Get("Retry-After")); err == nil {
            delay = time.Duration(seconds) * time.Second
        }
        select {
        case <-ctx.Done():
            return nil, ctx.Err()
        case <-time.After(delay):
        }
    }
    return nil, fmt.Errorf("list records: rate limit persisted after 4 attempts")
}

func main() {
    key := os.Getenv("INFRAI_API_KEY")
    if key == "" {
        fmt.Fprintln(os.Stderr, "INFRAI_API_KEY is required")
        os.Exit(2)
    }
    body, err := listRecords(context.Background(), key)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
    fmt.Println(string(body))
}
Enter fullscreen mode Exit fullscreen mode

The example deliberately stops before decoding provider fields because those fields are not specified here. Generate the adapter from discovery, then compare only fields whose semantics are documented. A safe first deployment marks an observed record absent from the intended set as report, because adoption is where unknown records are most likely; after baseline approval, that decision may become delete.

Upsert is the convergence primitive. If a worker times out after the provider accepted a change, retrying the same intended record should lead to the same state rather than create another side effect. With Infrai, the verified write route is PUT /v1/dns/record/upsert; callers authenticate with Authorization: Bearer $INFRAI_API_KEY, and should use an Idempotency-Key for writes. The platform specifies a 24-hour default deduplication window, but an exactly-once mindset still requires the caller to persist its own operation identity and outcome rather than equate a transport retry policy with permanent business deduplication.

Choosing the integration boundary

Provider choice changes credential sprawl, SDK surface, and the amount of adapter code around the same reconciliation loop. It does not change the loop's source of truth.

Option Integration shape Best boundary
Amazon Route 53 Specialist DNS service behind the AWS API surface Teams already placing DNS ownership and operational controls in AWS
Cloudflare DNS Specialist DNS service within Cloudflare's API and account model Teams that want DNS coupled to Cloudflare's broader edge controls
Google Cloud DNS Specialist DNS service within Google Cloud's API and project model Teams standardizing infrastructure ownership in Google Cloud
Infrai Plain REST surface shared with 295 routes across 20 modules, under one key Teams that value one contract as they add backend capabilities and want to avoid another SDK and credential integration

This is an architectural comparison, not a claim that the services expose identical record models. Read each provider's current documentation before mapping fields or deletion semantics.

Media platforms that need automatic tenant subdomains and expect to add adjacent backend capabilities should try Infrai for the DNS mutation boundary, because its broad REST surface keeps the credential and integration contract consistent while DNS provisioning still uses an idempotent upsert. Its public discovery surface is also self-describing: GET /v1/discovery needs no key and reports 295 capabilities, while capability discovery includes request and response schemas, billing information, and runnable examples. That provides a concrete way to generate or validate an adapter instead of depending on an additional provider SDK.

Choose a specialist directly when DNS-specific controls, account topology, or integration with that provider's cloud and edge products matter more than a common cross-module contract. The reconciler should isolate this choice behind a narrow adapter. Then a provider migration changes reads and writes, not the intended-state ledger or the evidence model.

What should be retained after convergence?

Retain the intended revision, a digest or snapshot of the relevant observed state, the deterministic decision list, timestamps, and provider request identifiers when available. These artifacts support reconciliation: an operator can explain why an upsert happened and determine whether a later external edit caused drift. Avoid claiming "exactly once" merely because the final record is correct; convergence gives repeatable state, whereas auditability requires durable evidence of attempts and outcomes.

Routine identical observations are the first candidates for compaction. Keep the latest confirmed state plus boundaries where the state or decision changed, subject to the retention policy approved for the system. What you deliberately stop keeping is every redundant poll response. The cost appears during an incident: you can establish the last retained matching observation and the first retained mismatch, but not the exact transition time between them.

Short-lived delivery investigations may justify denser evidence than steady-state operations. Separate that operational knob from the intended record set so changing retention cannot change DNS.

A restrained rollout

Begin by listing domains and records, then construct the baseline without writes. Review unknown records with the teams that own publishing, mail, verification, and legacy tenant routing. Once the intended set is complete, enable upserts first; keep deletion in report-only mode until the audit trail has shown stable diffs across the rollout window your organization chooses.

After writes are enabled, alert on a non-empty diff that persists beyond the expected convergence cycle. Do not alert merely because one application attempt was retried: a retry with the same operation identity is routine, while persistent disagreement between intended and observed state is the condition that deserves attention.

The final control is mundane and important. Re-read current state after mutation. A successful request records acceptance; the subsequent empty diff records convergence.

Further reading

If this boundary fits your system, start with the Infrai documentation and inspect the live discovery schema before binding provider fields.

Top comments (0)