From c96ebf237c93e93b34f96dc47c89951fc1e91996 Mon Sep 17 00:00:00 2001 From: Saul Paredes Date: Wed, 28 Feb 2024 11:51:40 -0800 Subject: [PATCH] genpolicy: add containerd pull method Add optional toggle to use existing containerd installation to pull and manage container images. This adds support to a wider set of images that are currently not supported by standard pull method, such as those that use v1 manifest. Fixes: #9144 Signed-off-by: Saul Paredes --- src/tools/genpolicy/Cargo.lock | 430 ++++++++++++++++-- src/tools/genpolicy/Cargo.toml | 4 + src/tools/genpolicy/src/config_map.rs | 3 +- src/tools/genpolicy/src/daemon_set.rs | 5 +- src/tools/genpolicy/src/deployment.rs | 5 +- src/tools/genpolicy/src/job.rs | 5 +- src/tools/genpolicy/src/list.rs | 5 +- src/tools/genpolicy/src/main.rs | 1 + src/tools/genpolicy/src/no_policy.rs | 3 +- src/tools/genpolicy/src/pod.rs | 15 +- src/tools/genpolicy/src/policy.rs | 2 +- src/tools/genpolicy/src/registry.rs | 31 +- .../genpolicy/src/registry_containerd.rs | 398 ++++++++++++++++ src/tools/genpolicy/src/replica_set.rs | 5 +- .../genpolicy/src/replication_controller.rs | 5 +- src/tools/genpolicy/src/secret.rs | 3 +- src/tools/genpolicy/src/stateful_set.rs | 5 +- src/tools/genpolicy/src/utils.rs | 13 + src/tools/genpolicy/src/yaml.rs | 11 +- 19 files changed, 872 insertions(+), 77 deletions(-) create mode 100644 src/tools/genpolicy/src/registry_containerd.rs diff --git a/src/tools/genpolicy/Cargo.lock b/src/tools/genpolicy/Cargo.lock index 7926e85e3e..53bb5c373d 100644 --- a/src/tools/genpolicy/Cargo.lock +++ b/src/tools/genpolicy/Cargo.lock @@ -64,6 +64,51 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "axum" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" +dependencies = [ + "async-trait", + "axum-core", + "bitflags 1.3.2", + "bytes", + "futures-util", + "http", + "http-body", + "hyper", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "mime", + "rustversion", + "tower-layer", + "tower-service", +] + [[package]] name = "backtrace" version = "0.3.69" @@ -79,15 +124,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base64" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" -dependencies = [ - "byteorder", -] - [[package]] name = "base64" version = "0.13.1" @@ -96,9 +132,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.0" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "bitflags" @@ -212,6 +248,20 @@ dependencies = [ "cc", ] +[[package]] +name = "containerd-client" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbd55a5b186b60273ed7361d18d566ede8d66db962bafd702dd4db7fd30f23f" +dependencies = [ + "prost 0.11.9", + "prost-types 0.11.9", + "tokio", + "tonic", + "tonic-build 0.9.2", + "tower", +] + [[package]] name = "core-foundation" version = "0.9.3" @@ -336,11 +386,11 @@ dependencies = [ [[package]] name = "docker_credential" -version = "1.2.0" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f2821ba7f89de240e70f4af347ba5260512d0799a53556c10750805bad7c7fc" +checksum = "8765d595e4f1c66eb5b94450209b316516366d403984664efda0d9b28a55ff9e" dependencies = [ - "base64 0.10.1", + "base64 0.21.7", "serde", "serde_json", ] @@ -373,6 +423,12 @@ dependencies = [ "termcolor", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" version = "0.2.8" @@ -432,6 +488,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + [[package]] name = "flate2" version = "1.0.26" @@ -551,12 +613,14 @@ version = "0.1.0" dependencies = [ "anyhow", "async-trait", - "base64 0.21.0", + "base64 0.21.7", "clap", + "containerd-client", "docker_credential", "env_logger", "flate2", "generic-array", + "k8s-cri", "log", "oci", "oci-distribution", @@ -572,9 +636,22 @@ dependencies = [ "tarindex", "tempfile", "tokio", + "tonic", + "tower", "zerocopy", ] +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "gimli" version = "0.28.0" @@ -593,7 +670,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 1.9.2", "slab", "tokio", "tokio-util", @@ -606,6 +683,12 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + [[package]] name = "heck" version = "0.3.3" @@ -727,6 +810,18 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-timeout" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +dependencies = [ + "hyper", + "pin-project-lite", + "tokio", + "tokio-io-timeout", +] + [[package]] name = "hyper-tls" version = "0.5.0" @@ -781,7 +876,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", ] [[package]] @@ -860,6 +965,18 @@ dependencies = [ "sha2", ] +[[package]] +name = "k8s-cri" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1ac03a0ee89d53fc350989682a56915a4f93fe7b51801a1066cb3caeb2a23f" +dependencies = [ + "prost 0.11.9", + "serde", + "tonic", + "tonic-build 0.8.4", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -921,6 +1038,12 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + [[package]] name = "memchr" version = "2.5.0" @@ -1142,8 +1265,38 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" dependencies = [ - "fixedbitset", - "indexmap", + "fixedbitset 0.2.0", + "indexmap 1.9.2", +] + +[[package]] +name = "petgraph" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +dependencies = [ + "fixedbitset 0.4.2", + "indexmap 2.2.3", +] + +[[package]] +name = "pin-project" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.13", ] [[package]] @@ -1164,6 +1317,22 @@ version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "prettyplease" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +dependencies = [ + "proc-macro2", + "syn 1.0.109", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -1190,9 +1359,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.56" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] @@ -1204,7 +1373,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de5e2533f59d08fcf364fd374ebda0692a70bd6d7e66ef97f306f45c6c5d8020" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.8.0", +] + +[[package]] +name = "prost" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +dependencies = [ + "bytes", + "prost-derive 0.11.9", ] [[package]] @@ -1218,9 +1397,31 @@ dependencies = [ "itertools", "log", "multimap", - "petgraph", - "prost", - "prost-types", + "petgraph 0.5.1", + "prost 0.8.0", + "prost-types 0.8.0", + "tempfile", + "which", +] + +[[package]] +name = "prost-build" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" +dependencies = [ + "bytes", + "heck 0.4.1", + "itertools", + "lazy_static", + "log", + "multimap", + "petgraph 0.6.4", + "prettyplease", + "prost 0.11.9", + "prost-types 0.11.9", + "regex", + "syn 1.0.109", "tempfile", "which", ] @@ -1238,6 +1439,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "prost-derive" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "prost-types" version = "0.8.0" @@ -1245,7 +1459,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "603bbd6394701d13f3f25aada59c7de9d35a6a5887cfc156181234a44002771b" dependencies = [ "bytes", - "prost", + "prost 0.8.0", +] + +[[package]] +name = "prost-types" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" +dependencies = [ + "prost 0.11.9", ] [[package]] @@ -1296,7 +1519,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77d6fbd6697c9e531873e81cec565a85e226b99a0f10e1acc079be057fe2fcba" dependencies = [ "anyhow", - "indexmap", + "indexmap 1.9.2", "log", "protobuf 3.3.0", "protobuf-support", @@ -1335,6 +1558,36 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -1376,7 +1629,7 @@ version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21eed90ec8570952d53b772ecf8f206aa1ec9a3d76b2521c56c42973f2d91ee9" dependencies = [ - "base64 0.21.0", + "base64 0.21.7", "bytes", "encoding_rs", "futures-core", @@ -1456,6 +1709,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + [[package]] name = "ryu" version = "1.0.13" @@ -1561,7 +1820,7 @@ version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" dependencies = [ - "indexmap", + "indexmap 1.9.2", "ryu", "serde", "yaml-rust", @@ -1641,6 +1900,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "tar" version = "0.4.38" @@ -1744,6 +2009,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "tokio-io-timeout" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" +dependencies = [ + "pin-project-lite", + "tokio", +] + [[package]] name = "tokio-macros" version = "2.1.0" @@ -1765,6 +2040,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-stream" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.7" @@ -1779,6 +2065,86 @@ dependencies = [ "tracing", ] +[[package]] +name = "tonic" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a" +dependencies = [ + "async-trait", + "axum", + "base64 0.21.7", + "bytes", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-timeout", + "percent-encoding", + "pin-project", + "prost 0.11.9", + "tokio", + "tokio-stream", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tonic-build" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf5e9b9c0f7e0a7c027dcfaba7b2c60816c7049171f679d99ee2ff65d0de8c4" +dependencies = [ + "prettyplease", + "proc-macro2", + "prost-build 0.11.9", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "tonic-build" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6fdaae4c2c638bb70fe42803a26fbd6fc6ac8c72f5c59f67ecc2a2dcabf4b07" +dependencies = [ + "prettyplease", + "proc-macro2", + "prost-build 0.11.9", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap 1.9.2", + "pin-project", + "pin-project-lite", + "rand", + "slab", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + [[package]] name = "tower-service" version = "0.3.2" @@ -1860,9 +2226,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0672eb06e5663ad190c7b93b2973f5d730259859b62e4e3381301a12a7441107" dependencies = [ "derive-new", - "prost", - "prost-build", - "prost-types", + "prost 0.8.0", + "prost-build 0.8.0", + "prost-types 0.8.0", "protobuf 2.28.0", "protobuf-codegen 2.28.0", "tempfile", diff --git a/src/tools/genpolicy/Cargo.toml b/src/tools/genpolicy/Cargo.toml index d3225c1a5d..42d08de0e8 100644 --- a/src/tools/genpolicy/Cargo.toml +++ b/src/tools/genpolicy/Cargo.toml @@ -59,3 +59,7 @@ sha2 = "0.10.6" tarindex = { git = "https://github.com/kata-containers/tardev-snapshotter", rev = "06183a5" } tempfile = "3.5.0" zerocopy = "0.6.1" +k8s-cri = "0.7.0" +tonic = "0.9.2" +tower = "0.4.13" +containerd-client = "0.4.0" diff --git a/src/tools/genpolicy/src/config_map.rs b/src/tools/genpolicy/src/config_map.rs index 7db847caf4..da6290f3e7 100644 --- a/src/tools/genpolicy/src/config_map.rs +++ b/src/tools/genpolicy/src/config_map.rs @@ -10,6 +10,7 @@ use crate::obj_meta; use crate::pod; use crate::policy; use crate::settings; +use crate::utils::Config; use crate::yaml; use async_trait::async_trait; @@ -81,7 +82,7 @@ pub fn get_value(value_from: &pod::EnvVarSource, config_maps: &Vec) - impl yaml::K8sResource for ConfigMap { async fn init( &mut self, - _use_cache: bool, + _config: &Config, doc_mapping: &serde_yaml::Value, _silent_unsupported_fields: bool, ) { diff --git a/src/tools/genpolicy/src/daemon_set.rs b/src/tools/genpolicy/src/daemon_set.rs index adc9053b90..04c88429c4 100644 --- a/src/tools/genpolicy/src/daemon_set.rs +++ b/src/tools/genpolicy/src/daemon_set.rs @@ -11,6 +11,7 @@ use crate::pod; use crate::pod_template; use crate::policy; use crate::settings; +use crate::utils::Config; use crate::yaml; use async_trait::async_trait; @@ -72,11 +73,11 @@ struct RollingUpdateDaemonSet { impl yaml::K8sResource for DaemonSet { async fn init( &mut self, - use_cache: bool, + config: &Config, doc_mapping: &serde_yaml::Value, _silent_unsupported_fields: bool, ) { - yaml::k8s_resource_init(&mut self.spec.template.spec, use_cache).await; + yaml::k8s_resource_init(&mut self.spec.template.spec, config).await; self.doc_mapping = doc_mapping.clone(); } diff --git a/src/tools/genpolicy/src/deployment.rs b/src/tools/genpolicy/src/deployment.rs index 4fcb75f7ca..45b80c83f7 100644 --- a/src/tools/genpolicy/src/deployment.rs +++ b/src/tools/genpolicy/src/deployment.rs @@ -11,6 +11,7 @@ use crate::pod; use crate::pod_template; use crate::policy; use crate::settings; +use crate::utils::Config; use crate::yaml; use async_trait::async_trait; @@ -70,11 +71,11 @@ struct RollingUpdateDeployment { impl yaml::K8sResource for Deployment { async fn init( &mut self, - use_cache: bool, + config: &Config, doc_mapping: &serde_yaml::Value, _silent_unsupported_fields: bool, ) { - yaml::k8s_resource_init(&mut self.spec.template.spec, use_cache).await; + yaml::k8s_resource_init(&mut self.spec.template.spec, config).await; self.doc_mapping = doc_mapping.clone(); } diff --git a/src/tools/genpolicy/src/job.rs b/src/tools/genpolicy/src/job.rs index 7b261ffc18..ce536e98e1 100644 --- a/src/tools/genpolicy/src/job.rs +++ b/src/tools/genpolicy/src/job.rs @@ -11,6 +11,7 @@ use crate::pod; use crate::pod_template; use crate::policy; use crate::settings; +use crate::utils::Config; use crate::yaml; use async_trait::async_trait; @@ -44,11 +45,11 @@ pub struct JobSpec { impl yaml::K8sResource for Job { async fn init( &mut self, - use_cache: bool, + config: &Config, doc_mapping: &serde_yaml::Value, _silent_unsupported_fields: bool, ) { - yaml::k8s_resource_init(&mut self.spec.template.spec, use_cache).await; + yaml::k8s_resource_init(&mut self.spec.template.spec, config).await; self.doc_mapping = doc_mapping.clone(); } diff --git a/src/tools/genpolicy/src/list.rs b/src/tools/genpolicy/src/list.rs index 20263b43f4..3b6667261b 100644 --- a/src/tools/genpolicy/src/list.rs +++ b/src/tools/genpolicy/src/list.rs @@ -9,6 +9,7 @@ use crate::pod; use crate::policy; use crate::settings; +use crate::utils::Config; use crate::yaml; use async_trait::async_trait; @@ -39,12 +40,12 @@ impl Debug for dyn yaml::K8sResource + Send + Sync { #[async_trait] impl yaml::K8sResource for List { - async fn init(&mut self, use_cache: bool, _doc_mapping: &serde_yaml::Value, silent: bool) { + async fn init(&mut self, config: &Config, _doc_mapping: &serde_yaml::Value, silent: bool) { // Create K8sResource objects for each item in this List. for item in &self.items { let yaml_string = serde_yaml::to_string(&item).unwrap(); let (mut resource, _kind) = yaml::new_k8s_resource(&yaml_string, silent).unwrap(); - resource.init(use_cache, item, silent).await; + resource.init(config, item, silent).await; self.resources.push(resource); } } diff --git a/src/tools/genpolicy/src/main.rs b/src/tools/genpolicy/src/main.rs index b7a57dd711..93c91d6020 100644 --- a/src/tools/genpolicy/src/main.rs +++ b/src/tools/genpolicy/src/main.rs @@ -19,6 +19,7 @@ mod pod; mod pod_template; mod policy; mod registry; +mod registry_containerd; mod replica_set; mod replication_controller; mod secret; diff --git a/src/tools/genpolicy/src/no_policy.rs b/src/tools/genpolicy/src/no_policy.rs index 7ed652303c..e5af283319 100644 --- a/src/tools/genpolicy/src/no_policy.rs +++ b/src/tools/genpolicy/src/no_policy.rs @@ -9,6 +9,7 @@ use crate::pod; use crate::policy; use crate::settings; +use crate::utils::Config; use crate::yaml; use async_trait::async_trait; @@ -24,7 +25,7 @@ pub struct NoPolicyResource { impl yaml::K8sResource for NoPolicyResource { async fn init( &mut self, - _use_cache: bool, + _config: &Config, _doc_mapping: &serde_yaml::Value, _silent_unsupported_fields: bool, ) { diff --git a/src/tools/genpolicy/src/pod.rs b/src/tools/genpolicy/src/pod.rs index e7015d636b..43d2639753 100644 --- a/src/tools/genpolicy/src/pod.rs +++ b/src/tools/genpolicy/src/pod.rs @@ -12,6 +12,7 @@ use crate::policy; use crate::registry; use crate::secret; use crate::settings; +use crate::utils::Config; use crate::volume; use crate::yaml; @@ -480,11 +481,9 @@ struct PodDNSConfigOption { } impl Container { - pub async fn init(&mut self, use_cache: bool) { + pub async fn init(&mut self, config: &Config) { // Load container image properties from the registry. - self.registry = registry::get_container(use_cache, &self.image) - .await - .unwrap(); + self.registry = registry::get_container(config, &self.image).await.unwrap(); } pub fn get_env_variables( @@ -691,8 +690,8 @@ impl EnvVar { #[async_trait] impl yaml::K8sResource for Pod { - async fn init(&mut self, use_cache: bool, doc_mapping: &serde_yaml::Value, _silent: bool) { - yaml::k8s_resource_init(&mut self.spec, use_cache).await; + async fn init(&mut self, config: &Config, doc_mapping: &serde_yaml::Value, _silent: bool) { + yaml::k8s_resource_init(&mut self.spec, config).await; self.doc_mapping = doc_mapping.clone(); } @@ -832,7 +831,7 @@ fn compress_capabilities(capabilities: &mut Vec, defaults: &policy::Comm } } -pub async fn add_pause_container(containers: &mut Vec, use_cache: bool) { +pub async fn add_pause_container(containers: &mut Vec, config: &Config) { debug!("Adding pause container..."); let mut pause_container = Container { // TODO: load this path from the settings file. @@ -849,7 +848,7 @@ pub async fn add_pause_container(containers: &mut Vec, use_cache: boo }), ..Default::default() }; - pause_container.init(use_cache).await; + pause_container.init(config).await; containers.insert(0, pause_container); debug!("pause container added."); } diff --git a/src/tools/genpolicy/src/policy.rs b/src/tools/genpolicy/src/policy.rs index 56c79412fe..a967c1b623 100644 --- a/src/tools/genpolicy/src/policy.rs +++ b/src/tools/genpolicy/src/policy.rs @@ -381,7 +381,7 @@ impl AgentPolicy { let yaml_string = serde_yaml::to_string(&doc_mapping)?; let silent = config.silent_unsupported_fields; let (mut resource, kind) = yaml::new_k8s_resource(&yaml_string, silent)?; - resource.init(config.use_cache, &doc_mapping, silent).await; + resource.init(config, &doc_mapping, silent).await; // ConfigMap and Secret documents contain additional input for policy generation. if kind.eq("ConfigMap") { diff --git a/src/tools/genpolicy/src/registry.rs b/src/tools/genpolicy/src/registry.rs index ccd5413aa8..c40ec05c98 100644 --- a/src/tools/genpolicy/src/registry.rs +++ b/src/tools/genpolicy/src/registry.rs @@ -10,6 +10,7 @@ use crate::containerd; use crate::policy; use crate::verity; +use crate::utils::Config; use anyhow::{anyhow, bail, Result}; use docker_credential::{CredentialRetrievalError, DockerCredential}; use log::warn; @@ -25,16 +26,16 @@ use tokio::{fs, io::AsyncWriteExt}; /// Container image properties obtained from an OCI repository. #[derive(Clone, Debug, Default)] pub struct Container { - config_layer: DockerConfigLayer, - image_layers: Vec, + pub config_layer: DockerConfigLayer, + pub image_layers: Vec, } /// Image config layer properties. #[derive(Clone, Debug, Default, Deserialize, Serialize)] -struct DockerConfigLayer { +pub struct DockerConfigLayer { architecture: String, config: DockerImageConfig, - rootfs: DockerRootfs, + pub rootfs: DockerRootfs, } /// Image config properties. @@ -50,9 +51,9 @@ struct DockerImageConfig { /// Container rootfs information. #[derive(Clone, Debug, Default, Deserialize, Serialize)] -struct DockerRootfs { +pub struct DockerRootfs { r#type: String, - diff_ids: Vec, + pub diff_ids: Vec, } /// This application's image layer properties. @@ -260,25 +261,25 @@ async fn get_image_layers( Ok(layers) } -fn get_verity_path(base_dir: &Path, file_name: &str) -> PathBuf { +pub fn get_verity_path(base_dir: &Path, file_name: &str) -> PathBuf { let mut verity_path: PathBuf = base_dir.join(file_name); verity_path.set_extension("verity"); verity_path } -fn get_decompressed_path(verity_path: &Path) -> PathBuf { +pub fn get_decompressed_path(verity_path: &Path) -> PathBuf { let mut decompressed_path = verity_path.to_path_buf().clone(); decompressed_path.set_extension("tar"); decompressed_path } -fn get_compressed_path(decompressed_path: &Path) -> PathBuf { +pub fn get_compressed_path(decompressed_path: &Path) -> PathBuf { let mut compressed_path = decompressed_path.to_path_buf().clone(); compressed_path.set_extension("gz"); compressed_path } -async fn delete_files(base_dir: &Path, file_name: &str) { +pub async fn delete_files(base_dir: &Path, file_name: &str) { let verity_path = get_verity_path(base_dir, file_name); let _ = fs::remove_file(&verity_path).await; @@ -399,7 +400,7 @@ async fn create_decompressed_layer_file( Ok(()) } -fn do_create_verity_hash_file(decompressed_path: &PathBuf) -> Result<()> { +pub fn do_create_verity_hash_file(decompressed_path: &PathBuf) -> Result<()> { info!("Calculating dm-verity root hash"); let mut file = std::fs::File::open(decompressed_path)?; let size = file.seek(std::io::SeekFrom::End(0))?; @@ -425,9 +426,11 @@ fn do_create_verity_hash_file(decompressed_path: &PathBuf) -> Result<()> { Ok(()) } - -pub async fn get_container(use_cache: bool, image: &str) -> Result { - Container::new(use_cache, image).await +pub async fn get_container(config: &Config, image: &str) -> Result { + if let Some(socket_path) = &config.containerd_socket_path { + return Container::new_containerd_pull(config.use_cache, image, socket_path).await; + } + Container::new(config.use_cache, image).await } fn build_auth(reference: &Reference) -> RegistryAuth { diff --git a/src/tools/genpolicy/src/registry_containerd.rs b/src/tools/genpolicy/src/registry_containerd.rs new file mode 100644 index 0000000000..ae66b35375 --- /dev/null +++ b/src/tools/genpolicy/src/registry_containerd.rs @@ -0,0 +1,398 @@ +// Copyright (c) 2023 Microsoft Corporation +// +// SPDX-License-Identifier: Apache-2.0 +// + +// Allow Docker image config field names. +#![allow(non_snake_case)] +use crate::registry::{ + delete_files, do_create_verity_hash_file, get_compressed_path, get_decompressed_path, + get_verity_path, Container, DockerConfigLayer, ImageLayer, +}; +use anyhow::{anyhow, bail, Result}; +use containerd_client::services::v1::GetImageRequest; +use containerd_client::with_namespace; +use docker_credential::{CredentialRetrievalError, DockerCredential}; +use k8s_cri::v1::{image_service_client::ImageServiceClient, AuthConfig}; +use log::warn; +use log::{debug, info}; +use oci_distribution::Reference; +use std::collections::HashMap; +use std::convert::TryFrom; +use std::{io::Seek, io::Write, path::Path, path::PathBuf}; +use tokio::io; +use tokio::io::{AsyncSeekExt, AsyncWriteExt}; +use tokio::net::UnixStream; +use tonic::transport::{Endpoint, Uri}; +use tonic::Request; +use tower::service_fn; + +impl Container { + pub async fn new_containerd_pull( + use_cached_files: bool, + image: &str, + containerd_socket_path: &str, + ) -> Result { + info!("============================================"); + info!("Using containerd socket: {:?}", containerd_socket_path); + + let ctrd_path = containerd_socket_path.to_string(); + let containerd_channel = Endpoint::try_from("http://[::]") + .unwrap() + .connect_with_connector(service_fn(move |_: Uri| { + UnixStream::connect(ctrd_path.clone()) + })) + .await?; + + let ctrd_client = containerd_client::Client::from(containerd_channel.clone()); + let k8_cri_image_client = ImageServiceClient::new(containerd_channel); + + let image_ref: Reference = image.to_string().parse().unwrap(); + + info!("Pulling image: {:?}", image_ref); + + pull_image(&image_ref, k8_cri_image_client.clone()).await?; + + let image_ref_str = &image_ref.to_string(); + + let manifest = get_image_manifest(image_ref_str, &ctrd_client).await?; + let config_layer = get_config_layer(image_ref_str, k8_cri_image_client) + .await + .unwrap(); + let image_layers = + get_image_layers(use_cached_files, &manifest, &config_layer, &ctrd_client).await?; + + Ok(Container { + config_layer, + image_layers, + }) + } +} +pub async fn get_content( + digest: &str, + client: &containerd_client::Client, +) -> Result { + let req = containerd_client::services::v1::ReadContentRequest { + digest: digest.to_string(), + offset: 0, + size: 0, + }; + let req = with_namespace!(req, "k8s.io"); + let mut c = client.content(); + let resp = c.read(req).await?; + let mut stream = resp.into_inner(); + + if let Some(chunk) = stream.message().await? { + if chunk.offset < 0 { + return Err(anyhow!("Negative offset in chunk")); + } + return Ok(serde_json::from_slice(&chunk.data)?); + } + + Err(anyhow!("Unable to find content for digest: {}", digest)) +} + +pub async fn get_image_manifest( + image_ref: &str, + client: &containerd_client::Client, +) -> Result { + let mut imageChannel = client.images(); + + let req = GetImageRequest { + name: image_ref.to_string(), + }; + let req = with_namespace!(req, "k8s.io"); + let resp = imageChannel.get(req).await?; + + let image_digest = resp.into_inner().image.unwrap().target.unwrap().digest; + + // content may be an image manifest (https://github.com/opencontainers/image-spec/blob/main/manifest.md) + //or an image index (https://github.com/opencontainers/image-spec/blob/main/image-index.md) + let content = get_content(&image_digest, client).await?; + + let is_image_manifest = content.get("layers").is_some(); + + if is_image_manifest { + return Ok(content); + } + + // else, content is an image index + let image_index = content; + + let manifests = image_index["manifests"].as_array().unwrap(); + + let mut manifestAmd64 = &serde_json::Value::Null; + + for entry in manifests { + let platform = entry["platform"].as_object().unwrap(); + let architecture = platform["architecture"].as_str().unwrap(); + let os = platform["os"].as_str().unwrap(); + if architecture == "amd64" && os == "linux" { + manifestAmd64 = entry; + break; + } + } + + let image_digest = manifestAmd64["digest"].as_str().unwrap(); + + get_content(image_digest, client).await +} + +pub async fn get_config_layer( + image_ref: &str, + mut client: ImageServiceClient, +) -> Result { + let req = k8s_cri::v1::ImageStatusRequest { + image: Some(k8s_cri::v1::ImageSpec { + image: image_ref.to_string(), + annotations: HashMap::new(), + }), + verbose: true, + }; + + let resp = client.image_status(req).await?; + let image_layers = resp.into_inner(); + + let status_info: serde_json::Value = + serde_json::from_str(image_layers.info.get("info").unwrap())?; + let image_spec = status_info["imageSpec"].as_object().unwrap(); + let docker_config_layer: DockerConfigLayer = + serde_json::from_value(serde_json::to_value(image_spec)?)?; + + Ok(docker_config_layer) +} + +pub async fn pull_image( + image_ref: &Reference, + mut client: ImageServiceClient, +) -> Result<()> { + let auth = build_auth(&image_ref); + + debug!("cri auth: {:?}", auth); + + let req = k8s_cri::v1::PullImageRequest { + image: Some(k8s_cri::v1::ImageSpec { + image: image_ref.to_string(), + annotations: HashMap::new(), + }), + auth, + sandbox_config: None, + }; + + client.pull_image(req).await?; + + Ok(()) +} + +pub fn build_auth(reference: &Reference) -> Option { + debug!("build_auth: {:?}", reference); + + let server = reference + .resolve_registry() + .strip_suffix('/') + .unwrap_or_else(|| reference.resolve_registry()); + + debug!("server: {:?}", server); + + match docker_credential::get_credential(server) { + Ok(DockerCredential::UsernamePassword(username, password)) => { + debug!("build_auth: Found docker credentials"); + return Some(AuthConfig { + username, + password, + auth: "".to_string(), + server_address: "".to_string(), + identity_token: "".to_string(), + registry_token: "".to_string(), + }); + } + Ok(DockerCredential::IdentityToken(identity_token)) => { + debug!("build_auth: Found identity token"); + return Some(AuthConfig { + username: "".to_string(), + password: "".to_string(), + auth: "".to_string(), + server_address: "".to_string(), + identity_token, + registry_token: "".to_string(), + }); + } + Err(CredentialRetrievalError::ConfigNotFound) => { + debug!("build_auth: Docker config not found - using anonymous access."); + } + Err(CredentialRetrievalError::NoCredentialConfigured) => { + debug!("build_auth: Docker credentials not configured - using anonymous access."); + } + Err(CredentialRetrievalError::ConfigReadError) => { + debug!("build_auth: Cannot read docker credentials - using anonymous access."); + } + Err(CredentialRetrievalError::HelperFailure { stdout, stderr }) => { + if stdout == "credentials not found in native keychain\n" { + // On WSL, this error is generated when credentials are not + // available in ~/.docker/config.json. + debug!("build_auth: Docker credentials not found - using anonymous access."); + } else { + warn!("build_auth: Docker credentials not found - using anonymous access. stderr = {}, stdout = {}", + &stderr, &stdout); + } + } + Err(e) => panic!("Error handling docker configuration file: {}", e), + } + + None +} + +pub async fn get_image_layers( + use_cached_files: bool, + manifest: &serde_json::Value, + config_layer: &DockerConfigLayer, + client: &containerd_client::Client, +) -> Result> { + let mut layer_index = 0; + let mut layersVec = Vec::new(); + + let layers = manifest["layers"].as_array().unwrap(); + + for layer in layers { + let layer_media_type = layer["mediaType"].as_str().unwrap(); + if layer_media_type.eq("application/vnd.docker.image.rootfs.diff.tar.gzip") + || layer_media_type.eq("application/vnd.oci.image.layer.v1.tar+gzip") + { + if layer_index < config_layer.rootfs.diff_ids.len() { + let imageLayer = ImageLayer { + diff_id: config_layer.rootfs.diff_ids[layer_index].clone(), + verity_hash: get_verity_hash( + use_cached_files, + client, + layer["digest"].as_str().unwrap(), + ) + .await?, + }; + layersVec.push(imageLayer); + } else { + return Err(anyhow!("Too many Docker gzip layers")); + } + layer_index += 1; + } + } + + Ok(layersVec) +} + +async fn get_verity_hash( + use_cached_files: bool, + client: &containerd_client::Client, + layer_digest: &str, +) -> Result { + // Use file names supported by both Linux and Windows. + let file_name = str::replace(layer_digest, ":", "-"); + + let base_dir = std::path::Path::new("layers_cache"); + let verity_path = get_verity_path(base_dir, &file_name); + + if use_cached_files && verity_path.exists() { + info!("Using cache file"); + } else if let Err(e) = create_verity_hash_file( + use_cached_files, + layer_digest, + base_dir, + &get_decompressed_path(&verity_path), + client, + ) + .await + { + delete_files(base_dir, &file_name).await; + bail!("{e}"); + } + + match std::fs::read_to_string(&verity_path) { + Err(e) => { + delete_files(base_dir, &file_name).await; + bail!("Failed to read {:?}, error {e}", &verity_path); + } + Ok(v) => { + if !use_cached_files { + let _ = std::fs::remove_dir_all(base_dir); + } + info!("dm-verity root hash: {v}"); + Ok(v) + } + } +} + +async fn create_verity_hash_file( + use_cached_files: bool, + layer_digest: &str, + base_dir: &Path, + decompressed_path: &PathBuf, + client: &containerd_client::Client, +) -> Result<()> { + if use_cached_files && decompressed_path.exists() { + info!("Using cached file {:?}", &decompressed_path); + } else { + std::fs::create_dir_all(base_dir)?; + create_decompressed_layer_file(use_cached_files, layer_digest, decompressed_path, client) + .await?; + } + + do_create_verity_hash_file(decompressed_path) +} + +async fn create_decompressed_layer_file( + use_cached_files: bool, + layer_digest: &str, + decompressed_path: &PathBuf, + client: &containerd_client::Client, +) -> Result<()> { + let compressed_path = get_compressed_path(decompressed_path); + + if use_cached_files && compressed_path.exists() { + info!("Using cached file {:?}", &compressed_path); + } else { + info!("Pulling layer {layer_digest}"); + let mut file = tokio::fs::File::create(&compressed_path) + .await + .map_err(|e| anyhow!(e))?; + + info!("Decompressing layer"); + + let req = containerd_client::services::v1::ReadContentRequest { + digest: layer_digest.to_string(), + offset: 0, + size: 0, + }; + let req = with_namespace!(req, "k8s.io"); + let mut c = client.content(); + let resp = c.read(req).await?; + let mut stream = resp.into_inner(); + + while let Some(chunk) = stream.message().await? { + if chunk.offset < 0 { + print!("oop") + } + file.seek(io::SeekFrom::Start(chunk.offset as u64)).await?; + file.write_all(&chunk.data).await?; + } + + file.flush() + .await + .map_err(|e| anyhow!(e)) + .expect("Failed to flush file"); + } + let compressed_file = std::fs::File::open(compressed_path).map_err(|e| anyhow!(e))?; + let mut decompressed_file = std::fs::OpenOptions::new() + .read(true) + .write(true) + .create(true) + .truncate(true) + .open(decompressed_path)?; + let mut gz_decoder = flate2::read::GzDecoder::new(compressed_file); + std::io::copy(&mut gz_decoder, &mut decompressed_file).map_err(|e| anyhow!(e))?; + + info!("Adding tarfs index to layer"); + decompressed_file.seek(std::io::SeekFrom::Start(0))?; + tarindex::append_index(&mut decompressed_file).map_err(|e| anyhow!(e))?; + decompressed_file.flush().map_err(|e| anyhow!(e))?; + + Ok(()) +} diff --git a/src/tools/genpolicy/src/replica_set.rs b/src/tools/genpolicy/src/replica_set.rs index 2181000304..f4a4e5f68e 100644 --- a/src/tools/genpolicy/src/replica_set.rs +++ b/src/tools/genpolicy/src/replica_set.rs @@ -11,6 +11,7 @@ use crate::pod; use crate::pod_template; use crate::policy; use crate::settings; +use crate::utils::Config; use crate::yaml; use async_trait::async_trait; @@ -45,8 +46,8 @@ struct ReplicaSetSpec { #[async_trait] impl yaml::K8sResource for ReplicaSet { - async fn init(&mut self, use_cache: bool, doc_mapping: &serde_yaml::Value, _silent: bool) { - yaml::k8s_resource_init(&mut self.spec.template.spec, use_cache).await; + async fn init(&mut self, config: &Config, doc_mapping: &serde_yaml::Value, _silent: bool) { + yaml::k8s_resource_init(&mut self.spec.template.spec, config).await; self.doc_mapping = doc_mapping.clone(); } diff --git a/src/tools/genpolicy/src/replication_controller.rs b/src/tools/genpolicy/src/replication_controller.rs index 4c05477a96..c23fd1fdc7 100644 --- a/src/tools/genpolicy/src/replication_controller.rs +++ b/src/tools/genpolicy/src/replication_controller.rs @@ -11,6 +11,7 @@ use crate::pod; use crate::pod_template; use crate::policy; use crate::settings; +use crate::utils::Config; use crate::yaml; use async_trait::async_trait; @@ -47,8 +48,8 @@ struct ReplicationControllerSpec { #[async_trait] impl yaml::K8sResource for ReplicationController { - async fn init(&mut self, use_cache: bool, doc_mapping: &serde_yaml::Value, _silent: bool) { - yaml::k8s_resource_init(&mut self.spec.template.spec, use_cache).await; + async fn init(&mut self, config: &Config, doc_mapping: &serde_yaml::Value, _silent: bool) { + yaml::k8s_resource_init(&mut self.spec.template.spec, config).await; self.doc_mapping = doc_mapping.clone(); } diff --git a/src/tools/genpolicy/src/secret.rs b/src/tools/genpolicy/src/secret.rs index aef45af371..62f8fe9ca0 100644 --- a/src/tools/genpolicy/src/secret.rs +++ b/src/tools/genpolicy/src/secret.rs @@ -10,6 +10,7 @@ use crate::obj_meta; use crate::pod; use crate::policy; use crate::settings; +use crate::utils::Config; use crate::yaml; use async_trait::async_trait; @@ -73,7 +74,7 @@ pub fn get_value(value_from: &pod::EnvVarSource, secrets: &Vec) -> Optio #[async_trait] impl yaml::K8sResource for Secret { - async fn init(&mut self, _use_cache: bool, doc_mapping: &serde_yaml::Value, _silent: bool) { + async fn init(&mut self, _config: &Config, doc_mapping: &serde_yaml::Value, _silent: bool) { self.doc_mapping = doc_mapping.clone(); } diff --git a/src/tools/genpolicy/src/stateful_set.rs b/src/tools/genpolicy/src/stateful_set.rs index 86f22eebb0..5b078eaf5b 100644 --- a/src/tools/genpolicy/src/stateful_set.rs +++ b/src/tools/genpolicy/src/stateful_set.rs @@ -12,6 +12,7 @@ use crate::pod; use crate::pod_template; use crate::policy; use crate::settings; +use crate::utils::Config; use crate::yaml; use async_trait::async_trait; @@ -95,8 +96,8 @@ struct RollingUpdateStatefulSetStrategy { #[async_trait] impl yaml::K8sResource for StatefulSet { - async fn init(&mut self, use_cache: bool, doc_mapping: &serde_yaml::Value, _silent: bool) { - yaml::k8s_resource_init(&mut self.spec.template.spec, use_cache).await; + async fn init(&mut self, config: &Config, doc_mapping: &serde_yaml::Value, _silent: bool) { + yaml::k8s_resource_init(&mut self.spec.template.spec, config).await; self.doc_mapping = doc_mapping.clone(); } diff --git a/src/tools/genpolicy/src/utils.rs b/src/tools/genpolicy/src/utils.rs index 34b2e53cc5..1d186ccc7f 100644 --- a/src/tools/genpolicy/src/utils.rs +++ b/src/tools/genpolicy/src/utils.rs @@ -64,6 +64,17 @@ struct CommandLineOptions { help = "Ignore unsupported input Kubernetes YAML fields. This is not recommeded unless you understand exactly how genpolicy works!" )] silent_unsupported_fields: bool, + + #[clap( + short = 'd', + long, + help = "If specified, will use existing containerd service to pull container images. This option is only supported on Linux", + // from https://docs.rs/clap/4.1.8/clap/struct.Arg.html#method.default_missing_value + default_missing_value = "/var/run/containerd/containerd.sock", // used if flag is present but no value is given + num_args = 0..=1, + require_equals= true + )] + containerd_socket_path: Option, } /// Application configuration, derived from on command line parameters. @@ -79,6 +90,7 @@ pub struct Config { pub silent_unsupported_fields: bool, pub raw_out: bool, pub base64_out: bool, + pub containerd_socket_path: Option, } impl Config { @@ -105,6 +117,7 @@ impl Config { silent_unsupported_fields: args.silent_unsupported_fields, raw_out: args.raw_out, base64_out: args.base64_out, + containerd_socket_path: args.containerd_socket_path, } } } diff --git a/src/tools/genpolicy/src/yaml.rs b/src/tools/genpolicy/src/yaml.rs index 05fbbc73b8..9ac1302f33 100644 --- a/src/tools/genpolicy/src/yaml.rs +++ b/src/tools/genpolicy/src/yaml.rs @@ -20,6 +20,7 @@ use crate::replication_controller; use crate::secret; use crate::settings; use crate::stateful_set; +use crate::utils::Config; use crate::volume; use async_trait::async_trait; @@ -43,7 +44,7 @@ pub struct YamlHeader { pub trait K8sResource { async fn init( &mut self, - use_cache: bool, + config: &Config, doc_mapping: &serde_yaml::Value, silent_unsupported_fields: bool, ); @@ -216,17 +217,17 @@ pub fn get_yaml_header(yaml: &str) -> anyhow::Result { Ok(serde_yaml::from_str(yaml)?) } -pub async fn k8s_resource_init(spec: &mut pod::PodSpec, use_cache: bool) { +pub async fn k8s_resource_init(spec: &mut pod::PodSpec, config: &Config) { for container in &mut spec.containers { - container.init(use_cache).await; + container.init(config).await; } - pod::add_pause_container(&mut spec.containers, use_cache).await; + pod::add_pause_container(&mut spec.containers, config).await; if let Some(init_containers) = &spec.initContainers { for container in init_containers { let mut new_container = container.clone(); - new_container.init(use_cache).await; + new_container.init(config).await; spec.containers.insert(1, new_container); } }