Let’s Encrypt and Certbot can provide wildcard certificates when the validation process is carried out via DNS. This post explains my setup and introduces some new scripts I’ve uploaded to make this task easier.
As I explained in a prior post, my DNS zones are configured for dynamic updates and use DNSSEC. This allows my own zones to easily participate in the
dns-01 ACME challenge to authenticate the certificate issuing process. In simple terms, Let’s Encrypt will provide with a randomly generated string that you need to add in a well known location under the apex of your DNS zone to prove that you are the one controlling it and by extension, that you are authorized to request issuance of a SSL certificate for your domain.
With the introduction of helper scripts to Certbot, the process of adding – and later removing – the authentication DNS records can be automated.
My Let’s Encrypt environment
In previous posts where I explained my scheme for managing multiple certificates with certbot and Certificate rotation with Let’s Encrypt, I explained how I reuse key pairs and the Certificate Signing Requests for certificates where pinning is desired. You might want to take a look at those posts to familiarize yourself with this layout – and to determine whether the method I present in this post will work for you.
This is the filesystem layout I use to manage my keypairs, where each domain (or group of domains) has a directory where multiple keypairs are generated and maintained automatically. There’s also support for generating encrypted backups of those keypairs, for off-line safekeeping, which is critical for good operational security practices.
Certificate creation, revisited
Place the nsupdate hook in a suitable location on the server where you’ll regularly issue or renew certificates. I’ll use
/usr/local/bin for now. This script will take care of adding the authentication records to the DNS via dynamic updates prior to requesting the certificate operation, and removing the records once the process is done.
nsupdate-hook.sh on its own as it will inform of any missing dependency, which should look like this:
The command would request generation or renewal of a test certificate using your CSR and keys in the Let’s Encrypt staging environment. Notice the use of shell variables on which you can replace your own values.
TSIGFILE are used by
nsupdate-hook.sh itself to invoke
Once you’re convinced that your certificate operation works as expected, you can remove the staging-specific options and point to the live Let’s Encrypt environment, as follows:
nsupdate-hook.sh takes care of issuing the DNS update as well as verifying that the update is visible at all authoritative name servers as well as an external name server. The update won’t proceed unless changes are visible at all servers, which helps prevent issues with random authorization failures is some scenarios.
You can test that the hook is working as expected by passing the required environment variables to the hook. At line 2 I set the test to use the
lem.click domain, with a ficticious validation token.
Depending on your setup, one or more
Failed validation messages can be produced, but within a few seconds the program should end. At this time you can easily check that the validation DNS records are present:
dig +short txt _acme-challenge.lem.click "fukuhara-sokisoki-15412"
If something goes wrong, the information that
nsupdate-hook.sh sends via syslog can be helpful:
In this case, the addition of the autentication DNS record did not make it to one of the name servers in time. The hook noticed this, waited for a little while and retried the validation which by then, had ample time to propagate and was successful.
Personally, I have a simple shell script that runs these commands for all the domains I need certificates for, and invoke this script from my
Keep in mind that after renewing the certificates, you’re responsible for copying them to their required destination and restart the affected services so that the new certificates can be used. This is also handled by my custom automatic renewal script.