certbot renew: An authentication script must be provided

Published in

For a personal project of mine I’ve been using a wildcard TLS certificate issued by Let’s Encrypt. certbot made the process of creating the certificate extremely easy, I just had to apt install certbot and then run the following command, duly copy-pasted from the Internet:

certbot --manual certonly --agree-tos --email ema@example.org --preferred-challenges=dns -d '*.example.org'

The command gave this output:

[...]
Please deploy a DNS TXT record under the name
_acme-challenge.example.org with the following value:

05REcrGYWuv_fTBQ3QQYTxmNm3f_LU2cN8JNf_f458z

Being a happy Gandi customer and Terraform user, I deployed the change with this configuration:

resource "gandi_livedns_record" "acme" {
    zone = "example.org"
    name = "_acme-challenge"
    type = "TXT"
    ttl = 300
    values = [
        "05REcrGYWuv_fTBQ3QQYTxmNm3f_LU2cN8JNf_f458z"
    ]
}

This was enough to issue the certificate, and I completely forgot about it till the nice Let’s Encrypt Expiry Bot emailed saying the certificate would expire in 20 days.

Didn’t I configure auto-renewal of the cert? I thought I did but then again who knows, weeks have gone by! It turns out I did, with this wonderful /etc/cron.weekly/certbot-renew script:

#!/bin/sh

certbot renew

Other than not being very advanced, the script was also failing claiming that The manual plugin is not working and that An authentication script must be provided with --manual-auth-hook:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/example.org.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert is due for renewal, auto-renewing...
Non-interactive renewal: random delay of 293 seconds
Could not choose appropriate plugin: The manual plugin is not working; there may be problems with your existing configuration.
The error was: PluginError('An authentication script must be provided with --manual-auth-hook when using the manual plugin non-interactively.')
Attempting to renew cert (example.org) from /etc/letsencrypt/renewal/example.org.conf produced an unexpected error: The manual plugin is not working; there may be problems with your existing configuration.
The error was: PluginError('An authentication script must be provided with --manual-auth-hook when using the manual plugin non-interactively.'). Skipping.
All renewal attempts failed. The following certs could not be renewed:
  /etc/letsencrypt/live/example.org/fullchain.pem (failure)

Unfortunately certbot did not guess that — even though the certificate was created manually — I wanted renewals to happen automatically. Luckily certbot also didn’t guess my Gandi API key.

When the certificate was issued, this /etc/letsencrypt/renewal/example.org.conf was created for me:

# renew_before_expiry = 30 days
version = 0.31.0
archive_dir = /etc/letsencrypt/archive/example.org
cert = /etc/letsencrypt/live/example.org/cert.pem
privkey = /etc/letsencrypt/live/example.org/privkey.pem
chain = /etc/letsencrypt/live/example.org/chain.pem
fullchain = /etc/letsencrypt/live/example.org/fullchain.pem

# Options used in the renewal process
[renewalparams]
account = redacted
pref_challs = dns-01,
authenticator = manual
manual_public_ip_logging_ok = True
server = https://acme-v02.api.letsencrypt.org/directory

The important line is authenticator = manual in the renewalparams section. We need to replace that with a plugin for the Gandi DNS service. Thankfully Yohann Leon was nice enough to write one, and Unit193 packaged it for Debian.

What I did to get certbot to automatically renew my wildcard certificate was:

1) installing the plugin with apt install python3-certbot-dns-gandi

2) replacing authenticator = manual with authenticator = certbot-plugin-gandi:dns

3) adding certbot_plugin_gandi:dns_credentials = /etc/letsencrypt/gandi.ini to tell the plugin where to find my credentials

4) creating /etc/letsencrypt/gandi.ini with dns_gandi_api_key=REDACTED

Almost. Now certbot renew failed saying that it cannot find certbot_plugin_gandi:dns_api_key:

Attempting to renew cert (example.org) from /etc/letsencrypt/renewal/example.org.conf produced an unexpected error: Missing property in credentials configuration file /etc/letsencrypt/gandi.ini:
 * Property "certbot_plugin_gandi:dns_api_key" not found (should be API key for Gandi account).. Skipping.

So apparently something was wrong with step (4). Though the docs use dns_gandi_api_key as the property name, it seems it should be certbot_plugin_gandi:dns_api_key instead.

And that’s it, here is the final configuration.

/etc/letsencrypt/renewal/example.org.conf

# renew_before_expiry = 30 days
version = 0.31.0
archive_dir = /etc/letsencrypt/archive/example.org
cert = /etc/letsencrypt/live/example.org/cert.pem
privkey = /etc/letsencrypt/live/example.org/privkey.pem
chain = /etc/letsencrypt/live/example.org/chain.pem
fullchain = /etc/letsencrypt/live/example.org/fullchain.pem

# Options used in the renewal process
[renewalparams]
authenticator = certbot-plugin-gandi:dns
certbot_plugin_gandi:dns_credentials = /etc/letsencrypt/gandi.ini
account = redacted
pref_challs = dns-01,
server = https://acme-v02.api.letsencrypt.org/directory

/etc/letsencrypt/gandi.ini

certbot_plugin_gandi:dns_api_key=REDACTED