Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

install: manually label {/etc/fstab,tmpfile.d/bootc-root-ssh.conf} #389

Merged
merged 1 commit into from
Mar 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion lib/src/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,7 @@ async fn initialize_ostree_root_from_self(
let root = rootfs_dir
.open_dir(path.as_str())
.context("Opening deployment dir")?;
let root_path = &rootfs.join(&path.as_str());
let mut f = {
let mut opts = cap_std::fs::OpenOptions::new();
root.open_with("etc/fstab", opts.append(true).write(true).create(true))
Expand All @@ -644,8 +645,16 @@ async fn initialize_ostree_root_from_self(
}
f.flush()?;

let fstab_path = root_path.join("etc/fstab");
state.lsm_label(&fstab_path, "/etc/fstab".into(), false)?;

if let Some(contents) = state.root_ssh_authorized_keys.as_deref() {
osconfig::inject_root_ssh_authorized_keys(&root, contents)?;
osconfig::inject_root_ssh_authorized_keys(
&root,
&root_path,
|target, path, recurse| state.lsm_label(target, path, recurse),
contents,
)?;
}

let uname = rustix::system::uname();
Expand Down
45 changes: 43 additions & 2 deletions lib/src/install/osconfig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,15 @@ const ETC_TMPFILES: &str = "etc/tmpfiles.d";
const ROOT_SSH_TMPFILE: &str = "bootc-root-ssh.conf";

#[context("Injecting root authorized_keys")]
pub(crate) fn inject_root_ssh_authorized_keys(root: &Dir, contents: &str) -> Result<()> {
pub(crate) fn inject_root_ssh_authorized_keys<F>(
root: &Dir,
root_path: &Utf8Path,
lsm_label_fn: F,
contents: &str,
) -> Result<()>
where
F: Fn(&Utf8Path, &Utf8Path, bool) -> Result<()>,
{
// While not documented right now, this one looks like it does not newline wrap
let b64_encoded = ostree_ext::glib::base64_encode(contents.as_bytes());
// See the example in https://systemd.io/CREDENTIALS/
Expand All @@ -18,20 +26,53 @@ pub(crate) fn inject_root_ssh_authorized_keys(root: &Dir, contents: &str) -> Res
root.create_dir_all(tmpfiles_dir)?;
let target = tmpfiles_dir.join(ROOT_SSH_TMPFILE);
root.atomic_write(&target, &tmpfiles_content)?;

let as_path = Utf8Path::new(ETC_TMPFILES).join(ROOT_SSH_TMPFILE);
lsm_label_fn(
&root_path.join(&as_path),
&Utf8Path::new("/").join(&as_path),
false,
)?;

println!("Injected: {target}");
Ok(())
}

#[test]
fn test_inject_root_ssh() -> Result<()> {
use camino::Utf8PathBuf;
use std::cell::Cell;

let fake_lsm_label_called = Cell::new(0);
let fake_lsm_label = |target: &Utf8Path, as_path: &Utf8Path, recurse: bool| -> Result<()> {
assert_eq!(
target,
format!("/root/path/etc/tmpfiles.d/{ROOT_SSH_TMPFILE}")
);
assert_eq!(as_path, format!("/etc/tmpfiles.d/{ROOT_SSH_TMPFILE}"));
assert_eq!(recurse, false);

fake_lsm_label_called.set(fake_lsm_label_called.get() + 1);
Ok(())
};

let root_path = &Utf8PathBuf::from("/root/path");
let root = &cap_std_ext::cap_tempfile::TempDir::new(cap_std::ambient_authority())?;

inject_root_ssh_authorized_keys(root, "ssh-ed25519 ABCDE example@demo\n").unwrap();
inject_root_ssh_authorized_keys(
root,
root_path,
fake_lsm_label,
"ssh-ed25519 ABCDE example@demo\n",
)
.unwrap();

let content = root.read_to_string(format!("etc/tmpfiles.d/{ROOT_SSH_TMPFILE}"))?;
assert_eq!(
content,
"f~ /root/.ssh/authorized_keys 600 root root - c3NoLWVkMjU1MTkgQUJDREUgZXhhbXBsZUBkZW1vCg==\n"
);
assert_eq!(fake_lsm_label_called, 1.into());

Ok(())
}