mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-08-31 08:28:34 +00:00
agent: Remove skopeo & umoci
Remove code paths that use skopeo to pull images & umoci to unpack them Fixes: #3970 Signed-off-by: stevenhorsman <steven@uk.ibm.com>
This commit is contained in:
@@ -1,17 +1,18 @@
|
|||||||
// Copyright (c) 2021 Alibaba Cloud
|
// Copyright (c) 2021 Alibaba Cloud
|
||||||
|
// Copyright (c) 2021, 2023 IBM Corporation
|
||||||
|
// Copyright (c) 2022 Intel Corporation
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
//
|
//
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fmt::Write as _;
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::{Command, ExitStatus};
|
use std::process::Command;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::{anyhow, ensure, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use protocols::image;
|
use protocols::image;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
@@ -24,9 +25,6 @@ use crate::AGENT_CONFIG;
|
|||||||
use image_rs::image::ImageClient;
|
use image_rs::image::ImageClient;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
const SKOPEO_PATH: &str = "/usr/bin/skopeo";
|
|
||||||
const UMOCI_PATH: &str = "/usr/local/bin/umoci";
|
|
||||||
const IMAGE_OCI: &str = "image_oci";
|
|
||||||
const AA_PATH: &str = "/usr/local/bin/attestation-agent";
|
const AA_PATH: &str = "/usr/local/bin/attestation-agent";
|
||||||
const AA_KEYPROVIDER_PORT: &str = "127.0.0.1:50000";
|
const AA_KEYPROVIDER_PORT: &str = "127.0.0.1:50000";
|
||||||
const AA_GETRESOURCE_PORT: &str = "127.0.0.1:50001";
|
const AA_GETRESOURCE_PORT: &str = "127.0.0.1:50001";
|
||||||
@@ -59,95 +57,6 @@ impl ImageService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pull_image_from_registry(
|
|
||||||
image: &str,
|
|
||||||
cid: &str,
|
|
||||||
source_creds: Option<&str>,
|
|
||||||
policy_path: Option<&str>,
|
|
||||||
aa_kbc_params: &str,
|
|
||||||
) -> Result<()> {
|
|
||||||
let source_image = format!("{}{}", "docker://", image);
|
|
||||||
|
|
||||||
let tmp_cid_path = Path::new("/tmp/").join(cid);
|
|
||||||
let oci_path = tmp_cid_path.join(IMAGE_OCI);
|
|
||||||
let target_path_oci = format!("oci://{}:latest", oci_path.to_string_lossy());
|
|
||||||
|
|
||||||
fs::create_dir_all(&oci_path)?;
|
|
||||||
|
|
||||||
let mut pull_command = Command::new(SKOPEO_PATH);
|
|
||||||
pull_command
|
|
||||||
.arg("copy")
|
|
||||||
.arg(source_image)
|
|
||||||
.arg(&target_path_oci)
|
|
||||||
.arg("--remove-signatures"); //umoci requires signatures to be removed
|
|
||||||
|
|
||||||
// If source credentials were passed (so not using an anonymous registry), pass them through
|
|
||||||
if let Some(source_creds) = source_creds {
|
|
||||||
pull_command.arg("--src-creds").arg(source_creds);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a policy_path provided, use it, otherwise fall back to allow all image registries
|
|
||||||
if let Some(policy_path) = policy_path {
|
|
||||||
pull_command.arg("--policy").arg(policy_path);
|
|
||||||
} else {
|
|
||||||
info!(
|
|
||||||
sl!(),
|
|
||||||
"No policy path was supplied, so revert to allow all images to be pulled."
|
|
||||||
);
|
|
||||||
pull_command.arg("--insecure-policy");
|
|
||||||
}
|
|
||||||
|
|
||||||
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()?;
|
|
||||||
|
|
||||||
if !status.success() {
|
|
||||||
let mut error_message = format!("failed to pull image: {:?}", status);
|
|
||||||
|
|
||||||
if let Err(e) = fs::remove_dir_all(&tmp_cid_path) {
|
|
||||||
let _ = write!(
|
|
||||||
error_message,
|
|
||||||
" and clean up of temporary container directory {:?} failed with error {:?}",
|
|
||||||
tmp_cid_path, e
|
|
||||||
);
|
|
||||||
};
|
|
||||||
return Err(anyhow!(error_message));
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unpack_image(cid: &str) -> Result<()> {
|
|
||||||
let tmp_cid_path = Path::new("/tmp/").join(cid);
|
|
||||||
let source_path_oci = tmp_cid_path.join(IMAGE_OCI);
|
|
||||||
|
|
||||||
let target_path_bundle = Path::new(CONTAINER_BASE).join(cid);
|
|
||||||
|
|
||||||
info!(sl!(), "unpack image {:?} to {:?}", cid, target_path_bundle);
|
|
||||||
|
|
||||||
// Unpack image
|
|
||||||
let status: ExitStatus = Command::new(UMOCI_PATH)
|
|
||||||
.arg("unpack")
|
|
||||||
.arg("--image")
|
|
||||||
.arg(&source_path_oci)
|
|
||||||
.arg(&target_path_bundle)
|
|
||||||
.status()?;
|
|
||||||
|
|
||||||
ensure!(status.success(), "failed to unpack image: {:?}", status);
|
|
||||||
|
|
||||||
// To save space delete the oci image after unpack
|
|
||||||
fs::remove_dir_all(&tmp_cid_path)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// pause image is packaged in rootfs for CC
|
// pause image is packaged in rootfs for CC
|
||||||
fn unpack_pause_image(cid: &str) -> Result<()> {
|
fn unpack_pause_image(cid: &str) -> Result<()> {
|
||||||
let cc_pause_bundle = Path::new(KATA_CC_PAUSE_BUNDLE);
|
let cc_pause_bundle = Path::new(KATA_CC_PAUSE_BUNDLE);
|
||||||
@@ -174,7 +83,7 @@ impl ImageService {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we fail to start the AA, Skopeo/ocicrypt won't be able to unwrap keys
|
// If we fail to start the AA, ocicrypt won't be able to unwrap keys
|
||||||
// and container decryption will fail.
|
// and container decryption will fail.
|
||||||
fn init_attestation_agent() -> Result<()> {
|
fn init_attestation_agent() -> Result<()> {
|
||||||
let config_path = OCICRYPT_CONFIG_PATH;
|
let config_path = OCICRYPT_CONFIG_PATH;
|
||||||
@@ -211,7 +120,7 @@ impl ImageService {
|
|||||||
let cid = if !req_cid.is_empty() {
|
let cid = if !req_cid.is_empty() {
|
||||||
req_cid.to_string()
|
req_cid.to_string()
|
||||||
} else if let Some(last) = req.get_image().rsplit('/').next() {
|
} else if let Some(last) = req.get_image().rsplit('/').next() {
|
||||||
// ':' have special meaning for umoci during upack
|
// ':' not valid for container id
|
||||||
last.replace(':', "_")
|
last.replace(':', "_")
|
||||||
} else {
|
} else {
|
||||||
return Err(anyhow!("Invalid image name. {}", req.get_image()));
|
return Err(anyhow!("Invalid image name. {}", req.get_image()));
|
||||||
@@ -235,9 +144,7 @@ impl ImageService {
|
|||||||
|
|
||||||
let cid = Self::cid_from_request(req)?;
|
let cid = Self::cid_from_request(req)?;
|
||||||
let image = req.get_image();
|
let image = req.get_image();
|
||||||
// Can switch to use cid directly when we remove umoci
|
if cid.starts_with("pause") {
|
||||||
let v: Vec<&str> = image.rsplit('/').collect();
|
|
||||||
if !v[0].is_empty() && v[0].starts_with("pause:") {
|
|
||||||
Self::unpack_pause_image(&cid)?;
|
Self::unpack_pause_image(&cid)?;
|
||||||
|
|
||||||
let mut sandbox = self.sandbox.lock().await;
|
let mut sandbox = self.sandbox.lock().await;
|
||||||
@@ -257,72 +164,58 @@ impl ImageService {
|
|||||||
Err(_) => info!(sl!(), "Attestation Agent already running"),
|
Err(_) => info!(sl!(), "Attestation Agent already running"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// If the attestation-agent is being used, then enable the authenticated credentials support
|
||||||
|
info!(
|
||||||
|
sl!(),
|
||||||
|
"image_client.config.auth set to: {}",
|
||||||
|
!aa_kbc_params.is_empty()
|
||||||
|
);
|
||||||
|
self.image_client.lock().await.config.auth = !aa_kbc_params.is_empty();
|
||||||
|
|
||||||
|
// Read enable signature verification from the agent config and set it in the image_client
|
||||||
|
let enable_signature_verification =
|
||||||
|
&AGENT_CONFIG.read().await.enable_signature_verification;
|
||||||
|
info!(
|
||||||
|
sl!(),
|
||||||
|
"enable_signature_verification set to: {}", enable_signature_verification
|
||||||
|
);
|
||||||
|
self.image_client.lock().await.config.security_validate = *enable_signature_verification;
|
||||||
|
|
||||||
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());
|
||||||
|
|
||||||
if Path::new(SKOPEO_PATH).exists() {
|
let bundle_path = Path::new(CONTAINER_BASE).join(&cid);
|
||||||
// Read the policy path from the agent config
|
fs::create_dir_all(&bundle_path)?;
|
||||||
let config_policy_path = &AGENT_CONFIG.read().await.container_policy_path;
|
|
||||||
let policy_path =
|
|
||||||
(!config_policy_path.is_empty()).then_some(config_policy_path.as_str());
|
|
||||||
Self::pull_image_from_registry(image, &cid, source_creds, policy_path, aa_kbc_params)?;
|
|
||||||
Self::unpack_image(&cid)?;
|
|
||||||
} else {
|
|
||||||
// Read enable signature verification from the agent config and set it in the image_client
|
|
||||||
let enable_signature_verification =
|
|
||||||
&AGENT_CONFIG.read().await.enable_signature_verification;
|
|
||||||
info!(
|
|
||||||
sl!(),
|
|
||||||
"enable_signature_verification set to: {}", enable_signature_verification
|
|
||||||
);
|
|
||||||
self.image_client.lock().await.config.security_validate =
|
|
||||||
*enable_signature_verification;
|
|
||||||
|
|
||||||
// If the attestation-agent is being used, then enable the authenticated credentials support
|
let decrypt_config = format!("provider:attestation-agent:{}", aa_kbc_params);
|
||||||
//TODO tidy logic once skopeo is removed to combine with aa_kbc_params check above
|
|
||||||
info!(
|
|
||||||
sl!(),
|
|
||||||
"image_client.config.auth set to: {}",
|
|
||||||
!aa_kbc_params.is_empty()
|
|
||||||
);
|
|
||||||
self.image_client.lock().await.config.auth = !aa_kbc_params.is_empty();
|
|
||||||
|
|
||||||
let bundle_path = Path::new(CONTAINER_BASE).join(&cid);
|
info!(sl!(), "pull image {:?}, bundle path {:?}", cid, bundle_path);
|
||||||
fs::create_dir_all(&bundle_path)?;
|
// Image layers will store at KATA_CC_IMAGE_WORK_DIR, generated bundles
|
||||||
|
// with rootfs and config.json will store under CONTAINER_BASE/cid.
|
||||||
|
let res = self
|
||||||
|
.image_client
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.pull_image(image, &bundle_path, &source_creds, &Some(&decrypt_config))
|
||||||
|
.await;
|
||||||
|
|
||||||
let decrypt_config = format!("provider:attestation-agent:{}", aa_kbc_params);
|
match res {
|
||||||
|
Ok(image) => {
|
||||||
info!(sl!(), "pull image {:?}, bundle path {:?}", cid, bundle_path);
|
info!(
|
||||||
// Image layers will store at KATA_CC_IMAGE_WORK_DIR, generated bundles
|
sl!(),
|
||||||
// with rootfs and config.json will store under CONTAINER_BASE/cid.
|
"pull and unpack image {:?}, cid: {:?}, with image-rs succeed. ", image, cid
|
||||||
let res = self
|
);
|
||||||
.image_client
|
}
|
||||||
.lock()
|
Err(e) => {
|
||||||
.await
|
error!(
|
||||||
.pull_image(image, &bundle_path, &source_creds, &Some(&decrypt_config))
|
sl!(),
|
||||||
.await;
|
"pull and unpack image {:?}, cid: {:?}, with image-rs failed with {:?}. ",
|
||||||
|
image,
|
||||||
match res {
|
cid,
|
||||||
Ok(image) => {
|
e.to_string()
|
||||||
info!(
|
);
|
||||||
sl!(),
|
return Err(e);
|
||||||
"pull and unpack image {:?}, cid: {:?}, with image-rs succeed. ",
|
}
|
||||||
image,
|
};
|
||||||
cid
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
error!(
|
|
||||||
sl!(),
|
|
||||||
"pull and unpack image {:?}, cid: {:?}, with image-rs failed with {:?}. ",
|
|
||||||
image,
|
|
||||||
cid,
|
|
||||||
e.to_string()
|
|
||||||
);
|
|
||||||
return Err(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut sandbox = self.sandbox.lock().await;
|
let mut sandbox = self.sandbox.lock().await;
|
||||||
sandbox.images.insert(String::from(image), cid);
|
sandbox.images.insert(String::from(image), cid);
|
||||||
|
Reference in New Issue
Block a user