Industry

dns-persist-01: the DNS validation record you set once, and what it binds you to

October 10, 202610 min readCertPulse Engineering

Every DNS-01 setup I've inherited looks roughly the same. Somewhere in the renewal path sits an API token that can write to a DNS zone. Maybe it's a Route 53 IAM user on a Jenkins box, or a Cloudflare token in a Kubernetes secret, or an account-wide key for some registrar's DNS that nobody remembers creating. The token can almost always do far more than write one TXT record. And it gets copied to every place that renews a certificate.

dns-persist-01 is the first serious attempt to get that credential out of the renewal path. You publish one TXT record, once, and the CA checks it whenever it needs to validate. Your renewal host never writes to DNS again. For a lot of teams that's a real improvement. It's also a standing authorization sitting in public DNS. That record is a credential in everything but name, and it never rotates unless you rotate it.

Domain validation is the part that breaks first

Most coverage of SC-081v3 is about certificate lifetimes dropping to 47 days by March 2029. The change that will actually bite people is the domain control validation reuse period. The 200-day limit that took effect on March 15, 2026 drops to 100 days on March 15, 2027, and to 10 days on March 15, 2029. Once DCV reuse is shorter than your renewal interval, every renewal needs a fresh validation.

Let's Encrypt users are mostly there already. Authorizations are reused for 30 days today, and the published plan for the default profile cuts that to 10 days in February 2027 and 7 hours in February 2028. If you renew through DNS-01 with Let's Encrypt, your renewal host is already writing to DNS on almost every run.

The teams who'll really feel it are the ones buying OV certificates from commercial CAs. For many of them the process today goes like this: once a year someone logs into DigiCert CertCentral or Sectigo Certificate Manager, pastes a random token into a TXT record, clicks validate, and forgets about it for twelve months. At 100 days that's four times a year per domain. At 10 days no human keeps up. You either automate the DNS writes or move to a validation method that doesn't need them.

Automating DNS writes is exactly where the credential sprawl comes from. Route 53 can restrict changes to specific record names with IAM condition keys, but I rarely see anyone set that up. Plenty of DNS providers only offer tokens scoped to a whole zone. Some only do whole-account. So in practice, "automate DCV" has meant handing a powerful DNS credential to every machine that renews certificates.

What SC-088v3 defines

The CA/B Forum adopted ballot SC-088v3 in October 2025, and it landed in the Baseline Requirements in November 2025 as section 3.2.2.4.22, "DNS TXT Record with Persistent Value." That same month the IETF ACME working group adopted a matching draft, draft-ietf-acme-dns-persist, which defines the dns-persist-01 challenge type.

The mechanics are simple. You create a TXT record at a _validation-persist label under the domain you want validated. The value starts with the CA's issuer domain name, the same identifier you'd put in a CAA record (letsencrypt.org, pki.goog, and so on), followed by parameters:

  • accounturi (required) ties the authorization to one specific ACME account.
  • policy (optional) has one defined value, wildcard, which extends the authorization to subdomains and wildcard certificates.
  • persistUntil (optional) is a Unix timestamp. Once it passes, the CA must refuse to use the record for new validations.

Leave out persistUntil and the record never expires. To authorize more than one CA, you publish one record per CA at the same label, and each CA reads only its own.

The DCV reuse period still applies, and the CA still has to validate inside that window. What changes is who does the work. Validation becomes a DNS lookup on the CA's side, and your renewal host writes nothing.

The spec hasn't settled, though. Draft -01, published in March 2026, put the plain ACME account URL in accounturi. Draft -02, published in September 2026, swapped that for a hash of the domain name, the account key's thumbprint, and the account URL, so the same setup now produces a different record value. Before you write anything into a zone, read the current draft on the IETF datatracker and the ballot text on cabforum.org, and find out which revision your CA actually implements.

Where support stands

Here's what I can confirm from public sources as of October 2026.

Let's Encrypt announced dns-persist-01 in February 2026. Pebble, their test server, supported it, staging was planned for late Q1, and production was targeted for Q2. Production hasn't shipped. The rollout is reportedly paused, and a Let's Encrypt engineer said in June they won't deploy until an open issue in the IETF draft is resolved.

Google Trust Services announced support on September 28, 2026, implementing draft -01. Their announcement warns that early adopters may need to update records if the final standard changes. Given what -02 just did to accounturi, I'd plan on it.

SwissSign has published its own go-live plans. For any other CA, ask them directly. The Baseline Requirements method exists whether or not a CA exposes it over ACME.

Client support is patchy. As of mid-September:

  • lego's v5 release included an implementation against draft -01.
  • acme.sh announced support in version 3.1.4.
  • Certbot had an open issue and no merged implementation.
  • cert-manager had an open feature request and nothing released.

None of this works unless your CA and your client both support the method and implement the same draft revision. I wouldn't hang a 2027 renewal plan on it yet. If you have to, check the CA, the client, and the draft revision before you commit.

The tradeoffs nobody puts on the slide

The record is a standing authorization

