diff --git a/src/agent/Cargo.lock b/src/agent/Cargo.lock index fa8a6f392e..1bd9336229 100644 --- a/src/agent/Cargo.lock +++ b/src/agent/Cargo.lock @@ -2124,6 +2124,7 @@ dependencies = [ "cgroups-rs", "clap", "const_format", + "derivative", "futures", "image-rs", "ipnetwork", diff --git a/src/agent/Cargo.toml b/src/agent/Cargo.toml index be57aaab6d..2feb4c7c0e 100644 --- a/src/agent/Cargo.toml +++ b/src/agent/Cargo.toml @@ -25,6 +25,7 @@ kata-sys-util = { path = "../libs/kata-sys-util" } kata-types = { path = "../libs/kata-types" } const_format = "0.2.30" url = "2.2.2" +derivative = "2.2.0" # Async helpers async-trait = "0.1.42" diff --git a/src/agent/src/cdh.rs b/src/agent/src/cdh.rs new file mode 100644 index 0000000000..c82acdebcd --- /dev/null +++ b/src/agent/src/cdh.rs @@ -0,0 +1,66 @@ +// Copyright (c) 2023 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 +// + +// Confidential Data Hub client wrapper. +// Confidential Data Hub is a service running inside guest to provide resource related APIs. +// https://github.com/confidential-containers/guest-components/tree/main/confidential-data-hub + +use anyhow::{anyhow, Result}; +use protocols::{ + sealed_secret, sealed_secret_ttrpc_async, sealed_secret_ttrpc_async::SealedSecretServiceClient, +}; +const CDH_ADDR: &str = "unix:///run/confidential-containers/cdh.sock"; + +#[derive(Clone)] +pub struct CDHClient { + sealed_secret_client: SealedSecretServiceClient, +} + +impl CDHClient { + pub fn new() -> Result { + let c = ttrpc::asynchronous::Client::connect(CDH_ADDR)?; + let ssclient = sealed_secret_ttrpc_async::SealedSecretServiceClient::new(c); + Ok(CDHClient { + sealed_secret_client: ssclient, + }) + } + + pub async fn unseal_secret_async( + &self, + sealed: &str, + ) -> Result { + let secret = sealed + .strip_prefix("sealed.") + .ok_or(anyhow!("strip_prefix sealed. failed"))?; + let mut input = sealed_secret::UnsealSecretInput::new(); + input.set_secret(secret.into()); + let unseal = self + .sealed_secret_client + .unseal_secret( + ttrpc::context::with_timeout(50 * 1000 * 1000 * 1000), + &input, + ) + .await?; + Ok(unseal) + } + + pub async fn unseal_env(&self, env: &str) -> Result { + let (key, value) = env.split_once('=').unwrap(); + if value.starts_with("sealed.") { + let unsealed_value = self.unseal_secret_async(value).await; + match unsealed_value { + Ok(v) => { + let plain_env = + format!("{}={}", key, std::str::from_utf8(&v.plaintext).unwrap()); + return Ok(plain_env); + } + Err(e) => { + return Err(e); + } + }; + } + Ok((*env.to_owned()).to_string()) + } +} diff --git a/src/agent/src/main.rs b/src/agent/src/main.rs index 6d63ab428f..0761e230f3 100644 --- a/src/agent/src/main.rs +++ b/src/agent/src/main.rs @@ -37,6 +37,8 @@ use std::process::Command; use std::sync::Arc; use tracing::{instrument, span}; +#[cfg(feature = "confidential-data-hub")] +mod cdh; mod config; mod console; mod device; diff --git a/src/agent/src/rpc.rs b/src/agent/src/rpc.rs index 6db6bbcc0b..654edf1657 100644 --- a/src/agent/src/rpc.rs +++ b/src/agent/src/rpc.rs @@ -71,6 +71,7 @@ use crate::AGENT_CONFIG; use crate::trace_rpc_call; use crate::tracer::extract_carrier_from_ttrpc; +use derivative::Derivative; use opentelemetry::global; use tracing::span; use tracing_opentelemetry::OpenTelemetrySpanExt; @@ -89,6 +90,9 @@ use std::io::{BufRead, BufReader, Write}; use std::os::unix::fs::FileExt; use std::path::PathBuf; +#[cfg(feature = "sealed-secret")] +use crate::cdh::CDHClient; + pub const CONTAINER_BASE: &str = "/run/kata-containers"; const MODPROBE_PATH: &str = "/sbin/modprobe"; const CONFIG_JSON: &str = "config.json"; @@ -139,10 +143,14 @@ fn is_allowed(req: &impl MessageDyn) -> ttrpc::Result<()> { } } -#[derive(Clone, Debug)] +#[derive(Derivative)] +#[derivative(Clone, Debug)] pub struct AgentService { sandbox: Arc>, init_mode: bool, + #[derivative(Debug = "ignore")] + #[cfg(feature = "sealed-secret")] + cdh_client: Option, } // A container ID must match this regex: @@ -201,6 +209,25 @@ impl AgentService { // cannot predict everything from the caller. add_devices(&req.devices, &mut oci, &self.sandbox).await?; + if cfg!(feature = "sealed-secret") { + let process = oci + .process + .as_mut() + .ok_or_else(|| anyhow!("Spec didn't contain process field"))?; + + for env in process.env.iter_mut() { + let client = self + .cdh_client + .as_ref() + .ok_or(anyhow!("get cdh_client failed"))?; + let unsealed_env = client + .unseal_env(env) + .await + .map_err(|e| anyhow!("unseal env failed: {:?}", e))?; + *env = unsealed_env.to_string(); + } + } + let linux = oci .linux .as_mut() @@ -1697,6 +1724,8 @@ pub async fn start( let agent_service = Box::new(AgentService { sandbox: s.clone(), init_mode, + #[cfg(feature = "sealed-secret")] + cdh_client: Some(CDHClient::new()?), }) as Box; let aservice = agent_ttrpc::create_agent_service(Arc::new(agent_service)); @@ -2226,7 +2255,6 @@ mod tests { async fn test_update_routes() { let logger = slog::Logger::root(slog::Discard, o!()); let sandbox = Sandbox::new(&logger).unwrap(); - let agent_service = Box::new(AgentService { sandbox: Arc::new(Mutex::new(sandbox)), init_mode: true, @@ -2244,7 +2272,6 @@ mod tests { async fn test_add_arp_neighbors() { let logger = slog::Logger::root(slog::Discard, o!()); let sandbox = Sandbox::new(&logger).unwrap(); - let agent_service = Box::new(AgentService { sandbox: Arc::new(Mutex::new(sandbox)), init_mode: true,