k8s.io/kubernetes@v1.29.3/test/e2e/common/node/sysctl.go (about) 1 /* 2 Copyright 2014 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package node 18 19 import ( 20 "context" 21 22 v1 "k8s.io/api/core/v1" 23 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 "k8s.io/apimachinery/pkg/util/uuid" 25 "k8s.io/kubernetes/test/e2e/environment" 26 "k8s.io/kubernetes/test/e2e/framework" 27 e2epod "k8s.io/kubernetes/test/e2e/framework/pod" 28 e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper" 29 imageutils "k8s.io/kubernetes/test/utils/image" 30 admissionapi "k8s.io/pod-security-admission/api" 31 32 "github.com/onsi/ginkgo/v2" 33 "github.com/onsi/gomega" 34 ) 35 36 var _ = SIGDescribe("Sysctls [LinuxOnly]", framework.WithNodeConformance(), func() { 37 38 ginkgo.BeforeEach(func() { 39 // sysctl is not supported on Windows. 40 e2eskipper.SkipIfNodeOSDistroIs("windows") 41 }) 42 43 f := framework.NewDefaultFramework("sysctl") 44 f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged 45 var podClient *e2epod.PodClient 46 47 testPod := func() *v1.Pod { 48 podName := "sysctl-" + string(uuid.NewUUID()) 49 pod := v1.Pod{ 50 ObjectMeta: metav1.ObjectMeta{ 51 Name: podName, 52 Annotations: map[string]string{}, 53 }, 54 Spec: v1.PodSpec{ 55 Containers: []v1.Container{ 56 { 57 Name: "test-container", 58 Image: imageutils.GetE2EImage(imageutils.BusyBox), 59 }, 60 }, 61 RestartPolicy: v1.RestartPolicyNever, 62 }, 63 } 64 65 return &pod 66 } 67 68 ginkgo.BeforeEach(func() { 69 podClient = e2epod.NewPodClient(f) 70 }) 71 72 /* 73 Release: v1.21 74 Testname: Sysctl, test sysctls 75 Description: Pod is created with kernel.shm_rmid_forced sysctl. Kernel.shm_rmid_forced must be set to 1 76 [LinuxOnly]: This test is marked as LinuxOnly since Windows does not support sysctls 77 [Environment:NotInUserNS]: The test fails in UserNS (as expected): `open /proc/sys/kernel/shm_rmid_forced: permission denied` 78 */ 79 framework.ConformanceIt("should support sysctls [MinimumKubeletVersion:1.21]", environment.NotInUserNS, func(ctx context.Context) { 80 pod := testPod() 81 pod.Spec.SecurityContext = &v1.PodSecurityContext{ 82 Sysctls: []v1.Sysctl{ 83 { 84 Name: "kernel.shm_rmid_forced", 85 Value: "1", 86 }, 87 }, 88 } 89 pod.Spec.Containers[0].Command = []string{"/bin/sysctl", "kernel.shm_rmid_forced"} 90 91 ginkgo.By("Creating a pod with the kernel.shm_rmid_forced sysctl") 92 pod = podClient.Create(ctx, pod) 93 94 ginkgo.By("Watching for error events or started pod") 95 // watch for events instead of termination of pod because the kubelet deletes 96 // failed pods without running containers. This would create a race as the pod 97 // might have already been deleted here. 98 ev, err := e2epod.NewPodClient(f).WaitForErrorEventOrSuccess(ctx, pod) 99 framework.ExpectNoError(err) 100 gomega.Expect(ev).To(gomega.BeNil()) 101 102 ginkgo.By("Waiting for pod completion") 103 err = e2epod.WaitForPodNoLongerRunningInNamespace(ctx, f.ClientSet, pod.Name, f.Namespace.Name) 104 framework.ExpectNoError(err) 105 pod, err = podClient.Get(ctx, pod.Name, metav1.GetOptions{}) 106 framework.ExpectNoError(err) 107 108 ginkgo.By("Checking that the pod succeeded") 109 gomega.Expect(pod.Status.Phase).To(gomega.Equal(v1.PodSucceeded)) 110 111 ginkgo.By("Getting logs from the pod") 112 log, err := e2epod.GetPodLogs(ctx, f.ClientSet, f.Namespace.Name, pod.Name, pod.Spec.Containers[0].Name) 113 framework.ExpectNoError(err) 114 115 ginkgo.By("Checking that the sysctl is actually updated") 116 gomega.Expect(log).To(gomega.ContainSubstring("kernel.shm_rmid_forced = 1")) 117 }) 118 119 /* 120 Release: v1.21 121 Testname: Sysctls, reject invalid sysctls 122 Description: Pod is created with one valid and two invalid sysctls. Pod should not apply invalid sysctls. 123 [LinuxOnly]: This test is marked as LinuxOnly since Windows does not support sysctls 124 */ 125 framework.ConformanceIt("should reject invalid sysctls [MinimumKubeletVersion:1.21]", func(ctx context.Context) { 126 pod := testPod() 127 pod.Spec.SecurityContext = &v1.PodSecurityContext{ 128 Sysctls: []v1.Sysctl{ 129 // Safe parameters 130 { 131 Name: "foo-", 132 Value: "bar", 133 }, 134 { 135 Name: "kernel.shmmax", 136 Value: "100000000", 137 }, 138 { 139 Name: "safe-and-unsafe", 140 Value: "100000000", 141 }, 142 { 143 Name: "bar..", 144 Value: "42", 145 }, 146 }, 147 } 148 149 ginkgo.By("Creating a pod with one valid and two invalid sysctls") 150 client := f.ClientSet.CoreV1().Pods(f.Namespace.Name) 151 _, err := client.Create(ctx, pod, metav1.CreateOptions{}) 152 153 gomega.Expect(err).To(gomega.MatchError(gomega.SatisfyAll( 154 gomega.ContainSubstring(`Invalid value: "foo-"`), 155 gomega.ContainSubstring(`Invalid value: "bar.."`), 156 gomega.Not(gomega.ContainSubstring(`safe-and-unsafe`)), 157 gomega.Not(gomega.ContainSubstring("kernel.shmmax")), 158 ))) 159 }) 160 161 // Pod is created with kernel.msgmax, an unsafe sysctl. 162 ginkgo.It("should not launch unsafe, but not explicitly enabled sysctls on the node [MinimumKubeletVersion:1.21]", func(ctx context.Context) { 163 pod := testPod() 164 pod.Spec.SecurityContext = &v1.PodSecurityContext{ 165 Sysctls: []v1.Sysctl{ 166 { 167 Name: "kernel.msgmax", 168 Value: "10000000000", 169 }, 170 }, 171 } 172 173 ginkgo.By("Creating a pod with an ignorelisted, but not allowlisted sysctl on the node") 174 pod = podClient.Create(ctx, pod) 175 176 ginkgo.By("Wait for pod failed reason") 177 // watch for pod failed reason instead of termination of pod 178 err := e2epod.WaitForPodFailedReason(ctx, f.ClientSet, pod, "SysctlForbidden", f.Timeouts.PodStart) 179 framework.ExpectNoError(err) 180 }) 181 182 /* 183 Release: v1.23 184 Testname: Sysctl, test sysctls supports slashes 185 Description: Pod is created with kernel/shm_rmid_forced sysctl. Support slashes as sysctl separator. The '/' separator is also accepted in place of a '.' 186 [LinuxOnly]: This test is marked as LinuxOnly since Windows does not support sysctls 187 [Environment:NotInUserNS]: The test fails in UserNS (as expected): `open /proc/sys/kernel/shm_rmid_forced: permission denied` 188 */ 189 f.It("should support sysctls with slashes as separator [MinimumKubeletVersion:1.23]", environment.NotInUserNS, func(ctx context.Context) { 190 pod := testPod() 191 pod.Spec.SecurityContext = &v1.PodSecurityContext{ 192 Sysctls: []v1.Sysctl{ 193 { 194 Name: "kernel/shm_rmid_forced", 195 Value: "1", 196 }, 197 }, 198 } 199 pod.Spec.Containers[0].Command = []string{"/bin/sysctl", "kernel/shm_rmid_forced"} 200 201 ginkgo.By("Creating a pod with the kernel/shm_rmid_forced sysctl") 202 pod = podClient.Create(ctx, pod) 203 204 ginkgo.By("Watching for error events or started pod") 205 // watch for events instead of termination of pod because the kubelet deletes 206 // failed pods without running containers. This would create a race as the pod 207 // might have already been deleted here. 208 ev, err := e2epod.NewPodClient(f).WaitForErrorEventOrSuccess(ctx, pod) 209 framework.ExpectNoError(err) 210 gomega.Expect(ev).To(gomega.BeNil()) 211 212 ginkgo.By("Waiting for pod completion") 213 err = e2epod.WaitForPodNoLongerRunningInNamespace(ctx, f.ClientSet, pod.Name, f.Namespace.Name) 214 framework.ExpectNoError(err) 215 pod, err = podClient.Get(ctx, pod.Name, metav1.GetOptions{}) 216 framework.ExpectNoError(err) 217 218 ginkgo.By("Checking that the pod succeeded") 219 gomega.Expect(pod.Status.Phase).To(gomega.Equal(v1.PodSucceeded)) 220 221 ginkgo.By("Getting logs from the pod") 222 log, err := e2epod.GetPodLogs(ctx, f.ClientSet, f.Namespace.Name, pod.Name, pod.Spec.Containers[0].Name) 223 framework.ExpectNoError(err) 224 225 ginkgo.By("Checking that the sysctl is actually updated") 226 // Note that either "/" or "." may be used as separators within sysctl variable names. 227 // "kernel.shm_rmid_forced=1" and "kernel/shm_rmid_forced=1" are equivalent. 228 // Run "/bin/sysctl kernel/shm_rmid_forced" command on Linux system 229 // The displayed result is "kernel.shm_rmid_forced=1" 230 // Therefore, the substring that needs to be checked for the obtained pod log is 231 // "kernel.shm_rmid_forced=1" instead of "kernel/shm_rmid_forced=1". 232 gomega.Expect(log).To(gomega.ContainSubstring("kernel.shm_rmid_forced = 1")) 233 }) 234 })