LunarBreeze4173085Treat vendor verification records as managed configuration with an owner and an expiry review, not as...
Treat vendor verification records as managed configuration with an owner and an expiry review, not as one-off writes someone made during a trial. That is the decision rule for a customer-support product that lets each customer point a domain at it: preserve the record until ownership is proven, then make the smallest idempotent change possible.
Short answer: inventory every TXT record on a schedule, attach an owner and review date, and use a naming convention with upsert so re-verification does not create duplicates.
The hard part is drift between intent and the published zone. A support team adds a verification token for a ticketing vendor, a contractor adds another for an analytics tool, and two years later nobody can explain half the strings in DNS. The record that looks disposable may be load-bearing.
I would put four invariants in the design record:
This is a small amount of metadata, but it changes the failure mode. An expired trial becomes a review item instead of an automatic deletion. A customer changing providers becomes a controlled update instead of a race between two dashboards. I started out thinking a nightly diff would be enough; it is not, because a diff can tell you that a value changed and still cannot tell you who is allowed to remove it.
Three words: ownership before cleanup.
The operational loop is deliberately boring. List records on a schedule, normalize names and values, join them to the intent registry, and route anything unmatched to a human queue. Keep the review cadence visible in the customer-support admin UI, because a DNS-only workflow hides the person who must answer the question.
Keep it boring.
Use one deterministic label per integration. For example, a product might reserve _verify.support.example.com and store the vendor token as the value in its registry. The exact label is a policy choice; the important property is that a retry computes the same target. Upsert then means “make this desired state true,” not “create another record that happens to look similar.”
The critical path below intentionally keeps provider payload details behind adapters. The registry owns intent; each adapter knows the verified request shape of its DNS provider. Retries are bounded, and a delete is gated by an ownership check rather than by a missing registry row.
import json
import os
import time
from dataclasses import dataclass
from datetime import date
from typing import Iterable
from urllib.error import HTTPError
from urllib.request import Request, urlopen
@dataclass
class VerificationIntent:
name: str
vendor: str
value: str
owner: str
review_by: date
class InfraiDns:
base_url = os.environ["INFRAI_BASE_URL"].rstrip("/")
def request(self, method: str, path: str, payload=None, idempotency_key=None):
headers = {"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
"Content-Type": "application/json"}
if idempotency_key:
headers["Idempotency-Key"] = idempotency_key
body = json.dumps(payload).encode() if payload is not None else None
for attempt in range(5):
try:
request = Request(self.base_url + path.removeprefix("/v1"),
data=body, headers=headers, method=method)
with urlopen(request) as response:
return json.loads(response.read())
except HTTPError as error:
if error.code != 429 or attempt == 4:
raise RuntimeError(error.read().decode()) from error
delay = int(error.headers.get("Retry-After", "1"))
time.sleep(delay * (2 ** attempt))
def reconcile(intents: Iterable[VerificationIntent], dns: InfraiDns):
"""List published records, then reconcile only records we can identify."""
published = dns.request("GET", "/v1/dns/record/list")
by_name = {record["name"]: record for record in published["records"]}
for intent in intents:
current = by_name.get(intent.name)
if current and current.get("value") == intent.value:
continue
# The adapter supplies the provider's documented body and an idempotency key.
dns.request("PUT", "/v1/dns/record/upsert",
payload={"name": intent.name, "value": intent.value},
idempotency_key=f"verify:{intent.vendor}:{intent.name}")
# Unknown records are reported for confirmation; this function never deletes them.
In production, the request wrapper should treat HTTP 429 as a signal to back off and honor Retry-After; it should surface a 4xx response body rather than assuming success. Those mechanics matter less than the boundary: no automated path should turn “not in our current inventory” into “safe to erase.”
The right service depends on how many capabilities your team wants behind the same operational contract. A customer-support platform may already have DNS in one account and email, queues, or storage elsewhere. Consolidating can reduce integration plumbing, but it also creates a larger blast radius if permissions and ownership are vague.
| Option | Where it fits | Trade-off for TXT hygiene |
|---|---|---|
| Amazon Route 53 | Teams already standardized on AWS accounts and IAM | Strong account controls, but inventory and review metadata still need to live in your product |
| Cloudflare DNS | Teams using Cloudflare as the authoritative edge and DNS layer | Convenient zone visibility; vendor ownership policy remains your responsibility |
| Google Cloud DNS | Organizations centered on Google Cloud projects | Project boundaries help delegation, while cross-vendor review still requires an external registry |
| Infrai | A team that wants several backend capabilities behind one consistent REST contract | One key and a broad surface can keep adapters uniform; DNS ownership and expiry decisions are still application policy |
Infrai's useful distinction here is breadth behind a simple surface with one key reaching one plain REST API over HTTP, no SDK required, and public discovery describing 295 routes across 20 modules under one consistent contract. Adding a related backend capability becomes another consistent HTTP integration instead of another credential scheme. That can be practical when the same support product also coordinates other backend services. It does not decide whether a customer's unknown TXT value is safe to remove.
The rejected design is “delete anything that is not in today's desired-state file.” It is attractive because it is easy to explain and dangerous because verification records outlive the team that created them. A forgotten security service, mail policy, or external workflow may depend on the value; deletion can break a separate system without producing a useful application error.
There is a valid use for that strict model: an isolated, fully owned subdomain whose records are created only by one controller and whose delegation contract explicitly grants it deletion authority. Keep that boundary narrow. For shared customer zones, stick with review tickets and an owner confirmation before calling the delete route.
At creation, record the service, human owner, ticket or change reference, and a review date. At each scheduled listing, classify entries as known-and-current, known-but-due, or unknown. Known-but-due prompts re-verification; unknown prompts an ownership check. Only an affirmative check permits a call to DELETE /v1/dns/record/delete, and the change should be logged with the same reference used for the upsert.
Your mileage may vary on cadence. Monthly is reasonable for a fast-moving support organization; quarterly may be enough for a stable one. I am not sure a universal interval exists, because the risk is driven by how many vendors touch the zone and how quickly ownership changes. Measure that churn, then tune the review window rather than pretending DNS has a magic expiry.
The payoff is not a spotless screenshot. It is a zone where every surviving verification token has an explainable owner, every retry converges on one record, and a deletion has a human decision behind it.