[pbs-devel] [RFC proxmox-backup 11/39] config: introduce s3 object store client configuration
Christian Ebner
c.ebner at proxmox.com
Mon May 19 13:46:12 CEST 2025
Adds the client configuration for s3 object store as dedicated
configuration files, with secrets being stored separately from the
regular configuration and excluded from api responses for security
reasons.
Signed-off-by: Christian Ebner <c.ebner at proxmox.com>
---
pbs-config/src/lib.rs | 1 +
pbs-config/src/s3.rs | 73 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 74 insertions(+)
create mode 100644 pbs-config/src/s3.rs
diff --git a/pbs-config/src/lib.rs b/pbs-config/src/lib.rs
index 9c4d77c24..d03c079ab 100644
--- a/pbs-config/src/lib.rs
+++ b/pbs-config/src/lib.rs
@@ -10,6 +10,7 @@ pub mod network;
pub mod notifications;
pub mod prune;
pub mod remote;
+pub mod s3;
pub mod sync;
pub mod tape_job;
pub mod token_shadow;
diff --git a/pbs-config/src/s3.rs b/pbs-config/src/s3.rs
new file mode 100644
index 000000000..5496b12bb
--- /dev/null
+++ b/pbs-config/src/s3.rs
@@ -0,0 +1,73 @@
+use std::sync::LazyLock;
+
+use anyhow::Error;
+
+use proxmox_schema::*;
+use proxmox_section_config::{SectionConfig, SectionConfigData, SectionConfigPlugin};
+
+use pbs_api_types::{S3ClientConfig, S3ClientSecretsConfig, JOB_ID_SCHEMA};
+
+use crate::{open_backup_lockfile, replace_backup_config, BackupLockGuard};
+
+pub static CONFIG: LazyLock<SectionConfig> = LazyLock::new(init);
+
+fn init() -> SectionConfig {
+ let obj_schema = match S3ClientConfig::API_SCHEMA {
+ Schema::Object(ref obj_schema) => obj_schema,
+ _ => unreachable!(),
+ };
+ let secrets_obj_schema = match S3ClientSecretsConfig::API_SCHEMA {
+ Schema::Object(ref obj_schema) => obj_schema,
+ _ => unreachable!(),
+ };
+
+ let plugin =
+ SectionConfigPlugin::new("s3client".to_string(), Some(String::from("id")), obj_schema);
+ let secrets_plugin = SectionConfigPlugin::new(
+ "s3secrets".to_string(),
+ Some(String::from("secrets-id")),
+ secrets_obj_schema,
+ );
+ let mut config = SectionConfig::new(&JOB_ID_SCHEMA);
+ config.register_plugin(plugin);
+ config.register_plugin(secrets_plugin);
+
+ config
+}
+
+pub const S3_CFG_FILENAME: &str = "/etc/proxmox-backup/s3.cfg";
+pub const S3_SECRETS_CFG_FILENAME: &str = "/etc/proxmox-backup/s3-secrets.cfg";
+pub const S3_CFG_LOCKFILE: &str = "/etc/proxmox-backup/.s3.lck";
+
+/// Get exclusive lock
+pub fn lock_config() -> Result<BackupLockGuard, Error> {
+ open_backup_lockfile(S3_CFG_LOCKFILE, None, true)
+}
+
+pub fn config() -> Result<(SectionConfigData, [u8; 32]), Error> {
+ parse_config(S3_CFG_FILENAME)
+}
+
+pub fn secrets_config() -> Result<(SectionConfigData, [u8; 32]), Error> {
+ parse_config(S3_SECRETS_CFG_FILENAME)
+}
+
+pub fn save_config(config: &SectionConfigData, secrets: &SectionConfigData) -> Result<(), Error> {
+ let raw = CONFIG.write(S3_CFG_FILENAME, config)?;
+ replace_backup_config(S3_CFG_FILENAME, raw.as_bytes())?;
+
+ let secrets_raw = CONFIG.write(S3_SECRETS_CFG_FILENAME, secrets)?;
+ // Secrets are stored with `backup` permissions to allow reading from
+ // not protected api endpoints as well.
+ replace_backup_config(S3_SECRETS_CFG_FILENAME, secrets_raw.as_bytes())?;
+
+ Ok(())
+}
+
+fn parse_config(path: &str) -> Result<(SectionConfigData, [u8; 32]), Error> {
+ let content = proxmox_sys::fs::file_read_optional_string(path)?;
+ let content = content.unwrap_or_default();
+ let digest = openssl::sha::sha256(content.as_bytes());
+ let data = CONFIG.parse(path, &content)?;
+ Ok((data, digest))
+}
--
2.39.5
More information about the pbs-devel
mailing list