Skip to content

Commit 35633bc

Browse files
author
Gareth Widlansky
committed
sdboot: add support for key enrollment in bootc install
Signed-off-by: Gareth Widlansky <[email protected]> cleanup Signed-off-by: Gareth Widlansky <[email protected]> don't expect `/usr/lib/bootc/keys` to exist Signed-off-by: Gareth Widlansky <[email protected]> remove comment Signed-off-by: Gareth Widlansky <[email protected]> don't use ambient authority Signed-off-by: Gareth Widlansky <[email protected]> use option rather than an enum Signed-off-by: Gareth Widlansky <[email protected]> use fs.open_dir_optional Signed-off-by: Gareth Widlansky <[email protected]> use basedir, link spec, add docs to `bootc install` docs: rework manpage Signed-off-by: Gareth Widlansky <[email protected]> nits
1 parent f687add commit 35633bc

File tree

3 files changed

+91
-3
lines changed

3 files changed

+91
-3
lines changed

crates/lib/src/bootc_composefs/boot.rs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ use std::fs::create_dir_all;
6666
use std::io::Write;
6767
use std::path::Path;
6868

69-
use anyhow::{anyhow, Context, Result};
69+
use anyhow::{anyhow, bail, Context, Result};
7070
use bootc_blockdev::find_parent_devices;
7171
use bootc_kernel_cmdline::utf8::{Cmdline, Parameter};
7272
use bootc_mount::inspect_filesystem_of_dir;
@@ -132,6 +132,10 @@ const SYSTEMD_LOADER_CONF_PATH: &str = "loader/loader.conf";
132132
const INITRD: &str = "initrd";
133133
const VMLINUZ: &str = "vmlinuz";
134134

135+
const BOOTC_AUTOENROLL_PATH: &str = "usr/lib/bootc/install/secureboot-keys";
136+
137+
const AUTH_EXT: &str = "auth";
138+
135139
/// We want to be able to control the ordering of UKIs so we put them in a directory that's not the
136140
/// directory specified by the BLS spec. We do this because we want systemd-boot to only look at
137141
/// our config files and not show the actual UKIs in the bootloader menu
@@ -1142,6 +1146,52 @@ pub(crate) fn setup_composefs_uki_boot(
11421146
Ok(())
11431147
}
11441148

1149+
pub struct SecurebootKeys {
1150+
pub dir: Dir,
1151+
pub keys: Vec<Utf8PathBuf>,
1152+
}
1153+
1154+
fn get_secureboot_keys(fs: &Dir, p: &str) -> Result<Option<SecurebootKeys>> {
1155+
let mut entries = vec![];
1156+
1157+
// if the dir doesn't exist, return None
1158+
let keys_dir = match fs.open_dir_optional(p)? {
1159+
Some(d) => d,
1160+
_ => return Ok(None),
1161+
};
1162+
1163+
// https://github.com/systemd/systemd/blob/26b2085d54ebbfca8637362eafcb4a8e3faf832f/man/systemd-boot.xml#L392
1164+
1165+
for entry in keys_dir.entries()? {
1166+
let dir_e = entry?;
1167+
let dirname = dir_e.file_name();
1168+
if !dir_e.file_type()?.is_dir() {
1169+
bail!("/{p}/{dirname:?} is not a directory");
1170+
}
1171+
1172+
let dir_path: Utf8PathBuf = dirname.try_into()?;
1173+
let dir = dir_e.open_dir()?;
1174+
for entry in dir.entries()? {
1175+
let e = entry?;
1176+
let local: Utf8PathBuf = e.file_name().try_into()?;
1177+
let path = dir_path.join(local);
1178+
1179+
if path.extension() != Some(AUTH_EXT) {
1180+
continue;
1181+
}
1182+
1183+
if !e.file_type()?.is_file() {
1184+
bail!("/{p}/{path:?} is not a file");
1185+
}
1186+
entries.push(path);
1187+
}
1188+
}
1189+
return Ok(Some(SecurebootKeys {
1190+
dir: keys_dir,
1191+
keys: entries,
1192+
}));
1193+
}
1194+
11451195
#[context("Setting up composefs boot")]
11461196
pub(crate) fn setup_composefs_boot(
11471197
root_setup: &RootSetup,
@@ -1181,6 +1231,7 @@ pub(crate) fn setup_composefs_boot(
11811231
&root_setup.physical_root_path,
11821232
&state.config_opts,
11831233
None,
1234+
get_secureboot_keys(&mounted_fs, BOOTC_AUTOENROLL_PATH)?,
11841235
)?;
11851236
}
11861237

