From 9a13ca457e72edc08482d700c8eaca852d934443 Mon Sep 17 00:00:00 2001 From: Terence Lee Date: Thu, 9 Apr 2026 15:39:19 -0500 Subject: [PATCH] system-reinstall-bootc: SSH key handling via cloud-init detection If cloud-init is detected in the target image: 1. Check the host for existing root SSH keys at /root/.ssh/authorized_keys. 2. If host keys exist, automatically configure inheritance via /target/root/.ssh/authorized_keys. 3. If no host keys exist, proceed without manual interaction, trusting cloud-init in the new system to handle key provisioning. If cloud-init is not detected, maintain the existinginteractive behavior to prevent user lock-out. Ref: #1300 Signed-off-by: Terence Lee --- crates/system-reinstall-bootc/src/main.rs | 32 ++++++++++++++----- crates/system-reinstall-bootc/src/podman.rs | 35 ++++++++++++++++----- 2 files changed, 52 insertions(+), 15 deletions(-) diff --git a/crates/system-reinstall-bootc/src/main.rs b/crates/system-reinstall-bootc/src/main.rs index d4626456c..042fe6a5b 100644 --- a/crates/system-reinstall-bootc/src/main.rs +++ b/crates/system-reinstall-bootc/src/main.rs @@ -73,20 +73,36 @@ fn run() -> Result<()> { let has_clean = podman::bootc_has_clean(&opts.image)?; spinner.finish_and_clear(); - let ssh_key_file = tempfile::NamedTempFile::new()?; - let ssh_key_file_path = ssh_key_file - .path() - .to_str() - .ok_or_else(|| anyhow::anyhow!("unable to create authorized_key temp file"))?; + let mut _ssh_key_tempfile = None; + let mut ssh_key_file_path = None; + + if podman::image_has_cloud_init(&opts.image)? { + let host_root_keys = std::path::Path::new("/root/.ssh/authorized_keys"); + if host_root_keys.exists() { + println!("Detected cloud-init and host keys. Inheriting keys automatically."); + ssh_key_file_path = Some(host_root_keys.to_string_lossy().into_owned()); + } else { + println!("Detected cloud-init. Proceeding without host key inheritance."); + } + } else { + let file = tempfile::NamedTempFile::new()?; + let file_path = file + .path() + .to_str() + .ok_or_else(|| anyhow::anyhow!("unable to create authorized_key temp file"))?; + + tracing::trace!("ssh_key_file_path: {}", file_path); - tracing::trace!("ssh_key_file_path: {}", ssh_key_file_path); + prompt::get_ssh_keys(file_path)?; - prompt::get_ssh_keys(ssh_key_file_path)?; + ssh_key_file_path = Some(file_path.to_string()); + _ssh_key_tempfile = Some(file); + } prompt::mount_warning()?; let mut reinstall_podman_command = - podman::reinstall_command(&opts, ssh_key_file_path, has_clean)?; + podman::reinstall_command(&opts, ssh_key_file_path.as_deref(), has_clean)?; println!(); println!("Going to run command:"); diff --git a/crates/system-reinstall-bootc/src/podman.rs b/crates/system-reinstall-bootc/src/podman.rs index 7a9e104f8..e2e1b3a1b 100644 --- a/crates/system-reinstall-bootc/src/podman.rs +++ b/crates/system-reinstall-bootc/src/podman.rs @@ -1,7 +1,7 @@ -use crate::{ReinstallOpts, prompt}; +use crate::{prompt, ReinstallOpts}; use super::ROOT_KEY_MOUNT_POINT; -use anyhow::{Context, Result, ensure}; +use anyhow::{ensure, Context, Result}; use bootc_utils::CommandRunExt; use fn_error_context::context; use std::process::Command; @@ -24,10 +24,29 @@ pub(crate) fn bootc_has_clean(image: &str) -> Result { Ok(stdout_str.contains("--cleanup")) } +#[context("image_has_cloud_init")] +pub(crate) fn image_has_cloud_init(image: &str) -> Result { + let result = Command::new("podman") + .args([ + "run", + "--rm", + "--entrypoint", + "sh", + image, + "-c", + "command -v cloud-init", + ]) + .stdout(std::process::Stdio::null()) + .stderr(std::process::Stdio::null()) + .status()?; + + Ok(result.success()) +} + #[context("reinstall_command")] pub(crate) fn reinstall_command( opts: &ReinstallOpts, - ssh_key_file: &str, + ssh_key_file: Option<&str>, has_clean: bool, ) -> Result { let mut podman_command_and_args = [ @@ -88,11 +107,13 @@ pub(crate) fn reinstall_command( bootc_command_and_args.push("--cleanup".to_string()); } - podman_command_and_args.push("-v".to_string()); - podman_command_and_args.push(format!("{ssh_key_file}:{ROOT_KEY_MOUNT_POINT}")); + if let Some(ssh_key_file) = ssh_key_file { + podman_command_and_args.push("-v".to_string()); + podman_command_and_args.push(format!("{ssh_key_file}:{ROOT_KEY_MOUNT_POINT}")); - bootc_command_and_args.push("--root-ssh-authorized-keys".to_string()); - bootc_command_and_args.push(ROOT_KEY_MOUNT_POINT.to_string()); + bootc_command_and_args.push("--root-ssh-authorized-keys".to_string()); + bootc_command_and_args.push(ROOT_KEY_MOUNT_POINT.to_string()); + } let all_args = [ podman_command_and_args,