From: "Fabian Grünbichler" <f.gruenbichler@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [PATCH proxmox-backup 4/6] sync: wire up strict encryption mode
Date: Wed, 29 Apr 2026 16:09:25 +0200 [thread overview]
Message-ID: <20260429140941.3537494-5-f.gruenbichler@proxmox.com> (raw)
In-Reply-To: <20260429140941.3537494-1-f.gruenbichler@proxmox.com>
enabling it requires configured encryption/decryption keys, disabling or
unsetting it does not.
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
src/api2/config/sync.rs | 30 +++++++++++++++++++++++++++++-
src/api2/pull.rs | 13 +++++++++----
src/api2/push.rs | 10 ++++++++--
src/server/sync.rs | 2 +-
4 files changed, 47 insertions(+), 8 deletions(-)
diff --git a/src/api2/config/sync.rs b/src/api2/config/sync.rs
index eb82745d9..ac1e6350e 100644
--- a/src/api2/config/sync.rs
+++ b/src/api2/config/sync.rs
@@ -276,9 +276,16 @@ pub fn create_sync_job(
.unwrap_or_else(|| Authid::root_auth_id());
if sync_direction == SyncDirection::Push {
+ if (config.strict_encryption_mode == Some(true)) != config.active_encryption_key.is_some() {
+ bail!("'strict-encryption-mode' requires encryption key");
+ }
sync_user_can_access_optional_key(config.active_encryption_key.as_deref(), owner, true)?;
} else {
- for key in config.associated_key.as_deref().unwrap_or(&[]) {
+ let keys = config.associated_key.as_deref().unwrap_or(&[]);
+ if (config.strict_encryption_mode == Some(true)) == keys.is_empty() {
+ bail!("'strict-encryption-mode' requires encryption key(s)");
+ }
+ for key in keys {
sync_user_can_access_optional_key(Some(key), owner, false)?;
}
}
@@ -398,6 +405,8 @@ pub enum DeletableProperty {
ActiveEncryptionKey,
/// Delete associated key property,
AssociatedKey,
+ /// Delete strict encryption_mode property,
+ StrictEncryptionMode,
}
#[api(
@@ -538,6 +547,9 @@ pub fn update_sync_job(
// Previous active encryption key might be added as associated below.
data.associated_key = None;
}
+ DeletableProperty::StrictEncryptionMode => {
+ data.strict_encryption_mode = None;
+ }
}
}
keep_previous_key_as_associated(
@@ -654,6 +666,21 @@ pub fn update_sync_job(
data.associated_key = Some(associated_key);
}
+ if let Some(strict_encryption_mode) = update.strict_encryption_mode {
+ data.strict_encryption_mode = Some(strict_encryption_mode);
+ }
+
+ if data.sync_direction == Some(SyncDirection::Push) {
+ if (data.strict_encryption_mode == Some(true)) != data.active_encryption_key.is_some() {
+ bail!("'strict-encryption-mode' requires encryption key");
+ }
+ } else {
+ let keys = data.associated_key.as_deref().unwrap_or(&[]);
+ if (data.strict_encryption_mode == Some(true)) == keys.is_empty() {
+ bail!("'strict-encryption-mode' requires encryption key(s)");
+ }
+ }
+
if update.limit.rate_in.is_some() {
data.limit.rate_in = update.limit.rate_in;
}
@@ -829,6 +856,7 @@ acl:1:/remote/remote1/remotestore1:write@pbs:RemoteSyncOperator
worker_threads: None,
active_encryption_key: None,
associated_key: None,
+ strict_encryption_mode: None,
};
// should work without ACLs
diff --git a/src/api2/pull.rs b/src/api2/pull.rs
index b80bc9a7d..2d91fbc44 100644
--- a/src/api2/pull.rs
+++ b/src/api2/pull.rs
@@ -10,8 +10,8 @@ use pbs_api_types::{
Authid, BackupNamespace, GroupFilter, RateLimitConfig, SyncJobConfig, CRYPT_KEY_ID_SCHEMA,
DATASTORE_SCHEMA, GROUP_FILTER_LIST_SCHEMA, NS_MAX_DEPTH_REDUCED_SCHEMA, PRIV_DATASTORE_BACKUP,
PRIV_DATASTORE_PRUNE, PRIV_REMOTE_READ, REMOTE_ID_SCHEMA, REMOVE_VANISHED_BACKUPS_SCHEMA,
- RESYNC_CORRUPT_SCHEMA, SYNC_ENCRYPTED_ONLY_SCHEMA, SYNC_VERIFIED_ONLY_SCHEMA,
- SYNC_WORKER_THREADS_SCHEMA, TRANSFER_LAST_SCHEMA,
+ RESYNC_CORRUPT_SCHEMA, SYNC_ENCRYPTED_ONLY_SCHEMA, SYNC_STRICT_ENCRYPTION_MODE_SCHEMA,
+ SYNC_VERIFIED_ONLY_SCHEMA, SYNC_WORKER_THREADS_SCHEMA, TRANSFER_LAST_SCHEMA,
};
use pbs_config::CachedUserInfo;
use proxmox_rest_server::WorkerTask;
@@ -93,7 +93,7 @@ impl TryFrom<&SyncJobConfig> for PullParameters {
sync_job.resync_corrupt,
sync_job.worker_threads,
sync_job.associated_key.clone(),
- None,
+ sync_job.strict_encryption_mode,
)
}
}
@@ -163,6 +163,10 @@ impl TryFrom<&SyncJobConfig> for PullParameters {
},
optional: true,
},
+ "strict-decryption-mode": {
+ schema: SYNC_STRICT_ENCRYPTION_MODE_SCHEMA,
+ optional: true,
+ }
},
},
access: {
@@ -192,6 +196,7 @@ async fn pull(
resync_corrupt: Option<bool>,
worker_threads: Option<usize>,
decryption_keys: Option<Vec<String>>,
+ strict_decryption_mode: Option<bool>,
rpcenv: &mut dyn RpcEnvironment,
) -> Result<String, Error> {
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
@@ -234,7 +239,7 @@ async fn pull(
resync_corrupt,
worker_threads,
decryption_keys,
- None,
+ strict_decryption_mode,
)?;
// fixme: set to_stdout to false?
diff --git a/src/api2/push.rs b/src/api2/push.rs
index 54dc1e4ee..2ec467161 100644
--- a/src/api2/push.rs
+++ b/src/api2/push.rs
@@ -6,7 +6,8 @@ use pbs_api_types::{
GROUP_FILTER_LIST_SCHEMA, NS_MAX_DEPTH_REDUCED_SCHEMA, PRIV_DATASTORE_BACKUP,
PRIV_DATASTORE_READ, PRIV_REMOTE_DATASTORE_BACKUP, PRIV_REMOTE_DATASTORE_PRUNE,
REMOTE_ID_SCHEMA, REMOVE_VANISHED_BACKUPS_SCHEMA, SYNC_ENCRYPTED_ONLY_SCHEMA,
- SYNC_VERIFIED_ONLY_SCHEMA, SYNC_WORKER_THREADS_SCHEMA, TRANSFER_LAST_SCHEMA,
+ SYNC_STRICT_ENCRYPTION_MODE_SCHEMA, SYNC_VERIFIED_ONLY_SCHEMA, SYNC_WORKER_THREADS_SCHEMA,
+ TRANSFER_LAST_SCHEMA,
};
use proxmox_rest_server::WorkerTask;
use proxmox_router::{Permission, Router, RpcEnvironment};
@@ -116,6 +117,10 @@ fn check_push_privs(
schema: CRYPT_KEY_ID_SCHEMA,
optional: true,
},
+ "strict-encryption-mode": {
+ schema: SYNC_STRICT_ENCRYPTION_MODE_SCHEMA,
+ optional: true,
+ }
},
},
access: {
@@ -143,6 +148,7 @@ async fn push(
transfer_last: Option<usize>,
worker_threads: Option<usize>,
encryption_key: Option<String>,
+ strict_encryption_mode: Option<bool>,
rpcenv: &mut dyn RpcEnvironment,
) -> Result<String, Error> {
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
@@ -176,7 +182,7 @@ async fn push(
transfer_last,
worker_threads,
encryption_key,
- None,
+ strict_encryption_mode,
)
.await?;
diff --git a/src/server/sync.rs b/src/server/sync.rs
index 590ad01eb..c78213c7f 100644
--- a/src/server/sync.rs
+++ b/src/server/sync.rs
@@ -733,7 +733,7 @@ pub fn do_sync_job(
sync_job.transfer_last,
sync_job.worker_threads,
sync_job.active_encryption_key,
- None,
+ sync_job.strict_encryption_mode,
)
.await?;
push_store(push_params).await?
--
2.47.3
next prev 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 ` [PATCH proxmox-backup 3/6] push: add support for strict encryption checking Fabian Grünbichler
2026-04-29 14:09 ` Fabian Grünbichler [this message]
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-5-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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox