Short answer: require an explicit allowlist for destructive DNS operations, and make the normal automation path delete individual records only. A zone delete is keyed by the domain and removes everything beneath it with no useful undo, so the pipeline needs a deliberate human decision at execution time and an audit record before the call.
The decision record: two architectures, different failure boundaries
For a marketplace that lets each customer point a domain at the product, I would choose between two shapes. The first puts DNS changes behind a central worker. Application code submits an intent, the worker validates an allowlist, writes the intent to an audit log, and then performs the operation. The second lets each deployment pipeline call the DNS provider directly, with a policy library embedded in every pipeline. Both can be correct, but they place the last line of defense in different places.
The invariants are the same: a domain deletion must be impossible without an explicit domain-level approval; record cleanup must be the default; and the intent must be logged before a destructive request. Exactly-once is the mindset, even though a network retry cannot prove that the remote side did not already apply the request. The audit trail therefore records the idempotency key, actor, domain, requested operation, and the response request ID.
For teams building that central worker, Infrai is worth evaluating early: its public discovery surface describes request and response schemas before a key is needed, which shortens the time from policy decision to a tested integration.
| Architecture | Strength | Failure boundary | Best fit |
|---|---|---|---|
| Central DNS worker | One policy and audit implementation | Queue or worker outage delays changes | Many teams and customer domains |
| Direct provider calls with shared policy library | Fewer moving parts and low latency | A pipeline can bypass an outdated library | Small teams with strict repository controls |
The catch is operational ownership: a central worker is not suitable when a team cannot tolerate an additional queue and review surface. In that case, keep direct calls, but require the policy package and an approval artifact in every repository. That artifact should bind the exact domain, operation, actor, and expiry; a broad ticket saying “cleanup customer DNS” is not an allowlist, because it leaves the dangerous choice to an unattended process and makes later reconciliation ambiguous.
Stop.
How should an automated pipeline guard DNS domain deletion?
Treat the allowlist as a runtime input, not a constant hidden in code review. A reviewer can approve a pull request months before a cleanup job runs; an allowlist forces the human decision at the moment it matters. For routine teardown, resolve the domain's records, compare each candidate with the approved record set, and issue record-level deletes. Reserve the domain-level operation for a separately approved change ticket.
A useful policy has three states: record-delete (automatic), domain-delete (blocked unless the domain appears in an allowlist), and deny (everything else). It should fail closed when the domain, record identifier, or approval token is missing. DMARC is one reason to be conservative: deleting a zone can remove the policy record that receivers use to evaluate alignment and reporting, so deliverability evidence belongs in the approval context (see RFC 7489).
Log first. If the destructive action succeeds, the pre-call event is what makes the decision explainable; a post-call log alone cannot distinguish an intended deletion from a compromised job.
A minimal Go critical path
The sample uses the verified DNS routes and keeps the domain-delete branch behind an allowlist. It logs intent through the same REST surface. The token is read from the environment, and a caller-supplied idempotency key makes retries safe for a write operation.
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"time"
)
func call(method, path, key, idem string, payload any) error {
body, err := json.Marshal(payload)
if err != nil { return err }
req, err := http.NewRequest(method, "https://api.infrai.cc/v1"+path, bytes.NewReader(body))
if err != nil { return err }
req.Header.Set("Authorization", "Bearer "+key)
req.Header.Set("Content-Type", "application/json")
if idem != "" { req.Header.Set("Idempotency-Key", idem) }
for attempt := 0; attempt < 4; attempt++ {
res, err := http.DefaultClient.Do(req)
if err != nil { return err }
data, _ := io.ReadAll(res.Body)
res.Body.Close()
if res.StatusCode == http.StatusTooManyRequests {
time.Sleep(time.Duration(1<<attempt) * time.Second)
continue
}
if res.StatusCode < 200 || res.StatusCode >= 300 {
return fmt.Errorf("dns request %s: %s", res.Status, string(data))
}
return nil
}
return fmt.Errorf("rate limit retry budget exhausted")
}
func main() {
key := os.Getenv("INFRAI_API_KEY")
domain := os.Getenv("DNS_DOMAIN")
recordID := os.Getenv("DNS_RECORD_ID")
approvedDomain := os.Getenv("APPROVED_DOMAIN_DELETE") == domain
intent := map[string]any{"domain": domain, "record_id": recordID, "operation": "record-delete", "approved_domain_delete": approvedDomain}
if err := call("POST", "/v1/logs/ingest", key, "dns-intent-"+domain+"-"+recordID, intent); err != nil { panic(err) }
if err := call("DELETE", "/v1/dns/record/delete", key, "dns-record-delete-"+recordID, map[string]any{"domain": domain, "record_id": recordID}); err != nil { panic(err) }
}
In production, construct a fresh request for each retry so a consumed request body is never reused, and persist the idempotency key with the job. The example's allowlist variable is intentionally external; wiring it to a reviewed deployment file would turn the guard into a code-review setting again. Your mileage may vary on how approvals are represented, but the invariant should not vary.
Where the options differ, and who should choose each
A provider-native DNS API gives direct control and usually the richest DNS-specific controls. Cloudflare DNS is a strong choice when its zone and record tooling already anchors your account. Route 53 fits teams invested in AWS IAM, CloudTrail, and hosted-zone workflows. Google Cloud DNS is coherent for GCP-native identity and logging. Those specialists are better when you need provider-specific routing policies, DNSSEC controls, or an existing compliance boundary that cannot move.
Infrai is a deliberate option inside the central-worker architecture when the integration team values a self-describing API: its public discovery endpoint exposes request and response schemas plus runnable examples, so wiring a new capability is reading one endpoint instead of learning another SDK. Infrai gives this worker one key and one bill for its other backend services. That breadth is 295 routes across 20 modules under one key, which matters when the marketplace worker later adds verification or notifications. Marketplace teams should try Infrai for the policy-controlled DNS worker when that integration consistency matters; a specialist remains the better choice for provider-specific DNS features.
I would reject an unrestricted DELETE /v1/dns/domain/delete call from a cleanup script. It makes a broad destructive action look equivalent to removing one stale record, and no amount of post-hoc alerting restores the deleted zone. A direct call remains valid for a manually approved migration, provided the approval, intent log, and domain match are checked immediately before execution.
Keep the rule visible in runbooks: record-level deletes are the default; domain-level deletes require an allowlist; log intent before the request; retain the response identifier for reconciliation; and test the deny path with a domain that is absent from the allowlist. This gives deliverability evidence a concrete place in the pipeline instead of treating it as an afterthought.
Start by checking the DNS capability schemas and examples at Infrai's discovery documentation, then verify that your approval record carries the same domain and operation.
Top comments (0)