From 207a965b3fffc1f816441588c8e640a587a8e613 Mon Sep 17 00:00:00 2001 From: Tim Allclair Date: Wed, 21 Feb 2024 11:58:54 -0800 Subject: [PATCH] Update AppArmor e2e tests --- test/e2e/framework/security/apparmor.go | 29 +++++++++++++++------- test/e2e/node/apparmor.go | 33 ++++++++++++++++++++++--- test/e2e/upgrades/node/apparmor.go | 6 +++-- 3 files changed, 54 insertions(+), 14 deletions(-) diff --git a/test/e2e/framework/security/apparmor.go b/test/e2e/framework/security/apparmor.go index 82f093289a5..cb218d239dc 100644 --- a/test/e2e/framework/security/apparmor.go +++ b/test/e2e/framework/security/apparmor.go @@ -48,8 +48,8 @@ func LoadAppArmorProfiles(ctx context.Context, nsName string, clientset clientse // CreateAppArmorTestPod creates a pod that tests apparmor profile enforcement. The pod exits with // an error code if the profile is incorrectly enforced. If runOnce is true the pod will exit after // a single test, otherwise it will repeat the test every 1 second until failure. -func CreateAppArmorTestPod(ctx context.Context, nsName string, clientset clientset.Interface, podClient *e2epod.PodClient, unconfined bool, runOnce bool) *v1.Pod { - profile := "localhost/" + appArmorProfilePrefix + nsName +func AppArmorTestPod(nsName string, unconfined bool, runOnce bool) *v1.Pod { + localhostProfile := appArmorProfilePrefix + nsName testCmd := fmt.Sprintf(` if touch %[1]s; then echo "FAILURE: write to %[1]s should be denied" @@ -64,7 +64,6 @@ elif [[ $(< /proc/self/attr/current) != "%[3]s" ]]; then fi`, appArmorDeniedPath, appArmorAllowedPath, appArmorProfilePrefix+nsName) if unconfined { - profile = v1.AppArmorBetaProfileNameUnconfined testCmd = ` if cat /proc/sysrq-trigger 2>&1 | grep 'Permission denied'; then echo 'FAILURE: reading /proc/sysrq-trigger should be allowed' @@ -94,17 +93,25 @@ done`, testCmd) }, } + profile := &v1.AppArmorProfile{} + if unconfined { + profile.Type = v1.AppArmorProfileTypeUnconfined + } else { + profile.Type = v1.AppArmorProfileTypeLocalhost + profile.LocalhostProfile = &localhostProfile + } + pod := &v1.Pod{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "test-apparmor-", - Annotations: map[string]string{ - v1.AppArmorBetaContainerAnnotationKeyPrefix + "test": profile, - }, Labels: map[string]string{ "test": "apparmor", }, }, Spec: v1.PodSpec{ + SecurityContext: &v1.PodSecurityContext{ + AppArmorProfile: profile, + }, Affinity: loaderAffinity, Containers: []v1.Container{{ Name: "test", @@ -115,20 +122,24 @@ done`, testCmd) }, } + return pod +} + +func RunAppArmorTestPod(ctx context.Context, pod *v1.Pod, clientset clientset.Interface, podClient *e2epod.PodClient, runOnce bool) *v1.Pod { if runOnce { pod = podClient.Create(ctx, pod) framework.ExpectNoError(e2epod.WaitForPodSuccessInNamespace(ctx, - clientset, pod.Name, nsName)) + clientset, pod.Name, pod.Namespace)) var err error pod, err = podClient.Get(ctx, pod.Name, metav1.GetOptions{}) framework.ExpectNoError(err) } else { pod = podClient.CreateSync(ctx, pod) - framework.ExpectNoError(e2epod.WaitTimeoutForPodReadyInNamespace(ctx, clientset, pod.Name, nsName, framework.PodStartTimeout)) + framework.ExpectNoError(e2epod.WaitTimeoutForPodReadyInNamespace(ctx, clientset, pod.Name, pod.Namespace, framework.PodStartTimeout)) } // Verify Pod affinity colocated the Pods. - loader := getRunningLoaderPod(ctx, nsName, clientset) + loader := getRunningLoaderPod(ctx, pod.Namespace, clientset) gomega.Expect(pod.Spec.NodeName).To(gomega.Equal(loader.Spec.NodeName)) return pod diff --git a/test/e2e/node/apparmor.go b/test/e2e/node/apparmor.go index 2d84d7de33a..dc36c256596 100644 --- a/test/e2e/node/apparmor.go +++ b/test/e2e/node/apparmor.go @@ -19,6 +19,7 @@ package node import ( "context" + v1 "k8s.io/api/core/v1" "k8s.io/kubernetes/test/e2e/framework" e2ekubectl "k8s.io/kubernetes/test/e2e/framework/kubectl" e2epod "k8s.io/kubernetes/test/e2e/framework/pod" @@ -45,12 +46,38 @@ var _ = SIGDescribe("AppArmor", func() { e2ekubectl.LogFailedContainers(ctx, f.ClientSet, f.Namespace.Name, framework.Logf) }) - ginkgo.It("should enforce an AppArmor profile", func(ctx context.Context) { - e2esecurity.CreateAppArmorTestPod(ctx, f.Namespace.Name, f.ClientSet, e2epod.NewPodClient(f), false, true) + ginkgo.It("should enforce an AppArmor profile specified on the pod", func(ctx context.Context) { + pod := e2esecurity.AppArmorTestPod(f.Namespace.Name, false, true) + e2esecurity.RunAppArmorTestPod(ctx, pod, f.ClientSet, e2epod.NewPodClient(f), true) + }) + + ginkgo.It("should enforce an AppArmor profile specified on the container", func(ctx context.Context) { + pod := e2esecurity.AppArmorTestPod(f.Namespace.Name, false, true) + // Move AppArmor profile to the container. + pod.Spec.Containers[0].SecurityContext = &v1.SecurityContext{ + AppArmorProfile: pod.Spec.SecurityContext.AppArmorProfile, + } + pod.Spec.SecurityContext = nil + + e2esecurity.RunAppArmorTestPod(ctx, pod, f.ClientSet, e2epod.NewPodClient(f), true) + }) + + ginkgo.It("should enforce an AppArmor profile specified in annotations", func(ctx context.Context) { + pod := e2esecurity.AppArmorTestPod(f.Namespace.Name, false, true) + // Move AppArmor profile to the annotations. + profile := pod.Spec.SecurityContext.AppArmorProfile + key := v1.AppArmorBetaContainerAnnotationKeyPrefix + pod.Spec.Containers[0].Name + pod.Annotations = map[string]string{ + key: v1.AppArmorBetaProfileNamePrefix + *profile.LocalhostProfile, + } + pod.Spec.SecurityContext = nil + + e2esecurity.RunAppArmorTestPod(ctx, pod, f.ClientSet, e2epod.NewPodClient(f), true) }) ginkgo.It("can disable an AppArmor profile, using unconfined", func(ctx context.Context) { - e2esecurity.CreateAppArmorTestPod(ctx, f.Namespace.Name, f.ClientSet, e2epod.NewPodClient(f), true, true) + pod := e2esecurity.AppArmorTestPod(f.Namespace.Name, true, true) + e2esecurity.RunAppArmorTestPod(ctx, pod, f.ClientSet, e2epod.NewPodClient(f), true) }) }) }) diff --git a/test/e2e/upgrades/node/apparmor.go b/test/e2e/upgrades/node/apparmor.go index 8470f7ce4bc..6a94c4d65be 100644 --- a/test/e2e/upgrades/node/apparmor.go +++ b/test/e2e/upgrades/node/apparmor.go @@ -63,7 +63,8 @@ func (t *AppArmorUpgradeTest) Setup(ctx context.Context, f *framework.Framework) // Create the initial test pod. ginkgo.By("Creating a long-running AppArmor enabled pod.") - t.pod = e2esecurity.CreateAppArmorTestPod(ctx, f.Namespace.Name, f.ClientSet, e2epod.NewPodClient(f), false, false) + pod := e2esecurity.AppArmorTestPod(f.Namespace.Name, false, false) + t.pod = e2esecurity.RunAppArmorTestPod(ctx, pod, f.ClientSet, e2epod.NewPodClient(f), false) // Verify initial state. t.verifyNodesAppArmorEnabled(ctx, f) @@ -99,7 +100,8 @@ func (t *AppArmorUpgradeTest) verifyPodStillUp(ctx context.Context, f *framework func (t *AppArmorUpgradeTest) verifyNewPodSucceeds(ctx context.Context, f *framework.Framework) { ginkgo.By("Verifying an AppArmor profile is enforced for a new pod") - e2esecurity.CreateAppArmorTestPod(ctx, f.Namespace.Name, f.ClientSet, e2epod.NewPodClient(f), false, true) + pod := e2esecurity.AppArmorTestPod(f.Namespace.Name, false, true) + t.pod = e2esecurity.RunAppArmorTestPod(ctx, pod, f.ClientSet, e2epod.NewPodClient(f), true) } func (t *AppArmorUpgradeTest) verifyNodesAppArmorEnabled(ctx context.Context, f *framework.Framework) {