@@ -9,13 +9,15 @@ pub mod ingress;
99pub mod kms_proxy;
1010pub mod launcher;
1111
12- use anyhow:: Result ;
12+ use anyhow:: { anyhow , Context , Result } ;
1313use clap:: Parser ;
14- use log:: { error, info} ;
14+ use log:: { error, info, warn} ;
15+ use std:: collections:: HashMap ;
1516use std:: ffi:: OsString ;
1617use std:: sync:: Arc ;
18+ use tokio:: time;
1719
18- use enclaver:: constants:: { APP_LOG_PORT , STATUS_PORT } ;
20+ use enclaver:: constants:: { APP_LOG_PORT , ENV_SYNC_PORT , STATUS_PORT } ;
1921use enclaver:: nsm:: Nsm ;
2022
2123use api:: ApiService ;
@@ -25,6 +27,8 @@ use egress::EgressService;
2527use ingress:: IngressService ;
2628use kms_proxy:: KmsProxyService ;
2729
30+ const ENV_SYNC_TIMEOUT : time:: Duration = time:: Duration :: from_secs ( 10 ) ;
31+
2832#[ derive( Parser ) ]
2933struct CliArgs {
3034 #[ clap( long = "no-bootstrap" , action) ]
@@ -57,11 +61,12 @@ async fn launch(args: &CliArgs) -> Result<launcher::ExitStatus> {
5761 let ingress = IngressService :: start ( & config) ?;
5862 let kms_proxy = KmsProxyService :: start ( config. clone ( ) , nsm. clone ( ) ) . await ?;
5963 let api = ApiService :: start ( & config, nsm. clone ( ) ) . await ?;
64+ let env = sync_environment ( & config) . await ?;
6065
6166 let creds = launcher:: Credentials { uid : 0 , gid : 0 } ;
6267
6368 info ! ( "Starting {:?}" , args. entrypoint) ;
64- let exit_status = launcher:: start_child ( args. entrypoint . clone ( ) , creds) . await ??;
69+ let exit_status = launcher:: start_child ( args. entrypoint . clone ( ) , creds, env ) . await ??;
6570 info ! ( "Entrypoint {}" , exit_status) ;
6671
6772 api. stop ( ) . await ;
@@ -72,6 +77,69 @@ async fn launch(args: &CliArgs) -> Result<launcher::ExitStatus> {
7277 Ok ( exit_status)
7378}
7479
80+ async fn sync_environment ( config : & Configuration ) -> Result < HashMap < String , String > > {
81+ use futures:: stream:: StreamExt ;
82+ use tokio:: io:: AsyncReadExt ;
83+
84+ let mut env: HashMap < String , String > = HashMap :: new ( ) ;
85+
86+ if let Some ( ref keys) = config. manifest . env {
87+ if !keys. is_empty ( ) {
88+ info ! ( "Starting the environment sync" ) ;
89+
90+ let mut incoming = enclaver:: vsock:: serve ( ENV_SYNC_PORT ) ?;
91+
92+ match time:: timeout ( ENV_SYNC_TIMEOUT , incoming. next ( ) ) . await {
93+ Ok ( Some ( mut sock) ) => {
94+ let mut env_buf: Vec < u8 > = Vec :: new ( ) ;
95+ let mut read_buf = vec ! [ 0u8 ; 1024 ] ;
96+ const ARG_MAX : usize = 128 * 1024 ;
97+
98+ loop {
99+ match time:: timeout ( ENV_SYNC_TIMEOUT , sock. read ( & mut read_buf) ) . await {
100+ Ok ( Ok ( 0 ) ) => break ,
101+ Ok ( Ok ( n) ) => {
102+ if env_buf. len ( ) + n > ARG_MAX {
103+ return Err ( anyhow ! ( "Maximum environment size exceeded" ) ) ;
104+ }
105+ env_buf. extend_from_slice ( & read_buf[ ..n] ) ;
106+ }
107+ Ok ( Err ( err) ) => {
108+ return Err ( anyhow ! ( "Error reading environment: {:#}" , err) )
109+ }
110+ Err ( _) => return Err ( anyhow ! ( "Timed out while reading environment" ) ) ,
111+ }
112+ }
113+
114+ let mut synced_env: HashMap < String , String > = serde_json:: from_slice ( & env_buf)
115+ . context ( "Failed to parse the synced environment" ) ?;
116+
117+ for k in keys. iter ( ) {
118+ if let Some ( v) = synced_env. remove ( k) {
119+ info ! ( "Syncing environment variable: {}" , k) ;
120+ env. insert ( k. clone ( ) , v) ;
121+ }
122+ }
123+ }
124+ Ok ( None ) => {
125+ return Err ( anyhow ! (
126+ "Failed to accept environment sync vsock connection"
127+ ) ) ;
128+ }
129+ Err ( _) => {
130+ return Err ( anyhow ! ( "Timed out while waiting for environment sync" ) ) ;
131+ }
132+ }
133+
134+ info ! ( "Environment sync complete" ) ;
135+ } else {
136+ warn ! ( "The list of environment keys in the manifest is empty, skipping the sync" ) ;
137+ }
138+ }
139+
140+ Ok ( env)
141+ }
142+
75143async fn run ( args : & CliArgs ) -> Result < ( ) > {
76144 // Start the status and logs listeners ASAP so that if we fail to
77145 // initialize, we can communicate the status and stream the logs
0 commit comments