crates/lib/src/bootloader.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::fs::create_dir_all;
12
use std::process::Command;
23

34
use anyhow::{anyhow, bail, Context, Result};
@@ -9,7 +10,7 @@ use fn_error_context::context;
910
use bootc_blockdev::{Partition, PartitionTable};
1011
use bootc_mount as mount;
1112

12-
use crate::bootc_composefs::boot::mount_esp;
13+
use crate::bootc_composefs::boot::{mount_esp, SecurebootKeys};
1314
use crate::{discoverable_partition_specification, utils};
1415

1516
/// The name of the mountpoint for efi (as a subdirectory of /boot, or at the toplevel)
@@ -19,6 +20,9 @@ pub(crate) const EFI_DIR: &str = "efi";
1920
#[allow(dead_code)]
2021
const BOOTUPD_UPDATES: &str = "usr/lib/bootupd/updates";
2122

23+
// from: https://github.com/systemd/systemd/blob/26b2085d54ebbfca8637362eafcb4a8e3faf832f/man/systemd-boot.xml#L392
24+
const SYSTEMD_KEY_DIR: &str = "loader/keys";
25+
2226
#[allow(dead_code)]
2327
pub(crate) fn esp_in(device: &PartitionTable) -> Result<&Partition> {
2428
device
@@ -74,6 +78,7 @@ pub(crate) fn install_systemd_boot(
7478
_rootfs: &Utf8Path,
7579
_configopts: &crate::install::InstallConfigOpts,
7680
_deployment_path: Option<&str>,
81+
autoenroll: Option<SecurebootKeys>,
7782
) -> Result<()> {
7883
let esp_part = device
7984
.find_partition_of_type(discoverable_partition_specification::ESP)
@@ -87,7 +92,35 @@ pub(crate) fn install_systemd_boot(
8792
Command::new("bootctl")
8893
.args(["install", "--esp-path", esp_path.as_str()])
8994
.log_debug()
90-
.run_inherited_with_cmd_context()
95+
.run_inherited_with_cmd_context()?;
96+
97+
if let Some(SecurebootKeys { dir, keys }) = autoenroll {
98+
let path = esp_path.join(SYSTEMD_KEY_DIR);
99+
create_dir_all(&path)?;
100+
101+
let keys_dir = esp_mount
102+
.fd
103+
.open_dir(SYSTEMD_KEY_DIR)
104+
.with_context(|| format!("Opening {path}"))?;
105+
106+
for filename in keys.iter() {
107+
let p = path.join(&filename);
108+
109+
// create directory if it doesn't already exist
110+
if let Some(parent) = p.parent() {
111+
create_dir_all(parent)?;
112+
}
113+
114+
dir.copy(&filename, &keys_dir, &filename)
115+
.with_context(|| format!("Copying secure boot key: {p}"))?;
116+
println!("Wrote Secure Boot key: {p}");
117+
}
118+
if keys.is_empty() {
119+
tracing::debug!("No Secure Boot keys provided for systemd-boot enrollment");
120+
}
121+
}
122+
123+
Ok(())
91124
}
92125

93126
#[context("Installing bootloader using zipl")]

docs/src/man/bootc-install.8.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ updates.
2828
An installation is not simply a copy of the container filesystem, but
2929
includes other setup and metadata.
3030

31+
## Secure Boot Keys
32+
33+
When installing with `systemd-boot`, bootc can let `systemd-boot` can handle enrollment of Secure Boot keys by putting signed EFI signature lists in `/usr/lib/bootc/install/secureboot-keys` which will copy over into `ESP/loader/keys` after bootloader installation. The keys will be copied to `loader/keys` subdirectory of the ESP. after installing `systemd-boot` to the system. More information on how key enrollment works with `systemd-boot` is available [systemd-boot](https://github.com/systemd/systemd/blob/26b2085d54ebbfca8637362eafcb4a8e3faf832f/man/systemd-boot.xml#L392) man page.
34+
3135
<!-- BEGIN GENERATED OPTIONS -->
3236
<!-- END GENERATED OPTIONS -->
3337

0 commit comments

Comments
 (0)