genpolicy: fix validation of env variables sourced from metadata.namespace

Use $(sandbox-namespace) wildcard in case none is specified in yaml. If wildcard is present, compare
input against annotation value.

Fixes regression introduced in https://github.com/microsoft/kata-containers/pull/273
where samples that use metadata.namespace env var were no longer working.

Signed-off-by: Saul Paredes <saulparedes@microsoft.com>
This commit is contained in:
Saul Paredes 2025-01-14 17:25:03 -08:00 committed by Ankita Pareek
parent a113b9eefd
commit 1e466bf39c
2 changed files with 61 additions and 26 deletions

View File

@ -268,7 +268,10 @@ allow_by_anno(p_oci, i_oci, p_storages, i_storages) {
i_s_name := i_oci.Annotations[S_NAME_KEY]
print("allow_by_anno 1: i_s_name =", i_s_name)
allow_by_sandbox_name(p_oci, i_oci, p_storages, i_storages, i_s_name)
i_s_namespace := i_oci.Annotations[S_NAMESPACE_KEY]
print("allow_by_anno 1: i_s_namespace =", i_s_namespace)
allow_by_sandbox_name(p_oci, i_oci, p_storages, i_storages, i_s_name, i_s_namespace)
print("allow_by_anno 1: true")
}
@ -280,19 +283,23 @@ allow_by_anno(p_oci, i_oci, p_storages, i_storages) {
print("allow_by_anno 2: i_s_name =", i_s_name, "p_s_name =", p_s_name)
allow_sandbox_name(p_s_name, i_s_name)
allow_by_sandbox_name(p_oci, i_oci, p_storages, i_storages, i_s_name)
i_s_namespace := i_oci.Annotations[S_NAMESPACE_KEY]
print("allow_by_anno 2: i_s_namespace =", i_s_namespace)
allow_by_sandbox_name(p_oci, i_oci, p_storages, i_storages, i_s_name, i_s_namespace)
print("allow_by_anno 2: true")
}
allow_by_sandbox_name(p_oci, i_oci, p_storages, i_storages, s_name) {
allow_by_sandbox_name(p_oci, i_oci, p_storages, i_storages, s_name, s_namespace) {
print("allow_by_sandbox_name: start")
i_namespace := i_oci.Annotations[S_NAMESPACE_KEY]
allow_by_container_types(p_oci, i_oci, s_name, i_namespace)
allow_by_bundle_or_sandbox_id(p_oci, i_oci, p_storages, i_storages)
allow_process(p_oci.Process, i_oci.Process, s_name)
allow_process(p_oci.Process, i_oci.Process, s_name, s_namespace)
print("allow_by_sandbox_name: true")
}
@ -668,7 +675,7 @@ allow_by_bundle_or_sandbox_id(p_oci, i_oci, p_storages, i_storages) {
print("allow_by_bundle_or_sandbox_id: true")
}
allow_process_common(p_process, i_process, s_name) {
allow_process_common(p_process, i_process, s_name, s_namespace) {
print("allow_process_common: p_process =", p_process)
print("allow_process_common: i_process = ", i_process)
print("allow_process_common: s_name =", s_name)
@ -677,17 +684,17 @@ allow_process_common(p_process, i_process, s_name) {
p_process.NoNewPrivileges == i_process.NoNewPrivileges
allow_user(p_process, i_process)
allow_env(p_process, i_process, s_name)
allow_env(p_process, i_process, s_name, s_namespace)
print("allow_process_common: true")
}
# Compare the OCI Process field of a policy container with the input OCI Process from a CreateContainerRequest
allow_process(p_process, i_process, s_name) {
allow_process(p_process, i_process, s_name, s_namespace) {
print("allow_process: start")
allow_args(p_process, i_process, s_name)
allow_process_common(p_process, i_process, s_name)
allow_process_common(p_process, i_process, s_name, s_namespace)
allow_caps(p_process.Capabilities, i_process.Capabilities)
p_process.Terminal == i_process.Terminal
@ -695,10 +702,10 @@ allow_process(p_process, i_process, s_name) {
}
# Compare the OCI Process field of a policy container with the input process field from ExecProcessRequest
allow_interactive_process(p_process, i_process, s_name) {
allow_interactive_process(p_process, i_process, s_name, s_namespace) {
print("allow_interactive_process: start")
allow_process_common(p_process, i_process, s_name)
allow_process_common(p_process, i_process, s_name, s_namespace)
allow_exec_caps(i_process.Capabilities)
# These are commands enabled using ExecProcessRequest commands and/or regex from the settings file.
@ -708,10 +715,10 @@ allow_interactive_process(p_process, i_process, s_name) {
}
# Compare the OCI Process field of a policy container with the input process field from ExecProcessRequest
allow_probe_process(p_process, i_process, s_name) {
allow_probe_process(p_process, i_process, s_name, s_namespace) {
print("allow_probe_process: start")
allow_process_common(p_process, i_process, s_name)
allow_process_common(p_process, i_process, s_name, s_namespace)
allow_exec_caps(i_process.Capabilities)
p_process.Terminal == i_process.Terminal
@ -783,38 +790,48 @@ allow_arg(i, i_arg, p_process, s_name) {
}
# OCI process.Env field
allow_env(p_process, i_process, s_name) {
allow_env(p_process, i_process, s_name, s_namespace) {
print("allow_env: p env =", p_process.Env)
print("allow_env: i env =", i_process.Env)
every i_var in i_process.Env {
print("allow_env: i_var =", i_var)
allow_var(p_process, i_process, i_var, s_name)
allow_var(p_process, i_process, i_var, s_name, s_namespace)
}
print("allow_env: true")
}
# Allow input env variables that are present in the policy data too.
allow_var(p_process, i_process, i_var, s_name) {
allow_var(p_process, i_process, i_var, s_name, s_namespace) {
some p_var in p_process.Env
p_var == i_var
print("allow_var 1: true")
}
# Match input with one of the policy variables, after substituting $(sandbox-name).
allow_var(p_process, i_process, i_var, s_name) {
allow_var(p_process, i_process, i_var, s_name, s_namespace) {
some p_var in p_process.Env
p_var2 := replace(p_var, "$(sandbox-name)", s_name)
print("allow_var 2: p_var2 =", p_var2)
p_var2 == i_var
print("allow_var 2: p_var =", p_var)
p_var_split := split(p_var, "=")
count(p_var_split) == 2
p_var_split[1] == "$(sandbox-name)"
i_var_split := split(i_var, "=")
count(i_var_split) == 2
i_var_split[0] == p_var_split[0]
regex.match(s_name, i_var_split[1])
print("allow_var 2: true")
}
# Allow input env variables that match with a request_defaults regex.
allow_var(p_process, i_process, i_var, s_name) {
allow_var(p_process, i_process, i_var, s_name, s_namespace) {
some p_regex1 in policy_data.request_defaults.CreateContainerRequest.allow_env_regex
p_regex2 := replace(p_regex1, "$(ipv4_a)", policy_data.common.ipv4_a)
p_regex3 := replace(p_regex2, "$(ip_p)", policy_data.common.ip_p)
@ -828,7 +845,7 @@ allow_var(p_process, i_process, i_var, s_name) {
}
# Allow fieldRef "fieldPath: status.podIP" values.
allow_var(p_process, i_process, i_var, s_name) {
allow_var(p_process, i_process, i_var, s_name, s_namespace) {
name_value := split(i_var, "=")
count(name_value) == 2
is_ip(name_value[1])
@ -840,7 +857,7 @@ allow_var(p_process, i_process, i_var, s_name) {
}
# Allow common fieldRef variables.
allow_var(p_process, i_process, i_var, s_name) {
allow_var(p_process, i_process, i_var, s_name, s_namespace) {
name_value := split(i_var, "=")
count(name_value) == 2
@ -859,7 +876,7 @@ allow_var(p_process, i_process, i_var, s_name) {
}
# Allow fieldRef "fieldPath: status.hostIP" values.
allow_var(p_process, i_process, i_var, s_name) {
allow_var(p_process, i_process, i_var, s_name, s_namespace) {
name_value := split(i_var, "=")
count(name_value) == 2
is_ip(name_value[1])
@ -871,7 +888,7 @@ allow_var(p_process, i_process, i_var, s_name) {
}
# Allow resourceFieldRef values (e.g., "limits.cpu").
allow_var(p_process, i_process, i_var, s_name) {
allow_var(p_process, i_process, i_var, s_name, s_namespace) {
name_value := split(i_var, "=")
count(name_value) == 2
@ -889,6 +906,16 @@ allow_var(p_process, i_process, i_var, s_name) {
print("allow_var 7: true")
}
allow_var(p_process, i_process, i_var, s_name, s_namespace) {
some p_var in p_process.Env
p_var2 := replace(p_var, "$(sandbox-namespace)", s_namespace)
print("allow_var 8: p_var2 =", p_var2)
p_var2 == i_var
print("allow_var 8: true")
}
allow_pod_ip_var(var_name, p_var) {
print("allow_pod_ip_var: var_name =", var_name, "p_var =", p_var)
@ -1337,7 +1364,8 @@ allow_exec(p_container, i_process) {
p_oci = p_container.OCI
p_s_name = p_oci.Annotations[S_NAME_KEY]
allow_probe_process(p_oci.Process, i_process, p_s_name)
s_namespace = get_state_val("namespace")
allow_probe_process(p_oci.Process, i_process, p_s_name, s_namespace)
print("allow_exec: true")
}
@ -1347,7 +1375,8 @@ allow_interactive_exec(p_container, i_process) {
p_oci = p_container.OCI
p_s_name = p_oci.Annotations[S_NAME_KEY]
allow_interactive_process(p_oci.Process, i_process, p_s_name)
s_namespace = get_state_val("namespace")
allow_interactive_process(p_oci.Process, i_process, p_s_name, s_namespace)
print("allow_interactive_exec: true")
}

View File

@ -782,7 +782,13 @@ impl EnvVar {
let path: &str = &field_ref.fieldPath;
match path {
"metadata.name" => return "$(sandbox-name)".to_string(),
"metadata.namespace" => return namespace.to_string(),
"metadata.namespace" => {
return if namespace.is_empty() {
"$(sandbox-namespace)".to_string()
} else {
namespace.to_string()
};
}
"metadata.uid" => return "$(pod-uid)".to_string(),
"status.hostIP" => return "$(host-ip)".to_string(),
"status.podIP" => return "$(pod-ip)".to_string(),