move tape_encryption_keys.rs to pbs_config workspace

This commit is contained in:
Dietmar Maurer
2021-09-07 10:37:08 +02:00
parent bbdda58b35
commit 5839c469c1
9 changed files with 36 additions and 59 deletions

View File

@ -11,9 +11,22 @@ use proxmox::{
},
};
use pbs_api_types::{Fingerprint, KeyInfo, Kdf};
use pbs_api_types::{
Fingerprint, KeyInfo, Kdf,
TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
PROXMOX_CONFIG_DIGEST_SCHEMA, PASSWORD_HINT_SCHEMA,
};
use pbs_config::key_config::KeyConfig;
use pbs_config::open_backup_lockfile;
use pbs_config::tape_encryption_keys::{
TAPE_KEYS_LOCKFILE,
load_keys,
load_key_configs,
save_keys,
save_key_configs,
insert_key,
};
use crate::{
config::{
@ -21,19 +34,6 @@ use crate::{
PRIV_TAPE_AUDIT,
PRIV_TAPE_MODIFY,
},
tape_encryption_keys::{
TAPE_KEYS_LOCKFILE,
load_keys,
load_key_configs,
save_keys,
save_key_configs,
insert_key,
},
},
api2::types::{
TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
PROXMOX_CONFIG_DIGEST_SCHEMA,
PASSWORD_HINT_SCHEMA,
},
};

View File

