mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-06-23 22:17:19 +00:00
Test using the host path /tmp/k8s-policy-pod-test instead of /var/lib/kubelet/pods. /var/lib/kubelet/pods might happen to contain files that CopyFileRequest would try to send to the Guest before CreateContainerRequest. Such CopyFileRequest was an unintended side effect of this test. Signed-off-by: Dan Mihai <dmihai@microsoft.com>
286 lines
11 KiB
Bash
286 lines
11 KiB
Bash
#!/usr/bin/env bats
|
|
#
|
|
# Copyright (c) 2024 Microsoft.
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
#
|
|
|
|
load "${BATS_TEST_DIRNAME}/../../common.bash"
|
|
load "${BATS_TEST_DIRNAME}/tests_common.sh"
|
|
|
|
issue="https://github.com/kata-containers/kata-containers/issues/10297"
|
|
|
|
setup() {
|
|
auto_generate_policy_enabled || skip "Auto-generated policy tests are disabled."
|
|
|
|
configmap_name="policy-configmap"
|
|
pod_name="policy-pod"
|
|
priority_class_name="test-high-priority"
|
|
|
|
get_pod_config_dir
|
|
policy_settings_dir="$(create_tmp_policy_settings_dir "${pod_config_dir}")"
|
|
|
|
exec_command=(printenv data-3)
|
|
add_exec_to_policy_settings "${policy_settings_dir}" "${exec_command[@]}"
|
|
add_requests_to_policy_settings "${policy_settings_dir}" "ReadStreamRequest"
|
|
|
|
correct_configmap_yaml="${pod_config_dir}/k8s-policy-configmap.yaml"
|
|
pre_generate_configmap_yaml="${pod_config_dir}/k8s-policy-configmap-pre-generation.yaml"
|
|
incorrect_configmap_yaml="${pod_config_dir}/k8s-policy-configmap-incorrect.yaml"
|
|
testcase_pre_generate_configmap_yaml="${pod_config_dir}/k8s-policy-configmap-testcase-pre-generation.yaml"
|
|
|
|
correct_pod_yaml="${pod_config_dir}/k8s-policy-pod.yaml"
|
|
priority_class_yaml="${pod_config_dir}/k8s-priority-class.yaml"
|
|
pre_generate_pod_yaml="${pod_config_dir}/k8s-policy-pod-pre-generation.yaml"
|
|
incorrect_pod_yaml="${pod_config_dir}/k8s-policy-pod-incorrect.yaml"
|
|
testcase_pre_generate_pod_yaml="${pod_config_dir}/k8s-policy-pod-testcase-pre-generation.yaml"
|
|
|
|
kubectl create -f "${priority_class_yaml}"
|
|
|
|
# Save some time by executing genpolicy a single time.
|
|
if [ "${BATS_TEST_NUMBER}" == "1" ]; then
|
|
# Work around #10297 if needed.
|
|
prometheus_image_supported || replace_prometheus_image
|
|
|
|
# Save pre-generated yaml files
|
|
cp "${correct_configmap_yaml}" "${pre_generate_configmap_yaml}"
|
|
cp "${correct_pod_yaml}" "${pre_generate_pod_yaml}"
|
|
|
|
# Add policy to the correct pod yaml file
|
|
auto_generate_policy "${policy_settings_dir}" "${correct_pod_yaml}" "${correct_configmap_yaml}"
|
|
fi
|
|
|
|
# Start each test case with a copy of the correct yaml files.
|
|
cp "${correct_configmap_yaml}" "${incorrect_configmap_yaml}"
|
|
cp "${correct_pod_yaml}" "${incorrect_pod_yaml}"
|
|
|
|
# Also give each testcase a copy of the pre-generated yaml files.
|
|
cp "${pre_generate_configmap_yaml}" "${testcase_pre_generate_configmap_yaml}"
|
|
cp "${pre_generate_pod_yaml}" "${testcase_pre_generate_pod_yaml}"
|
|
}
|
|
|
|
prometheus_image_supported() {
|
|
[[ "${SNAPSHOTTER:-}" == "nydus" ]] && return 1
|
|
return 0
|
|
}
|
|
|
|
replace_prometheus_image() {
|
|
info "Replacing prometheus image with busybox to work around ${issue}"
|
|
|
|
yq -i \
|
|
'.spec.containers[0].name = "busybox"' \
|
|
"${correct_pod_yaml}"
|
|
yq -i \
|
|
'.spec.containers[0].image = "quay.io/prometheus/busybox:latest"' \
|
|
"${correct_pod_yaml}"
|
|
}
|
|
|
|
# Common function for several test cases from this bats script.
|
|
wait_for_pod_ready() {
|
|
kubectl create -f "${correct_configmap_yaml}"
|
|
kubectl create -f "${correct_pod_yaml}"
|
|
kubectl wait --for=condition=Ready "--timeout=${timeout}" pod "${pod_name}"
|
|
}
|
|
|
|
@test "Successful pod with auto-generated policy" {
|
|
wait_for_pod_ready
|
|
}
|
|
|
|
@test "Able to read env variables sourced from configmap using envFrom" {
|
|
wait_for_pod_ready
|
|
expected_env_var=$(kubectl exec "${pod_name}" -- "${exec_command[@]}")
|
|
[ "$expected_env_var" = "value-3" ] || fail "expected_env_var is not equal to value-3"
|
|
}
|
|
|
|
@test "Successful pod with auto-generated policy and runtimeClassName filter" {
|
|
runtime_class_name=$(yq ".spec.runtimeClassName" < "${testcase_pre_generate_pod_yaml}")
|
|
|
|
auto_generate_policy "${pod_config_dir}" "${testcase_pre_generate_pod_yaml}" "${testcase_pre_generate_configmap_yaml}" \
|
|
"--runtime-class-names=other-runtime-class-name --runtime-class-names=${runtime_class_name}"
|
|
|
|
kubectl create -f "${testcase_pre_generate_configmap_yaml}"
|
|
kubectl create -f "${testcase_pre_generate_pod_yaml}"
|
|
kubectl wait --for=condition=Ready "--timeout=${timeout}" pod "${pod_name}"
|
|
}
|
|
|
|
@test "Successful pod with auto-generated policy and custom layers cache path" {
|
|
tmp_path=$(mktemp -d)
|
|
|
|
auto_generate_policy "${pod_config_dir}" "${testcase_pre_generate_pod_yaml}" "${testcase_pre_generate_configmap_yaml}" \
|
|
"--layers-cache-file-path=${tmp_path}/cache.json"
|
|
|
|
[ -f "${tmp_path}/cache.json" ]
|
|
rm -r "${tmp_path}"
|
|
|
|
kubectl create -f "${testcase_pre_generate_configmap_yaml}"
|
|
kubectl create -f "${testcase_pre_generate_pod_yaml}"
|
|
kubectl wait --for=condition=Ready "--timeout=${timeout}" pod "${pod_name}"
|
|
}
|
|
|
|
# Common function for several test cases from this bats script.
|
|
test_pod_policy_error() {
|
|
kubectl create -f "${correct_configmap_yaml}"
|
|
kubectl create -f "${incorrect_pod_yaml}"
|
|
wait_for_blocked_request "CreateContainerRequest" "${pod_name}"
|
|
}
|
|
|
|
@test "Policy failure: unexpected container image" {
|
|
# Change the container image after generating the policy. The different image has
|
|
# different attributes (e.g., different command line) so the policy will reject it.
|
|
yq -i \
|
|
'.spec.containers[0].image = "quay.io/footloose/ubuntu18.04:latest"' \
|
|
"${incorrect_pod_yaml}"
|
|
|
|
test_pod_policy_error
|
|
}
|
|
|
|
@test "Policy failure: unexpected privileged security context" {
|
|
# Changing the pod spec after generating its policy will cause CreateContainer to be denied.
|
|
yq -i \
|
|
'.spec.containers[0].securityContext.privileged = true' \
|
|
"${incorrect_pod_yaml}"
|
|
|
|
test_pod_policy_error
|
|
}
|
|
|
|
@test "Policy failure: unexpected terminationMessagePath" {
|
|
# Changing the pod spec after generating its policy will cause CreateContainer to be denied.
|
|
yq -i \
|
|
'.spec.containers[0].terminationMessagePath = "/dev/termination-custom-log"' \
|
|
"${incorrect_pod_yaml}"
|
|
|
|
test_pod_policy_error
|
|
}
|
|
|
|
@test "Policy failure: unexpected hostPath volume mount" {
|
|
# Changing the pod spec after generating its policy will cause CreateContainer to be denied.
|
|
yq -i \
|
|
'.spec.containers[0].volumeMounts += [{"name": "mountpoint-dir", "mountPath": "/hostpath-volume"}]' \
|
|
"${incorrect_pod_yaml}"
|
|
|
|
yq -i \
|
|
'.spec.volumes += [{"hostPath": {"path": "/tmp/k8s-policy-pod-test", "type": "DirectoryOrCreate"}, "name": "mountpoint-dir"}]' \
|
|
"${incorrect_pod_yaml}"
|
|
|
|
test_pod_policy_error
|
|
}
|
|
|
|
@test "Policy failure: unexpected config map" {
|
|
yq -i \
|
|
'.data.data-2 = "foo"' \
|
|
"${incorrect_configmap_yaml}"
|
|
|
|
# These commands are different from the test_pod_policy_error() commands above
|
|
# because in this case an incorrect config map spec is used.
|
|
kubectl create -f "${incorrect_configmap_yaml}"
|
|
kubectl create -f "${correct_pod_yaml}"
|
|
wait_for_blocked_request "CreateContainerRequest" "${pod_name}"
|
|
}
|
|
|
|
@test "Policy failure: unexpected lifecycle.postStart.exec.command" {
|
|
# Add a postStart command after generating the policy and verify that the post
|
|
# start hook command gets blocked by policy.
|
|
yq -i \
|
|
'.spec.containers[0].lifecycle.postStart.exec.command += ["echo"]' \
|
|
"${incorrect_pod_yaml}"
|
|
|
|
yq -i \
|
|
'.spec.containers[0].lifecycle.postStart.exec.command += ["hello"]' \
|
|
"${incorrect_pod_yaml}"
|
|
|
|
kubectl create -f "${correct_configmap_yaml}"
|
|
kubectl create -f "${incorrect_pod_yaml}"
|
|
|
|
command="kubectl describe pod ${pod_name} | grep FailedPostStartHook"
|
|
info "Waiting ${wait_time} seconds for: ${command}"
|
|
|
|
# Don't print the "Message:" line because it contains a truncated policy log.
|
|
waitForProcess "${wait_time}" "$sleep_time" "${command}" | grep -v "Message:"
|
|
}
|
|
|
|
@test "RuntimeClassName filter: no policy" {
|
|
# Solve a bats warning:
|
|
# BW02: Using flags on `run` requires at least BATS_VERSION=1.5.0.
|
|
# Use `bats_require_minimum_version 1.5.0` to fix this message.
|
|
bats_require_minimum_version 1.5.0
|
|
|
|
# The policy should not be generated because the pod spec does not have a runtimeClassName.
|
|
runtime_class_name=$(yq ".spec.runtimeClassName" < "${testcase_pre_generate_pod_yaml}")
|
|
|
|
auto_generate_policy "${pod_config_dir}" "${testcase_pre_generate_pod_yaml}" "${testcase_pre_generate_configmap_yaml}" \
|
|
"--runtime-class-names=other-${runtime_class_name}"
|
|
|
|
# Check that the pod yaml does not contain a policy annotation.
|
|
run ! grep -q "io.katacontainers.config.agent.policy" "${testcase_pre_generate_pod_yaml}"
|
|
}
|
|
|
|
@test "ExecProcessRequest tests" {
|
|
wait_for_pod_ready
|
|
|
|
# Execute commands allowed by the policy.
|
|
pod_exec_allowed_command "${pod_name}" "echo" "livenessProbe" "test"
|
|
pod_exec_allowed_command "${pod_name}" "echo" "-n" "readinessProbe with space characters"
|
|
pod_exec_allowed_command "${pod_name}" "echo" "startupProbe" "test"
|
|
|
|
# Try to execute commands disallowed by the policy.
|
|
pod_exec_blocked_command "${pod_name}" "echo" "livenessProbe test"
|
|
pod_exec_blocked_command "${pod_name}" "echo" "livenessProbe" "test2"
|
|
pod_exec_blocked_command "${pod_name}" "echo" "livenessProbe" "test" "yes"
|
|
pod_exec_blocked_command "${pod_name}" "echo" "livenessProbe" "test foo"
|
|
pod_exec_blocked_command "${pod_name}" "echo" "hello"
|
|
}
|
|
|
|
@test "Successful pod: runAsUser having the same value as the UID from the container image" {
|
|
prometheus_image_supported || skip "Test case not supported due to ${issue}"
|
|
|
|
# This container image specifies user = "nobody" that corresponds to UID = 65534. Setting
|
|
# the same value for runAsUser in the YAML file doesn't change the auto-generated Policy.
|
|
yq -i \
|
|
'.spec.containers[0].securityContext.runAsUser = 65534' \
|
|
"${incorrect_pod_yaml}"
|
|
|
|
kubectl create -f "${correct_configmap_yaml}"
|
|
kubectl create -f "${incorrect_pod_yaml}"
|
|
kubectl wait --for=condition=Ready "--timeout=${timeout}" pod "${pod_name}"
|
|
}
|
|
|
|
@test "Policy failure: unexpected UID = 0" {
|
|
prometheus_image_supported || skip "Test case not supported due to ${issue}"
|
|
|
|
# Change the container UID to 0 after the policy has been generated, and verify that the
|
|
# change gets rejected by the policy. UID = 0 is the default value from genpolicy, but
|
|
# this container image specifies user = "nobody" that corresponds to UID = 65534.
|
|
yq -i \
|
|
'.spec.containers[0].securityContext.runAsUser = 0' \
|
|
"${incorrect_pod_yaml}"
|
|
|
|
test_pod_policy_error
|
|
}
|
|
|
|
@test "Policy failure: unexpected UID = 1234" {
|
|
# Change the container UID to 1234 after the policy has been generated, and verify that the
|
|
# change gets rejected by the policy. This container image specifies user = "nobody" that
|
|
# corresponds to UID = 65534.
|
|
yq -i \
|
|
'.spec.containers[0].securityContext.runAsUser = 1234' \
|
|
"${incorrect_pod_yaml}"
|
|
|
|
test_pod_policy_error
|
|
}
|
|
|
|
teardown() {
|
|
auto_generate_policy_enabled || skip "Auto-generated policy tests are disabled."
|
|
|
|
# Debugging information. Don't print the "Message:" line because it contains a truncated policy log.
|
|
kubectl describe pod "${pod_name}" | grep -v "Message:"
|
|
|
|
# Clean-up
|
|
kubectl delete pod "${pod_name}"
|
|
kubectl delete configmap "${configmap_name}"
|
|
kubectl delete priorityClass "${priority_class_name}"
|
|
rm -f "${incorrect_pod_yaml}"
|
|
rm -f "${incorrect_configmap_yaml}"
|
|
rm -f "${testcase_pre_generate_pod_yaml}"
|
|
rm -f "${testcase_pre_generate_configmap_yaml}"
|
|
}
|