Published: 21.04.2021 | Edited: 09.05.2021 | Tags: 100daystooffload,security,acme

Wildcard certificate with acme.sh

This post is a sequel to my previous post. The post demonstrated how to setup HTTPS for Nginx by obtaining a certificate via 3rd party client called acme.sh. There is also some basic underlying theory about these terms. Consider reading it if feeling uncertain.

Start by creating a wildcard DNS type A record by entering an asterisk (*) in the place of a subdomain. Let's consider domain example.com again, the record should hold *.example.com value.

Trying a wildcard with ALPN mode:

acme.sh --issue --alpn -d "*.example.com"

Ends up with the error message:

The supported validation types are: dns-01, but you specified: tls-alpn-01

We know that tls-alpn-01 is the ALPN mode. What's the meaning behind the dns-01 mode?

DNS-01 challenge

There's a reason why acme.sh complains about unsupported validation type. A validation type is defined as a challenge in the ACME standard. In acme.sh documetation it is referred to as mode. The reason is that ALPN (or standalone, or webroot, or even nginx/apache) mode works by proving we have control over the host by doing a temporary changes on it, that can be securely verified from the outside. By outside in this scenario means by LetsEncrypt. LetsEncrypt, by performing this verification, has as proof that we are in fact in control of the domain the certificate is issued to.

Now the DNS-01 challenge does this slightly differently. It requires adding a TXT record to the domain. During the challenge, the TXT record is read by LetsEncrypt (if it had enough time to propagate) and if correct, the certificate is issued.

Using DNS API can be dangerous

The above step can be automated as any domain registrars today provide an API access to manipulate the domain records on their nameservers programmatically. Before continuing further, make sure you understand the risks involved.

Warning: depending on your DNS provider, it can be incredibly dangerous to automate LetsEncrypt renewal via DNS-01 challenges, as the API keys must be available in plaintext and most providers offer too much control via their APIs. A compromised machine could result in all host records being changed, or (with some providers) a change in domain registrant details or even an outright domain transfer.

Ways to mitigate this are:

  • do not store the auth token, and trigger the renewal manually
  • run the renewal on a machine that is not on the public Internet, and SFTP/SCP the certificates onto your server
  • run an instance of acme-dns, delegate your _acme-challenge to it, and automate the process with that.

Consider yourself warned and avoid keeping this mode unmitigated/automated on the business critical services.

Wildcard DNS API mode

We use porkbun.com API for this example:

export PORKBUN_API_KEY="..."
export PORKBUN_SECRET_API_KEY="..."
acme.sh --issue --dns dns_porkbun -d "*.example.com"

If there is an error stating that the hook is not available (because it was not included in the package for instance):

Can not find dns api hook for: dns_porkbun

Try downloading the required hook from the master branch into /root/.acme.sh:

wget -P /root/.acme.sh/ https://raw.githubusercontent.com/acmesh-official/acme.sh/master/dnsapi/dns_porkbun.sh

Tip: the API keys are stored in the .acme.sh/account.conf, should the need to delete them arises. Consider also revoking the keys and disabling the API access as safer options, as once they keys are exposed, there is very little guarantee that deleting them solves the problem.

Remaining steps of the setup are identical with the setup mentioned in the post at the beginning.

This is a 42th post of #100daystooffload.

Links