From 03d83914041fc8dc2bd7815414a619d94cbaf82c Mon Sep 17 00:00:00 2001 From: Xynnn007 Date: Mon, 24 Apr 2023 16:54:59 +0800 Subject: [PATCH] agent: add container launch control parameters from kernel commandline `image_policy_file` is the URI of the image security policy file which is used to control the allowlist and denylist of the containers to be run inside the guest. `image_registry_auth_file` is the URI of the auth file which is needed to access an private registry. `simple_signing_sigstore_config` is a configuration file that shows where the signature files are when simple signing is enabled. All the config items support both `kbs://..` scheme, `file://..` scheme, or a direct absolute path `/...`, which means either the file is to be fetched from a remote KBS that `aa_kbc_params` points to, or from the local filesystem of the guest. Fixes: #6640 Signed-off-by: Xynnn007 --- src/agent/src/config.rs | 109 +++++++++++++++++++++++++++++++++++++ src/agent/src/image_rpc.rs | 24 +++++++- src/agent/src/main.rs | 2 +- src/agent/src/rpc.rs | 10 +++- 4 files changed, 138 insertions(+), 7 deletions(-) diff --git a/src/agent/src/config.rs b/src/agent/src/config.rs index 72e1d7dfb4..803487cdb7 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 { @@ -337,6 +356,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) { @@ -518,6 +562,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] @@ -542,6 +589,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<'_> { @@ -563,6 +613,9 @@ mod tests { no_proxy: "", data_integrity: false, enable_signature_verification: true, + image_policy_file: "", + image_registry_auth_file: "", + simple_signing_sigstore_config: "", } } } @@ -1007,6 +1060,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"); @@ -1068,6 +1166,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 3ae36cae2f..e5df875e51 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 5c4c7d5764..7a7205e133 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 a30ecb3d8b..9c3e43a0f5 100644 --- a/src/agent/src/rpc.rs +++ b/src/agent/src/rpc.rs @@ -1820,7 +1820,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, @@ -1831,8 +1835,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);