diff --git a/src/agent/src/config.rs b/src/agent/src/config.rs index 8a299a2ae4..e9d1d75fdd 100644 --- a/src/agent/src/config.rs +++ b/src/agent/src/config.rs @@ -31,6 +31,9 @@ const HTTPS_PROXY: &str = "agent.https_proxy"; const NO_PROXY: &str = "agent.no_proxy"; const ENABLE_DATA_INTEGRITY: &str = "agent.data_integrity"; const ENABLE_SIGNATURE_VERIFICATION: &str = "agent.enable_signature_verification"; +const IMAGE_POLICY_FILE: &str = "agent.image_policy"; +const IMAGE_REGISTRY_AUTH_FILE: &str = "agent.image_registry_auth"; +const SIMPLE_SIGNING_SIGSTORE_CONFIG: &str = "agent.simple_signing_sigstore_config"; const DEFAULT_LOG_LEVEL: slog::Level = slog::Level::Info; const DEFAULT_HOTPLUG_TIMEOUT: time::Duration = time::Duration::from_secs(3); @@ -89,6 +92,9 @@ pub struct AgentConfig { pub no_proxy: String, pub data_integrity: bool, pub enable_signature_verification: bool, + pub image_policy_file: String, + pub image_registry_auth_file: String, + pub simple_signing_sigstore_config: String, } #[derive(Debug, Deserialize)] @@ -110,6 +116,9 @@ pub struct AgentConfigBuilder { pub no_proxy: Option, pub data_integrity: Option, pub enable_signature_verification: Option, + pub image_policy_file: Option, + pub image_registry_auth_file: Option, + pub simple_signing_sigstore_config: Option, } macro_rules! config_override { @@ -177,6 +186,9 @@ impl Default for AgentConfig { no_proxy: String::from(""), data_integrity: false, enable_signature_verification: true, + image_policy_file: String::from(""), + image_registry_auth_file: String::from(""), + simple_signing_sigstore_config: String::from(""), } } } @@ -215,6 +227,13 @@ impl FromStr for AgentConfig { agent_config, enable_signature_verification ); + config_override!(agent_config_builder, agent_config, image_policy_file); + config_override!(agent_config_builder, agent_config, image_registry_auth_file); + config_override!( + agent_config_builder, + agent_config, + simple_signing_sigstore_config + ); // Populate the allowed endpoints hash set, if we got any from the config file. if let Some(endpoints) = agent_config_builder.endpoints { @@ -339,6 +358,31 @@ impl AgentConfig { config.enable_signature_verification, get_bool_value ); + + // URI of the image security file + parse_cmdline_param!( + param, + IMAGE_POLICY_FILE, + config.image_policy_file, + get_string_value + ); + + // URI of the registry auth file + parse_cmdline_param!( + param, + IMAGE_REGISTRY_AUTH_FILE, + config.image_registry_auth_file, + get_string_value + ); + + // URI of the simple signing sigstore file + // used when simple signing verification is used + parse_cmdline_param!( + param, + SIMPLE_SIGNING_SIGSTORE_CONFIG, + config.simple_signing_sigstore_config, + get_string_value + ); } if let Ok(addr) = env::var(SERVER_ADDR_ENV_VAR) { @@ -521,6 +565,9 @@ mod tests { assert_eq!(config.hotplug_timeout, DEFAULT_HOTPLUG_TIMEOUT); assert_eq!(config.container_policy_path, ""); assert!(config.enable_signature_verification); + assert_eq!(config.image_policy_file, ""); + assert_eq!(config.image_registry_auth_file, ""); + assert_eq!(config.simple_signing_sigstore_config, ""); } #[test] @@ -545,6 +592,9 @@ mod tests { no_proxy: &'a str, data_integrity: bool, enable_signature_verification: bool, + image_policy_file: &'a str, + image_registry_auth_file: &'a str, + simple_signing_sigstore_config: &'a str, } impl Default for TestData<'_> { @@ -566,6 +616,9 @@ mod tests { no_proxy: "", data_integrity: false, enable_signature_verification: true, + image_policy_file: "", + image_registry_auth_file: "", + simple_signing_sigstore_config: "", } } } @@ -1010,6 +1063,51 @@ mod tests { enable_signature_verification: false, ..Default::default() }, + TestData { + contents: "agent.image_policy=file:///etc/policy.json", + image_policy_file: "file:///etc/policy.json", + ..Default::default() + }, + TestData { + contents: "agent.image_policy=kbs:///default/security-policy/test", + image_policy_file: "kbs:///default/security-policy/test", + ..Default::default() + }, + TestData { + contents: "agent.image_policy=kbs://example.kbs.org/default/security-policy/test", + image_policy_file: "kbs://example.kbs.org/default/security-policy/test", + ..Default::default() + }, + TestData { + contents: "agent.image_registry_auth=file:///etc/auth.json", + image_registry_auth_file: "file:///etc/auth.json", + ..Default::default() + }, + TestData { + contents: "agent.image_registry_auth=kbs:///default/credential/test", + image_registry_auth_file: "kbs:///default/credential/test", + ..Default::default() + }, + TestData { + contents: "agent.image_registry_auth=kbs://example.kbs.org/default/credential/test", + image_registry_auth_file: "kbs://example.kbs.org/default/credential/test", + ..Default::default() + }, + TestData { + contents: "agent.simple_signing_sigstore_config=file:///etc/containers/signature/default.yml", + simple_signing_sigstore_config: "file:///etc/containers/signature/default.yml", + ..Default::default() + }, + TestData { + contents: "agent.simple_signing_sigstore_config=kbs:///default/sigstore-config/test", + simple_signing_sigstore_config: "kbs:///default/sigstore-config/test", + ..Default::default() + }, + TestData { + contents: "agent.simple_signing_sigstore_config=kbs://example.kbs.org/default/sigstore-config/test", + simple_signing_sigstore_config: "kbs://example.kbs.org/default/sigstore-config/test", + ..Default::default() + }, ]; let dir = tempdir().expect("failed to create tmpdir"); @@ -1071,6 +1169,17 @@ mod tests { "{}", msg ); + assert_eq!(d.image_policy_file, config.image_policy_file, "{}", msg); + assert_eq!( + d.image_registry_auth_file, config.image_registry_auth_file, + "{}", + msg + ); + assert_eq!( + d.simple_signing_sigstore_config, config.simple_signing_sigstore_config, + "{}", + msg + ); for v in vars_to_unset { env::remove_var(v); diff --git a/src/agent/src/image_rpc.rs b/src/agent/src/image_rpc.rs index a5afc343dc..571994a0d1 100644 --- a/src/agent/src/image_rpc.rs +++ b/src/agent/src/image_rpc.rs @@ -53,12 +53,30 @@ pub struct ImageService { } impl ImageService { - pub fn new(sandbox: Arc>) -> Self { + pub async fn new(sandbox: Arc>) -> Self { env::set_var("CC_IMAGE_WORK_DIR", KATA_CC_IMAGE_WORK_DIR); + let mut image_client = ImageClient::default(); + + let image_policy_file = &AGENT_CONFIG.read().await.image_policy_file; + if !image_policy_file.is_empty() { + image_client.config.file_paths.sigstore_config = image_policy_file.clone(); + } + + let simple_signing_sigstore_config = + &AGENT_CONFIG.read().await.simple_signing_sigstore_config; + if !simple_signing_sigstore_config.is_empty() { + image_client.config.file_paths.sigstore_config = simple_signing_sigstore_config.clone(); + } + + let image_registry_auth_file = &AGENT_CONFIG.read().await.image_registry_auth_file; + if !image_registry_auth_file.is_empty() { + image_client.config.file_paths.auth_file = image_registry_auth_file.clone(); + } + Self { sandbox, attestation_agent_started: AtomicBool::new(false), - image_client: Arc::new(Mutex::new(ImageClient::default())), + image_client: Arc::new(Mutex::new(image_client)), container_count: Arc::new(AtomicU16::new(0)), } } @@ -333,7 +351,7 @@ mod tests { let logger = slog::Logger::root(slog::Discard, o!()); let s = Sandbox::new(&logger).unwrap(); - let image_service = ImageService::new(Arc::new(Mutex::new(s))); + let image_service = ImageService::new(Arc::new(Mutex::new(s))).await; for case in &cases { let mut req = image::PullImageRequest::new(); req.set_image(case.image.to_string()); diff --git a/src/agent/src/main.rs b/src/agent/src/main.rs index 598ce21a32..1b6b5fe423 100644 --- a/src/agent/src/main.rs +++ b/src/agent/src/main.rs @@ -346,7 +346,7 @@ async fn start_sandbox( sandbox.lock().await.sender = Some(tx); // vsock:///dev/vsock, port - let mut server = rpc::start(sandbox.clone(), config.server_addr.as_str(), init_mode)?; + let mut server = rpc::start(sandbox.clone(), config.server_addr.as_str(), init_mode).await?; server.start().await?; rx.await?; diff --git a/src/agent/src/rpc.rs b/src/agent/src/rpc.rs index 46c282bb9a..fd43baed11 100644 --- a/src/agent/src/rpc.rs +++ b/src/agent/src/rpc.rs @@ -1842,7 +1842,11 @@ async fn read_stream(reader: Arc>>, l: usize) -> Resu Ok(content) } -pub fn start(s: Arc>, server_address: &str, init_mode: bool) -> Result { +pub async fn start( + s: Arc>, + server_address: &str, + init_mode: bool, +) -> Result { let agent_service = Box::new(AgentService { sandbox: s.clone(), init_mode, @@ -1853,8 +1857,8 @@ pub fn start(s: Arc>, server_address: &str, init_mode: bool) -> R let health_service = Box::new(HealthService {}) as Box; let health_worker = Arc::new(health_service); - let image_service = - Box::new(image_rpc::ImageService::new(s)) as Box; + let image_service = Box::new(image_rpc::ImageService::new(s).await) + as Box; let aservice = agent_ttrpc::create_agent_service(agent_worker);