With dns-persist-01, anyone holding the ACME account key named in the record can get a certificate for that domain without touching DNS. The draft's own security considerations say so. The credential you need to protect is now the ACME account key, not the DNS API token.

That key is the narrower credential, since a stolen DNS token can also rewrite your records. The problem is that ACME account keys usually get handled far more carelessly than DNS credentials. I've found one account key baked into a base image and present on every host. I've seen every cluster's cert-manager issuer keep its own copy in a secret. I've worked with teams that couldn't tell me how many machines still had the accounts directory from a certbot install three years back. Under dns-01, a leaked account key alone couldn't get anyone a certificate for your domains. Under dns-persist-01 it can.

The account's lifecycle is now the DNS lifecycle

Every record names an account. Lose the key, or deactivate the account after a compromise, and every record pointing at it stops working until you rewrite it in every zone.

Key rollover is messier. As I read draft -02, the CA retains the account's earlier keys and keeps checking records against them. That makes routine rotation painless. It also means rotating the key does nothing to lock out an attacker. The only way to revoke the authorization is to deactivate the account, and that breaks every renewal depending on it at once.

Multi-CA fallback doubles the records

Keeping a backup CA is good practice. With this method, each backup CA means another standing authorization per name, tied to a different account. Two CAs across three hundred zones is six hundred records to keep correct.

Wildcard policy widens the blast radius

Put policy=wildcard on the apex and that account can get a certificate for every name under it, including subdomains you've delegated to other teams or vendors. Scope the record to the exact name unless you actually issue wildcards.

Records outlive the services they were for

This is the one I'd bet causes the first real incidents. Someone decommissions a service, deletes the A record, and leaves the _validation-persist record alone because nobody knows what it's for. Without persistUntil, it keeps authorizing issuance forever. It's the dangling-CNAME problem all over again, except what's left dangling is permission to get a certificate.

Compared to the alternatives

CNAME delegation with acme-dns already solves most of the credential problem, and you stay on plain dns-01. You point the _acme-challenge name at a dedicated validation zone, and the renewal host only holds a credential that can update one TXT record there. You still write to DNS on every renewal. But the write can't touch your real zone, and every CA and mainstream client supports it today.

CAA with accounturi (RFC 8657) works alongside the persistent record rather than replacing it. It restricts issuance to one account regardless of validation method. The draft treats the CAA check and the persist-record check independently, so use both.

Plain dns-01 is still the better fit for:

  • Teams that already have scoped, audited DNS automation, either acme-dns or cert-manager with tightly scoped credentials
  • Teams whose CA or client doesn't support the method yet
  • Anyone protecting high-value names who wants every issuance to require a fresh DNS write

dns-persist-01 actually wins when DNS belongs to another team, a vendor, or a registrar with no API, and clicking validate in a CA portal was the only option you had. That's where I'd reach for it first.

How I'd roll it out

Start with an inventory. List every domain that renews through DNS-01, the client and CA each one uses, and where its DNS write credential lives. That last column usually surprises people.

Then decide zone by zone, because zones have different owners and different risks. A marketing zone at a registrar with no API is a good candidate. The apex of your primary domain probably isn't.

Always set persistUntil, and pair the record with CAA accounturi. An expiry means someone has to renew the authorization on purpose. Pick a horizon you'll actually review, six or twelve months, and put the renewal on someone's calendar or into automation.

Manage the records as code with a named owner. Keep them in Terraform or OctoDNS, review changes in pull requests, and comment each record with the team and service it belongs to. A record without an owner is tomorrow's dangling authorization.

Don't pull the DNS credentials until a full renewal cycle works without them. Run both methods in parallel and check the CA's order details to confirm renewals actually went through dns-persist-01. Then revoke the DNS token.

Monitor the record itself. Under dns-01, a broken DNS credential shows up as an obvious renewal failure. Under dns-persist-01, the record can vanish or change quietly. Someone "cleans up" TXT records they don't recognize. A DNS provider migration drops it. Or persistUntil just passes. Renewal then fails for a reason that has nothing to do with the renewal host, and the renewal host is the first place everyone looks. Alert when the record disappears, when its value changes, and when its expiry gets close.

Watch CT logs too. Once issuance doesn't need a DNS change, your DNS audit trail stops recording it, and a certificate you didn't expect shows up in Certificate Transparency logs instead. This is part of why I built CertPulse: it watches CT logs for your domains, alerts on new entries, and tracks expiry across ACM, Key Vault, GCP Certificate Manager, and external endpoints.

You publish the record once. Whoever holds that account key stays trusted for as long as the record exists. It's a credential sitting in public DNS, so review it like one.

This is why we built CertPulse

CertPulse connects to your AWS, Azure, and GCP accounts, enumerates every certificate, monitors your external endpoints, and watches Certificate Transparency logs. One dashboard for every cert. Alerts when auto-renewal fails. Alerts when certs approach expiry. Alerts when someone issues a cert for your domain that you didn't request.

If you're looking for complete certificate visibility without maintaining scripts, we can get you there in about 5 minutes.