github fabriziosalmi/certmate v2.40.0
v2.40.0 (what the settings say, and the certificate that lost its key)

latest release: v2.41.0
4 hours ago

v2.40.0 (what the settings say, and the certificate that lost its key)

Two kinds of change. First, settings and actions that did less than they said:
a renewal threshold above 30 days, a reissue that dropped its configuration or
its CA account, events announced twice, a restore into another directory, a
batch that used the wrong DNS account. Second, a state that had no name: a
certificate with no private key anywhere, which is what restoring a share-safe
backup leaves. It now has a name, a code, a place on the dashboard and one
action that repairs all of them.

The API contract moves to 2.29, from 2.23. Read it from
X-CertMate-API-Version on any response, or api_contract_version in
/api/health. Six MINOR steps, each written down beside the constant in
modules/core/constants.py; nothing was removed or retyped.

step what grew
2.24 auth_mode and assume_role_arn on the S3-compatible and AWS Secrets Manager storage backends (#971)
2.25 reissue_required and next_step on a successful restore (#982)
2.26 a new renewal error code, REISSUE_REQUIRED (#981)
2.27 a new endpoint, POST /api/certificates/reissue-keyless (#985)
2.28 reissue_required on every certificate record (#988)
2.29 challenge_type accepts prevalidated (#983)

Read this before upgrading

A renewal threshold above 30 days now renews when it says

certbot has a renewal gate of its own: without being forced, it renews only
inside 30 days of expiry. CertMate asked it unforced, so a
renewal_threshold_days of 45 behaved as 30, and the sweep booked the gap as
skipped_not_due every night. Measured with the real binary: 60, 45 and 31
days left all came back "not yet due".

When the threshold, and only the threshold, calls a certificate due while
certbot would refuse, the renewal is now forced (#991), as the CA's renewal
window already was in v2.39.0. If your threshold is above 30, expect
renewals to start earlier after the upgrade
, spread by two guards:

  • at most early_renewals_per_sweep forced renewals per nightly sweep
    (default 10, between 1 and 50); the rest wait for the next night and are
    counted as early_deferred;
  • a certificate issued less than 7 days ago is never forced, so a threshold at
    or above the certificate's lifetime costs at most one renewal a week.

A threshold of 30 or less changes nothing. A certificate that needs attention
for another reason, a served key that is missing or does not match, is not
forced: it is repaired from its lineage without a new key.

Since v2.36.0, actions from the dashboard announced everything twice

An issuance or renewal started from the dashboard published its event twice,
so deploy hooks, webhooks and notifications ran twice for one certificate
(#975). One issuance is now one event.

Edit & Reissue kept less than it should

  • It rewrote the certificate's metadata from the request alone, so a reissue
    in a default install dropped the deployment configuration (#976). Create,
    reissue and renew now share one commit step that keeps what the certificate
    already had.
  • It used the CA's default account instead of the one the certificate was
    issued under (#983). A certificate issued under a second account of the same
    CA, a second ZeroSSL or Sectigo EAB account, came back issued under the
    first. The recorded account is now kept while the CA does not change.

Other things that did less than they said

  • A backup restored into another directory failed every renewal: certbot's
    renewal/<domain>.conf carries absolute paths, which now follow the lineage
    (#973).
  • Batch create bypassed the service: no audit record, no event, and the
    issuance used the default DNS account instead of the one named (#984).
  • Issuance with a DNS alias on another provider waited for the primary
    provider's propagation, not the alias zone's, as renewal already did (#977).
  • The copy in an external storage backend carried a storage warning about
    itself after a successful store (#979).
  • A healthy container logged two ERROR lines at every start (#972).

A certificate with no private key anywhere

Restoring a share-safe backup brings certificates back without their private
keys, by design. Before this release that was discovered at the first nightly
sweep, as a generic certbot parse failure, and repaired one certificate at a
time.

where what it says now
the restore lists them at once, as reissue_required, with the next step (#982)
the renewal REISSUE_REQUIRED (422), not a failure of certbot, and the notification says what to do (#981)
the dashboard a banner naming them, with Reissue all for operators (#988); each row reads Needs reissue with a key instead of a padlock, and it leaves the Valid count, chip and filter (#992)
the API reissue_required on every certificate, and POST /api/certificates/reissue-keyless (#985)

Reissue all is paced. It queues at most limit reissues per call
(default 10, at most 50), two at a time, and answers what was queued, what
remains and what was refused, so a restore of forty certificates is not forty
orders against the CA in one minute.

Unattended instances can opt in. With "auto_reissue_keyless": true in
settings.json, off by default, the nightly sweep reissues at most
auto_reissue_keyless_per_sweep of them itself (default 5). It is off by
default because a reissue changes the key, and deploy hooks ship it.


New

  • Sectigo prevalidated authorizations (#983, contributed by QuentinBtd).
    challenge_type: prevalidated issues from a Sectigo SCM account whose names
    are already authorized, with no DNS or HTTP challenge. A name the account
    has not authorized fails cleanly without touching DNS. See
    CA providers.
  • AWS IAM roles for certificate storage (#971, contributed by
    QuentinBtd). The S3-compatible and AWS Secrets Manager backends can use the
    AWS credential chain and STS AssumeRole instead of static keys.
  • Extra volumes in the Helm chart (#994, contributed by QuentinBtd).
    extraVolumes and extraVolumeMounts mount existing ConfigMaps, Secrets or
    claims; the chart README shows how to mount deploy-hook scripts executable.

Clearer when something fails

  • A certbot killed mid-order (the out-of-memory killer in a small
    container) says so: "certbot was killed by SIGKILL before it reported an
    error", with the last thing it printed. It used to say only "Saving debug
    log to …", on create and on renew alike (#987).
  • Renewals run from the API or the dashboard reach Prometheus:
    certmate_certificate_renewals_total, the duration histogram and the
    rate-limit counter were fed by the nightly sweep only (#990).

Dependencies


How it was checked

Every behaviour change above was reproduced before it was fixed, and verified
after, against Let's Encrypt staging with the real certbot and Cloudflare
DNS-01:

  • the keyless path: two certificates, a share-safe backup, a wipe, a
    restore that listed both, reissue-keyless with limit: 1 reissuing one
    (new serial, key matches) and the sweep with auto_reissue_keyless
    reissuing the other;
  • the threshold: at 100 days, main answered "not yet due" for both
    certificates; this release deferred both while they were fresh, then with
    the age guard satisfied renewed one and deferred one under a cap of 1;
  • Sectigo prevalidated, through Let's Encrypt's own authorization reuse,
    which puts certbot in the same state: a validated name issued with no
    challenge, a new one failed without touching DNS;
  • the killed certbot: a real order killed with SIGKILL, and the message
    built from what it actually left behind;
  • the manual renewal metric: a forced renewal through the API, then
    /metrics.

The dashboard changes were checked in a browser, as admin and as viewer.

Don't miss a new certmate release

NewReleases is sending notifications on new releases.