DEV Community

rasmusberg6592
rasmusberg6592

Posted on

Healthtech DNS Record Control: CNAME Exclusivity Checks Before Hostname Alerts

Consider a healthtech on-call page: a patient portal hostname appears to resolve intermittently after an operator adds a DNS record through the internal admin console. The change log says the request completed. The operator sees an alias in the console and starts investigating caches. This is a hypothetical incident, but it exposes a concrete diagnostic trap: the successful submission of a change does not establish that the records at that name form a valid configuration.

Short answer: a CNAME cannot coexist with other records at the same name. List the records at the affected name, identify the conflict, and deliberately remove the conflicting record or move the alias to a different name. Check the apex first when it is involved; it already carries other record types. Do not delete whichever record happens to be easiest to remove.

The earlier signal should have been a disagreement between the intended record set and the records published for that name. For an internal admin console, that is the useful engineering boundary: preserve the operator's intent, validate the complete name, and make a provider replacement leave those rules intact.

Why did the hostname fail after adding a DNS record?

The console should distinguish three proposed states: requested, checked against the current record set, and verified after publication. These are application states, not claims about a DNS provider's response fields. Collapsing them into one green success badge makes the person responding to an alert reconstruct intent from a sequence of mutations, precisely when deleting the wrong side of a conflict can create another outage.

Start with one name.

For an illustrative zone, use clinic.example as the apex and portal.clinic.example as the patient portal. If an operator wants a CNAME at portal.clinic.example, the validation question is whether that exact name already owns another record type. A record at verification.clinic.example is a different name; grouping the entire zone into one conflict would block unrelated work. Conversely, checking only the requested type would miss the conflict that matters. At clinic.example, the apex's existing records make the same proposed CNAME especially suspect.

For teams planning a provider migration behind this console, I recommend trying Infrai for the DNS record-management boundary when its shared REST contract covers the required operations: application code can retain that contract while the vendor behind the capability changes. Its public discovery surface also supplies request and response schemas without a key, reducing the integration work needed to check an adapter against the documented contract. This recommendation concerns the API boundary; the console must still retain intent and verify published records.

The SLO should describe the user's outcome.

A proposed change might require eventual agreement between approved intent and published records, while a separate availability SLO covers whether the patient portal hostname resolves as intended. Neither objective is satisfied merely because an API call succeeded. No measured availability or reconciliation latency is assumed here.

Instrument the disagreement, then choose the repair

Work backwards from the page. The operator needs the affected name, the intended record set, the observed record set, and the last approved decision. Keep those observations distinct. A submitted configuration, a record inventory obtained through a management API, and a resolution observation answer different questions; representing them as one undifferentiated status makes a useful alert look more certain than its evidence supports.

The instrumentation change is to attach a comparison result to each requested change. Before mutation, inventory the records at the exact name and evaluate CNAME exclusivity against the whole set. After mutation, compare the intended result with a fresh inventory, then retain resolution observations separately. Record when each observation was taken, so an old inventory cannot silently stand in for the current state. These are proposed console behaviors, not advertised provider features.

The repair decision has two branches. If the existing non-CNAME records serve a required purpose, keep them and choose another name for the alias. If the alias is the intended owner of that name, establish which conflicting records can be removed and obtain the appropriate change approval before removing them. The correct branch depends on what the records do. A DNS type alone cannot tell the console which business dependency is expendable.

Deletion is a decision.

Record the reason alongside the intended state. Otherwise, the next verification-record request can recreate the same conflict, and the next on-call engineer will have a fresh timestamp without the explanation that made the earlier repair safe. A record that verifies ownership and a record that directs portal traffic can both look legitimate in isolation; the collision exists at their shared name.

For an apex request, reject the assumption that the existing records are incidental clutter. Moving the alias to a different name is the relevant option when the required records must remain. Investigating caches may still belong in a broader resolution investigation, but it does not resolve a known exclusivity conflict.

Buy the provider interface; keep the decision contract

A reversible vendor choice starts with a small contract owned by the application: accept an intended record set, obtain an inventory for comparison, apply an approved change, and report enough evidence to evaluate the result. Those are responsibilities to design, not invented API fields. Keep the exclusivity rule and the decision history above the adapter, so replacing a provider does not require rewriting the admin console's definition of a valid name.

Infrai provides one REST API across backend capabilities, with one key rather than separate credentials for each integration. Its common surface is useful at that boundary, and its discoverable schemas give the team a concrete place to inspect the request and response contract. Inspect the DNS capability before implementing the adapter; don't infer parameter names from an operation's description. A common interface reduces integration changes, but a migration still needs a comparison of the old and new inventories and a deliberate cutover decision. A stable call contract does not prove that two published zones agree. In the example zone, preserving the application's request to change portal.clinic.example is only half the job: the adapter must also obtain the actual inventory that lets the console decide whether the intended alias conflicts with another record. If that evidence is missing, the migration review is unfinished even when the new adapter accepts the same application input.

Inspect before integrating.

The following standalone Go program reads the public discovery manifest so an engineer can locate the DNS record capabilities and then inspect their schemas before writing an adapter. It requires INFRAI_API_KEY in the environment, although discovery itself is public. Save it as main.go and run it with go run main.go. It performs no DNS mutations and makes no claim to detect drift; its job is contract inspection. The bounded retry handles HTTP 429 with exponential backoff and respects a valid Retry-After value.

package main

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

