all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: "Fabian Grünbichler" <f.gruenbichler@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [PATCH proxmox-backup 3/6] push: add support for strict encryption checking
Date: Wed, 29 Apr 2026 16:09:24 +0200	[thread overview]
Message-ID: <20260429140941.3537494-4-f.gruenbichler@proxmox.com> (raw)
In-Reply-To: <20260429140941.3537494-1-f.gruenbichler@proxmox.com>

if enabled, this mode will refuse to sync already encrypted snapshots, unless
they are encrypted using the active encryption key and carry a valid signature.

since pushing now checks the manifest more closely, also log whether synced
pre-encrypted snapshots use a matching key or not if the mode is disabled.

Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
 src/api2/push.rs   |  1 +
 src/server/push.rs | 41 ++++++++++++++++++++++++++++++++++++-----
 src/server/sync.rs |  1 +
 3 files changed, 38 insertions(+), 5 deletions(-)

diff --git a/src/api2/push.rs b/src/api2/push.rs
index 44629de06..54dc1e4ee 100644
--- a/src/api2/push.rs
+++ b/src/api2/push.rs
@@ -176,6 +176,7 @@ async fn push(
         transfer_last,
         worker_threads,
         encryption_key,
+        None,
     )
     .await?;
 
diff --git a/src/server/push.rs b/src/server/push.rs
index dac62c84a..c85654ed1 100644
--- a/src/server/push.rs
+++ b/src/server/push.rs
@@ -97,6 +97,8 @@ pub(crate) struct PushParameters {
     /// Encryption key to use for pushing unencrypted backup snapshots. Does not affect
     /// already encrypted snapshots.
     crypt_config: Option<(String, Arc<CryptConfig>)>,
+    /// Refuse to sync already encrypted snapshots
+    strict_encryption_mode: bool,
 }
 
 impl PushParameters {
@@ -118,6 +120,7 @@ impl PushParameters {
         transfer_last: Option<usize>,
         worker_threads: Option<usize>,
         active_encryption_key: Option<String>,
+        strict_encryption_mode: Option<bool>,
     ) -> Result<Self, Error> {
         if let Some(max_depth) = max_depth {
             ns.check_max_depth(max_depth)?;
@@ -126,6 +129,7 @@ impl PushParameters {
         let remove_vanished = remove_vanished.unwrap_or(false);
         let encrypted_only = encrypted_only.unwrap_or(false);
         let verified_only = verified_only.unwrap_or(false);
+        let strict_encryption_mode = strict_encryption_mode.unwrap_or(false);
         let lookup = crate::tools::lookup_with(store, Operation::Read);
         let store = DataStore::lookup_datastore(lookup)?;
 
@@ -191,6 +195,7 @@ impl PushParameters {
             transfer_last,
             worker_threads,
             crypt_config,
+            strict_encryption_mode,
         })
     }
 
@@ -1075,7 +1080,7 @@ pub(crate) async fn push_snapshot(
     }
 
     let mut encrypt_using_key = None;
-    if params.crypt_config.is_some() {
+    if let Some((id, key)) = params.crypt_config.as_ref() {
         // Check if snapshot is fully encrypted or not encrypted at all:
         // refuse progress otherwise to upload partially unencrypted contents or mix encryption key.
         let files = source_manifest.files();
@@ -1103,10 +1108,36 @@ pub(crate) async fn push_snapshot(
             ).await?;
             return Ok(stats);
         } else {
-            log_sender.log(
-                Level::INFO,
-                format!("Snapshot '{snapshot}' already encrypted with client key, not re-encrypting with configured active encryption key"),
-            ).await?;
+            let correct_key = source_manifest
+                .fingerprint()
+                .ok()
+                .flatten()
+                .map(|fp| *fp.bytes())
+                == Some(key.fingerprint());
+            if correct_key && source_manifest.check_signature(&key).is_err() {
+                log_sender.log(
+                    Level::WARN,
+                    format!("Snapshot '{snapshot}' already encrypted with matching key {id}, but signature check failed"),
+                ).await?;
+                return Ok(stats);
+            }
+            if correct_key {
+                log_sender.log(
+                    Level::INFO,
+                    format!("Snapshot '{snapshot}' already encrypted with matching key {id}, syncing as-is"),
+                ).await?;
+            } else if params.strict_encryption_mode {
+                log_sender.log(
+                    Level::INFO,
+                    format!("Snapshot '{snapshot}' already encrypted with different key, strict encryption mode enabled, skip"),
+                ).await?;
+                return Ok(stats);
+            } else {
+                log_sender.log(
+                    Level::INFO,
+                    format!("Snapshot '{snapshot}' already encrypted with different key, not re-encrypting with configured active encryption key"),
+                ).await?;
+            }
         }
     }
 
diff --git a/src/server/sync.rs b/src/server/sync.rs
index f7d96811e..590ad01eb 100644
--- a/src/server/sync.rs
+++ b/src/server/sync.rs
@@ -733,6 +733,7 @@ pub fn do_sync_job(
                             sync_job.transfer_last,
                             sync_job.worker_threads,
                             sync_job.active_encryption_key,
+                            None,
                         )
                         .await?;
                         push_store(push_params).await?
-- 
2.47.3





  parent reply	other threads:[~2026-04-29 14:09 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-29 14:09 [PATCH proxmox{,-backup} 0/6] sync: add strict encryption mode Fabian Grünbichler
2026-04-29 14:09 ` [PATCH proxmox 1/6] pbs-api-types: sync job: add strict-encryption-mode Fabian Grünbichler
2026-04-29 14:09 ` [PATCH proxmox-backup 2/6] pull: add support for strict decryption checking Fabian Grünbichler
2026-04-29 14:09 ` Fabian Grünbichler [this message]
2026-04-29 14:09 ` [PATCH proxmox-backup 4/6] sync: wire up strict encryption mode Fabian Grünbichler
2026-04-29 14:09 ` [PATCH proxmox-backup 5/6] ui: add strict-encryption-mode to SyncJobEdit window Fabian Grünbichler
2026-04-29 14:09 ` [PATCH proxmox-backup 6/6] docs: sync: add strict encryption mode Fabian Grünbichler

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=20260429140941.3537494-4-f.gruenbichler@proxmox.com \
    --to=f.gruenbichler@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