@ -26,7 +26,6 @@ use pbs_datastore::task_log;
use crate::{
config::{
self,
cached_user_info::CachedUserInfo,
acl::{
PRIV_TAPE_AUDIT,
@ -658,7 +657,7 @@ pub async fn restore_key(
if let Some(key_config) = key_config {
let password_fn = || { Ok(password.as_bytes().to_vec()) };
let (key, ..) = key_config.decrypt(&password_fn)?;
config::tape_encryption_keys::insert_key(key, key_config, true)?;
pbs_config::tape_encryption_keys::insert_key(key, key_config, true)?;
} else {
bail!("media does not contain any encryption key configuration");
}

View File

@ -11,24 +11,16 @@ use proxmox::{
sys::linux::tty,
};
use pbs_api_types::{Fingerprint, Kdf};
use pbs_datastore::paperkey::{PaperkeyFormat, generate_paper_key};
use proxmox_backup::{
api2::{
self,
types::{
DRIVE_NAME_SCHEMA,
TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
PASSWORD_HINT_SCHEMA,
},
},
config::tape_encryption_keys::{
load_key_configs,
complete_key_fingerprint,
},
use pbs_api_types::{
Fingerprint, Kdf, DRIVE_NAME_SCHEMA, TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
PASSWORD_HINT_SCHEMA,
};
use pbs_datastore::paperkey::{PaperkeyFormat, generate_paper_key};
use pbs_config::tape_encryption_keys::{load_key_configs,complete_key_fingerprint};
use proxmox_backup::api2;
pub fn encryption_key_commands() -> CommandLineInterface {
let cmd_def = CliCommandMap::new()

View File

@ -10,21 +10,11 @@ use proxmox::{
},
};
use pbs_api_types::MEDIA_POOL_NAME_SCHEMA;
use pbs_config::media_pool::complete_pool_name;
use pbs_config::tape_encryption_keys::complete_key_fingerprint;
use proxmox_backup::{
api2::{
self,
types::{
MEDIA_POOL_NAME_SCHEMA,
},
},
config::{
tape_encryption_keys:: {
complete_key_fingerprint,
},
},
};
use proxmox_backup::api2;
pub fn pool_commands() -> CommandLineInterface {

View File

@ -25,7 +25,6 @@ pub mod tfa;
pub mod token_shadow;
pub mod user;
pub mod verify;
pub mod tape_encryption_keys;
pub mod tape_job;
/// Check configuration directory permissions

View File

@ -1,193 +0,0 @@
//! Store Tape encryptions keys
//!
//! This module can store 256bit encryption keys for tape backups,
//! indexed by key fingerprint.
//!
//! We store the plain key (unencrypted), as well as a encrypted
//! version protected by password (see struct `KeyConfig`)
//!
//! Tape backups store the password protected version on tape, so that
//! it is possible to restore the key from tape if you know the
//! password.
use std::collections::HashMap;
use anyhow::{bail, Error};
use serde::{Deserialize, Serialize};
use proxmox::tools::fs::file_read_optional_string;
use pbs_api_types::Fingerprint;
use pbs_config::key_config::KeyConfig;
use pbs_config::{open_backup_lockfile, replace_secret_config};
mod hex_key {
use serde::{self, Deserialize, Serializer, Deserializer};
pub fn serialize<S>(
csum: &[u8; 32],
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let s = proxmox::tools::digest_to_hex(csum);
serializer.serialize_str(&s)
}
pub fn deserialize<'de, D>(
deserializer: D,
) -> Result<[u8; 32], D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
proxmox::tools::hex_to_digest(&s).map_err(serde::de::Error::custom)
}
}
/// Store Hardware Encryption keys (plain, unprotected keys)
#[derive(Deserialize, Serialize)]
pub struct EncryptionKeyInfo {
/// Key fingerprint (we verify the fingerprint on load)
pub fingerprint: Fingerprint,
/// The plain encryption key
#[serde(with = "hex_key")]
pub key: [u8; 32],
}
impl EncryptionKeyInfo {
pub fn new(key: [u8; 32], fingerprint: Fingerprint) -> Self {
Self { fingerprint, key }
}
}
pub const TAPE_KEYS_FILENAME: &str = "/etc/proxmox-backup/tape-encryption-keys.json";
pub const TAPE_KEY_CONFIG_FILENAME: &str = "/etc/proxmox-backup/tape-encryption-key-config.json";
pub const TAPE_KEYS_LOCKFILE: &str = "/etc/proxmox-backup/.tape-encryption-keys.lck";
/// Load tape encryption keys (plain, unprotected keys)
pub fn load_keys() -> Result<(HashMap<Fingerprint, EncryptionKeyInfo>, [u8;32]), Error> {
let content = file_read_optional_string(TAPE_KEYS_FILENAME)?;
let content = content.unwrap_or_else(|| String::from("[]"));
let digest = openssl::sha::sha256(content.as_bytes());
let key_list: Vec<EncryptionKeyInfo> = serde_json::from_str(&content)?;
let mut map = HashMap::new();
for item in key_list {
let key_config = KeyConfig::without_password(item.key)?; // to compute fingerprint
let expected_fingerprint = key_config.fingerprint.unwrap();
if item.fingerprint != expected_fingerprint {
bail!(
"inconsistent fingerprint ({} != {})",
item.fingerprint,
expected_fingerprint,
);
}
if map.insert(item.fingerprint.clone(), item).is_some() {
bail!("found duplicate fingerprint");
}
}
Ok((map, digest))
}
/// Load tape encryption key configurations (password protected keys)
pub fn load_key_configs() -> Result<(HashMap<Fingerprint, KeyConfig>, [u8;32]), Error> {
let content = file_read_optional_string(TAPE_KEY_CONFIG_FILENAME)?;
let content = content.unwrap_or_else(|| String::from("[]"));
let digest = openssl::sha::sha256(content.as_bytes());
let key_list: Vec<KeyConfig> = serde_json::from_str(&content)?;
let mut map = HashMap::new();
for key_config in key_list {
match key_config.fingerprint {
Some(ref fingerprint) => {
if map.insert(fingerprint.clone(), key_config).is_some() {
bail!("found duplicate fingerprint");
}
}
None => bail!("missing fingerprint"),
}
}
Ok((map, digest))
}
/// Store tape encryption keys (plain, unprotected keys)
///
/// The file is only accessible by user root (mode 0600).
pub fn save_keys(map: HashMap<Fingerprint, EncryptionKeyInfo>) -> Result<(), Error> {
let mut list = Vec::new();
for (_fp, item) in map {
list.push(item);
}
let raw = serde_json::to_string_pretty(&list)?;
replace_secret_config(TAPE_KEYS_FILENAME, raw.as_bytes())
}
/// Store tape encryption key configurations (password protected keys)
pub fn save_key_configs(map: HashMap<Fingerprint, KeyConfig>) -> Result<(), Error> {
let mut list = Vec::new();
for (_fp, item) in map {
list.push(item);
}
let raw = serde_json::to_string_pretty(&list)?;
pbs_config::replace_backup_config(TAPE_KEY_CONFIG_FILENAME, raw.as_bytes())
}
/// Insert a new key
///
/// Get the lock, load both files, insert the new key, store files.
pub fn insert_key(key: [u8;32], key_config: KeyConfig, force: bool) -> Result<(), Error> {
let _lock = open_backup_lockfile(TAPE_KEYS_LOCKFILE, None, true)?;
let (mut key_map, _) = load_keys()?;
let (mut config_map, _) = load_key_configs()?;
let fingerprint = match key_config.fingerprint.clone() {
Some(fingerprint) => fingerprint,
None => bail!("missing encryption key fingerprint - internal error"),
};
if !force {
if config_map.get(&fingerprint).is_some() {
bail!("encryption key '{}' already exists.", fingerprint);
}
}
let item = EncryptionKeyInfo::new(key, fingerprint.clone());
key_map.insert(fingerprint.clone(), item);
save_keys(key_map)?;
config_map.insert(fingerprint.clone(), key_config);
save_key_configs(config_map)?;
Ok(())
}
// shell completion helper
/// Complete tape encryption key fingerprints
pub fn complete_key_fingerprint(_arg: &str, _param: &HashMap<String, String>) -> Vec<String> {
let data = match load_key_configs() {
Ok((data, _digest)) => data,
Err(_) => return Vec::new(),
};
data.keys().map(|fp| pbs_tools::format::as_fingerprint(fp.bytes())).collect()
}

View File

@ -27,18 +27,13 @@ use proxmox::{
sys::error::SysResult,
};
use pbs_api_types::Fingerprint;
use pbs_api_types::{
Fingerprint, MamAttribute, LtoDriveAndMediaStatus, LtoTapeDrive, Lp17VolumeStatistics,
};
use pbs_config::key_config::KeyConfig;
use pbs_tools::run_command;
use crate::{
config,
api2::types::{
MamAttribute,
LtoDriveAndMediaStatus,
LtoTapeDrive,
Lp17VolumeStatistics,
},
tape::{
TapeRead,
TapeWrite,
@ -378,7 +373,7 @@ impl TapeDriver for LtoTapeHandle {
if let Some((ref key_fingerprint, ref uuid)) = key_fingerprint {
let (key_map, _digest) = config::tape_encryption_keys::load_keys()?;
let (key_map, _digest) = pbs_config::tape_encryption_keys::load_keys()?;
match key_map.get(key_fingerprint) {
Some(item) => {

View File

@ -14,6 +14,7 @@ use anyhow::{bail, Error};
use proxmox::tools::Uuid;
use pbs_datastore::task_log;
use pbs_config::tape_encryption_keys::load_key_configs;
use crate::{
backup::{
@ -42,7 +43,6 @@ use crate::{
media_changer,
},
},
config::tape_encryption_keys::load_key_configs,
};