1
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
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
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
96
97
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
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
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
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
178 err := e2epod.WaitForPodFailedReason(ctx, f.ClientSet, pod, "SysctlForbidden", f.Timeouts.PodStart)
179 framework.ExpectNoError(err)
180 })
181
182
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
206
207
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
227
228
229
230
231
232 gomega.Expect(log).To(gomega.ContainSubstring("kernel.shm_rmid_forced = 1"))
233 })
234 })
235
View as plain text