agent: Support https_proxy/no_proxy config for image download in guest

Containerd can support set a proxy when downloading images with a environment variable.
For CC stack, image download is offload to the kata agent, we need support similar feature.
Current we add https_proxy and no_proxy, http_proxy is not added since it is insecure.

Signed-off-by: ChengyuZhu6 <chengyu.zhu@intel.com>
Co-authored-by: Arron Wang <arron.wang@intel.com>
This commit is contained in:
ChengyuZhu6 2023-11-22 17:13:25 +08:00 committed by Fabiano Fidêncio
parent 9cddd5813c
commit cec1916196
No known key found for this signature in database
GPG Key ID: EE926C2BDACC177B
4 changed files with 77 additions and 16 deletions

25
src/agent/Cargo.lock generated
View File

@ -1353,11 +1353,10 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]] [[package]]
name = "form_urlencoded" name = "form_urlencoded"
version = "1.0.1" version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
dependencies = [ dependencies = [
"matches",
"percent-encoding", "percent-encoding",
] ]
@ -1746,11 +1745,10 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]] [[package]]
name = "idna" name = "idna"
version = "0.2.3" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
dependencies = [ dependencies = [
"matches",
"unicode-bidi", "unicode-bidi",
"unicode-normalization", "unicode-normalization",
] ]
@ -2047,6 +2045,7 @@ dependencies = [
"tracing-opentelemetry", "tracing-opentelemetry",
"tracing-subscriber", "tracing-subscriber",
"ttrpc", "ttrpc",
"url",
"vsock-exporter", "vsock-exporter",
"which", "which",
] ]
@ -2321,12 +2320,6 @@ dependencies = [
"regex-automata 0.1.10", "regex-automata 0.1.10",
] ]
[[package]]
name = "matches"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
[[package]] [[package]]
name = "matchit" name = "matchit"
version = "0.7.3" version = "0.7.3"
@ -2971,9 +2964,9 @@ dependencies = [
[[package]] [[package]]
name = "percent-encoding" name = "percent-encoding"
version = "2.1.0" version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]] [[package]]
name = "petgraph" name = "petgraph"
@ -5118,9 +5111,9 @@ dependencies = [
[[package]] [[package]]
name = "url" name = "url"
version = "2.3.0" version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22fe195a4f217c25b25cb5058ced57059824a678474874038dc88d211bf508d3" checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
dependencies = [ dependencies = [
"form_urlencoded", "form_urlencoded",
"idna", "idna",

View File

@ -22,6 +22,7 @@ thiserror = "1.0.26"
regex = "1.5.6" regex = "1.5.6"
serial_test = "0.5.1" serial_test = "0.5.1"
oci-distribution = "0.10.0" oci-distribution = "0.10.0"
url = "2.5.0"
kata-sys-util = { path = "../libs/kata-sys-util" } kata-sys-util = { path = "../libs/kata-sys-util" }
kata-types = { path = "../libs/kata-types" } kata-types = { path = "../libs/kata-types" }
safe-path = { path = "../libs/safe-path" } safe-path = { path = "../libs/safe-path" }

View File

@ -10,6 +10,7 @@ use std::fs;
use std::str::FromStr; use std::str::FromStr;
use std::time; use std::time;
use tracing::instrument; use tracing::instrument;
use url::Url;
use kata_types::config::default::DEFAULT_AGENT_VSOCK_PORT; use kata_types::config::default::DEFAULT_AGENT_VSOCK_PORT;
@ -26,6 +27,11 @@ const CONTAINER_PIPE_SIZE_OPTION: &str = "agent.container_pipe_size";
const UNIFIED_CGROUP_HIERARCHY_OPTION: &str = "agent.unified_cgroup_hierarchy"; const UNIFIED_CGROUP_HIERARCHY_OPTION: &str = "agent.unified_cgroup_hierarchy";
const CONFIG_FILE: &str = "agent.config_file"; const CONFIG_FILE: &str = "agent.config_file";
// Configure the proxy settings for HTTPS requests in the guest,
// to solve the problem of not being able to access the specified image in some cases.
const HTTPS_PROXY: &str = "agent.https_proxy";
const NO_PROXY: &str = "agent.no_proxy";
const DEFAULT_LOG_LEVEL: slog::Level = slog::Level::Info; const DEFAULT_LOG_LEVEL: slog::Level = slog::Level::Info;
const DEFAULT_HOTPLUG_TIMEOUT: time::Duration = time::Duration::from_secs(3); const DEFAULT_HOTPLUG_TIMEOUT: time::Duration = time::Duration::from_secs(3);
const DEFAULT_CONTAINER_PIPE_SIZE: i32 = 0; const DEFAULT_CONTAINER_PIPE_SIZE: i32 = 0;
@ -66,6 +72,8 @@ pub struct AgentConfig {
pub unified_cgroup_hierarchy: bool, pub unified_cgroup_hierarchy: bool,
pub tracing: bool, pub tracing: bool,
pub supports_seccomp: bool, pub supports_seccomp: bool,
pub https_proxy: String,
pub no_proxy: String,
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
@ -81,6 +89,8 @@ pub struct AgentConfigBuilder {
pub passfd_listener_port: Option<i32>, pub passfd_listener_port: Option<i32>,
pub unified_cgroup_hierarchy: Option<bool>, pub unified_cgroup_hierarchy: Option<bool>,
pub tracing: Option<bool>, pub tracing: Option<bool>,
pub https_proxy: Option<String>,
pub no_proxy: Option<String>,
} }
macro_rules! config_override { macro_rules! config_override {
@ -142,6 +152,8 @@ impl Default for AgentConfig {
unified_cgroup_hierarchy: false, unified_cgroup_hierarchy: false,
tracing: false, tracing: false,
supports_seccomp: rpc::have_seccomp(), supports_seccomp: rpc::have_seccomp(),
https_proxy: String::from(""),
no_proxy: String::from(""),
} }
} }
} }
@ -171,6 +183,8 @@ impl FromStr for AgentConfig {
config_override!(agent_config_builder, agent_config, passfd_listener_port); config_override!(agent_config_builder, agent_config, passfd_listener_port);
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, https_proxy);
config_override!(agent_config_builder, agent_config, no_proxy);
Ok(agent_config) Ok(agent_config)
} }
@ -270,6 +284,8 @@ impl AgentConfig {
config.unified_cgroup_hierarchy, config.unified_cgroup_hierarchy,
get_bool_value get_bool_value
); );
parse_cmdline_param!(param, HTTPS_PROXY, config.https_proxy, get_url_value);
parse_cmdline_param!(param, NO_PROXY, config.no_proxy, get_string_value);
} }
if let Ok(addr) = env::var(SERVER_ADDR_ENV_VAR) { if let Ok(addr) = env::var(SERVER_ADDR_ENV_VAR) {
@ -417,6 +433,12 @@ fn get_container_pipe_size(param: &str) -> Result<i32> {
Ok(value) Ok(value)
} }
#[instrument]
fn get_url_value(param: &str) -> Result<String> {
let value = get_string_value(param)?;
Ok(Url::parse(&value)?.to_string())
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use test_utils::assert_result; use test_utils::assert_result;
@ -453,6 +475,8 @@ mod tests {
server_addr: &'a str, server_addr: &'a str,
unified_cgroup_hierarchy: bool, unified_cgroup_hierarchy: bool,
tracing: bool, tracing: bool,
https_proxy: &'a str,
no_proxy: &'a str,
} }
impl Default for TestData<'_> { impl Default for TestData<'_> {
@ -468,6 +492,8 @@ mod tests {
server_addr: TEST_SERVER_ADDR, server_addr: TEST_SERVER_ADDR,
unified_cgroup_hierarchy: false, unified_cgroup_hierarchy: false,
tracing: false, tracing: false,
https_proxy: "",
no_proxy: "",
} }
} }
} }
@ -837,6 +863,26 @@ mod tests {
tracing: true, tracing: true,
..Default::default() ..Default::default()
}, },
TestData {
contents: "agent.https_proxy=http://proxy.url.com:81/",
https_proxy: "http://proxy.url.com:81/",
..Default::default()
},
TestData {
contents: "agent.https_proxy=http://192.168.1.100:81/",
https_proxy: "http://192.168.1.100:81/",
..Default::default()
},
TestData {
contents: "agent.no_proxy=*.internal.url.com",
no_proxy: "*.internal.url.com",
..Default::default()
},
TestData {
contents: "agent.no_proxy=192.168.1.0/24,172.16.0.0/12",
no_proxy: "192.168.1.0/24,172.16.0.0/12",
..Default::default()
},
]; ];
let dir = tempdir().expect("failed to create tmpdir"); let dir = tempdir().expect("failed to create tmpdir");
@ -884,6 +930,8 @@ mod tests {
assert_eq!(d.container_pipe_size, config.container_pipe_size, "{}", msg); assert_eq!(d.container_pipe_size, config.container_pipe_size, "{}", msg);
assert_eq!(d.server_addr, config.server_addr, "{}", msg); assert_eq!(d.server_addr, config.server_addr, "{}", msg);
assert_eq!(d.tracing, config.tracing, "{}", msg); assert_eq!(d.tracing, config.tracing, "{}", msg);
assert_eq!(d.https_proxy, config.https_proxy, "{}", msg);
assert_eq!(d.no_proxy, config.no_proxy, "{}", msg);
for v in vars_to_unset { for v in vars_to_unset {
env::remove_var(v); env::remove_var(v);

View File

@ -17,6 +17,7 @@ use image_rs::image::ImageClient;
use tokio::sync::Mutex; use tokio::sync::Mutex;
use crate::rpc::CONTAINER_BASE; use crate::rpc::CONTAINER_BASE;
use crate::AGENT_CONFIG;
const KATA_IMAGE_WORK_DIR: &str = "/run/kata-containers/image/"; const KATA_IMAGE_WORK_DIR: &str = "/run/kata-containers/image/";
@ -59,6 +60,22 @@ impl ImageService {
self.images.lock().await.insert(image, cid); self.images.lock().await.insert(image, cid);
} }
/// Set proxy environment from AGENT_CONFIG
fn set_proxy_env_vars() {
if env::var("HTTPS_PROXY").is_err() {
let https_proxy = &AGENT_CONFIG.https_proxy;
if !https_proxy.is_empty() {
env::set_var("HTTPS_PROXY", https_proxy);
}
}
if env::var("NO_PROXY").is_err() {
let no_proxy = &AGENT_CONFIG.no_proxy;
if !no_proxy.is_empty() {
env::set_var("NO_PROXY", no_proxy);
}
}
}
/// pull_image is used for call image-rs to pull image in the guest. /// pull_image is used for call image-rs to pull image in the guest.
/// # Parameters /// # Parameters
/// - `image`: Image name (exp: quay.io/prometheus/busybox:latest) /// - `image`: Image name (exp: quay.io/prometheus/busybox:latest)
@ -73,6 +90,8 @@ impl ImageService {
image_metadata: &HashMap<String, String>, image_metadata: &HashMap<String, String>,
) -> Result<String> { ) -> Result<String> {
info!(sl(), "image metadata: {image_metadata:?}"); info!(sl(), "image metadata: {image_metadata:?}");
Self::set_proxy_env_vars();
let bundle_base_dir = scoped_join(CONTAINER_BASE, cid)?; let bundle_base_dir = scoped_join(CONTAINER_BASE, cid)?;
fs::create_dir_all(&bundle_base_dir)?; fs::create_dir_all(&bundle_base_dir)?;
let bundle_path = scoped_join(&bundle_base_dir, "images")?; let bundle_path = scoped_join(&bundle_base_dir, "images")?;