diff --git a/src/tools/genpolicy/Cargo.lock b/src/tools/genpolicy/Cargo.lock index 7e7f18af8d..6dafe279f6 100644 --- a/src/tools/genpolicy/Cargo.lock +++ b/src/tools/genpolicy/Cargo.lock @@ -876,12 +876,14 @@ dependencies = [ "fs2", "generic-array", "k8s-cri", + "libz-ng-sys", "log", "oci-distribution", "oci-spec", "openssl", "protobuf 3.3.0", "protocols", + "regorus", "serde", "serde-transcode", "serde_ignored", @@ -1229,6 +1231,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.6" @@ -1337,9 +1348,9 @@ checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libz-ng-sys" -version = "1.1.9" +version = "1.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2468756f34903b582fe7154dc1ffdebd89d0562c4a43b53c621bb0f1b1043ccb" +checksum = "c6409efc61b12687963e602df8ecf70e8ddacf95bc6576bcf16e3ac6328083c5" dependencies = [ "cmake", "libc", @@ -1508,10 +1519,74 @@ dependencies = [ ] [[package]] -name = "num-traits" -version = "0.2.17" +name = "num" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] @@ -1626,6 +1701,15 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "openssl-src" +version = "111.28.2+1.1.1w" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb1830e20a48a975ca898ca8c1d036a36c3c6c5cb7dabc1c216706587857920f" +dependencies = [ + "cc", +] + [[package]] name = "openssl-sys" version = "0.9.90" @@ -1634,6 +1718,7 @@ checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" dependencies = [ "cc", "libc", + "openssl-src", "pkg-config", "vcpkg", ] @@ -1794,7 +1879,7 @@ checksum = "355f634b43cdd80724ee7848f95770e7e70eefa6dcf14fea676216573b8fd603" dependencies = [ "bytes", "heck 0.3.3", - "itertools", + "itertools 0.10.5", "log", "multimap", "petgraph 0.5.1", @@ -1812,7 +1897,7 @@ checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" dependencies = [ "bytes", "heck 0.4.1", - "itertools", + "itertools 0.10.5", "lazy_static", "log", "multimap", @@ -1833,7 +1918,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "600d2f334aa05acb02a755e217ef1ab6dea4d51b58b7846588b747edec04efba" dependencies = [ "anyhow", - "itertools", + "itertools 0.10.5", "proc-macro2", "quote", "syn 1.0.109", @@ -1846,7 +1931,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", - "itertools", + "itertools 0.10.5", "proc-macro2", "quote", "syn 1.0.109", @@ -2082,6 +2167,23 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +[[package]] +name = "regorus" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77dd872918e5c172bd42ac49716f89a15e35be513bba3d902e355a531529a87f" +dependencies = [ + "anyhow", + "itertools 0.12.1", + "lazy_static", + "num", + "rand", + "regex", + "scientific", + "serde", + "serde_json", +] + [[package]] name = "rend" version = "0.4.2" @@ -2259,6 +2361,26 @@ dependencies = [ "windows-sys 0.42.0", ] +[[package]] +name = "scientific" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38a4b339a8de779ecb098a772ecbba2ace74e23ed959a5b4f30631d8bf1799a8" +dependencies = [ + "scientific-macro", +] + +[[package]] +name = "scientific-macro" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ee4885492bb655bfa05d039cd9163eb8fe9f79ddebf00ca23a1637510c2fd2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.58", +] + [[package]] name = "seahash" version = "4.1.0" diff --git a/src/tools/genpolicy/Cargo.toml b/src/tools/genpolicy/Cargo.toml index a9f0162260..72f92ab9ad 100644 --- a/src/tools/genpolicy/Cargo.toml +++ b/src/tools/genpolicy/Cargo.toml @@ -40,8 +40,9 @@ anyhow = "1.0.32" async-trait = "0.1.68" docker_credential = "1.3.1" flate2 = { version = "1.0.26", features = ["zlib-ng"], default-features = false } +libz-ng-sys = "1.1.15" # force newer version that compiles on ppc64le oci-distribution = { version = "0.10.0" } -openssl = { version = "0.10.54" } +openssl = { version = "0.10.54", features = ["vendored"] } serde_ignored = "0.1.7" serde_json = "1.0.39" serde-transcode = "1.1.1" @@ -67,3 +68,6 @@ k8s-cri = "0.7.0" tonic = "0.9.2" tower = "0.4.13" containerd-client = "0.4.0" + +[dev-dependencies] +regorus = { version = "0.1.4", default-features = false, features = ["arc", "regex"]} diff --git a/src/tools/genpolicy/Makefile b/src/tools/genpolicy/Makefile index 3143385700..7410e20eda 100644 --- a/src/tools/genpolicy/Makefile +++ b/src/tools/genpolicy/Makefile @@ -40,7 +40,8 @@ clean: vendor: cargo vendor -test: +test: $(GENERATED_FILES) + @RUSTFLAGS="$(EXTRA_RUSTFLAGS) --deny warnings" cargo test --all-targets --all-features --target $(TRIPLE) install: $(GENERATED_FILES) @RUSTFLAGS="$(EXTRA_RUSTFLAGS) --deny warnings" cargo install --locked --target $(TRIPLE) --path . diff --git a/src/tools/genpolicy/src/mount_and_storage.rs b/src/tools/genpolicy/src/mount_and_storage.rs index cdb0b9dab2..fd64b3d1df 100644 --- a/src/tools/genpolicy/src/mount_and_storage.rs +++ b/src/tools/genpolicy/src/mount_and_storage.rs @@ -57,8 +57,8 @@ pub fn get_policy_mounts( .find(|m| m.destination.eq(&s_mount.destination)) { // Update an already existing mount. - policy_mount.type_ = mount.type_.clone(); - policy_mount.source = mount.source.clone(); + policy_mount.type_.clone_from(&mount.type_); + policy_mount.source.clone_from(&mount.source); policy_mount.options = mount.options.iter().map(String::from).collect(); } else { // Add a new mount. @@ -94,7 +94,7 @@ fn keep_settings_mount( fn adjust_termination_path(mount: &mut policy::KataMount, yaml_container: &pod::Container) { if mount.destination == "/dev/termination-log" { if let Some(path) = &yaml_container.terminationMessagePath { - mount.destination = path.clone(); + mount.destination.clone_from(path); } } } diff --git a/src/tools/genpolicy/src/policy.rs b/src/tools/genpolicy/src/policy.rs index 879c67f330..026010ea26 100644 --- a/src/tools/genpolicy/src/policy.rs +++ b/src/tools/genpolicy/src/policy.rs @@ -570,10 +570,12 @@ impl AgentPolicy { linux.Namespaces = get_kata_namespaces(is_pause_container, use_host_network); if !c_settings.Linux.MaskedPaths.is_empty() { - linux.MaskedPaths = c_settings.Linux.MaskedPaths.clone(); + linux.MaskedPaths.clone_from(&c_settings.Linux.MaskedPaths); } if !c_settings.Linux.ReadonlyPaths.is_empty() { - linux.ReadonlyPaths = c_settings.Linux.ReadonlyPaths.clone(); + linux + .ReadonlyPaths + .clone_from(&c_settings.Linux.ReadonlyPaths); } let sandbox_pidns = if is_pause_container { @@ -722,7 +724,7 @@ fn get_image_layer_storages( "previous_chain_id = {}, chain_id = {}", &previous_chain_id, &chain_id ); - previous_chain_id = chain_id.clone(); + previous_chain_id.clone_from(&chain_id); layer_names.push(name_to_hash(&chain_id)); layer_hashes.push(layer.verity_hash.to_string()); diff --git a/src/tools/genpolicy/src/registry.rs b/src/tools/genpolicy/src/registry.rs index dc4ff14755..1bee737e3c 100644 --- a/src/tools/genpolicy/src/registry.rs +++ b/src/tools/genpolicy/src/registry.rs @@ -215,7 +215,7 @@ impl Container { if let Some(working_dir) = &docker_config.WorkingDir { if !working_dir.is_empty() { - process.Cwd = working_dir.clone(); + process.Cwd.clone_from(working_dir); } } @@ -344,6 +344,7 @@ pub fn add_verity_to_store(cache_file: &str, diff_id: &str, verity_hash: &str) - .read(true) .write(true) .create(true) + .truncate(false) .open(cache_file)?; let mut data: Vec = if let Ok(vec) = serde_json::from_reader(read_file) { diff --git a/src/tools/genpolicy/tests/main.rs b/src/tools/genpolicy/tests/main.rs new file mode 100644 index 0000000000..565b3e2a0b --- /dev/null +++ b/src/tools/genpolicy/tests/main.rs @@ -0,0 +1,101 @@ +// Copyright (c) 2024 Edgeless Systems GmbH +// +// SPDX-License-Identifier: Apache-2.0 +// + +use std::any; +use std::fs::{self, File}; +use std::path; +use std::process::Command; +use std::str; + +use protocols::agent::{CopyFileRequest, CreateSandboxRequest}; +use serde::de::DeserializeOwned; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Deserialize, Serialize)] +struct TestCase { + description: String, + allowed: bool, + request: T, +} + +/// Run tests from the given directory. +/// The directory is searched under `src/tools/genpolicy/tests/testdata`, and +/// it must contain a `resources.yaml` file as well as a `testcases.json` file. +/// The resources must produce a policy when fed into genpolicy, so there +/// should be exactly one entry with a PodSpec. The test case file must contain +/// a JSON list of [TestCase] instances appropriate for `T`. +fn runtests(test_case_dir: &str) +where + T: DeserializeOwned + Serialize, +{ + // Prepare temp dir for running genpolicy. + + let workdir = path::PathBuf::from(env!("CARGO_TARGET_TMPDIR")).join(test_case_dir); + fs::create_dir_all(&workdir) + .expect("should be able to create directories under CARGO_TARGET_TMPDIR"); + + let genpolicy_dir = path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); + + for base in ["rules.rego", "genpolicy-settings.json"] { + fs::copy(genpolicy_dir.join(base), workdir.join(base)) + .expect("copying files around should not fail"); + } + + let test_data = genpolicy_dir.join("tests/testdata").join(test_case_dir); + fs::copy(test_data.join("pod.yaml"), workdir.join("pod.yaml")) + .expect("copying files around should not fail"); + + // Run the command and return the generated policy. + + let output = Command::new(env!("CARGO_BIN_EXE_genpolicy")) + .current_dir(workdir) + .args(["-u", "-r", "-y", "pod.yaml"]) + .output() + .expect("executing the genpolicy command should not fail"); + + assert_eq!( + output.status.code(), + Some(0), + "genpolicy failed: {}", + str::from_utf8(output.stderr.as_slice()).expect("genpolicy should return status code 0") + ); + let policy = str::from_utf8(output.stdout.as_slice()) + .unwrap() + .to_string(); + + // Set up the policy engine. + + let mut pol = regorus::Engine::new(); + pol.add_policy("policy.rego".to_string(), policy).unwrap(); + + // Run through the test cases and evaluate the canned requests. + + let case_file = + File::open(test_data.join("testcases.json")).expect("test case file should open"); + let test_cases: Vec> = + serde_json::from_reader(case_file).expect("test case file should parse"); + + for test_case in test_cases { + println!("\n== case: {} ==\n", test_case.description); + + let v = serde_json::to_value(&test_case.request).unwrap(); + pol.set_input(v.into()); + let query = format!( + "data.agent_policy.{}", + any::type_name::().split("::").last().unwrap() + ); + assert_eq!(test_case.allowed, pol.eval_deny_query(query, true)); + } +} + +#[test] +fn test_copyfile() { + runtests::("copyfile"); +} + +#[test] +fn test_create_sandbox() { + runtests::("createsandbox"); +} diff --git a/src/tools/genpolicy/tests/testdata/copyfile/pod.yaml b/src/tools/genpolicy/tests/testdata/copyfile/pod.yaml new file mode 100644 index 0000000000..7ac6554ed9 --- /dev/null +++ b/src/tools/genpolicy/tests/testdata/copyfile/pod.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Pod +metadata: + name: dummy +spec: + runtimeClassName: kata-cc-isolation + containers: + - name: dummy + image: registry.k8s.io/pause:3.6@sha256:3d380ca8864549e74af4b29c10f9cb0956236dfb01c40ca076fb6c37253234db diff --git a/src/tools/genpolicy/tests/testdata/copyfile/testcases.json b/src/tools/genpolicy/tests/testdata/copyfile/testcases.json new file mode 100644 index 0000000000..0d420d81cf --- /dev/null +++ b/src/tools/genpolicy/tests/testdata/copyfile/testcases.json @@ -0,0 +1,16 @@ +[ + { + "description": "copy initiated by k8s mount", + "allowed": true, + "request": { + "path": "/run/kata-containers/shared/containers/81e5f43bc8599c5661e66f959ac28df5bfb30da23c5d583f2dcc6f9e0c5186dc-ce23cfeb91e75aaa-resolv.conf" + } + }, + { + "description": "attempt to copy outside of container root", + "allowed": false, + "request": { + "path": "/etc/ssl/cert.pem" + } + } +] diff --git a/src/tools/genpolicy/tests/testdata/createsandbox/pod.yaml b/src/tools/genpolicy/tests/testdata/createsandbox/pod.yaml new file mode 100644 index 0000000000..7ac6554ed9 --- /dev/null +++ b/src/tools/genpolicy/tests/testdata/createsandbox/pod.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Pod +metadata: + name: dummy +spec: + runtimeClassName: kata-cc-isolation + containers: + - name: dummy + image: registry.k8s.io/pause:3.6@sha256:3d380ca8864549e74af4b29c10f9cb0956236dfb01c40ca076fb6c37253234db diff --git a/src/tools/genpolicy/tests/testdata/createsandbox/testcases.json b/src/tools/genpolicy/tests/testdata/createsandbox/testcases.json new file mode 100644 index 0000000000..4a024221b1 --- /dev/null +++ b/src/tools/genpolicy/tests/testdata/createsandbox/testcases.json @@ -0,0 +1,9 @@ +[ + { + "description": "no pidns", + "allowed": true, + "request": { + "sandbox_pidns": false + } + } +] diff --git a/tools/packaging/static-build/tools/Dockerfile b/tools/packaging/static-build/tools/Dockerfile index ed112b72e4..cc87360ed6 100644 --- a/tools/packaging/static-build/tools/Dockerfile +++ b/tools/packaging/static-build/tools/Dockerfile @@ -30,5 +30,6 @@ RUN apk --no-cache add \ openssl-libs-static \ make \ musl-dev \ + perl \ protoc && \ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain ${RUST_TOOLCHAIN}