genpolicy: add support for runAsUser

Add ability to auto-generate policy for SecurityContext.runAsUser and
PodSecurityContext.runAsUser.

Fixes: #8879

Signed-off-by: Dan Mihai <dmihai@microsoft.com>
This commit is contained in:
Dan Mihai 2024-07-13 01:10:43 +00:00
parent 5282701b5b
commit f087044ecb
4 changed files with 42 additions and 14 deletions

View File

@ -32,7 +32,7 @@ pub fn get_process(privileged_container: bool, common: &policy::CommonData) -> p
Env: Vec::new(), Env: Vec::new(),
Cwd: "/".to_string(), Cwd: "/".to_string(),
Capabilities: capabilities, Capabilities: capabilities,
NoNewPrivileges: true, NoNewPrivileges: false,
} }
} }

View File

@ -92,6 +92,9 @@ pub struct PodSpec {
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
topologySpreadConstraints: Option<Vec<TopologySpreadConstraint>>, topologySpreadConstraints: Option<Vec<TopologySpreadConstraint>>,
#[serde(skip_serializing_if = "Option::is_none")]
securityContext: Option<PodSecurityContext>,
} }
/// See Reference / Kubernetes API / Workload Resources / Pod. /// See Reference / Kubernetes API / Workload Resources / Pod.
@ -231,7 +234,7 @@ struct Probe {
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
tcpSocket: Option<TCPSocketAction>, tcpSocket: Option<TCPSocketAction>,
// TODO: additional fiels. // TODO: additional fields.
} }
/// See Reference / Kubernetes API / Workload Resources / Pod. /// See Reference / Kubernetes API / Workload Resources / Pod.
@ -259,7 +262,7 @@ struct HTTPGetAction {
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
httpHeaders: Option<Vec<HTTPHeader>>, httpHeaders: Option<Vec<HTTPHeader>>,
// TODO: additional fiels. // TODO: additional fields.
} }
/// See Reference / Kubernetes API / Workload Resources / Pod. /// See Reference / Kubernetes API / Workload Resources / Pod.
@ -301,6 +304,14 @@ struct SeccompProfile {
localhostProfile: Option<String>, localhostProfile: Option<String>,
} }
/// See Reference / Kubernetes API / Workload Resources / Pod.
#[derive(Clone, Debug, Serialize, Deserialize)]
struct PodSecurityContext {
#[serde(skip_serializing_if = "Option::is_none")]
runAsUser: Option<i64>,
// TODO: additional fields.
}
/// See Reference / Kubernetes API / Workload Resources / Pod. /// See Reference / Kubernetes API / Workload Resources / Pod.
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
struct Lifecycle { struct Lifecycle {
@ -316,7 +327,7 @@ struct Lifecycle {
struct LifecycleHandler { struct LifecycleHandler {
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
exec: Option<ExecAction>, exec: Option<ExecAction>,
// TODO: additional fiels. // TODO: additional fields.
} }
/// See Reference / Kubernetes API / Workload Resources / Pod. /// See Reference / Kubernetes API / Workload Resources / Pod.
@ -571,15 +582,6 @@ impl Container {
false 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 { pub fn read_only_root_filesystem(&self) -> bool {
if let Some(context) = &self.securityContext { if let Some(context) = &self.securityContext {
if let Some(read_only) = context.readOnlyRootFilesystem { if let Some(read_only) = context.readOnlyRootFilesystem {
@ -811,6 +813,14 @@ impl yaml::K8sResource for Pod {
.clone() .clone()
.or_else(|| Some(String::new())) .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 { impl Container {
@ -858,6 +868,17 @@ impl Container {
} }
compress_default_capabilities(capabilities, defaults); 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( fn compress_default_capabilities(

View File

@ -657,8 +657,10 @@ impl AgentPolicy {
substitute_env_variables(&mut process.Env); substitute_env_variables(&mut process.Env);
substitute_args_env_variables(&mut process.Args, &process.Env); substitute_args_env_variables(&mut process.Args, &process.Env);
c_settings.get_process_fields(&mut process); 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 process
} }

View File

@ -94,6 +94,11 @@ pub trait K8sResource {
fn get_runtime_class_name(&self) -> Option<String> { fn get_runtime_class_name(&self) -> Option<String> {
None 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. /// See Reference / Kubernetes API / Common Definitions / LabelSelector.