all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: Manuel Federanko <m.federanko@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [PATCH proxmox-backup] acme: partially fix #6372: scale certificate renewal checks by lifetime
Date: Tue, 21 Apr 2026 16:46:45 +0200	[thread overview]
Message-ID: <20260421144645.275884-1-m.federanko@proxmox.com> (raw)

Start renewing a certificate once 2/3 of its total lifetime have passed,
instead of the hardcoded 30 days. This stays consistent with many
certificates, which are valid for 90 days.

The update service runs daily, impose a 3 day minimum remaining lifetime
to still be able to handle transient failures for certificate renewals.

Signed-off-by: Manuel Federanko <m.federanko@proxmox.com>
Fixes: https://bugzilla.proxmox.com/show_bug.cgi?id=6372
---
 src/api2/node/certificates.rs          | 21 +++++++++++++++++++--
 src/bin/proxmox-daily-update.rs        |  3 ++-
 src/bin/proxmox_backup_manager/acme.rs |  3 ++-
 3 files changed, 23 insertions(+), 4 deletions(-)

diff --git a/src/api2/node/certificates.rs b/src/api2/node/certificates.rs
index a69f6511..6e7b3326 100644
--- a/src/api2/node/certificates.rs
+++ b/src/api2/node/certificates.rs
@@ -306,16 +306,33 @@ pub fn new_acme_cert(force: bool, rpcenv: &mut dyn RpcEnvironment) -> Result<Str
 /// parameter is set).
 pub fn renew_acme_cert(force: bool, rpcenv: &mut dyn RpcEnvironment) -> Result<String, Error> {
     if !cert_expires_soon()? && !force {
-        bail!("Certificate does not expire within the next 30 days and 'force' is not set.")
+        let lead = cert_renew_lead_time()? / (24 * 60 * 60);
+        bail!("Certificate does not expire within the next {lead} days and 'force' is not set.")
     }
 
     spawn_certificate_worker("acme-renew-cert", force, rpcenv)
 }
 
+/// When to start checking for new certs.
+pub fn cert_renew_lead_time() -> Result<i64, Error> {
+    let cert = pem_to_cert_info(get_certificate_pem()?.as_bytes())?;
+    if let (Some(notafter), Some(notbefore)) =
+        (cert.not_after_unix().ok(), cert.not_before_unix().ok())
+    {
+        // gets usually checked every day by the daily-update service,
+        // start checking at least 3 days before expiry
+        let lifetime = notafter - notbefore;
+        let lead = std::cmp::max(lifetime / 3, 3 * 24 * 60 * 60);
+        Ok(lead)
+    } else {
+        Ok(30 * 24 * 60 * 60)
+    }
+}
+
 /// Check whether the current certificate expires within the next 30 days.
 pub fn cert_expires_soon() -> Result<bool, Error> {
     let cert = pem_to_cert_info(get_certificate_pem()?.as_bytes())?;
-    cert.is_expired_after_epoch(proxmox_time::epoch_i64() + 30 * 24 * 60 * 60)
+    cert.is_expired_after_epoch(proxmox_time::epoch_i64() + cert_renew_lead_time()?)
         .map_err(|err| format_err!("Failed to check certificate expiration date: {}", err))
 }
 
diff --git a/src/bin/proxmox-daily-update.rs b/src/bin/proxmox-daily-update.rs
index c4d68e30..e5e96eb9 100644
--- a/src/bin/proxmox-daily-update.rs
+++ b/src/bin/proxmox-daily-update.rs
@@ -75,7 +75,8 @@ async fn check_acme_certificates(rpcenv: &mut dyn RpcEnvironment) -> Result<(),
     }
 
     if !api2::node::certificates::cert_expires_soon()? {
-        log::info!("Certificate does not expire within the next 30 days, not renewing.");
+        let lead = api2::node::certificates::cert_renew_lead_time()? / (24 * 60 * 60);
+        log::info!("Certificate does not expire within the next {lead} days, not renewing.");
         return Ok(());
     }
 
diff --git a/src/bin/proxmox_backup_manager/acme.rs b/src/bin/proxmox_backup_manager/acme.rs
index 57431225..d1a2323f 100644
--- a/src/bin/proxmox_backup_manager/acme.rs
+++ b/src/bin/proxmox_backup_manager/acme.rs
@@ -415,7 +415,8 @@ pub fn plugin_cli() -> CommandLineInterface {
 async fn order_acme_cert(param: Value, rpcenv: &mut dyn RpcEnvironment) -> Result<(), Error> {
     if !param["force"].as_bool().unwrap_or(false) && !api2::node::certificates::cert_expires_soon()?
     {
-        println!("Certificate does not expire within the next 30 days, not renewing.");
+        let lead = api2::node::certificates::cert_renew_lead_time()? / (24 * 60 * 60);
+        println!("Certificate does not expire within the next {lead} days, not renewing.");
         return Ok(());
     }
 
-- 
2.47.3




                 reply	other threads:[~2026-04-21 14:47 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260421144645.275884-1-m.federanko@proxmox.com \
    --to=m.federanko@proxmox.com \
    --cc=pbs-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal