From bec3c3e2aa5d155d4d46601aec86cf843dca4f86 Mon Sep 17 00:00:00 2001 From: Xianglin Gao Date: Thu, 1 Dec 2016 21:15:47 +0800 Subject: [PATCH] add test cases Signed-off-by: Xianglin Gao --- Dockerfile | 1 + Makefile | 2 +- test/apparmor.bats | 137 +++++++++++++++++++++++++ test/helpers.bash | 29 +++++- test/testdata/apparmor_test_deny_write | 10 ++ 5 files changed, 175 insertions(+), 4 deletions(-) create mode 100644 test/apparmor.bats create mode 100644 test/testdata/apparmor_test_deny_write diff --git a/Dockerfile b/Dockerfile index 6ceb28f7..7d99e145 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,6 +19,7 @@ RUN apt-get update && apt-get install -y \ protobuf-compiler \ python-minimal \ libglib2.0-dev \ + libapparmor-dev \ --no-install-recommends # install bats diff --git a/Makefile b/Makefile index 2d719955..4df37f71 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ ETCDIR ?= ${DESTDIR}/etc ETCDIR_OCID ?= ${ETCDIR}/ocid GO_MD2MAN ?= $(shell which go-md2man) export GOPATH := ${CURDIR}/vendor -BUILDTAGS := selinux seccomp +BUILDTAGS := selinux seccomp apparmor all: binaries ocid.conf docs diff --git a/test/apparmor.bats b/test/apparmor.bats new file mode 100644 index 00000000..4b656133 --- /dev/null +++ b/test/apparmor.bats @@ -0,0 +1,137 @@ +#!/usr/bin/env bats + +load helpers + +function teardown() { + cleanup_test +} + +# 1. test running with loading the default apparmor profile. +# test that we can run with the default apparomr profile which will not block touching a file in `.` +@test "load default apparomr profile and run a container with it" { + # this test requires docker, thus it can't yet be run in a container + if [ "$TRAVIS" = "true" ]; then # instead of $TRAVIS, add a function is_containerized to skip here + skip "cannot yet run this test in a container, use sudo make localintegration" + fi + + start_ocid + + sed -e 's/%VALUE%/,"container\.apparmor\.security\.beta\.kubernetes\.io\/testname1": "runtime\/default"/g' "$TESTDATA"/sandbox_config_seccomp.json > "$TESTDIR"/apparmor1.json + + run ocic pod create --name apparmor1 --config "$TESTDIR"/apparmor1.json + echo "$output" + [ "$status" -eq 0 ] + pod_id="$output" + run ocic ctr create --name testname1 --config "$TESTDATA"/container_redis.json --pod "$pod_id" + echo "$output" + [ "$status" -eq 0 ] + ctr_id="$output" + run ocic ctr start --id "$ctr_id" + echo "$output" + [ "$status" -eq 0 ] + run ocic ctr execsync --id "$ctr_id" touch test.txt + echo "$output" + [ "$status" -eq 0 ] + + + cleanup_ctrs + cleanup_pods + stop_ocid +} + +# 2. test running with loading a specific apparmor profile as ocid default apparmor profile. +# test that we can run with a specific apparmor profile which will block touching a file in `.` as ocid default apparmor profile. +@test "load a specific apparomr profile as default apparmor and run a container with it" { + # this test requires docker, thus it can't yet be run in a container + if [ "$TRAVIS" = "true" ]; then # instead of $TRAVIS, add a function is_containerized to skip here + skip "cannot yet run this test in a container, use sudo make localintegration" + fi + + load_apparmor_test_profile + start_ocid_with_apparmor_profile_name "$APPARMOR_TEST_PROFILE_NAME" + + sed -e 's/%VALUE%/,"container\.apparmor\.security\.beta\.kubernetes\.io\/testname2": "apparmor_test_deny_write"/g' "$TESTDATA"/sandbox_config_seccomp.json > "$TESTDIR"/apparmor2.json + + run ocic pod create --name apparmor2 --config "$TESTDIR"/apparmor2.json + echo "$output" + [ "$status" -eq 0 ] + pod_id="$output" + run ocic ctr create --name testname2 --config "$TESTDATA"/container_redis.json --pod "$pod_id" + echo "$output" + [ "$status" -eq 0 ] + ctr_id="$output" + run ocic ctr start --id "$ctr_id" + echo "$output" + [ "$status" -eq 0 ] + run ocic ctr execsync --id "$ctr_id" touch test.txt + echo "$output" + [ "$status" -ne 0 ] + [[ "$output" =~ "Permission denied" ]] + + cleanup_ctrs + cleanup_pods + stop_ocid + remove_apparmor_test_profile +} + +# 3. test running with loading a specific apparmor profile but not as ocid default apparmor profile. +# test that we can run with a specific apparmor profile which will block touching a file in `.` +@test "load default apparomr profile and run a container with another apparmor profile" { + # this test requires docker, thus it can't yet be run in a container + if [ "$TRAVIS" = "true" ]; then # instead of $TRAVIS, add a function is_containerized to skip here + skip "cannot yet run this test in a container, use sudo make localintegration" + fi + + load_apparmor_test_profile + start_ocid + + sed -e 's/%VALUE%/,"container\.apparmor\.security\.beta\.kubernetes\.io\/testname3": "apparmor_test_deny_write"/g' "$TESTDATA"/sandbox_config_seccomp.json > "$TESTDIR"/apparmor3.json + + run ocic pod create --name apparmor3 --config "$TESTDIR"/apparmor3.json + echo "$output" + [ "$status" -eq 0 ] + pod_id="$output" + run ocic ctr create --name testname3 --config "$TESTDATA"/container_redis.json --pod "$pod_id" + echo "$output" + [ "$status" -eq 0 ] + ctr_id="$output" + run ocic ctr start --id "$ctr_id" + echo "$output" + [ "$status" -eq 0 ] + run ocic ctr execsync --id "$ctr_id" touch test.txt + echo "$output" + [ "$status" -ne 0 ] + [[ "$output" =~ "Permission denied" ]] + + cleanup_ctrs + cleanup_pods + stop_ocid + remove_apparmor_test_profile +} + +# 1. test running with wrong apparmor profile name. +# test that we can will fail when running a ctr with rong apparmor profile name. +@test "run a container with wrong apparmor profile name" { + # this test requires docker, thus it can't yet be run in a container + if [ "$TRAVIS" = "true" ]; then # instead of $TRAVIS, add a function is_containerized to skip here + skip "cannot yet run this test in a container, use sudo make localintegration" + fi + + start_ocid + + sed -e 's/%VALUE%/,"container\.apparmor\.security\.beta\.kubernetes\.io\/testname4": "not-exists"/g' "$TESTDATA"/sandbox_config_seccomp.json > "$TESTDIR"/apparmor4.json + + run ocic pod create --name apparmor4 --config "$TESTDIR"/apparmor4.json + echo "$output" + [ "$status" -eq 0 ] + pod_id="$output" + run ocic ctr create --name testname4 --config "$TESTDATA"/container_redis.json --pod "$pod_id" + echo "$output" + [ "$status" -ne 0 ] + [[ "$output" =~ "Creating container failed" ]] + + + cleanup_ctrs + cleanup_pods + stop_ocid +} diff --git a/test/helpers.bash b/test/helpers.bash index d02f5988..54895fee 100644 --- a/test/helpers.bash +++ b/test/helpers.bash @@ -17,11 +17,19 @@ OCIC_BINARY=${OCIC_BINARY:-${OCID_ROOT}/cri-o/ocic} CONMON_BINARY=${CONMON_BINARY:-${OCID_ROOT}/cri-o/conmon/conmon} # Path of the pause binary. PAUSE_BINARY=${PAUSE_BINARY:-${OCID_ROOT}/cri-o/pause/pause} -# Path of the default seccomp profile +# Path of the default seccomp profile. SECCOMP_PROFILE=${SECCOMP_PROFILE:-${OCID_ROOT}/cri-o/seccomp.json} +# Name of the default apparmor profile. +APPARMOR_DEFAULT_PROFILE=${SECCOMP_PROFILE:-ocid-default} # Path of the runc binary. RUNC_PATH=$(command -v runc || true) RUNC_BINARY=${RUNC_PATH:-/usr/local/sbin/runc} +# Path of the apparmor_parser binary. +APPARMOR_PARSER_BINARY=${APPARMOR_PARSER_BINARY:-/sbin/apparmor_parser} +# Path of the apparmor profile for test. +APPARMOR_TEST_PROFILE_PATH=${APPARMOR_TEST_PROFILE_PATH:-${TESTDATA}/apparmor_test_deny_write} +# Name of the apparmor profile for test. +APPARMOR_TEST_PROFILE_NAME=${APPARMOR_TEST_PROFILE_NAME:-apparmor_test_deny_write} TESTDIR=$(mktemp -d) if [ -e /usr/sbin/selinuxenabled ] && /usr/sbin/selinuxenabled; then @@ -80,13 +88,19 @@ function wait_until_reachable() { # Start ocid. function start_ocid() { - "$OCID_BINARY" --conmon "$CONMON_BINARY" --pause "$PAUSE_BINARY" --listen "$OCID_SOCKET" --runtime "$RUNC_BINARY" --root "$TESTDIR/ocid" --sandboxdir "$TESTDIR/sandboxes" --containerdir "$TESTDIR/ocid/containers" --seccomp-profile "$SECCOMP_PROFILE" config >$OCID_CONFIG + "$OCID_BINARY" --conmon "$CONMON_BINARY" --pause "$PAUSE_BINARY" --listen "$OCID_SOCKET" --runtime "$RUNC_BINARY" --root "$TESTDIR/ocid" --sandboxdir "$TESTDIR/sandboxes" --containerdir "$TESTDIR/ocid/containers" --seccomp-profile "$SECCOMP_PROFILE" --apparmor-profile "$APPARMOR_PROFILE" config >$OCID_CONFIG "$OCID_BINARY" --debug --config "$OCID_CONFIG" & OCID_PID=$! wait_until_reachable } function start_ocid_with_seccomp_path() { - "$OCID_BINARY" --conmon "$CONMON_BINARY" --pause "$PAUSE_BINARY" --listen "$OCID_SOCKET" --runtime "$RUNC_BINARY" --root "$TESTDIR/ocid" --sandboxdir "$TESTDIR/sandboxes" --containerdir "$TESTDIR/ocid/containers" --seccomp-profile "$1" config >$OCID_CONFIG + "$OCID_BINARY" --conmon "$CONMON_BINARY" --pause "$PAUSE_BINARY" --listen "$OCID_SOCKET" --runtime "$RUNC_BINARY" --root "$TESTDIR/ocid" --sandboxdir "$TESTDIR/sandboxes" --containerdir "$TESTDIR/ocid/containers" --seccomp-profile "$1" --apparmor-profile "$APPARMOR_PROFILE" config >$OCID_CONFIG + "$OCID_BINARY" --debug --config "$OCID_CONFIG" & OCID_PID=$! + wait_until_reachable +} + +function start_ocid_with_apparmor_profile_name() { + "$OCID_BINARY" --conmon "$CONMON_BINARY" --pause "$PAUSE_BINARY" --listen "$OCID_SOCKET" --runtime "$RUNC_BINARY" --root "$TESTDIR/ocid" --sandboxdir "$TESTDIR/sandboxes" --containerdir "$TESTDIR/ocid/containers" --seccomp-profile "$SECCOMP_PROFILE" --apparmor-profile "$1" config >$OCID_CONFIG "$OCID_BINARY" --debug --config "$OCID_CONFIG" & OCID_PID=$! wait_until_reachable } @@ -128,3 +142,12 @@ function stop_ocid() { function cleanup_test() { rm -rf "$TESTDIR" } + + +function load_apparmor_test_profile() { + "$APPARMOR_PARSER_BINARY" -r "$APPARMOR_TEST_PROFILE_PATH" +} + +function remove_apparmor_test_profile() { + "$APPARMOR_PARSER_BINARY" -R "$APPARMOR_TEST_PROFILE_PATH" +} diff --git a/test/testdata/apparmor_test_deny_write b/test/testdata/apparmor_test_deny_write new file mode 100644 index 00000000..55311aaf --- /dev/null +++ b/test/testdata/apparmor_test_deny_write @@ -0,0 +1,10 @@ +#include + +profile apparmor-test-deny-write flags=(attach_disconnected) { + #include + + file, + + # Deny all file writes. + deny /** w, +}