mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-08-23 18:21:27 +00:00
Agent: Attestation Agent Integration
Pull an encrypted image using the Attestation Agent as a keyprovider. Fixes: #3022 Signed-off-by: Tobin Feldman-Fitzthum <tobin@linux.ibm.com> Co-authored-by: Jakob Naucke <jakob.naucke@ibm.com>
This commit is contained in:
parent
27c0dc260c
commit
7c41af4082
@ -83,6 +83,7 @@ pub struct AgentConfig {
|
|||||||
pub endpoints: AgentEndpoints,
|
pub endpoints: AgentEndpoints,
|
||||||
pub supports_seccomp: bool,
|
pub supports_seccomp: bool,
|
||||||
pub container_policy_path: String,
|
pub container_policy_path: String,
|
||||||
|
pub aa_kbc_params: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
@ -99,6 +100,7 @@ pub struct AgentConfigBuilder {
|
|||||||
pub tracing: Option<bool>,
|
pub tracing: Option<bool>,
|
||||||
pub endpoints: Option<EndpointsConfig>,
|
pub endpoints: Option<EndpointsConfig>,
|
||||||
pub container_policy_path: Option<String>,
|
pub container_policy_path: Option<String>,
|
||||||
|
pub aa_kbc_params: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! config_override {
|
macro_rules! config_override {
|
||||||
@ -161,6 +163,7 @@ impl Default for AgentConfig {
|
|||||||
endpoints: Default::default(),
|
endpoints: Default::default(),
|
||||||
supports_seccomp: rpc::have_seccomp(),
|
supports_seccomp: rpc::have_seccomp(),
|
||||||
container_policy_path: String::from(""),
|
container_policy_path: String::from(""),
|
||||||
|
aa_kbc_params: String::from(""),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -190,6 +193,7 @@ impl FromStr for AgentConfig {
|
|||||||
config_override!(agent_config_builder, agent_config, unified_cgroup_hierarchy);
|
config_override!(agent_config_builder, agent_config, unified_cgroup_hierarchy);
|
||||||
config_override!(agent_config_builder, agent_config, tracing);
|
config_override!(agent_config_builder, agent_config, tracing);
|
||||||
config_override!(agent_config_builder, agent_config, container_policy_path);
|
config_override!(agent_config_builder, agent_config, container_policy_path);
|
||||||
|
config_override!(agent_config_builder, agent_config, aa_kbc_params);
|
||||||
|
|
||||||
// Populate the allowed endpoints hash set, if we got any from the config file.
|
// Populate the allowed endpoints hash set, if we got any from the config file.
|
||||||
if let Some(endpoints) = agent_config_builder.endpoints {
|
if let Some(endpoints) = agent_config_builder.endpoints {
|
||||||
|
@ -4,8 +4,10 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::io::Write;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::{Command, ExitStatus};
|
use std::process::{Command, ExitStatus};
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::{anyhow, ensure, Result};
|
use anyhow::{anyhow, ensure, Result};
|
||||||
@ -21,6 +23,9 @@ use crate::AGENT_CONFIG;
|
|||||||
const SKOPEO_PATH: &str = "/usr/bin/skopeo";
|
const SKOPEO_PATH: &str = "/usr/bin/skopeo";
|
||||||
const UMOCI_PATH: &str = "/usr/local/bin/umoci";
|
const UMOCI_PATH: &str = "/usr/local/bin/umoci";
|
||||||
const IMAGE_OCI: &str = "image_oci:latest";
|
const IMAGE_OCI: &str = "image_oci:latest";
|
||||||
|
const AA_PATH: &str = "/usr/local/bin/attestation-agent";
|
||||||
|
const AA_PORT: &str = "127.0.0.1:50000";
|
||||||
|
const OCICRYPT_CONFIG_PATH: &str = "/tmp/ocicrypt_config.json";
|
||||||
|
|
||||||
// Convenience macro to obtain the scope logger
|
// Convenience macro to obtain the scope logger
|
||||||
macro_rules! sl {
|
macro_rules! sl {
|
||||||
@ -31,11 +36,15 @@ macro_rules! sl {
|
|||||||
|
|
||||||
pub struct ImageService {
|
pub struct ImageService {
|
||||||
sandbox: Arc<Mutex<Sandbox>>,
|
sandbox: Arc<Mutex<Sandbox>>,
|
||||||
|
attestation_agent_started: AtomicBool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ImageService {
|
impl ImageService {
|
||||||
pub fn new(sandbox: Arc<Mutex<Sandbox>>) -> Self {
|
pub fn new(sandbox: Arc<Mutex<Sandbox>>) -> Self {
|
||||||
Self { sandbox }
|
Self {
|
||||||
|
sandbox,
|
||||||
|
attestation_agent_started: AtomicBool::new(false),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pull_image_from_registry(
|
fn pull_image_from_registry(
|
||||||
@ -43,6 +52,7 @@ impl ImageService {
|
|||||||
cid: &str,
|
cid: &str,
|
||||||
source_creds: &Option<&str>,
|
source_creds: &Option<&str>,
|
||||||
policy_path: &Option<&String>,
|
policy_path: &Option<&String>,
|
||||||
|
aa_kbc_params: &str,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let source_image = format!("{}{}", "docker://", image);
|
let source_image = format!("{}{}", "docker://", image);
|
||||||
|
|
||||||
@ -78,6 +88,15 @@ impl ImageService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
debug!(sl!(), "skopeo command: {:?}", &pull_command);
|
debug!(sl!(), "skopeo command: {:?}", &pull_command);
|
||||||
|
if !aa_kbc_params.is_empty() {
|
||||||
|
// Skopeo will copy an unencrypted image even if the decryption key argument is provided.
|
||||||
|
// Thus, this does not guarantee that the image was encrypted.
|
||||||
|
pull_command
|
||||||
|
.arg("--decryption-key")
|
||||||
|
.arg(format!("provider:attestation-agent:{}", aa_kbc_params))
|
||||||
|
.env("OCICRYPT_KEYPROVIDER_CONFIG", OCICRYPT_CONFIG_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
let status: ExitStatus = pull_command.status()?;
|
let status: ExitStatus = pull_command.status()?;
|
||||||
|
|
||||||
if !status.success() {
|
if !status.success() {
|
||||||
@ -118,10 +137,40 @@ impl ImageService {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we fail to start the AA, Skopeo/ocicrypt won't be able to unwrap keys
|
||||||
|
// and container decryption will fail.
|
||||||
|
fn init_attestation_agent() {
|
||||||
|
let config_path = OCICRYPT_CONFIG_PATH;
|
||||||
|
|
||||||
|
// The image will need to be encrypted using a keyprovider
|
||||||
|
// that has the same name (at least according to the config).
|
||||||
|
let ocicrypt_config = serde_json::json!({
|
||||||
|
"key-providers": {
|
||||||
|
"attestation-agent":{
|
||||||
|
"grpc":AA_PORT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut config_file = fs::File::create(config_path).unwrap();
|
||||||
|
config_file
|
||||||
|
.write_all(ocicrypt_config.to_string().as_bytes())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// The Attestation Agent will run for the duration of the guest.
|
||||||
|
Command::new(AA_PATH)
|
||||||
|
.arg("--grpc_sock")
|
||||||
|
.arg(AA_PORT)
|
||||||
|
.spawn()
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
async fn pull_image(&self, req: &image::PullImageRequest) -> Result<String> {
|
async fn pull_image(&self, req: &image::PullImageRequest) -> Result<String> {
|
||||||
let image = req.get_image();
|
let image = req.get_image();
|
||||||
let mut cid = req.get_container_id();
|
let mut cid = req.get_container_id();
|
||||||
|
|
||||||
|
let aa_kbc_params = &AGENT_CONFIG.read().await.aa_kbc_params;
|
||||||
|
|
||||||
if cid.is_empty() {
|
if cid.is_empty() {
|
||||||
let v: Vec<&str> = image.rsplit('/').collect();
|
let v: Vec<&str> = image.rsplit('/').collect();
|
||||||
if !v[0].is_empty() {
|
if !v[0].is_empty() {
|
||||||
@ -133,6 +182,18 @@ impl ImageService {
|
|||||||
verify_cid(cid)?;
|
verify_cid(cid)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !aa_kbc_params.is_empty() {
|
||||||
|
match self.attestation_agent_started.compare_exchange_weak(
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
Ordering::SeqCst,
|
||||||
|
Ordering::SeqCst,
|
||||||
|
) {
|
||||||
|
Ok(_) => Self::init_attestation_agent(),
|
||||||
|
Err(_) => info!(sl!(), "Attestation Agent already running"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let source_creds = (!req.get_source_creds().is_empty()).then(|| req.get_source_creds());
|
let source_creds = (!req.get_source_creds().is_empty()).then(|| req.get_source_creds());
|
||||||
|
|
||||||
// Read the policy path from the agent config
|
// Read the policy path from the agent config
|
||||||
@ -140,7 +201,7 @@ impl ImageService {
|
|||||||
let policy_path = (!config_policy_path.is_empty()).then(|| config_policy_path);
|
let policy_path = (!config_policy_path.is_empty()).then(|| config_policy_path);
|
||||||
info!(sl!(), "Using container policy_path: {:?}...", &policy_path);
|
info!(sl!(), "Using container policy_path: {:?}...", &policy_path);
|
||||||
|
|
||||||
Self::pull_image_from_registry(image, cid, &source_creds, &policy_path)?;
|
Self::pull_image_from_registry(image, cid, &source_creds, &policy_path, aa_kbc_params)?;
|
||||||
Self::unpack_image(cid)?;
|
Self::unpack_image(cid)?;
|
||||||
|
|
||||||
let mut sandbox = self.sandbox.lock().await;
|
let mut sandbox = self.sandbox.lock().await;
|
||||||
|
Loading…
Reference in New Issue
Block a user