Skip to content

Commit

Permalink
osconfig: install root ssh keys to /var/roothome
Browse files Browse the repository at this point in the history
The current location via tmpfiles.d to install the root ssh keys
seems to be not working. There is an error that `/root/.ssh` does
not exist from `systemd-tmpfiles-setup` and indeed the authorized_keys
file is on in `/root/.ssh`.

It seems like everything else in the firstboot in
tmpfiles.d is refering to `/var/roothome` instead of `/root` and
switching to this for the location of the ssh keys solves the
issue.

Co-authored-by: Colin Walters <[email protected]>
  • Loading branch information
mvo5 and cgwalters committed Mar 20, 2024
1 parent 4222b38 commit bd69633
Showing 1 changed file with 48 additions and 3 deletions.
51 changes: 48 additions & 3 deletions lib/src/install/osconfig.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use std::borrow::Cow;
use std::io::Write;

use anyhow::Result;
use anyhow::{Context, Result};
use camino::{Utf8Path, Utf8PathBuf};
use cap_std::fs::Dir;
use cap_std_ext::cap_std;
use cap_std_ext::{cap_std, dirext::CapStdExtDirExt};
use fn_error_context::context;
use ostree_ext::ostree;

Expand All @@ -17,8 +19,22 @@ pub(crate) fn inject_root_ssh_authorized_keys(
) -> 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());

// Eagerly resolve the path of /root in order to avoid tmpfiles.d clashes/problems.
// If it's local state (i.e. /root -> /var/roothome) then we resolve that symlink now.
let roothome_meta = root.symlink_metadata_optional("root")?;
let root_path = if roothome_meta.as_ref().filter(|m| m.is_symlink()).is_some() {
let path = root.read_link("root")?;
Utf8PathBuf::try_from(path)
.context("Reading /root symlink")
.map(Cow::Owned)?
} else {
Cow::Borrowed(Utf8Path::new("root"))
};

// See the example in https://systemd.io/CREDENTIALS/
let tmpfiles_content = format!("f~ /root/.ssh/authorized_keys 600 root root - {b64_encoded}\n");
let tmpfiles_content =
format!("f~ /{root_path}/.ssh/authorized_keys 600 root root - {b64_encoded}\n");

crate::lsm::ensure_dir_labeled(root, ETC_TMPFILES, None, 0o755.into(), sepolicy)?;
let tmpfiles_dir = root.open_dir(ETC_TMPFILES)?;
Expand All @@ -40,6 +56,35 @@ fn test_inject_root_ssh() -> Result<()> {

// The code expects this to exist, reasonably so
root.create_dir("etc")?;
// Test with a symlink
root.symlink("var/roothome", "root")?;
inject_root_ssh_authorized_keys(root, None, "ssh-ed25519 ABCDE example@demo\n").unwrap();

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

root.create_dir("etc")?;
root.remove_file("root")?;
root.create_dir("root")?;
inject_root_ssh_authorized_keys(root, None, "ssh-ed25519 ABCDE example@demo\n").unwrap();

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

#[test]
fn test_inject_root_ssh_dir() -> Result<()> {
let root = &cap_std_ext::cap_tempfile::TempDir::new(cap_std::ambient_authority())?;

root.create_dir("etc")?;
root.create_dir("root")?;
inject_root_ssh_authorized_keys(root, None, "ssh-ed25519 ABCDE example@demo\n").unwrap();

let content = root.read_to_string(format!("etc/tmpfiles.d/{ROOT_SSH_TMPFILE}"))?;
Expand Down

0 comments on commit bd69633

Please sign in to comment.