question:
how do we make certbot aware of the existence of certs which have been provisioned by mechanisms other than running certbot to obtain the cert?
here is our use case:
we never use wildcard certificates.
we provision new cloud instances on a very regular basis using terraform and other automation technologies.
sometimes an instance has issues that occur after certbot has successfully requested and received a certificate against its fqdn. often the simplest solution is to destroy the problematic instance and re-provision a new instance with the same fqdn. when we do this, our automation securely stores a copy of the certbot certificate (all four archive pem files) in our secret store and deploys that copy (and the live symlinks) to the re-provisioned instance using the expected filesystem permissions and ownerships. we learned the hard way that if we don't do that, we get throttled by letsencrypt for requesting new certificates for fqdns that we have already been issued certificates against (ie: when an instance deployment has had multiple consecutive deployment failures). if that happens we must wait a week to request a new cert for the fqdn. this is why we always keep a copy of issued certs in our secret store. it's also useful if we need to move a deployed instance to a different geography or cloud provider.
problems occur when certificates that have been deployed from our secret store expire. this is because the certbot service on these instances was never aware of the certificate existence. our re-provisioning process places certs in the conventional locations (/etc/letsencrypt/{live,archive}
) but we've not yet figured out how to make certbot aware that it should renew these certs on expiry.
actually, writing the above has made me realise that it's quite likely that if we were to also populate /etc/letsencrypt/renewal
with a correctly structured .conf
file, the certbot service would include the re-provisioned cert in its renewal processes. i may have answered my own question.
testing creating the missing renewal .conf
theory now...
ok, that worked.
a possible answer:
here's what i did (i already had authentic, but soon to expire letsencrypt certs in the archive
folder and symlinks in the live
folder, i assume this is significant because it allows the certbot client to authenticate properly):
state at start:
$ sudo ls -ahl /etc/letsencrypt/{live,archive,renewal}
/etc/letsencrypt/archive:
total 12K
drwx------ 5 root root 4.0K Jan 20 11:07 .
drwxr-xr-x 9 root root 4.0K May 31 07:27 ..
drwxr-xr-x 2 root root 4.0K Mar 18 13:51 pectinata.manta.systems
/etc/letsencrypt/live:
total 16K
drwx------ 5 root root 4.0K Jan 20 11:07 .
drwxr-xr-x 9 root root 4.0K May 31 07:27 ..
-rw-r--r-- 1 root root 740 Nov 12 2021 README
drwxr-xr-x 2 root root 4.0K Mar 18 13:51 pectinata.manta.systems
/etc/letsencrypt/renewal:
total 8.0K
drwxr-xr-x 2 root root 4.0K May 30 13:39 .
drwxr-xr-x 9 root root 4.0K May 31 07:27 ..
$ sudo certbot certificates
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
No certs found.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
create the renewal .conf
:
cert_name=$(hostname -f)
client_version=$(certbot --version | cut -d ' ' -f2)
client_account=$(sudo ls /etc/letsencrypt/accounts/acme-v02.api.letsencrypt.org/directory)
sudo bash -c "cat << EOF > /etc/letsencrypt/renewal/${cert_name}.conf
# renew_before_expiry = 30 days
version = ${client_version}
archive_dir = /etc/letsencrypt/archive/${cert_name}
cert = /etc/letsencrypt/live/${cert_name}/cert.pem
privkey = /etc/letsencrypt/live/${cert_name}/privkey.pem
chain = /etc/letsencrypt/live/${cert_name}/chain.pem
fullchain = /etc/letsencrypt/live/${cert_name}/fullchain.pem
# Options used in the renewal process
[renewalparams]
account = ${client_account}
pref_challs = http-01,
authenticator = standalone
server = https://acme-v02.api.letsencrypt.org/directory
EOF"
check if certbot is now aware of the cert:
$ sudo certbot certificates
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Found the following certs:
Certificate Name: pectinata.manta.systems
Domains: pectinata.manta.systems para.metrics.pectinata.manta.systems relay.metrics.pectinata.manta.systems rpc.pectinata.manta.systems
Expiry Date: 2022-06-16 12:51:13+00:00 (VALID: 16 days)
Certificate Path: /etc/letsencrypt/live/pectinata.manta.systems/fullchain.pem
Private Key Path: /etc/letsencrypt/live/pectinata.manta.systems/privkey.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
attempt renewal:
$ sudo certbot renew
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/pectinata.manta.systems.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert is due for renewal, auto-renewing...
Plugins selected: Authenticator standalone, Installer None
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for para.metrics.pectinata.manta.systems
http-01 challenge for pectinata.manta.systems
http-01 challenge for relay.metrics.pectinata.manta.systems
http-01 challenge for rpc.pectinata.manta.systems
Waiting for verification...
Cleaning up challenges
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/pectinata.manta.systems/fullchain.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all renewals succeeded. The following certs have been renewed:
/etc/letsencrypt/live/pectinata.manta.systems/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
state at completion:
$ sudo certbot certificates
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Found the following certs:
Certificate Name: pectinata.manta.systems
Domains: pectinata.manta.systems para.metrics.pectinata.manta.systems relay.metrics.pectinata.manta.systems rpc.pectinata.manta.systems
Expiry Date: 2022-08-29 07:11:11+00:00 (VALID: 89 days)
Certificate Path: /etc/letsencrypt/live/pectinata.manta.systems/fullchain.pem
Private Key Path: /etc/letsencrypt/live/pectinata.manta.systems/privkey.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
great. our problem is solved, but back to my feature request. all the information required for this import was present on the system (as demonstrated above). wouldn't it be great if i could have run a certbot command to do all this? eg:
# when certs are in conventional location
sudo certbot import --cert-name $(hostname -f) [ --standalone, etc... ]
# when certs are elsewhere
sudo certbot import --path /tmp/$(hostname -f) [ --standalone, etc... ]