[PATCH proxmox-backup 07/20] api: config: add endpoints for encryption key manipulation

Christian Ebner
2026-04-01T07:55:41Z

Defines the api endpoints for listing existing keys as defined in the
config and create new keys.

Signed-off-by: Christian Ebner <c.ebner@proxmox.com>
---
src/api2/config/encryption_keys.rs | 115 +++++++++++++++++++++++++++++
src/api2/config/mod.rs | 2 +
2 files changed, 117 insertions(+)
create mode 100644 src/api2/config/encryption_keys.rs

diff --git a/src/api2/config/encryption_keys.rs b/src/api2/config/encryption_keys.rs
new file mode 100644
index 000000000..bc3ee2908
--- /dev/null
+++ b/src/api2/config/encryption_keys.rs
@@ -0,0 +1,115 @@
+use anyhow::{format_err, Error};
+use serde_json::Value;
+
+use proxmox_router::{Permission, Router, RpcEnvironment};
+use proxmox_schema::api;
+
+use pbs_api_types::{
+ Authid, EncryptionKey, ENCRYPTION_KEY_ID_SCHEMA, PRIV_SYS_AUDIT, PRIV_SYS_MODIFY,
+};
+
+use pbs_config::encryption_keys::{self, ENCRYPTION_KEYS_CFG_TYPE_ID};
+use pbs_config::CachedUserInfo;
+
+use pbs_key_config::KeyConfig;
+
+#[api(
+ input: {
+ properties: {},
+ },
+ returns: {
+ description: "List of configured encryption keys.",
+ type: Array,
+ items: { type: EncryptionKey },
+ },
+ access: {
+ permission: &Permission::Anybody,
+ description: "List configured encryption keys filtered by Sys.Audit privileges",
+ },
+)]
+/// List configured encryption keys.
+pub fn list_keys(
+ _param: Value,
+ rpcenv: &mut dyn RpcEnvironment,
+) -> Result<Vec<EncryptionKey>, Error> {
+ let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
+ let user_info = CachedUserInfo::new()?;
+
+ let (config, digest) = encryption_keys::config()?;
+
+ let list: Vec<EncryptionKey> = config.convert_to_typed_array(ENCRYPTION_KEYS_CFG_TYPE_ID)?;
+ let list = list
+ .into_iter()
+ .filter(|key| {
+ let privs = user_info.lookup_privs(&auth_id, &["system", "encryption-keys", &key.id]);
+ privs & PRIV_SYS_AUDIT != 0
+ })
+ .collect();
+
+ rpcenv["digest"] = hex::encode(digest).into();
+
+ Ok(list)
+}
+
+#[api(
+ protected: true,
+ input: {
+ properties: {
+ id: {
+ schema: ENCRYPTION_KEY_ID_SCHEMA,
+ },
+ key: {
+ description: "Use provided key instead of creating new one.",
+ type: String,
+ optional: true,
+ },
+ },
+ },
+ access: {
+ permission: &Permission::Privilege(&["system", "encryption-keys"], PRIV_SYS_MODIFY, false),
+ },
+)]
+/// Create new encryption key instance or use the provided one.
+pub fn create_key(
+ id: String,
+ key: Option<String>,
+ _rpcenv: &mut dyn RpcEnvironment,
+) -> Result<KeyConfig, Error> {
+ let key_config = if let Some(key) = &key {
+ serde_json::from_str(key)
+ .map_err(|err| format_err!("failed to parse provided key: {err}"))?
+ } else {
+ let mut raw_key = [0u8; 32];
+ proxmox_sys::linux::fill_with_random_data(&mut raw_key)?;
+ KeyConfig::without_password(raw_key)?
+ };
+
+ encryption_keys::store_key(&id, &key_config)?;
+
+ Ok(key_config)
+}
+
+#[api(
+ protected: true,
+ input: {
+ properties: {
+ id: {
+ schema: ENCRYPTION_KEY_ID_SCHEMA,
+ },
+ },
+ },
+ access: {
+ permission: &Permission::Privilege(&["system", "encryption-keys", "{id}"], PRIV_SYS_MODIFY, false),
+ },
+)]
+/// Remove encryption key (makes the key unusable, but keeps a backup).
+pub fn delete_key(id: String, _rpcenv: &mut dyn RpcEnvironment) -> Result<(), Error> {
+ encryption_keys::delete_key(&id).map_err(|err| format_err!("failed to delete key: {err}"))
+}
+
+const ITEM_ROUTER: Router = Router::new().delete(&API_METHOD_DELETE_KEY);
+
+pub const ROUTER: Router = Router::new()
+ .get(&API_METHOD_LIST_KEYS)
+ .post(&API_METHOD_CREATE_KEY)
+ .match_all("id", &ITEM_ROUTER);
diff --git a/src/api2/config/mod.rs b/src/api2/config/mod.rs
index 1cd9ead76..0281bcfae 100644
--- a/src/api2/config/mod.rs
+++ b/src/api2/config/mod.rs
@@ -9,6 +9,7 @@ pub mod acme;
pub mod changer;
pub mod datastore;
pub mod drive;
+pub mod encryption_keys;
pub mod media_pool;
pub mod metrics;
pub mod notifications;
@@ -28,6 +29,7 @@ const SUBDIRS: SubdirMap = &sorted!([
("changer", &changer::ROUTER),
("datastore", &datastore::ROUTER),
("drive", &drive::ROUTER),
+ ("encryption-keys", &encryption_keys::ROUTER),
("media-pool", &media_pool::ROUTER),
("metrics", &metrics::ROUTER),
("notifications", &notifications::ROUTER),
--
2.47.3