123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341 |
- /*
- Copyright 2017 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package common
- import (
- "fmt"
- "strings"
- v1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/util/uuid"
- "k8s.io/kubernetes/pkg/kubelet/events"
- "k8s.io/kubernetes/test/e2e/framework"
- e2elog "k8s.io/kubernetes/test/e2e/framework/log"
- imageutils "k8s.io/kubernetes/test/utils/image"
- "k8s.io/utils/pointer"
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
- )
- var _ = framework.KubeDescribe("Security Context", func() {
- f := framework.NewDefaultFramework("security-context-test")
- var podClient *framework.PodClient
- BeforeEach(func() {
- podClient = f.PodClient()
- })
- Context("When creating a container with runAsUser", func() {
- makeUserPod := func(podName, image string, command []string, userid int64) *v1.Pod {
- return &v1.Pod{
- ObjectMeta: metav1.ObjectMeta{
- Name: podName,
- },
- Spec: v1.PodSpec{
- RestartPolicy: v1.RestartPolicyNever,
- Containers: []v1.Container{
- {
- Image: image,
- Name: podName,
- Command: command,
- SecurityContext: &v1.SecurityContext{
- RunAsUser: &userid,
- },
- },
- },
- },
- }
- }
- createAndWaitUserPod := func(userid int64) {
- podName := fmt.Sprintf("busybox-user-%d-%s", userid, uuid.NewUUID())
- podClient.Create(makeUserPod(podName,
- framework.BusyBoxImage,
- []string{"sh", "-c", fmt.Sprintf("test $(id -u) -eq %d", userid)},
- userid,
- ))
- podClient.WaitForSuccess(podName, framework.PodStartTimeout)
- }
- /*
- Release : v1.12
- Testname: Security Context: runAsUser (id:65534)
- Description: Container created with runAsUser option, passing an id (id:65534) uses that
- given id when running the container.
- This test is marked LinuxOnly since Windows does not support running as UID / GID.
- */
- It("should run the container with uid 65534 [LinuxOnly] [NodeConformance]", func() {
- createAndWaitUserPod(65534)
- })
- /*
- Release : v1.12
- Testname: Security Context: runAsUser (id:0)
- Description: Container created with runAsUser option, passing an id (id:0) uses that
- given id when running the container.
- This test is marked LinuxOnly since Windows does not support running as UID / GID.
- */
- It("should run the container with uid 0 [LinuxOnly] [NodeConformance]", func() {
- createAndWaitUserPod(0)
- })
- })
- Context("When creating a container with runAsNonRoot", func() {
- rootImage := imageutils.GetE2EImage(imageutils.BusyBox)
- nonRootImage := imageutils.GetE2EImage(imageutils.NonRoot)
- makeNonRootPod := func(podName, image string, userid *int64) *v1.Pod {
- return &v1.Pod{
- ObjectMeta: metav1.ObjectMeta{
- Name: podName,
- },
- Spec: v1.PodSpec{
- RestartPolicy: v1.RestartPolicyNever,
- Containers: []v1.Container{
- {
- Image: image,
- Name: podName,
- Command: []string{"id", "-u"}, // Print UID and exit
- SecurityContext: &v1.SecurityContext{
- RunAsNonRoot: pointer.BoolPtr(true),
- RunAsUser: userid,
- },
- },
- },
- },
- }
- }
- It("should run with an explicit non-root user ID", func() {
- name := "explicit-nonroot-uid"
- pod := makeNonRootPod(name, rootImage, pointer.Int64Ptr(1234))
- pod = podClient.Create(pod)
- podClient.WaitForSuccess(name, framework.PodStartTimeout)
- framework.ExpectNoError(podClient.MatchContainerOutput(name, name, "1234"))
- })
- It("should not run with an explicit root user ID", func() {
- name := "explicit-root-uid"
- pod := makeNonRootPod(name, nonRootImage, pointer.Int64Ptr(0))
- pod = podClient.Create(pod)
- ev, err := podClient.WaitForErrorEventOrSuccess(pod)
- framework.ExpectNoError(err)
- Expect(ev).NotTo(BeNil())
- Expect(ev.Reason).To(Equal(events.FailedToCreateContainer))
- })
- It("should run with an image specified user ID", func() {
- name := "implicit-nonroot-uid"
- pod := makeNonRootPod(name, nonRootImage, nil)
- pod = podClient.Create(pod)
- podClient.WaitForSuccess(name, framework.PodStartTimeout)
- framework.ExpectNoError(podClient.MatchContainerOutput(name, name, "1234"))
- })
- It("should not run without a specified user ID", func() {
- name := "implicit-root-uid"
- pod := makeNonRootPod(name, rootImage, nil)
- pod = podClient.Create(pod)
- ev, err := podClient.WaitForErrorEventOrSuccess(pod)
- framework.ExpectNoError(err)
- Expect(ev).NotTo(BeNil())
- Expect(ev.Reason).To(Equal(events.FailedToCreateContainer))
- })
- })
- Context("When creating a pod with readOnlyRootFilesystem", func() {
- makeUserPod := func(podName, image string, command []string, readOnlyRootFilesystem bool) *v1.Pod {
- return &v1.Pod{
- ObjectMeta: metav1.ObjectMeta{
- Name: podName,
- },
- Spec: v1.PodSpec{
- RestartPolicy: v1.RestartPolicyNever,
- Containers: []v1.Container{
- {
- Image: image,
- Name: podName,
- Command: command,
- SecurityContext: &v1.SecurityContext{
- ReadOnlyRootFilesystem: &readOnlyRootFilesystem,
- },
- },
- },
- },
- }
- }
- createAndWaitUserPod := func(readOnlyRootFilesystem bool) string {
- podName := fmt.Sprintf("busybox-readonly-%v-%s", readOnlyRootFilesystem, uuid.NewUUID())
- podClient.Create(makeUserPod(podName,
- framework.BusyBoxImage,
- []string{"sh", "-c", "touch checkfile"},
- readOnlyRootFilesystem,
- ))
- if readOnlyRootFilesystem {
- podClient.WaitForFailure(podName, framework.PodStartTimeout)
- } else {
- podClient.WaitForSuccess(podName, framework.PodStartTimeout)
- }
- return podName
- }
- /*
- Release : v1.12
- Testname: Security Context: readOnlyRootFilesystem=true.
- Description: when a container has configured readOnlyRootFilesystem to true, write operations are not allowed.
- This test is marked LinuxOnly since Windows does not support creating containers with read-only access.
- */
- It("should run the container with readonly rootfs when readOnlyRootFilesystem=true [LinuxOnly] [NodeConformance]", func() {
- createAndWaitUserPod(true)
- })
- /*
- Release : v1.12
- Testname: Security Context: readOnlyRootFilesystem=false.
- Description: when a container has configured readOnlyRootFilesystem to false, write operations are allowed.
- */
- It("should run the container with writable rootfs when readOnlyRootFilesystem=false [NodeConformance]", func() {
- createAndWaitUserPod(false)
- })
- })
- Context("When creating a pod with privileged", func() {
- makeUserPod := func(podName, image string, command []string, privileged bool) *v1.Pod {
- return &v1.Pod{
- ObjectMeta: metav1.ObjectMeta{
- Name: podName,
- },
- Spec: v1.PodSpec{
- RestartPolicy: v1.RestartPolicyNever,
- Containers: []v1.Container{
- {
- Image: image,
- Name: podName,
- Command: command,
- SecurityContext: &v1.SecurityContext{
- Privileged: &privileged,
- },
- },
- },
- },
- }
- }
- createAndWaitUserPod := func(privileged bool) string {
- podName := fmt.Sprintf("busybox-privileged-%v-%s", privileged, uuid.NewUUID())
- podClient.Create(makeUserPod(podName,
- framework.BusyBoxImage,
- []string{"sh", "-c", "ip link add dummy0 type dummy || true"},
- privileged,
- ))
- podClient.WaitForSuccess(podName, framework.PodStartTimeout)
- return podName
- }
- It("should run the container as unprivileged when false [LinuxOnly] [NodeConformance]", func() {
- // This test is marked LinuxOnly since it runs a Linux-specific command, and Windows does not support Windows escalation.
- podName := createAndWaitUserPod(false)
- logs, err := framework.GetPodLogs(f.ClientSet, f.Namespace.Name, podName, podName)
- if err != nil {
- framework.Failf("GetPodLogs for pod %q failed: %v", podName, err)
- }
- e2elog.Logf("Got logs for pod %q: %q", podName, logs)
- if !strings.Contains(logs, "Operation not permitted") {
- framework.Failf("unprivileged container shouldn't be able to create dummy device")
- }
- })
- })
- Context("when creating containers with AllowPrivilegeEscalation", func() {
- makeAllowPrivilegeEscalationPod := func(podName string, allowPrivilegeEscalation *bool, uid int64) *v1.Pod {
- return &v1.Pod{
- ObjectMeta: metav1.ObjectMeta{
- Name: podName,
- },
- Spec: v1.PodSpec{
- RestartPolicy: v1.RestartPolicyNever,
- Containers: []v1.Container{
- {
- Image: imageutils.GetE2EImage(imageutils.Nonewprivs),
- Name: podName,
- SecurityContext: &v1.SecurityContext{
- AllowPrivilegeEscalation: allowPrivilegeEscalation,
- RunAsUser: &uid,
- },
- },
- },
- },
- }
- }
- createAndMatchOutput := func(podName, output string, allowPrivilegeEscalation *bool, uid int64) error {
- podClient.Create(makeAllowPrivilegeEscalationPod(podName,
- allowPrivilegeEscalation,
- uid,
- ))
- podClient.WaitForSuccess(podName, framework.PodStartTimeout)
- return podClient.MatchContainerOutput(podName, podName, output)
- }
- /*
- Testname: allowPrivilegeEscalation unset and uid != 0.
- Description: Configuring the allowPrivilegeEscalation unset, allows the privilege escalation operation.
- A container is configured with allowPrivilegeEscalation not specified (nil) and a given uid which is not 0.
- When the container is run, the container is run using uid=0.
- This test is marked LinuxOnly since Windows does not support running as UID / GID, or privilege escalation.
- */
- It("should allow privilege escalation when not explicitly set and uid != 0 [LinuxOnly] [NodeConformance]", func() {
- podName := "alpine-nnp-nil-" + string(uuid.NewUUID())
- if err := createAndMatchOutput(podName, "Effective uid: 0", nil, 1000); err != nil {
- framework.Failf("Match output for pod %q failed: %v", podName, err)
- }
- })
- /*
- Testname: allowPrivilegeEscalation=false.
- Description: Configuring the allowPrivilegeEscalation to false, does not allow the privilege escalation operation.
- A container is configured with allowPrivilegeEscalation=false and a given uid (1000) which is not 0.
- When the container is run, the container is run using uid=1000.
- This test is marked LinuxOnly since Windows does not support running as UID / GID, or privilege escalation.
- */
- It("should not allow privilege escalation when false [LinuxOnly] [NodeConformance]", func() {
- podName := "alpine-nnp-false-" + string(uuid.NewUUID())
- apeFalse := false
- if err := createAndMatchOutput(podName, "Effective uid: 1000", &apeFalse, 1000); err != nil {
- framework.Failf("Match output for pod %q failed: %v", podName, err)
- }
- })
- /*
- Testname: allowPrivilegeEscalation=true.
- Description: Configuring the allowPrivilegeEscalation to true, allows the privilege escalation operation.
- A container is configured with allowPrivilegeEscalation=true and a given uid (1000) which is not 0.
- When the container is run, the container is run using uid=0 (making use of the privilege escalation).
- This test is marked LinuxOnly since Windows does not support running as UID / GID.
- */
- It("should allow privilege escalation when true [LinuxOnly] [NodeConformance]", func() {
- podName := "alpine-nnp-true-" + string(uuid.NewUUID())
- apeTrue := true
- if err := createAndMatchOutput(podName, "Effective uid: 0", &apeTrue, 1000); err != nil {
- framework.Failf("Match output for pod %q failed: %v", podName, err)
- }
- })
- })
- })
|