88// and filesystem setup.
99pub ( crate ) mod baseline;
1010pub ( crate ) mod config;
11+ pub ( crate ) mod osconfig;
1112
1213use std:: io:: BufWriter ;
1314use std:: io:: Write ;
@@ -132,6 +133,16 @@ pub(crate) struct InstallConfigOpts {
132133 /// Add a kernel argument
133134 karg : Option < Vec < String > > ,
134135
136+ /// The path to an `authorized_keys` that will be injected into the `root` account.
137+ ///
138+ /// The implementation of this uses systemd `tmpfiles.d`, writing to a file named
139+ /// `/etc/tmpfiles.d/bootc-root-ssh.conf`. This will have the effect that by default,
140+ /// the SSH credentials will be set if not present. The intention behind this
141+ /// is to allow mounting the whole `/root` home directory as a `tmpfs`, while still
142+ /// getting the SSH key replaced on boot.
143+ #[ clap( long) ]
144+ root_ssh_authorized_keys : Option < Utf8PathBuf > ,
145+
135146 /// Perform configuration changes suitable for a "generic" disk image.
136147 /// At the moment:
137148 ///
@@ -261,6 +272,8 @@ pub(crate) struct State {
261272 pub ( crate ) config_opts : InstallConfigOpts ,
262273 pub ( crate ) target_imgref : ostree_container:: OstreeImageReference ,
263274 pub ( crate ) install_config : config:: InstallConfiguration ,
275+ /// The parsed contents of the authorized_keys (not the file path)
276+ pub ( crate ) root_ssh_authorized_keys : Option < String > ,
264277}
265278
266279impl State {
@@ -566,9 +579,9 @@ async fn initialize_ostree_root_from_self(
566579 options. proxy_cfg = proxy_cfg;
567580 println ! ( "Creating initial deployment" ) ;
568581 let target_image = state. target_imgref . to_string ( ) ;
569- let state =
582+ let imgstate =
570583 ostree_container:: deploy:: deploy ( & sysroot, stateroot, & src_imageref, Some ( options) ) . await ?;
571- let digest = state . manifest_digest . as_str ( ) ;
584+ let digest = imgstate . manifest_digest . as_str ( ) ;
572585 println ! ( "Installed: {target_image}" ) ;
573586 println ! ( " Digest: {digest}" ) ;
574587
@@ -596,9 +609,13 @@ async fn initialize_ostree_root_from_self(
596609 }
597610 f. flush ( ) ?;
598611
612+ if let Some ( contents) = state. root_ssh_authorized_keys . as_deref ( ) {
613+ osconfig:: inject_root_ssh_authorized_keys ( & root, contents) ?;
614+ }
615+
599616 let uname = rustix:: system:: uname ( ) ;
600617
601- let labels = crate :: status:: labels_of_config ( & state . configuration ) ;
618+ let labels = crate :: status:: labels_of_config ( & imgstate . configuration ) ;
602619 let timestamp = labels
603620 . and_then ( |l| {
604621 l. get ( oci_spec:: image:: ANNOTATION_CREATED )
@@ -607,7 +624,7 @@ async fn initialize_ostree_root_from_self(
607624 . and_then ( crate :: status:: try_deserialize_timestamp) ;
608625 let aleph = InstallAleph {
609626 image : src_imageref. imgref . name . clone ( ) ,
610- version : state . version ( ) . as_ref ( ) . map ( |s| s. to_string ( ) ) ,
627+ version : imgstate . version ( ) . as_ref ( ) . map ( |s| s. to_string ( ) ) ,
611628 timestamp,
612629 kernel : uname. release ( ) . to_str ( ) ?. to_string ( ) ,
613630 } ;
@@ -944,6 +961,14 @@ async fn prepare_install(
944961 let install_config = config:: load_config ( ) ?;
945962 tracing:: debug!( "Loaded install configuration" ) ;
946963
964+ // Eagerly read the file now to ensure we error out early if e.g. it doesn't exist,
965+ // instead of much later after we're 80% of the way through an install.
966+ let root_ssh_authorized_keys = config_opts
967+ . root_ssh_authorized_keys
968+ . as_ref ( )
969+ . map ( |p| std:: fs:: read_to_string ( p) . with_context ( || format ! ( "Reading {p}" ) ) )
970+ . transpose ( ) ?;
971+
947972 // Create our global (read-only) state which gets wrapped in an Arc
948973 // so we can pass it to worker threads too. Right now this just
949974 // combines our command line options along with some bind mounts from the host.
@@ -954,6 +979,7 @@ async fn prepare_install(
954979 config_opts,
955980 target_imgref,
956981 install_config,
982+ root_ssh_authorized_keys,
957983 } ) ;
958984
959985 Ok ( state)
0 commit comments