Skip to content

Commit 77ff056

Browse files
committed
cdh: Expose headerPath parameter
This change exposes the headerPath parameter to the luks2 block device encryption type. This way, users can supply the header path explicitly in both cases where ephemeral and persistent storages are being utilized. In case of persistent storages, the end user is responsible for ensuring the header path cannot be tampered with, for instance by sealing the header with a key backed by trustee. Signed-off-by: Manuel Huber <manuelh@nvidia.com>
1 parent 438c043 commit 77ff056

1 file changed

Lines changed: 66 additions & 6 deletions

File tree

  • confidential-data-hub/hub/src/storage/volume_type/blockdevice

confidential-data-hub/hub/src/storage/volume_type/blockdevice/mod.rs

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,18 @@ pub enum BlockDeviceEncryptType {
4747
/// Optional name for /dev/mapper/<name>
4848
#[serde(rename = "mapperName")]
4949
mapper_name: Option<String>,
50+
51+
/// Optional path to the LUKS header file (detached header).
52+
/// When creating (source empty): use this path for the header file; if
53+
/// not set, a path is generated and removed on umount.
54+
/// When opening (source encrypted): use this path to open the device;
55+
/// if not set, the header is read from the device.
56+
#[serde(
57+
default,
58+
skip_serializing_if = "Option::is_none",
59+
rename = "headerPath"
60+
)]
61+
header_path: Option<String>,
5062
},
5163
}
5264

@@ -212,21 +224,29 @@ impl BlockDevice {
212224
BlockDeviceEncryptType::Luks2 {
213225
data_integrity,
214226
mapper_name,
227+
header_path: user_header_path,
215228
} => {
216229
let integrity = data_integrity.map_or(false, |e| e.parse().unwrap_or(false));
217230
let formatter = Luks2Formatter::default().with_integrity(integrity);
218231
// 3.1 if the source type is empty, encrypt the device and create detached header
219232
let header_path = if parameters.source_type == SourceType::Empty {
220233
warn!("encrypting the device. This will wipe original data on the disk.");
221-
let header_path = luks2::luks_header_path(&device_path);
222-
luks2::prepare_luks_header_file(&header_path)?;
223-
self.temp_paths.push(header_path.clone());
234+
let path = if user_header_path.is_none() {
235+
let path = luks2::luks_header_path(&device_path);
236+
// Remove header on umount when we generated it (not user-provided)
237+
self.temp_paths.push(path.clone());
238+
path
239+
} else {
240+
user_header_path.clone().unwrap()
241+
};
242+
luks2::prepare_luks_header_file(&path)?;
224243
formatter
225-
.encrypt_device(&device_path, Some(&header_path), key.clone())
244+
.encrypt_device(&device_path, Some(&path), key.clone())
226245
.map_err(|source| BlockDeviceError::Luks2Error { source })?;
227-
Some(header_path)
246+
Some(path)
228247
} else {
229-
None
248+
// Re-opening: use user-provided header path, or None to read header from device
249+
user_header_path.clone()
230250
};
231251

232252
let devmapper_name = mapper_name.unwrap_or_else(|| {
@@ -476,6 +496,15 @@ mod tests {
476496
let mut bd = BlockDevice::default();
477497
let device_path = temp_device_file.path().to_string_lossy().to_string();
478498

499+
// Header file cleaned up automatically when header_dir is dropped at
500+
// the end of the test function.
501+
let header_dir = tempfile::TempDir::new().unwrap();
502+
let header_path = header_dir
503+
.path()
504+
.join("luks-header")
505+
.to_string_lossy()
506+
.to_string();
507+
479508
let options = HashMap::from([
480509
("sourceType".to_string(), "empty".to_string()),
481510
("targetType".to_string(), "fileSystem".to_string()),
@@ -487,6 +516,7 @@ mod tests {
487516
),
488517
("dataIntegrity".to_string(), integrity.to_string()),
489518
("filesystemType".to_string(), "ext4".to_string()),
519+
("headerPath".to_string(), header_path.clone()),
490520
]);
491521

492522
let tempdir = tempfile::TempDir::new().unwrap();
@@ -500,6 +530,36 @@ mod tests {
500530
.unwrap();
501531

502532
bd.umount().await.unwrap();
533+
drop(bd);
534+
535+
// Re-open the encrypted device using the same header path (create-then-open)
536+
let tempdir2 = tempfile::TempDir::new().unwrap();
537+
let mut bd2 = BlockDevice::default();
538+
let options_open = HashMap::from([
539+
("sourceType".to_string(), "encrypted".to_string()),
540+
("targetType".to_string(), "fileSystem".to_string()),
541+
("devicePath".to_string(), device_path.clone()),
542+
("encryptionType".to_string(), "luks2".to_string()),
543+
("dataIntegrity".to_string(), integrity.to_string()),
544+
(
545+
"key".to_string(),
546+
"file://./test_files/luks2-disk-passphrase".to_string(),
547+
),
548+
("filesystemType".to_string(), "ext4".to_string()),
549+
("headerPath".to_string(), header_path),
550+
]);
551+
552+
bd2.real_mount(&options_open, &[], tempdir2.path().to_str().unwrap())
553+
.await
554+
.unwrap();
555+
556+
assert!(tempdir2.path().join("test-file").exists());
557+
let content = tokio::fs::read_to_string(tempdir2.path().join("test-file"))
558+
.await
559+
.unwrap();
560+
assert_eq!(content, "some data");
561+
562+
bd2.umount().await.unwrap();
503563
}
504564

505565
#[cfg(feature = "luks2")]

0 commit comments

Comments
 (0)