DEV Community

ethanbrooks1486
ethanbrooks1486

Posted on

Customer Domain DNS Explained — Serving Assets with Signed URL Access

A marketplace can move customer-facing media without turning DNS into a leap of faith. Use a staged CNAME cutover, keep the old origin ready, and treat signed URLs as a separate authorization layer. The deciding factor is not feature count. It is how quickly the team can detect and reverse drift between the record it intended to publish and the record resolvers can actually observe.

Choice Drift visibility Rollback Operational load Best fit
Staged CNAME cutover with an observation gate High Fast, if the prior target stays live Moderate Customer hostnames with private or time-limited media
Direct cutover at the apex Lower and more provider-dependent Harder Low after setup A controlled zone where apex behavior is understood
HTTP redirect from the old host Does not validate DNS intent Fast at the application layer Moderate Public assets whose URLs may change

Recommendation: use the staged CNAME path for a marketplace hostname such as media.shop.example. Verify the published target from independent resolvers before issuing signed URLs for that host. Keep the previous target healthy through the rollback window. This adds one gate, but it keeps DNS routing and request authorization from becoming one opaque deployment.

Short answer: DNS proves where a hostname routes; a signed URL proves that a specific request is authorized under an application policy. Neither substitutes for the other.

How should DNS records serve assets from a customer domain?

The dangerous state is boring: the control plane says media.shop.example should point at the new edge, while recursive resolvers still return the previous target. A second variant is worse. Some resolvers see the new target and others see the old one. The marketplace then serves two populations at once, and a clean dashboard can hide the split.

Define intent as data, not as a screenshot in a ticket. For each hostname, record the expected DNS target, the previous target, the earliest activation time, and a cutover state. Then observe public DNS separately. Promotion happens only when observation agrees with intent.

This is the first criterion: can the system expose disagreement before traffic depends on it? A workflow that writes a record and immediately marks the hostname ready has a short time-to-first-call, but terrible time-to-first-truth. I would accept one more explicit state transition to remove that ambiguity. I would not accept twelve knobs for it.

A practical state model is small: pending, observed, active, and rollback. pending means the desired record exists in the ledger. observed means public lookup results match it. active permits URL issuance on the customer host. rollback points issuance back to the prior known-good host while operators restore the earlier DNS intent.

No magic.

Just 4 states.

DNS TTL affects how long cached answers may remain in use, so lowering a TTL shortly before a cutover does not erase answers already cached under an older TTL. Plan the observation and rollback windows from the previously published value, not the value you hope everyone has noticed.

Keep routing and access control separate

The second criterion is whether authorization survives a routing change without broadening access. A signed URL should bind the request properties your verifier relies on, such as the path and expiration time. The verifier should reject an expired token, a modified protected field, or a signature that does not validate. DNS does none of this. It maps names into the resolution process.

This separation matters during rollback. If authorization policy is embedded in the new routing target alone, falling back may silently change who can fetch an asset. Both the old and new serving paths need equivalent verification behavior for the duration of the cutover. Test that claim before DNS changes.

That is the trade-off.

Host binding is a deliberate policy choice. If the signature covers the hostname, a URL minted for the platform fallback host cannot be replayed on media.shop.example; rollback then requires issuing a new URL. If the signature omits the hostname, the same token may work across approved hosts, which is convenient but expands its replay surface. There is no universal winner. For private marketplace media, binding the host is the tighter default, provided the application can remint URLs during rollback.

Keep keys out of DNS. Publish only routing and domain-control records there. Signing keys belong in a key-management boundary, and verification should support overlap between an outgoing key and its replacement so rotation does not invalidate every unexpired link at once. The overlap must last at least as long as the longest URL validity window you permit.

A minimal drift gate in TypeScript

The implementation below compares declared intent with observed CNAME answers. It does not update DNS, issue certificates, or sign URLs. Those are separate jobs. That narrow boundary is useful: the gate can run in CI, a worker, or a CLI without inheriting the credentials used to change the zone.

import { resolveCname } from "node:dns/promises";

type CutoverIntent = {
  hostname: string;
  expectedTarget: string;
  previousTarget: string;
};

const normalizeDnsName = (value: string): string =>
  value.trim().toLowerCase().replace(/\.$/, "");

async function observeIntent(intent: CutoverIntent): Promise<{
  ready: boolean;
  answers: string[];
}> {
  const answers = (await resolveCname(intent.hostname)).map(normalizeDnsName);
  const expected = normalizeDnsName(intent.expectedTarget);
  return {
    ready: answers.length > 0 && answers.every((answer) => answer === expected),
    answers,
  };
}

const intent: CutoverIntent = {
  hostname: "media.shop.example",
  expectedTarget: "edge-new.cdn.example",
  previousTarget: "edge-old.cdn.example",
};

const result = await observeIntent(intent);
if (!result.ready) {
  throw new Error(`Cutover blocked: observed ${result.answers.join(", ") || "no CNAME"}`);
}
Enter fullscreen mode Exit fullscreen mode

One lookup is not enough evidence for activation. Run the same assertion from more than one network or resolver, retain the answers with timestamps, and require stable agreement across the observation interval chosen by your team. Do not invent a universal interval. It depends on the prior TTL, resolver behavior, and the rollback objective.

The limitation is real: this probe checks one record type from one runtime and cannot prove what every customer resolver sees. It also says nothing about certificate readiness, edge configuration, origin health, cache keys, or signature verification. Those checks belong beside the DNS gate, not inside it. A team that cannot operate probes from independent networks should use its existing external DNS monitoring and keep activation manual; pretending a local lookup represents the public internet is worse than admitting the gate is incomplete.

The benchmark I care about here has 2 clocks: time from declared intent to externally observed agreement, and time from a rollback decision to externally observed restoration. Measure both in a rehearsal. Counting API calls is less useful than knowing how long customers can receive mixed answers.

The preflight suite should also request one valid signed URL, one expired URL, one URL with a changed path, and one URL using the wrong host. Record status and cache behavior for each path. Avoid logging the complete query string because it may contain the credential being tested.

When is the runner-up better?

A redirect is the runner-up when assets are public, the old hostname is firmly under your control, and changing the visible URL is acceptable. It gives application operators a quick rollback lever and avoids coupling URL issuance to DNS observation. The staged CNAME method is not a fit when a customer cannot delegate the hostname or when the team cannot keep both serving paths policy-compatible. A redirect is itself a poor fit for private assets if it leaks a reusable destination or if clients do not follow redirects consistently.

An apex cutover can also be reasonable when the customer controls the full zone and the chosen DNS service has a clearly documented way to represent the desired target at the apex. The operational test remains the same: compare public answers with declared intent. Do not let a convenient control-panel label stand in for observed behavior.

Use fewer moving pieces for a hostname that serves immutable, public catalog thumbnails. Use the stricter staged flow for seller documents, embargoed product images, or any media whose access depends on expiration and request integrity. The data classification changes the decision more than the brand of CDN does.

The cutover rule I would ship

Activate a customer media hostname only after public observations match the declared target and both serving paths pass the same authorization tests. Roll back when observations diverge, signature verification differs, or the new path fails the agreed health checks. Keep the old path available until the DNS rollback window has elapsed.

This is intentionally plain.

A cutover ledger, a resolver probe, and 4 authorization cases are enough to make the state inspectable. More configuration should have to earn its place.

DMARC is adjacent, not part of this media-delivery design. It applies policy and reporting to email authentication and organizational domains. Do not copy email-specific record semantics into an asset hostname workflow merely because both involve DNS.

Further reading

Top comments (0)