From f087044ecb7741ec24bf6da2d7e4d6f69f4ffb0f Mon Sep 17 00:00:00 2001 From: Dan Mihai Date: Sat, 13 Jul 2024 01:10:43 +0000 Subject: [PATCH] genpolicy: add support for runAsUser Add ability to auto-generate policy for SecurityContext.runAsUser and PodSecurityContext.runAsUser. Fixes: #8879 Signed-off-by: Dan Mihai --- src/tools/genpolicy/src/containerd.rs | 2 +- src/tools/genpolicy/src/pod.rs | 45 ++++++++++++++++++++------- src/tools/genpolicy/src/policy.rs | 4 ++- src/tools/genpolicy/src/yaml.rs | 5 +++ 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/src/tools/genpolicy/src/containerd.rs b/src/tools/genpolicy/src/containerd.rs index 22edb32f3..075fced5b 100644 --- a/src/tools/genpolicy/src/containerd.rs +++ b/src/tools/genpolicy/src/containerd.rs @@ -32,7 +32,7 @@ pub fn get_process(privileged_container: bool, common: &policy::CommonData) -> p Env: Vec::new(), Cwd: "/".to_string(), Capabilities: capabilities, - NoNewPrivileges: true, + NoNewPrivileges: false, } } diff --git a/src/tools/genpolicy/src/pod.rs b/src/tools/genpolicy/src/pod.rs index 403ae845f..e18c30ad4 100644 --- a/src/tools/genpolicy/src/pod.rs +++ b/src/tools/genpolicy/src/pod.rs @@ -92,6 +92,9 @@ pub struct PodSpec { #[serde(skip_serializing_if = "Option::is_none")] topologySpreadConstraints: Option>, + + #[serde(skip_serializing_if = "Option::is_none")] + securityContext: Option, } /// See Reference / Kubernetes API / Workload Resources / Pod. @@ -231,7 +234,7 @@ struct Probe { #[serde(skip_serializing_if = "Option::is_none")] tcpSocket: Option, - // TODO: additional fiels. + // TODO: additional fields. } /// See Reference / Kubernetes API / Workload Resources / Pod. @@ -259,7 +262,7 @@ struct HTTPGetAction { #[serde(skip_serializing_if = "Option::is_none")] httpHeaders: Option>, - // TODO: additional fiels. + // TODO: additional fields. } /// See Reference / Kubernetes API / Workload Resources / Pod. @@ -301,6 +304,14 @@ struct SeccompProfile { localhostProfile: Option, } +/// See Reference / Kubernetes API / Workload Resources / Pod. +#[derive(Clone, Debug, Serialize, Deserialize)] +struct PodSecurityContext { + #[serde(skip_serializing_if = "Option::is_none")] + runAsUser: Option, + // TODO: additional fields. +} + /// See Reference / Kubernetes API / Workload Resources / Pod. #[derive(Clone, Debug, Serialize, Deserialize)] struct Lifecycle { @@ -316,7 +327,7 @@ struct Lifecycle { struct LifecycleHandler { #[serde(skip_serializing_if = "Option::is_none")] exec: Option, - // TODO: additional fiels. + // TODO: additional fields. } /// See Reference / Kubernetes API / Workload Resources / Pod. @@ -571,15 +582,6 @@ impl Container { false } - pub fn allow_privilege_escalation(&self) -> bool { - if let Some(context) = &self.securityContext { - if let Some(allow) = context.allowPrivilegeEscalation { - return allow; - } - } - true - } - pub fn read_only_root_filesystem(&self) -> bool { if let Some(context) = &self.securityContext { if let Some(read_only) = context.readOnlyRootFilesystem { @@ -811,6 +813,14 @@ impl yaml::K8sResource for Pod { .clone() .or_else(|| Some(String::new())) } + + fn get_process_fields(&self, process: &mut policy::KataProcess) { + if let Some(context) = &self.spec.securityContext { + if let Some(uid) = context.runAsUser { + process.User.UID = uid.try_into().unwrap(); + } + } + } } impl Container { @@ -858,6 +868,17 @@ impl Container { } compress_default_capabilities(capabilities, defaults); } + + pub fn get_process_fields(&self, process: &mut policy::KataProcess) { + if let Some(context) = &self.securityContext { + if let Some(uid) = context.runAsUser { + process.User.UID = uid.try_into().unwrap(); + } + if let Some(allow) = context.allowPrivilegeEscalation { + process.NoNewPrivileges = !allow + } + } + } } fn compress_default_capabilities( diff --git a/src/tools/genpolicy/src/policy.rs b/src/tools/genpolicy/src/policy.rs index c04e14e70..50f80310e 100644 --- a/src/tools/genpolicy/src/policy.rs +++ b/src/tools/genpolicy/src/policy.rs @@ -657,8 +657,10 @@ impl AgentPolicy { substitute_env_variables(&mut process.Env); substitute_args_env_variables(&mut process.Args, &process.Env); + c_settings.get_process_fields(&mut process); - process.NoNewPrivileges = !yaml_container.allow_privilege_escalation(); + resource.get_process_fields(&mut process); + yaml_container.get_process_fields(&mut process); process } diff --git a/src/tools/genpolicy/src/yaml.rs b/src/tools/genpolicy/src/yaml.rs index d2c905cde..45e4388a2 100644 --- a/src/tools/genpolicy/src/yaml.rs +++ b/src/tools/genpolicy/src/yaml.rs @@ -94,6 +94,11 @@ pub trait K8sResource { fn get_runtime_class_name(&self) -> Option { None } + + fn get_process_fields(&self, _process: &mut policy::KataProcess) { + // Just Pods can have a PodSecurityContext field, so the other + // resources can use this default get_process_fields implementation. + } } /// See Reference / Kubernetes API / Common Definitions / LabelSelector.