Skip to content

Commit

Permalink
Add online encrypt ability at engine level for Stratis pools
Browse files Browse the repository at this point in the history
  • Loading branch information
jbaublitz committed Jul 22, 2024
1 parent 95f55e0 commit 11eec29
Show file tree
Hide file tree
Showing 16 changed files with 446 additions and 153 deletions.
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ version = "0.2.147"
optional = true

[dependencies.libcryptsetup-rs]
version = "0.9.3"
version = "0.10.0"
features = ["mutex"]
optional = true

Expand Down
2 changes: 1 addition & 1 deletion src/dbus_api/pool/pool_3_0/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ pub fn add_cachedevs_method(f: &Factory<MTSync<TData>, TData>) -> Method<MTSync<
pub fn encrypted_property(f: &Factory<MTSync<TData>, TData>) -> Property<MTSync<TData>, TData> {
f.property::<bool, _>(consts::POOL_ENCRYPTED_PROP, ())
.access(Access::Read)
.emits_changed(EmitsChangedSignal::Const)
.emits_changed(EmitsChangedSignal::True)
.on_get(get_pool_encrypted)
}

Expand Down
18 changes: 13 additions & 5 deletions src/engine/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@ use crate::{
structures::{AllLockReadGuard, AllLockWriteGuard, SomeLockReadGuard, SomeLockWriteGuard},
types::{
ActionAvailability, BlockDevTier, Clevis, CreateAction, DeleteAction, DevUuid,
EncryptionInfo, FilesystemUuid, GrowAction, Key, KeyDescription, LockedPoolsInfo,
MappingCreateAction, MappingDeleteAction, Name, PoolDiff, PoolEncryptionInfo,
PoolIdentifier, PoolUuid, RegenAction, RenameAction, ReportType, SetCreateAction,
SetDeleteAction, SetUnlockAction, StartAction, StopAction, StoppedPoolsInfo,
StratFilesystemDiff, StratSigblockVersion, UdevEngineEvent, UnlockMethod,
EncryptedDevice, EncryptionInfo, FilesystemUuid, GrowAction, Key, KeyDescription,
LockedPoolsInfo, MappingCreateAction, MappingDeleteAction, Name, PoolDiff,
PoolEncryptionInfo, PoolIdentifier, PoolUuid, RegenAction, RenameAction, ReportType,
SetCreateAction, SetDeleteAction, SetUnlockAction, StartAction, StopAction,
StoppedPoolsInfo, StratFilesystemDiff, StratSigblockVersion, UdevEngineEvent,
UnlockMethod,
},
},
stratis::StratisResult,
Expand Down Expand Up @@ -342,6 +343,13 @@ pub trait Pool: Debug + Send + Sync {
limit: Option<Bytes>,
) -> StratisResult<PropChangeAction<Option<Sectors>>>;

/// Encrypted an unencrypted pool.
fn encrypt_pool(
&mut self,
pool_uuid: PoolUuid,
encryption_info: &EncryptionInfo,
) -> StratisResult<CreateAction<EncryptedDevice>>;

/// Return the metadata that would be written if metadata were written.
fn current_metadata(&self, pool_name: &Name) -> StratisResult<String>;

Expand Down
13 changes: 11 additions & 2 deletions src/engine/sim_engine/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ use crate::{
structures::Table,
types::{
ActionAvailability, BlockDevTier, Clevis, CreateAction, DeleteAction, DevUuid,
EncryptionInfo, FilesystemUuid, GrowAction, Key, KeyDescription, Name, PoolDiff,
PoolEncryptionInfo, PoolUuid, RegenAction, RenameAction, SetCreateAction,
EncryptedDevice, EncryptionInfo, FilesystemUuid, GrowAction, Key, KeyDescription, Name,
PoolDiff, PoolEncryptionInfo, PoolUuid, RegenAction, RenameAction, SetCreateAction,
SetDeleteAction, StratSigblockVersion,
},
PropChangeAction,
Expand Down Expand Up @@ -746,6 +746,15 @@ impl Pool for SimPool {
}
}

fn encrypt_pool(
&mut self,
_pool_uuid: PoolUuid,
enc: &EncryptionInfo,
) -> StratisResult<CreateAction<EncryptedDevice>> {
self.encryption_info = Some(enc.clone());
Ok(CreateAction::Created(EncryptedDevice))
}

fn current_metadata(&self, pool_name: &Name) -> StratisResult<String> {
serde_json::to_string(&self.record(pool_name)).map_err(|e| e.into())
}
Expand Down
35 changes: 34 additions & 1 deletion src/engine/strat_engine/backstore/backstore/v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

// Code to handle the backing store of a pool.

use std::{cmp, collections::HashMap, iter::once, path::PathBuf};
use std::{cmp, collections::HashMap, iter::once, path::Path, path::PathBuf};

