The Source of Truth

Connecting to a website? Sending an email? Which server1 you reach depends on DNS records. And CAA or SSHFP records establish trust for public key cryptographic protocols.

DNS records are the source of truth.

DNS API Tokens

Currently, wildcard certificates with Let’s Encrypt require to write an arbitrary string in a DNS record, for every single certificate renewed or issued. In practice, this often involves sharing a write API token to change the DNS. This is risky: should an attacker obtain the token, they can do a lot of damage: hijack traffic (and get valid certificates for it), receive and send emails using the corresponding domain…

And often API tokens are not scoped just to access one domain, through human error or because the provider lacks the feature. Then, they might give access to all domains in an account at the DNS provider and the attacker can move laterally to more targets.

With this in mind, I have not set up wildcard certificates with Let’s Encrypt so far. The risk simply outweighed the gains for the use cases I had. And I’m not alone: agnos was written to address the same concern. And the DNS challenge documentation calls this out: “Keeping API credentials on your web server is risky”.

DNS Challenges Without Tokens

So I’m really excited about this new challenge type, DNS-PERSIST-01. It is a static DNS TXT record that authorizes a particular Let’s Encrypt account2 to get certificates, even wildcard ones, for a particular domain. No need to share very sensitive DNS API token!
It also means that Let’s Encrypt clients don’t need to support the API of your DNS provider to emit wildcard certificates. Pick any client and DNS provider you want, including a self hosted one.

Looking forward to this being fully implemented and available to everyone!


  1. Or at least it’s IP ↩︎

  2. Granted, an account is tied to a private key on the machine requesting the certificate. But this is a lot less sensitive, it’s only used by Let’s Encrypt, not for everything attached to a domain. ↩︎