Merge pull request #114752 from hercules-ci/lazy-offline-acme

acme: Determine offline whether renewal is due
This commit is contained in:
Robert Hensing 2021-03-22 16:04:33 +01:00 committed by GitHub
commit bef62e8c81
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -235,7 +235,7 @@ let
# https://github.com/NixOS/nixpkgs/pull/81371#issuecomment-605526099 # https://github.com/NixOS/nixpkgs/pull/81371#issuecomment-605526099
wantedBy = optionals (!config.boot.isContainer) [ "multi-user.target" ]; wantedBy = optionals (!config.boot.isContainer) [ "multi-user.target" ];
path = with pkgs; [ lego coreutils diffutils ]; path = with pkgs; [ lego coreutils diffutils openssl ];
serviceConfig = commonServiceConfig // { serviceConfig = commonServiceConfig // {
Group = data.group; Group = data.group;
@ -274,6 +274,34 @@ let
script = '' script = ''
set -euxo pipefail set -euxo pipefail
# This reimplements the expiration date check, but without querying
# the acme server first. By doing this offline, we avoid errors
# when the network or DNS are unavailable, which can happen during
# nixos-rebuild switch.
is_expiration_skippable() {
pem=$1
# This function relies on set -e to exit early if any of the
# conditions or programs fail.
[[ -e $pem ]]
expiration_line="$(
set -euxo pipefail
openssl x509 -noout -enddate <$pem \
| grep notAfter \
| sed -e 's/^notAfter=//'
)"
[[ -n "$expiration_line" ]]
expiration_date="$(date -d "$expiration_line" +%s)"
now="$(date +%s)"
expiration_s=$[expiration_date - now]
expiration_days=$[expiration_s / (3600 * 24)] # rounds down
[[ $expiration_days -gt ${toString cfg.validMinDays} ]]
}
${optionalString (data.webroot != null) '' ${optionalString (data.webroot != null) ''
# Ensure the webroot exists # Ensure the webroot exists
mkdir -p '${data.webroot}/.well-known/acme-challenge' mkdir -p '${data.webroot}/.well-known/acme-challenge'
@ -288,8 +316,14 @@ let
# When domains are updated, there's no need to do a full # When domains are updated, there's no need to do a full
# Lego run, but it's likely renew won't work if days is too low. # Lego run, but it's likely renew won't work if days is too low.
if [ -e certificates/domainhash.txt ] && cmp -s domainhash.txt certificates/domainhash.txt; then if [ -e certificates/domainhash.txt ] && cmp -s domainhash.txt certificates/domainhash.txt; then
lego ${renewOpts} --days ${toString cfg.validMinDays} if is_expiration_skippable out/full.pem; then
echo 1>&2 "nixos-acme: skipping renewal because expiration isn't within the coming ${toString cfg.validMinDays} days"
else else
echo 1>&2 "nixos-acme: renewing now, because certificate expires within the configured ${toString cfg.validMinDays} days"
lego ${renewOpts} --days ${toString cfg.validMinDays}
fi
else
echo 1>&2 "certificate domain(s) have changed; will renew now"
# Any number > 90 works, but this one is over 9000 ;-) # Any number > 90 works, but this one is over 9000 ;-)
lego ${renewOpts} --days 9001 lego ${renewOpts} --days 9001
fi fi