use chrono::{DateTime, Utc};
use either::Either;
Expand All @@ -29,6 +29,7 @@ use crate::{
names::{format_backstore_ids, CacheRole},
serde_structs::{BackstoreSave, CapSave, PoolFeatures, PoolSave, Recordable},
shared::bds_to_bdas,
thinpool::ThinPool,
types::BDARecordResult,
writing::wipe_sectors,
},
Expand Down Expand Up @@ -1106,6 +1107,38 @@ impl Backstore {
self.data_tier.grow(dev)
}

pub fn encrypt(
&mut self,
pool_uuid: PoolUuid,
thinpool: &mut ThinPool<Self>,
encryption_info: &EncryptionInfo,
) -> StratisResult<bool> {
let (dm_name, _) = format_backstore_ids(pool_uuid, CacheRole::Cache);
match self.enc.as_ref() {
Some(inner) => {
let enc = match inner {
Either::Left(enc) => enc,
Either::Right(handle) => handle.encryption_info(),
};
if enc != encryption_info {
Err(StratisError::Msg("Encryption information does not match the existing encryption information for encrypted pool".to_string()))
} else {
Ok(false)
}
}
None => {
let handle = CryptHandle::encrypt(
pool_uuid,
thinpool,
Path::new(&format!("/dev/mapper/{}", &dm_name.to_string())),
encryption_info,
)?;
self.enc = Some(Either::Right(handle));
Ok(true)
}
}
}

/// A summary of block sizes
pub fn block_size_summary(&self, tier: BlockDevTier) -> Option<BlockSizeSummary> {
match tier {
Expand Down
28 changes: 5 additions & 23 deletions src/engine/strat_engine/crypt/handle/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use crate::{
engine::MAX_STRATIS_PASS_SIZE,
strat_engine::{
backstore::get_devno_from_path,
cmd::{clevis_decrypt, clevis_luks_bind, clevis_luks_regen, clevis_luks_unbind},
cmd::{clevis_luks_bind, clevis_luks_regen, clevis_luks_unbind},
crypt::{
consts::{
CLEVIS_LUKS_TOKEN_ID, DEFAULT_CRYPT_KEYSLOTS_SIZE, DEFAULT_CRYPT_METADATA_SIZE,
Expand All @@ -42,8 +42,8 @@ use crate::{
},
shared::{
acquire_crypt_device, activate, add_keyring_keyslot, check_luks2_token,
clevis_info_from_metadata, device_from_physical_path, ensure_inactive,
ensure_wiped, get_keyslot_number, interpret_clevis_config,
clevis_decrypt, clevis_info_from_metadata, device_from_physical_path,
ensure_inactive, ensure_wiped, get_keyslot_number, interpret_clevis_config,
key_desc_from_metadata, luks2_token_type_is_valid, read_key, wipe_fallback,
},
},
Expand Down Expand Up @@ -956,7 +956,7 @@ impl CryptHandle {
/// Add a keyring binding to the underlying LUKS2 volume.
pub fn bind_keyring(&mut self, key_desc: &KeyDescription) -> StratisResult<()> {
let mut device = self.acquire_crypt_device()?;
let key = Self::clevis_decrypt(&mut device)?.ok_or_else(|| {
let key = clevis_decrypt(&mut device)?.ok_or_else(|| {
StratisError::Msg(
"The Clevis token appears to have been wiped outside of \
Stratis; cannot add a keyring key binding without an existing \
Expand Down Expand Up @@ -1030,24 +1030,6 @@ impl CryptHandle {
replace_pool_name(&mut device, pool_name)
}

/// Decrypt a Clevis passphrase and return it securely.
fn clevis_decrypt(device: &mut CryptDevice) -> StratisResult<Option<SizedKeyMemory>> {
let mut token = match device.token_handle().json_get(CLEVIS_LUKS_TOKEN_ID).ok() {
Some(t) => t,
None => return Ok(None),
};
let jwe = token
.as_object_mut()
.and_then(|map| map.remove("jwe"))
.ok_or_else(|| {
StratisError::Msg(format!(
"Token slot {CLEVIS_LUKS_TOKEN_ID} is occupied but does not appear to be a Clevis \
token; aborting"
))
})?;
clevis_decrypt(&jwe).map(Some)
}

/// Deactivate the device referenced by the current device handle.
pub fn deactivate(&self) -> StratisResult<()> {
ensure_inactive(&mut self.acquire_crypt_device()?, self.activation_name())
Expand Down Expand Up @@ -1097,7 +1079,7 @@ impl CryptHandle {
StratisError::Msg("Failed to find key with key description".to_string())
})?
} else if self.encryption_info().clevis_info().is_some() {
Self::clevis_decrypt(&mut crypt)?.expect("Already checked token exists")
clevis_decrypt(&mut crypt)?.expect("Already checked token exists")
} else {
unreachable!("Must be encrypted")
};
Expand Down
Loading

0 comments on commit 11eec29

Please sign in to comment.