tape: use specialized encryption key per media-set
This commit is contained in:
parent
bc228e5eaf
commit
2b191385ea
@ -1053,7 +1053,9 @@ pub fn catalog_media(
|
||||
MediaCatalog::destroy(status_path, &media_id.label.uuid)?;
|
||||
return Ok(());
|
||||
}
|
||||
let encrypt_fingerprint = set.encryption_key_fingerprint.clone();
|
||||
let encrypt_fingerprint = set.encryption_key_fingerprint.clone()
|
||||
.map(|fp| (fp, set.uuid.clone()));
|
||||
|
||||
drive.set_encryption(encrypt_fingerprint)?;
|
||||
|
||||
set.pool.clone()
|
||||
|
@ -17,6 +17,7 @@ use proxmox::{
|
||||
cli::*,
|
||||
RpcEnvironment,
|
||||
},
|
||||
tools::Uuid,
|
||||
};
|
||||
|
||||
use proxmox_backup::{
|
||||
@ -26,6 +27,7 @@ use proxmox_backup::{
|
||||
LINUX_DRIVE_PATH_SCHEMA,
|
||||
DRIVE_NAME_SCHEMA,
|
||||
TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
|
||||
MEDIA_SET_UUID_SCHEMA,
|
||||
LinuxTapeDrive,
|
||||
},
|
||||
tape::{
|
||||
@ -193,6 +195,10 @@ fn tape_alert_flags(
|
||||
schema: TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
|
||||
optional: true,
|
||||
},
|
||||
uuid: {
|
||||
schema: MEDIA_SET_UUID_SCHEMA,
|
||||
optional: true,
|
||||
},
|
||||
drive: {
|
||||
schema: DRIVE_NAME_SCHEMA,
|
||||
optional: true,
|
||||
@ -212,13 +218,25 @@ fn tape_alert_flags(
|
||||
/// Set or clear encryption key
|
||||
fn set_encryption(
|
||||
fingerprint: Option<Fingerprint>,
|
||||
uuid: Option<Uuid>,
|
||||
param: Value,
|
||||
) -> Result<(), Error> {
|
||||
|
||||
let result = proxmox::try_block!({
|
||||
let mut handle = get_tape_handle(¶m)?;
|
||||
|
||||
handle.set_encryption(fingerprint)?;
|
||||
match (fingerprint, uuid) {
|
||||
(Some(fingerprint), Some(uuid)) => {
|
||||
handle.set_encryption(Some((fingerprint, uuid)))?;
|
||||
}
|
||||
(Some(_), None) => {
|
||||
bail!("missing media set uuid");
|
||||
}
|
||||
(None, _) => {
|
||||
handle.set_encryption(None)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}).map_err(|err: Error| err.to_string());
|
||||
|
||||
|
@ -7,6 +7,7 @@ use anyhow::{bail, format_err, Error};
|
||||
use nix::fcntl::{fcntl, FcntlArg, OFlag};
|
||||
|
||||
use proxmox::sys::error::SysResult;
|
||||
use proxmox::tools::Uuid;
|
||||
|
||||
use crate::{
|
||||
config,
|
||||
@ -535,16 +536,33 @@ impl TapeDriver for LinuxTapeHandle {
|
||||
/// Note: Only 'root' user may run RAW SG commands, so we need to
|
||||
/// spawn setuid binary 'sg-tape-cmd'. Also, encryption key file
|
||||
/// is only readable by root.
|
||||
fn set_encryption(&mut self, key_fingerprint: Option<Fingerprint>) -> Result<(), Error> {
|
||||
fn set_encryption(
|
||||
&mut self,
|
||||
key_fingerprint: Option<(Fingerprint, Uuid)>,
|
||||
) -> Result<(), Error> {
|
||||
|
||||
if nix::unistd::Uid::effective().is_root() {
|
||||
|
||||
if let Some(ref key_fingerprint) = key_fingerprint {
|
||||
if let Some((ref key_fingerprint, ref uuid)) = key_fingerprint {
|
||||
|
||||
let (key_map, _digest) = config::tape_encryption_keys::load_keys()?;
|
||||
match key_map.get(key_fingerprint) {
|
||||
Some(item) => {
|
||||
return set_encryption(&mut self.file, Some(item.key));
|
||||
|
||||
// derive specialized key for each media-set
|
||||
|
||||
let mut tape_key = [0u8; 32];
|
||||
|
||||
let uuid_bytes: [u8; 16] = uuid.as_bytes().clone();
|
||||
|
||||
openssl::pkcs5::pbkdf2_hmac(
|
||||
&item.key,
|
||||
&uuid_bytes,
|
||||
10,
|
||||
openssl::hash::MessageDigest::sha256(),
|
||||
&mut tape_key)?;
|
||||
|
||||
return set_encryption(&mut self.file, Some(tape_key));
|
||||
}
|
||||
None => bail!("unknown tape encryption key '{}'", key_fingerprint),
|
||||
}
|
||||
@ -556,9 +574,10 @@ impl TapeDriver for LinuxTapeHandle {
|
||||
let mut command = std::process::Command::new(
|
||||
"/usr/lib/x86_64-linux-gnu/proxmox-backup/sg-tape-cmd");
|
||||
command.args(&["encryption"]);
|
||||
if let Some(fingerprint) = key_fingerprint {
|
||||
if let Some((fingerprint, uuid)) = key_fingerprint {
|
||||
let fingerprint = crate::tools::format::as_fingerprint(fingerprint.bytes());
|
||||
command.args(&["--fingerprint", &fingerprint]);
|
||||
command.args(&["--uuid", &uuid.to_string()]);
|
||||
}
|
||||
command.args(&["--stdin"]);
|
||||
command.stdin(unsafe { std::process::Stdio::from_raw_fd(self.file.as_raw_fd())});
|
||||
|
@ -22,8 +22,13 @@ use anyhow::{bail, format_err, Error};
|
||||
use ::serde::{Deserialize};
|
||||
use serde_json::Value;
|
||||
|
||||
use proxmox::tools::io::ReadExt;
|
||||
use proxmox::api::section_config::SectionConfigData;
|
||||
use proxmox::{
|
||||
tools::{
|
||||
Uuid,
|
||||
io::ReadExt,
|
||||
},
|
||||
api::section_config::SectionConfigData,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
backup::{
|
||||
@ -190,7 +195,14 @@ pub trait TapeDriver {
|
||||
}
|
||||
|
||||
/// Set or clear encryption key
|
||||
fn set_encryption(&mut self, key_fingerprint: Option<Fingerprint>) -> Result<(), Error> {
|
||||
///
|
||||
/// We use the media_set_uuid to XOR the secret key with the
|
||||
/// uuid (first 16 bytes), so that each media set uses an uique
|
||||
/// key for encryption.
|
||||
fn set_encryption(
|
||||
&mut self,
|
||||
key_fingerprint: Option<(Fingerprint, Uuid)>,
|
||||
) -> Result<(), Error> {
|
||||
if key_fingerprint.is_some() {
|
||||
bail!("drive does not support encryption");
|
||||
}
|
||||
|
@ -231,12 +231,12 @@ impl PoolWriter {
|
||||
media.id(),
|
||||
)?;
|
||||
|
||||
let encrypt_fingerprint = media
|
||||
.media_set_label()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
let media_set = media.media_set_label().clone().unwrap();
|
||||
|
||||
let encrypt_fingerprint = media_set
|
||||
.encryption_key_fingerprint
|
||||
.clone();
|
||||
.clone()
|
||||
.map(|fp| (fp, media_set.uuid.clone()));
|
||||
|
||||
drive.set_encryption(encrypt_fingerprint)?;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user