tape: add hardware encryption key managenent api

This commit is contained in:
Dietmar Maurer
2021-01-18 07:16:06 +01:00
parent 4e9cc3e97c
commit d5a48b5ce4
15 changed files with 518 additions and 37 deletions

View File

@ -9,6 +9,8 @@ use nix::fcntl::{fcntl, FcntlArg, OFlag};
use proxmox::sys::error::SysResult;
use crate::{
config,
backup::Fingerprint,
tools::run_command,
api2::types::{
TapeDensity,
@ -24,6 +26,7 @@ use crate::{
mam_extract_media_usage,
read_tape_alert_flags,
read_volume_statistics,
set_encryption,
drive::{
LinuxTapeDrive,
TapeDriver,
@ -504,6 +507,43 @@ impl TapeDriver for LinuxTapeHandle {
.map_err(|err| format_err!("{}", err))
.map(|bits| TapeAlertFlags::from_bits_truncate(bits))
}
/// Set or clear encryption key
///
/// 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> {
if nix::unistd::Uid::effective().is_root() {
if let Some(ref key_fingerprint) = 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));
}
None => bail!("unknown tape encryption key '{}'", key_fingerprint),
}
} else {
return set_encryption(&mut self.file, None);
}
}
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 {
let fingerprint = crate::tools::format::as_fingerprint(fingerprint.bytes());
command.args(&["--fingerprint", &fingerprint]);
}
command.args(&["--stdin"]);
command.stdin(unsafe { std::process::Stdio::from_raw_fd(self.file.as_raw_fd())});
let output = run_command(command, None)?;
let result: Result<(), String> = serde_json::from_str(&output)?;
result.map_err(|err| format_err!("{}", err))
}
}
/// Write a single EOF mark without flushing buffers

View File

@ -25,6 +25,7 @@ use proxmox::tools::io::ReadExt;
use proxmox::api::section_config::SectionConfigData;
use crate::{
backup::Fingerprint,
api2::types::{
VirtualTapeDrive,
LinuxTapeDrive,
@ -163,6 +164,14 @@ pub trait TapeDriver {
fn tape_alert_flags(&mut self) -> Result<TapeAlertFlags, Error> {
Ok(TapeAlertFlags::empty())
}
/// Set or clear encryption key
fn set_encryption(&mut self, key_fingerprint: Option<Fingerprint>) -> Result<(), Error> {
if key_fingerprint.is_some() {
bail!("drive does not support encryption");
}
Ok(())
}
}
/// Get the media changer (MediaChange + name) associated with a tape drive.
@ -234,14 +243,12 @@ pub fn open_drive(
match section_type_name.as_ref() {
"virtual" => {
let tape = VirtualTapeDrive::deserialize(config)?;
let handle = tape.open()
.map_err(|err| format_err!("open drive '{}' ({}) failed - {}", drive, tape.path, err))?;
Ok(Box::new(handle))
let handle = tape.open()?;
Ok(Box::new(handle))
}
"linux" => {
let tape = LinuxTapeDrive::deserialize(config)?;
let handle = tape.open()
.map_err(|err| format_err!("open drive '{}' ({}) failed - {}", drive, tape.path, err))?;
let handle = tape.open()?;
Ok(Box::new(handle))
}
_ => bail!("unknown drive type '{}' - internal error"),

View File

@ -40,18 +40,20 @@ impl VirtualTapeDrive {
/// This needs to lock the drive
pub fn open(&self) -> Result<VirtualTapeHandle, Error> {
let mut lock_path = std::path::PathBuf::from(&self.path);
lock_path.push(".drive.lck");
proxmox::try_block!({
let mut lock_path = std::path::PathBuf::from(&self.path);
lock_path.push(".drive.lck");
let timeout = std::time::Duration::new(10, 0);
let lock = proxmox::tools::fs::open_file_locked(&lock_path, timeout, true)?;
let timeout = std::time::Duration::new(10, 0);
let lock = proxmox::tools::fs::open_file_locked(&lock_path, timeout, true)?;
Ok(VirtualTapeHandle {
_lock: lock,
drive_name: self.name.clone(),
max_size: self.max_size.unwrap_or(64*1024*1024),
path: std::path::PathBuf::from(&self.path),
})
Ok(VirtualTapeHandle {
_lock: lock,
drive_name: self.name.clone(),
max_size: self.max_size.unwrap_or(64*1024*1024),
path: std::path::PathBuf::from(&self.path),
})
}).map_err(|err: Error| format_err!("open drive '{}' ({}) failed - {}", self.name, self.path, err))
}
}