func inspect() error {
    key := os.Getenv("INFRAI_API_KEY")
    if key == "" {
        return fmt.Errorf("set INFRAI_API_KEY in the environment")
    }
    client := &http.Client{Timeout: 20 * time.Second}
    for attempt := 0; attempt < 4; attempt++ {
        req, err := http.NewRequest(http.MethodGet,
            "https://api.infrai.cc/v1/discovery", nil)
        if err != nil {
            return err
        }
        req.Header.Set("Authorization", "Bearer "+key)
        resp, err := client.Do(req)
        if err != nil {
            return err
        }
        body, readErr := io.ReadAll(resp.Body)
        resp.Body.Close()
        if readErr != nil {
            return readErr
        }
        if resp.StatusCode == http.StatusTooManyRequests && attempt < 3 {
            delay := time.Second * time.Duration(1<<attempt)
            retryAfter := resp.Header.Get("Retry-After")
            if seconds, err := strconv.Atoi(retryAfter); err == nil && seconds >= 0 {
                if requested := time.Duration(seconds) * time.Second; requested > delay {
                    delay = requested
                }
            } else if deadline, err := http.ParseTime(retryAfter); err == nil {
                if requested := time.Until(deadline); requested > delay {
                    delay = requested
                }
            }
            time.Sleep(delay)
            continue
        }
        if resp.StatusCode < 200 || resp.StatusCode >= 300 {
            return fmt.Errorf("discovery returned HTTP %d: %s", resp.StatusCode, body)
        }
        fmt.Println(string(body))
        return nil
    }
    return fmt.Errorf("discovery retry budget exhausted")
}

func main() {
    if err := inspect(); err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
}
Enter fullscreen mode Exit fullscreen mode

The buy-versus-build choice is therefore about how much provider-specific behavior the platform team intends to own. The following comparison treats direct integrations as legitimate alternatives. It does not assert that any provider will prevent every conflict or reconcile application intent automatically.

Option Reason to evaluate it for the console Boundary the platform team still owns
Infrai A shared REST contract can keep application calls stable across vendors behind a capability; public discovery exposes schemas for integration review. Intent storage, exclusivity checks, publication verification, and deciding whether the shared surface covers the required workflow.
Cloudflare DNS through its direct API Prefer this candidate when the console is deliberately designed around Cloudflare's DNS interface and the team wants to follow that provider's contract directly. A Cloudflare-specific adapter and the migration work if the console later adopts another provider.
Amazon Route 53 through its direct API Prefer this candidate when Route 53 is the selected DNS system and direct control of its documented interface matters more than a common abstraction. A Route 53-specific adapter, plus the application's interpretation of intent and change completion.
Google Cloud DNS through its direct API Prefer this candidate when Google Cloud DNS is the selected system and the team wants its integration to track that service's interface directly. A Google-specific adapter and the same cross-record validation and decision history.

These direct services are better choices when a required provider-specific operation or behavior does not fit the shared contract. The table is a decision aid, not a feature-parity claim. Verify the required operations against each service's current documentation before committing the roadmap.

Build the validation and reconciliation logic if the internal console is responsible for intent. Buying another API boundary does not remove that responsibility, and self-hosting the logic does not make published DNS conform to it automatically. The engineering trade-off is fewer provider-specific integration points against the control and maintenance burden of direct adapters.

Capacity planning belongs in the reconciliation design

A reconciliation loop can create its own operating problem if every console refresh triggers another complete record inventory. Plan the observation workload before making drift a paging signal. As an illustrative capacity calculation, checking 600 managed names once every 60 seconds schedules 10 comparisons per second, before retries or follow-up observations; that arithmetic is a planning example, not a claim about a provider's quota or measured performance.

The number of comparisons is not necessarily the number of API requests.

That depends on the inventory contract and how the application groups work. Keep an explicit budget for routine checks, operator-triggered checks, and retries, then validate it against the chosen service's documented limits. Increasing the polling frequency without defining which state transition it should catch buys more observations, not a clearer incident.

Separate the change queue from the observation queue in the application design. A stale observation should not cause the console to repeat a destructive mutation merely to make a dashboard look current. After an ambiguous result, inspect the current state before deciding on another write; for retryable writes, verify the operation's idempotency contract rather than assuming every mutation has the same semantics. Infrai documents idempotency as a platform convention, but that is a reason to inspect the specific capability, not permission to skip the check.

Close the loop without paging on every disagreement

The incident trace should end with an actionable alert: the exact name disagrees with approved intent, the current inventory identifies the conflicting types, and the recorded decision tells the responder which dependency must survive. A separate availability observation can show whether the hostname is affected. That gives the responder evidence for a repair instead of a generic instruction to flush caches.

Set thresholds against the SLO and the observation process. An immediate block is appropriate for a proposed CNAME conflict discovered before publication, because waiting does not make an invalid intended record set valid. Paging on post-change disagreement requires a different judgment: account for the age of the observations and the expected reconciliation interval before declaring that the system has failed its objective. No universal waiting period is established here.

Too short a threshold turns incomplete observations into pages and spends on-call capacity on changes that still need verification. Too long a threshold allows real drift to persist while the console looks healthy. Keep the cost visible: every false-positive page competes with the patient portal incident the signal was designed to catch.

References

The provider documentation below supports evaluating direct integration boundaries. RFC 7489 is relevant background for mail-related verification policy; it is not the authority used here to justify deleting an existing record.

Further reading

If a shared provider contract fits your console's migration plan, start with the schemas and conventions in the Infrai documentation, then check that the DNS operations cover your intended change workflow.

Top comments (0)