From 18c887f055b58fc88ad87e667a2cbd7b080e12ed Mon Sep 17 00:00:00 2001 From: Sumedh Alok Sharma Date: Fri, 13 Sep 2024 15:24:22 +0530 Subject: [PATCH] agent-ctl: Add SetPolicy support This patch adds support to call kata agents SetPolicy API. Also adds tests for SetPolicy API using agent-ctl. Fixes #9711 Signed-off-by: Sumedh Alok Sharma --- src/tools/agent-ctl/src/client.rs | 32 +++++++++++++- src/tools/agent-ctl/src/types.rs | 6 +++ src/tools/agent-ctl/src/utils.rs | 28 +++++++++++- .../api-tests/test_set_policy.bats | 44 +++++++++++++++++++ .../kata-agent-apis/setup_common.sh | 13 ++++++ 5 files changed, 120 insertions(+), 3 deletions(-) create mode 100755 tests/functional/kata-agent-apis/api-tests/test_set_policy.bats diff --git a/src/tools/agent-ctl/src/client.rs b/src/tools/agent-ctl/src/client.rs index 137dc75b78..42065b5aa9 100644 --- a/src/tools/agent-ctl/src/client.rs +++ b/src/tools/agent-ctl/src/client.rs @@ -5,7 +5,7 @@ // Description: Client side of ttRPC comms -use crate::types::{Config, CopyFileInput, Options}; +use crate::types::{Config, CopyFileInput, Options, SetPolicyInput}; use crate::utils; use anyhow::{anyhow, Result}; use byteorder::ByteOrder; @@ -288,6 +288,11 @@ static AGENT_CMDS: &[AgentCmd] = &[ st: ServiceType::Agent, fp: agent_cmd_container_write_stdin, }, + AgentCmd { + name: "SetPolicy", + st: ServiceType::Agent, + fp: agent_cmd_sandbox_set_policy, + }, ]; static BUILTIN_CMDS: & [BuiltinCmd] = &[ @@ -2115,3 +2120,28 @@ fn agent_cmd_sandbox_add_swap( Ok(()) } + +fn agent_cmd_sandbox_set_policy( + ctx: &Context, + client: &AgentServiceClient, + _health: &HealthClient, + _options: &mut Options, + args: &str, +) -> Result<()> { + let input: SetPolicyInput = utils::make_request(args)?; + + let req = utils::make_set_policy_request(&input)?; + + let ctx = clone_context(ctx); + + info!(sl!(), "sending request"; "request" => format!("{:?}", req)); + + let reply = client + .set_policy(ctx, &req) + .map_err(|e| anyhow!("{:?}", e).context(ERR_API_FAILED))?; + + info!(sl!(), "response received"; + "response" => format!("{:?}", reply)); + + Ok(()) +} diff --git a/src/tools/agent-ctl/src/types.rs b/src/tools/agent-ctl/src/types.rs index 547fa7beaa..743cc9bec8 100644 --- a/src/tools/agent-ctl/src/types.rs +++ b/src/tools/agent-ctl/src/types.rs @@ -27,3 +27,9 @@ pub struct CopyFileInput { pub src: String, pub dest: String, } + +// SetPolicy input request +#[derive(Debug, Default, Clone, Serialize, Deserialize)] +pub struct SetPolicyInput { + pub policy_file: String, +} diff --git a/src/tools/agent-ctl/src/utils.rs b/src/tools/agent-ctl/src/utils.rs index 22e030a679..a75a26b441 100644 --- a/src/tools/agent-ctl/src/utils.rs +++ b/src/tools/agent-ctl/src/utils.rs @@ -3,17 +3,18 @@ // SPDX-License-Identifier: Apache-2.0 // -use crate::types::{Config, CopyFileInput, Options}; +use crate::types::{Config, CopyFileInput, Options, SetPolicyInput}; use anyhow::{anyhow, Result}; use oci::{Root as ociRoot, Spec as ociSpec}; use oci_spec::runtime as oci; -use protocols::agent::CopyFileRequest; +use protocols::agent::{CopyFileRequest, SetPolicyRequest}; use protocols::oci::{Mount as ttrpcMount, Root as ttrpcRoot, Spec as ttrpcSpec}; use rand::Rng; use serde::de::DeserializeOwned; use slog::{debug, warn}; use std::collections::HashMap; use std::fs::{self, File}; +use std::io::Read; use std::os::unix::fs::MetadataExt; use std::path::PathBuf; use std::sync::{Arc, Mutex}; @@ -468,3 +469,26 @@ pub fn make_copy_file_request(input: &CopyFileInput) -> Result Ok(req) } + +pub fn make_set_policy_request(input: &SetPolicyInput) -> Result { + let mut policy_file = File::open(&input.policy_file)?; + let metadata = policy_file.metadata()?; + + let mut policy_data = String::new(); + match policy_file.read_to_string(&mut policy_data) { + Ok(bytes_read) => { + if bytes_read != metadata.len() as usize { + return Err(anyhow!( + "Failed to read all policy data, size {} read {}", + metadata.len(), + bytes_read + )); + } + } + Err(e) => return Err(anyhow!("Error reading policy file: {}", e)), + } + + let mut req = SetPolicyRequest::default(); + req.set_policy(policy_data); + Ok(req) +} diff --git a/tests/functional/kata-agent-apis/api-tests/test_set_policy.bats b/tests/functional/kata-agent-apis/api-tests/test_set_policy.bats new file mode 100755 index 0000000000..6d2f5df7ff --- /dev/null +++ b/tests/functional/kata-agent-apis/api-tests/test_set_policy.bats @@ -0,0 +1,44 @@ +#!/usr/bin/env bats + +# Copyright (c) 2024 Microsoft Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +load "${BATS_TEST_DIRNAME}/../../../common.bash" +load "${BATS_TEST_DIRNAME}/../setup_common.sh" + +setup_file() { + info "setup" +} + +@test "Test SetPolicy API: Set allow all policy" { + info "Upload policy document from under src/kata-opa" + repo_root_dir="${BATS_TEST_DIRNAME}/../../../../" + policy_dir="${repo_root_dir}/src/kata-opa" + policy_file="${policy_dir}/allow-all.rego" + local cmds=() + cmds+=("-c 'SetPolicy json://{\"policy_file\": \"$policy_file\"}'") + run_agent_ctl "${cmds[@]}" +} + +@test "Test SetPolicy API: Block CopyFile in policy" { + policy_file=$(mktemp) + deny_single_api_in_policy ${policy_file} "CopyFileRequest" + local cmds=() + cmds+=("-c 'SetPolicy json://{\"policy_file\": \"$policy_file\"}'") + run_agent_ctl "${cmds[@]}" + + src_file=$(mktemp) + local cmds=() + cmds+=("-c 'CopyFile json://{\"src\": \"$src_file\", \"dest\":\"/run/kata-containers/foo\"}'") + run run_agent_ctl "${cmds[@]}" + [ "$status" -ne 0 ] + + rm $src_file + rm $policy_file +} + +teardown_file() { + info "teardown" + sudo rm -r /run/kata-containers/ || echo "Failed to clean /run/kata-containers" +} diff --git a/tests/functional/kata-agent-apis/setup_common.sh b/tests/functional/kata-agent-apis/setup_common.sh index bc8d091a8a..09d6278003 100755 --- a/tests/functional/kata-agent-apis/setup_common.sh +++ b/tests/functional/kata-agent-apis/setup_common.sh @@ -205,3 +205,16 @@ try_and_remove_coco_attestation_procs() [ -f "${procs_path}${i}" ] && sudo mv "${procs_path}${i}" /tmp || true done } + +deny_single_api_in_policy() +{ + info "Setting default deny for single API in policy" + local pol_file=$1 + local deny_req=$2 + + [ ! -f $local_policy_file ] && install_policy_doc + + info "Not allowing ${deny_req}" + sudo cp $local_policy_file $pol_file + sed -i "s/\(.*$deny_req.*:= \)\(.*\)/\1false/" $pol_file +}