Skip to content

Commit

Permalink
Merge pull request #445 from cgwalters/tpm2-optin
Browse files Browse the repository at this point in the history
install: Add `block` to config, disable tpm2-luks unless opted-in
  • Loading branch information
jeckersb committed Apr 3, 2024
2 parents 9efeb79 + a615e2b commit 631e6bf
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 21 deletions.
9 changes: 1 addition & 8 deletions docs/src/bootc-install.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,7 @@ taking precedence. If for example you are building a derived container image fr
you could create a `50-myos.toml` that sets `type = "btrfs"` which will override the
prior setting.

Other available options, also under the `[install]` section:

`kargs`: This allows setting kernel arguments which apply only at the time of `bootc install`.
This option is particularly useful when creating derived/layered images; for example, a cloud
image may want to have its default `console=` set, in contrast with a default base image.
The values in this field are space separated.

`root-fs-type`: This value is the same as `install.filesystem.root.type`.
For other available options, see [bootc-install-config](man/bootc-install-config.md).

## Installing an "unconfigured" image

Expand Down
3 changes: 3 additions & 0 deletions docs/src/man-md/bootc-install-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ This is the only defined toplevel table.

The `install`` section supports two subfields:

- `block`: An array of supported `to-disk` backends enabled by this base container image;
if not specified, this will just be `direct`. The only other supported value is `tpm2-luks`.
The first value specified will be the default. To enable both, use `block = ["direct", "tpm2-luks"]`.
- `filesystem`: See below.
- `kargs`: An array of strings; this will be appended to the set of kernel arguments.

Expand Down
12 changes: 7 additions & 5 deletions lib/src/install/baseline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,8 @@ pub(crate) struct InstallBlockDeviceOpts {
///
/// direct: Filesystem written directly to block device
/// tpm2-luks: Bind unlock of filesystem to presence of the default tpm2 device.
#[clap(long, value_enum, default_value_t)]
#[serde(default)]
pub(crate) block_setup: BlockSetup,
#[clap(long, value_enum)]
pub(crate) block_setup: Option<BlockSetup>,

/// Target root filesystem type.
#[clap(long, value_enum)]
Expand Down Expand Up @@ -297,7 +296,10 @@ pub(crate) fn install_create_rootfs(
};

let base_rootdev = findpart(ROOTPN)?;
let (rootdev, root_blockdev_kargs) = match opts.block_setup {
let block_setup = state
.install_config
.get_block_setup(opts.block_setup.as_ref().copied())?;
let (rootdev, root_blockdev_kargs) = match block_setup {
BlockSetup::Direct => (base_rootdev, None),
BlockSetup::Tpm2Luks => {
let uuid = uuid::Uuid::new_v4().to_string();
Expand Down Expand Up @@ -394,7 +396,7 @@ pub(crate) fn install_create_rootfs(
mount::mount(espdev, &efifs_path)?;
}

let luks_device = match opts.block_setup {
let luks_device = match block_setup {
BlockSetup::Direct => None,
BlockSetup::Tpm2Luks => Some(luks_name.to_string()),
};
Expand Down
74 changes: 66 additions & 8 deletions lib/src/install/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use anyhow::{Context, Result};
use fn_error_context::context;
use serde::{Deserialize, Serialize};

use super::baseline::BlockSetup;

/// The toplevel config entry for installation configs stored
/// in bootc/install (e.g. /etc/bootc/install/05-custom.toml)
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
Expand Down Expand Up @@ -39,6 +41,8 @@ pub(crate) struct BasicFilesystems {
pub(crate) struct InstallConfiguration {
/// Root filesystem type
pub(crate) root_fs_type: Option<super::baseline::Filesystem>,
/// Enabled block storage configurations
pub(crate) block: Option<Vec<BlockSetup>>,
pub(crate) filesystem: Option<BasicFilesystems>,
/// Kernel arguments, applied at installation time
#[serde(skip_serializing_if = "Option::is_none")]
Expand Down Expand Up @@ -93,6 +97,7 @@ impl Mergeable for InstallConfiguration {
/// Apply any values in other, overriding any existing values in `self`.
fn merge(&mut self, other: Self) {
merge_basic(&mut self.root_fs_type, other.root_fs_type);
merge_basic(&mut self.block, other.block);
self.filesystem.merge(other.filesystem);
if let Some(other_kargs) = other.kargs {
self.kargs
Expand All @@ -103,8 +108,8 @@ impl Mergeable for InstallConfiguration {
}

impl InstallConfiguration {
/// Some fields can be specified multiple ways. This synchronizes the values of the fields
/// to ensure they're the same.
/// Set defaults (e.g. `block`), and also handle fields that can be specified multiple ways
/// by synchronizing the values of the fields to ensure they're the same.
///
/// - install.root-fs-type is synchronized with install.filesystems.root.type; if
/// both are set, then the latter takes precedence
Expand All @@ -117,6 +122,10 @@ impl InstallConfiguration {
let root = fs.root.get_or_insert_with(Default::default);
root.fstype = Some(*rootfs);
}

if self.block.is_none() {
self.block = Some(vec![BlockSetup::Direct]);
}
}

/// Convenience helper to access the root filesystem
Expand All @@ -128,6 +137,18 @@ impl InstallConfiguration {
pub(crate) fn filter_to_external(&mut self) {
self.kargs.take();
}

pub(crate) fn get_block_setup(&self, default: Option<BlockSetup>) -> Result<BlockSetup> {
let valid_block_setups = self.block.as_deref().unwrap_or_default();
let default_block = valid_block_setups.iter().next().ok_or_else(|| {
anyhow::anyhow!("Empty block storage configuration in install configuration")
})?;
let block_setup = default.as_ref().unwrap_or(default_block);
if !valid_block_setups.contains(block_setup) {
anyhow::bail!("Block setup {block_setup:?} is not enabled in installation config");
}
Ok(*block_setup)
}
}

#[context("Loading configuration")]
Expand Down Expand Up @@ -177,8 +198,7 @@ root-fs-type = "xfs"
let other = InstallConfigurationToplevel {
install: Some(InstallConfiguration {
root_fs_type: Some(Filesystem::Ext4),
filesystem: None,
kargs: None,
..Default::default()
}),
};
install.merge(other.install.unwrap());
Expand Down Expand Up @@ -206,14 +226,13 @@ kargs = ["console=ttyS0", "foo=bar"]
assert_eq!(install.root_fs_type.unwrap(), Filesystem::Ext4);
let other = InstallConfigurationToplevel {
install: Some(InstallConfiguration {
root_fs_type: None,
filesystem: None,
kargs: Some(
["console=tty0", "nosmt"]
.into_iter()
.map(ToOwned::to_owned)
.collect(),
),
..Default::default()
}),
};
install.merge(other.install.unwrap());
Expand Down Expand Up @@ -245,13 +264,12 @@ type = "xfs"
);
let other = InstallConfigurationToplevel {
install: Some(InstallConfiguration {
root_fs_type: None,
filesystem: Some(BasicFilesystems {
root: Some(RootFS {
fstype: Some(Filesystem::Ext4),
}),
}),
kargs: None,
..Default::default()
}),
};
install.merge(other.install.unwrap());
Expand All @@ -260,3 +278,43 @@ type = "xfs"
Filesystem::Ext4
);
}

#[test]
fn test_parse_block() {
let c: InstallConfigurationToplevel = toml::from_str(
r##"[install.filesystem.root]
type = "xfs"
"##,
)
.unwrap();
let mut install = c.install.unwrap();
// Verify the default (but note canonicalization mutates)
{
let mut install = install.clone();
install.canonicalize();
assert_eq!(install.get_block_setup(None).unwrap(), BlockSetup::Direct);
}
let other = InstallConfigurationToplevel {
install: Some(InstallConfiguration {
block: Some(vec![]),
..Default::default()
}),
};
install.merge(other.install.unwrap());
// Should be set, but zero length
assert_eq!(install.block.as_ref().unwrap().len(), 0);
assert!(install.get_block_setup(None).is_err());

let c: InstallConfigurationToplevel = toml::from_str(
r##"[install]
block = ["tpm2-luks"]"##,
)
.unwrap();
let mut install = c.install.unwrap();
install.canonicalize();
assert_eq!(install.block.as_ref().unwrap().len(), 1);
assert_eq!(install.get_block_setup(None).unwrap(), BlockSetup::Tpm2Luks);

// And verify passing a disallowed config is an error
assert!(install.get_block_setup(Some(BlockSetup::Direct)).is_err());
}

0 comments on commit 631e6bf

Please sign in to comment.