...
1#!/usr/bin/env bash
2
3# Copyright 2020 The Kubernetes Authors.
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17set -o errexit
18set -o nounset
19set -o pipefail
20
21run_kubectl_debug_pod_tests() {
22 set -o nounset
23 set -o errexit
24
25 create_and_use_new_namespace
26 kube::log::status "Testing kubectl debug (pod tests)"
27
28 ### Pod Troubleshooting by ephemeral containers
29
30 # Pre-Condition: Pod "nginx" is created
31 kubectl run target "--image=${IMAGE_NGINX:?}" "${kube_flags[@]:?}"
32 kube::test::get_object_assert pod "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:'
33 # Command: create a copy of target with a new debug container
34 kubectl debug target -it --image=busybox --attach=false -c debug-container "${kube_flags[@]:?}"
35 # Post-Conditions
36 kube::test::get_object_assert pod/target '{{range.spec.ephemeralContainers}}{{.name}}:{{end}}' 'debug-container:'
37 # Clean up
38 kubectl delete pod target "${kube_flags[@]:?}"
39
40 ### Pod Troubleshooting by Copy
41
42 # Pre-Condition: Pod "nginx" is created
43 kubectl run target "--image=${IMAGE_NGINX:?}" "${kube_flags[@]:?}"
44 kube::test::get_object_assert pod "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:'
45 # Command: create a copy of target with a new debug container
46 kubectl debug target -it --copy-to=target-copy --image=busybox --container=debug-container --attach=false "${kube_flags[@]:?}"
47 # Post-Conditions
48 kube::test::get_object_assert pod "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:target-copy:'
49 kube::test::get_object_assert pod/target-copy '{{range.spec.containers}}{{.name}}:{{end}}' 'target:debug-container:'
50 kube::test::get_object_assert pod/target-copy '{{range.spec.containers}}{{.image}}:{{end}}' "${IMAGE_NGINX:?}:busybox:"
51 # Clean up
52 kubectl delete pod target target-copy "${kube_flags[@]:?}"
53
54 # Pre-Condition: Pod "nginx" is created
55 kubectl run target "--image=${IMAGE_NGINX:?}" "${kube_flags[@]:?}"
56 kube::test::get_object_assert pod "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:'
57 # Command: create a copy of target with a new debug container replacing the previous pod
58 kubectl debug target -it --copy-to=target-copy --image=busybox --container=debug-container --attach=false --replace "${kube_flags[@]:?}"
59 # Post-Conditions
60 kube::test::get_object_assert pod "{{range.items}}{{${id_field:?}}}:{{end}}" 'target-copy:'
61 kube::test::get_object_assert pod/target-copy '{{range.spec.containers}}{{.name}}:{{end}}' 'target:debug-container:'
62 kube::test::get_object_assert pod/target-copy '{{range.spec.containers}}{{.image}}:{{end}}' "${IMAGE_NGINX:?}:busybox:"
63 # Clean up
64 kubectl delete pod target-copy "${kube_flags[@]:?}"
65
66 # Pre-Condition: Pod "nginx" is created
67 kubectl run target "--image=${IMAGE_NGINX:?}" "${kube_flags[@]:?}"
68 kube::test::get_object_assert pod "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:'
69 kube::test::get_object_assert pod/target '{{(index .spec.containers 0).name}}' 'target'
70 # Command: copy the pod and replace the image of an existing container
71 kubectl debug target --image=busybox --container=target --copy-to=target-copy "${kube_flags[@]:?}" -- sleep 1m
72 # Post-Conditions
73 kube::test::get_object_assert pod "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:target-copy:'
74 kube::test::get_object_assert pod/target-copy "{{(len .spec.containers)}}:{{${image_field:?}}}" '1:busybox'
75 # Clean up
76 kubectl delete pod target target-copy "${kube_flags[@]:?}"
77
78 # Pre-Condition: Pod "nginx" is created
79 kubectl run target "--image=${IMAGE_NGINX:?}" "${kube_flags[@]:?}"
80 kube::test::get_object_assert pod "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:'
81 kube::test::get_object_assert pod/target '{{(index .spec.containers 0).name}}' 'target'
82 # Command: copy the pod and replace the image of an existing container
83 kubectl get pod/target -o yaml > "${KUBE_TEMP}"/test-pod-debug.yaml
84 kubectl debug -f "${KUBE_TEMP}"/test-pod-debug.yaml --image=busybox --container=target --copy-to=target-copy "${kube_flags[@]:?}" -- sleep 1m
85 # Post-Conditions
86 kube::test::get_object_assert pod "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:target-copy:'
87 kube::test::get_object_assert pod/target-copy "{{(len .spec.containers)}}:{{${image_field:?}}}" '1:busybox'
88 # Clean up
89 kubectl delete pod target target-copy "${kube_flags[@]:?}"
90
91 set +o nounset
92 set +o errexit
93}
94
95run_kubectl_debug_node_tests() {
96 set -o nounset
97 set -o errexit
98
99 create_and_use_new_namespace
100 kube::log::status "Testing kubectl debug (pod tests)"
101
102 ### Node Troubleshooting by Privileged Container
103
104 # Pre-Condition: Pod "nginx" is created
105 kube::test::get_object_assert nodes "{{range.items}}{{${id_field:?}}}:{{end}}" '127.0.0.1:'
106 # Command: create a new node debugger pod
107 output_message=$(kubectl debug node/127.0.0.1 --image=busybox --attach=false "${kube_flags[@]:?}" -- true)
108 # Post-Conditions
109 kube::test::get_object_assert pod "{{(len .items)}}" '1'
110 debugger=$(kubectl get pod -o go-template="{{(index .items 0)${id_field:?}}}")
111 kube::test::if_has_string "${output_message:?}" "${debugger:?}"
112 kube::test::get_object_assert "pod/${debugger:?}" "{{${image_field:?}}}" 'busybox'
113 kube::test::get_object_assert "pod/${debugger:?}" '{{.spec.nodeName}}' '127.0.0.1'
114 kube::test::get_object_assert "pod/${debugger:?}" '{{.spec.hostIPC}}' 'true'
115 kube::test::get_object_assert "pod/${debugger:?}" '{{.spec.hostNetwork}}' 'true'
116 kube::test::get_object_assert "pod/${debugger:?}" '{{.spec.hostPID}}' 'true'
117 kube::test::get_object_assert "pod/${debugger:?}" '{{(index (index .spec.containers 0).volumeMounts 0).mountPath}}' '/host'
118 kube::test::get_object_assert "pod/${debugger:?}" '{{(index .spec.volumes 0).hostPath.path}}' '/'
119 # Clean up
120 # pod.spec.nodeName is set by kubectl debug node which causes the delete to hang,
121 # presumably waiting for a kubelet that's not present. Force the delete.
122 kubectl delete --force pod "${debugger:?}" "${kube_flags[@]:?}"
123
124 set +o nounset
125 set +o errexit
126}
127
128run_kubectl_debug_general_tests() {
129 set -o nounset
130 set -o errexit
131
132 create_and_use_new_namespace
133 kube::log::status "Testing kubectl debug profile general"
134
135 ### Debug by pod copy
136 ### probes are removed, sets SYS_PTRACE in debugging container, sets shareProcessNamespace
137
138 # Pre-Condition: Pod "nginx" is created
139 kubectl run target "--image=${IMAGE_NGINX:?}" "${kube_flags[@]:?}"
140 kube::test::get_object_assert pod "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:'
141 # Command: create a copy of target with a new debug container
142 kubectl debug --profile general target -it --copy-to=target-copy --image=busybox --container=debug-container --attach=false "${kube_flags[@]:?}"
143 # Post-Conditions
144 kube::test::get_object_assert pod "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:target-copy:'
145 kube::test::get_object_assert pod/target-copy '{{range.spec.containers}}{{.name}}:{{end}}' 'target:debug-container:'
146 kube::test::get_object_assert pod/target-copy '{{range.spec.containers}}{{.image}}:{{end}}' "${IMAGE_NGINX:?}:busybox:"
147 kube::test::get_object_assert pod/target-copy '{{range.spec.containers}}{{if (index . "livenessProbe")}}:{{end}}{{end}}' ''
148 kube::test::get_object_assert pod/target-copy '{{range.spec.containers}}{{if (index . "readinessProbe")}}:{{end}}{{end}}' ''
149 kube::test::get_object_assert pod/target-copy '{{range.spec.containers}}{{if (index . "startupProbe")}}:{{end}}{{end}}' ''
150 kube::test::get_object_assert pod/target-copy '{{(index (index .spec.containers 1).securityContext.capabilities.add 0)}}' 'SYS_PTRACE'
151 kube::test::get_object_assert pod/target-copy '{{.spec.shareProcessNamespace}}' 'true'
152 # Clean up
153 kubectl delete pod target target-copy "${kube_flags[@]:?}"
154
155 ### Debug by EC
156 ### sets SYS_PTRACE in ephemeral container
157
158 # Pre-Condition: Pod "nginx" is created
159 kubectl run target "--image=${IMAGE_NGINX:?}" "${kube_flags[@]:?}"
160 kube::test::get_object_assert pod "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:'
161 # Command: create a copy of target with a new debug container
162 kubectl debug --profile general target -it --image=busybox --container=debug-container --attach=false "${kube_flags[@]:?}"
163 # Post-Conditions
164 kube::test::get_object_assert pod/target '{{range.spec.ephemeralContainers}}{{.name}}:{{.image}}{{end}}' 'debug-container:busybox'
165 kube::test::get_object_assert pod/target '{{(index (index .spec.ephemeralContainers 0).securityContext.capabilities.add 0)}}' 'SYS_PTRACE'
166 # Clean up
167 kubectl delete pod target "${kube_flags[@]:?}"
168
169 set +o nounset
170 set +o errexit
171}
172
173run_kubectl_debug_general_node_tests() {
174 set -o nounset
175 set -o errexit
176
177 create_and_use_new_namespace
178 kube::log::status "Testing kubectl debug profile general (node)"
179
180 ### Debug node
181 ### empty securityContext, uses host namespaces, mounts root partition
182
183 # Pre-Condition: node exists
184 kube::test::get_object_assert nodes "{{range.items}}{{${id_field:?}}}:{{end}}" '127.0.0.1:'
185 # Command: create a new node debugger pod
186 output_message=$(kubectl debug --profile general node/127.0.0.1 --image=busybox --attach=false "${kube_flags[@]:?}" -- true)
187 # Post-Conditions
188 kube::test::get_object_assert pod "{{(len .items)}}" '1'
189 debugger=$(kubectl get pod -o go-template="{{(index .items 0)${id_field:?}}}")
190 kube::test::if_has_string "${output_message:?}" "${debugger:?}"
191 kube::test::get_object_assert "pod/${debugger:?}" "{{${image_field:?}}}" 'busybox'
192 kube::test::get_object_assert "pod/${debugger:?}" '{{.spec.nodeName}}' '127.0.0.1'
193 kube::test::get_object_assert "pod/${debugger:?}" '{{.spec.hostIPC}}' 'true'
194 kube::test::get_object_assert "pod/${debugger:?}" '{{.spec.hostNetwork}}' 'true'
195 kube::test::get_object_assert "pod/${debugger:?}" '{{.spec.hostPID}}' 'true'
196 kube::test::get_object_assert "pod/${debugger:?}" '{{(index (index .spec.containers 0).volumeMounts 0).mountPath}}' '/host'
197 kube::test::get_object_assert "pod/${debugger:?}" '{{(index .spec.volumes 0).hostPath.path}}' '/'
198 kube::test::get_object_assert "pod/${debugger:?}" '{{if (index (index .spec.containers 0) "securityContext")}}:{{end}}' ''
199 # Clean up
200 # pod.spec.nodeName is set by kubectl debug node which causes the delete to hang,
201 # presumably waiting for a kubelet that's not present. Force the delete.
202 kubectl delete --force pod "${debugger:?}" "${kube_flags[@]:?}"
203
204 set +o nounset
205 set +o errexit
206}
207
208run_kubectl_debug_baseline_tests() {
209 set -o nounset
210 set -o errexit
211
212 create_and_use_new_namespace
213 kube::log::status "Testing kubectl debug profile baseline"
214
215 ### Debug by pod copy
216 ### probes are removed, empty securityContext, sets shareProcessNamespace
217
218 # Pre-Condition: Pod "nginx" is created
219 kubectl run target "--image=${IMAGE_NGINX:?}" "${kube_flags[@]:?}"
220 kube::test::get_object_assert pod "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:'
221 # Command: create a copy of target with a new debug container
222 kubectl debug --profile baseline target -it --copy-to=target-copy --image=busybox --container=debug-container --attach=false "${kube_flags[@]:?}"
223 # Post-Conditions
224 kube::test::get_object_assert pod "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:target-copy:'
225 kube::test::get_object_assert pod/target-copy '{{range.spec.containers}}{{.name}}:{{end}}' 'target:debug-container:'
226 kube::test::get_object_assert pod/target-copy '{{range.spec.containers}}{{.image}}:{{end}}' "${IMAGE_NGINX:?}:busybox:"
227 kube::test::get_object_assert pod/target-copy '{{range.spec.containers}}{{if (index . "livenessProbe")}}:{{end}}{{end}}' ''
228 kube::test::get_object_assert pod/target-copy '{{range.spec.containers}}{{if (index . "readinessProbe")}}:{{end}}{{end}}' ''
229 kube::test::get_object_assert pod/target-copy '{{range.spec.containers}}{{if (index . "startupProbe")}}:{{end}}{{end}}' ''
230 kube::test::get_object_assert pod/target-copy '{{if (index (index .spec.containers 0) "securityContext")}}:{{end}}' ''
231 kube::test::get_object_assert pod/target-copy '{{.spec.shareProcessNamespace}}' 'true'
232 # Clean up
233 kubectl delete pod target target-copy "${kube_flags[@]:?}"
234
235 ### Debug by EC
236 ### empty securityContext
237
238 # Pre-Condition: Pod "nginx" is created
239 kubectl run target "--image=${IMAGE_NGINX:?}" "${kube_flags[@]:?}"
240 kube::test::get_object_assert pod "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:'
241 # Command: create a copy of target with a new debug container
242 kubectl debug --profile baseline target -it --image=busybox --container=debug-container --attach=false "${kube_flags[@]:?}"
243 # Post-Conditions
244 kube::test::get_object_assert pod/target '{{range.spec.ephemeralContainers}}{{.name}}:{{.image}}{{end}}' 'debug-container:busybox'
245 kube::test::get_object_assert pod/target '{{if (index (index .spec.ephemeralContainers 0) "securityContext")}}:{{end}}' ''
246 # Clean up
247 kubectl delete pod target "${kube_flags[@]:?}"
248
249 set +o nounset
250 set +o errexit
251}
252
253run_kubectl_debug_baseline_node_tests() {
254 set -o nounset
255 set -o errexit
256
257 create_and_use_new_namespace
258 kube::log::status "Testing kubectl debug profile baseline (node)"
259
260 ### Debug node
261 ### empty securityContext, uses isolated namespaces
262
263 # Pre-Condition: node exists
264 kube::test::get_object_assert nodes "{{range.items}}{{${id_field:?}}}:{{end}}" '127.0.0.1:'
265 # Command: create a new node debugger pod
266 output_message=$(kubectl debug --profile baseline node/127.0.0.1 --image=busybox --attach=false "${kube_flags[@]:?}" -- true)
267 # Post-Conditions
268 kube::test::get_object_assert pod "{{(len .items)}}" '1'
269 debugger=$(kubectl get pod -o go-template="{{(index .items 0)${id_field:?}}}")
270 kube::test::if_has_string "${output_message:?}" "${debugger:?}"
271 kube::test::get_object_assert "pod/${debugger:?}" "{{${image_field:?}}}" 'busybox'
272 kube::test::get_object_assert "pod/${debugger:?}" '{{.spec.nodeName}}' '127.0.0.1'
273 kube::test::get_object_assert "pod/${debugger:?}" '{{.spec.hostIPC}}' '<no value>'
274 kube::test::get_object_assert "pod/${debugger:?}" '{{.spec.hostNetwork}}' '<no value>'
275 kube::test::get_object_assert "pod/${debugger:?}" '{{.spec.hostPID}}' '<no value>'
276 kube::test::get_object_assert "pod/${debugger:?}" '{{if (index (index .spec.containers 0) "securityContext")}}:{{end}}' ''
277 # Clean up
278 # pod.spec.nodeName is set by kubectl debug node which causes the delete to hang,
279 # presumably waiting for a kubelet that's not present. Force the delete.
280 kubectl delete --force pod "${debugger:?}" "${kube_flags[@]:?}"
281
282 set +o nounset
283 set +o errexit
284}
285
286run_kubectl_debug_restricted_tests() {
287 set -o nounset
288 set -o errexit
289
290 create_and_use_new_namespace
291 kube::log::status "Testing kubectl debug profile restricted"
292
293 ### Pod Troubleshooting by ephemeral containers with restricted profile
294 # Pre-Condition: Pod "nginx" is created
295 kubectl run target "--image=${IMAGE_NGINX:?}" "${kube_flags[@]:?}"
296 kube::test::get_object_assert pod "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:'
297 # Restricted profile just works in not restricted namespace
298 # Command: add a new debug container with restricted profile
299 output_message=$(kubectl debug target -it --image=busybox --attach=false -c debug-container --profile=restricted "${kube_flags[@]:?}")
300 kube::test::if_has_not_string "${output_message}" 'forbidden: violates PodSecurity'
301 # Post-Conditions
302 kube::test::get_object_assert pod/target '{{range.spec.ephemeralContainers}}{{.name}}:{{end}}' 'debug-container:'
303 # Clean up
304 kubectl delete pod target "${kube_flags[@]:?}"
305
306 ### Pod Troubleshooting by pod copy with restricted profile
307 # Pre-Condition: Pod "nginx" is created
308 kubectl run target "--image=${IMAGE_NGINX:?}" "${kube_flags[@]:?}"
309 kube::test::get_object_assert pod "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:'
310 # Restricted profile just works in not restricted namespace
311 # Command: create a copy of target with a new debug container
312 kubectl debug target -it --copy-to=target-copy --image=busybox --container=debug-container --attach=false --profile=restricted "${kube_flags[@]:?}"
313 # Post-Conditions
314 kube::test::get_object_assert pod "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:target-copy:'
315 kube::test::get_object_assert pod/target-copy '{{range.spec.containers}}{{.name}}:{{end}}' 'target:debug-container:'
316 kube::test::get_object_assert pod/target-copy '{{range.spec.containers}}{{.image}}:{{end}}' "${IMAGE_NGINX:?}:busybox:"
317 # Clean up
318 kubectl delete pod target target-copy "${kube_flags[@]:?}"
319
320 ns_name="namespace-restricted"
321 # Command: create namespace and add a label
322 kubectl create namespace "${ns_name}"
323 kubectl label namespace "${ns_name}" pod-security.kubernetes.io/enforce=restricted
324 output_message=$(kubectl get namespaces "${ns_name}" --show-labels)
325 kube::test::if_has_string "${output_message}" 'pod-security.kubernetes.io/enforce=restricted'
326
327 ### Pod Troubleshooting by ephemeral containers with restricted profile (restricted namespace)
328 # Pre-Condition: Pod "busybox" is created that complies with the restricted policy
329 kubectl create -f hack/testdata/pod-restricted-runtime-default.yaml -n "${ns_name}"
330 kube::test::get_object_assert "pod -n ${ns_name}" "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:'
331 # Restricted profile works when pod's seccompProfile is RuntimeDefault
332 # Command: add a new debug container with restricted profile
333 output_message=$(kubectl debug target -it --image=busybox --attach=false -c debug-container --profile=restricted -n "${ns_name}" "${kube_flags[@]:?}")
334 kube::test::if_has_not_string "${output_message}" 'forbidden: violates PodSecurity'
335 # Post-Conditions
336 kube::test::get_object_assert "pod/target -n ${ns_name}" '{{range.spec.ephemeralContainers}}{{.name}}:{{end}}' 'debug-container:'
337 # Clean up
338 kubectl delete pod target -n "${ns_name}" "${kube_flags[@]:?}"
339
340 ### Pod Troubleshooting by pod copy with restricted profile (restricted namespace)
341 # Pre-Condition: Pod "nginx" is created
342 kubectl create -f hack/testdata/pod-restricted-runtime-default.yaml -n "${ns_name}"
343 kube::test::get_object_assert "pod -n ${ns_name}" "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:'
344 # Restricted profile works when pod's seccompProfile is RuntimeDefault
345 # Command: create a copy of target with a new debug container
346 kubectl debug target -it --copy-to=target-copy --image=busybox --container=debug-container --attach=false --profile=restricted -n ${ns_name} "${kube_flags[@]:?}"
347 # Post-Conditions
348 kube::test::get_object_assert "pod -n ${ns_name}" "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:target-copy:'
349 kube::test::get_object_assert "pod/target-copy -n ${ns_name}" '{{range.spec.containers}}{{.name}}:{{end}}' 'target:debug-container:'
350 kube::test::get_object_assert "pod/target-copy -n ${ns_name}" '{{range.spec.containers}}{{.image}}:{{end}}' "busybox:busybox:"
351 # Clean up
352 kubectl delete pod target target-copy -n "${ns_name}" "${kube_flags[@]:?}"
353
354 ### Pod Troubleshooting by ephemeral containers with restricted profile (restricted namespace)
355 # Pre-Condition: Pod "busybox" is created that complies with the restricted policy
356 kubectl create -f hack/testdata/pod-restricted-localhost.yaml -n "${ns_name}"
357 kube::test::get_object_assert "pod -n ${ns_name}" "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:'
358 # Restricted profile works when pod's seccompProfile is Localhost
359 # Command: add a new debug container with restricted profile
360 output_message=$(kubectl debug target -it --image=busybox --attach=false -c debug-container --profile=restricted -n ${ns_name} "${kube_flags[@]:?}")
361 kube::test::if_has_not_string "${output_message}" 'forbidden: violates PodSecurity'
362 # Post-Conditions
363 kube::test::get_object_assert "pod/target -n ${ns_name}" '{{range.spec.ephemeralContainers}}{{.name}}:{{end}}' 'debug-container:'
364 # Clean up
365 kubectl delete pod target -n ${ns_name} "${kube_flags[@]:?}"
366
367 ### Pod Troubleshooting by pod copy with restricted profile (restricted namespace)
368 # Pre-Condition: Pod "nginx" is created
369 kubectl create -f hack/testdata/pod-restricted-localhost.yaml -n "${ns_name}"
370 kube::test::get_object_assert "pod -n ${ns_name}" "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:'
371 # Restricted profile works when pod's seccompProfile is Localhost
372 # Command: create a copy of target with a new debug container
373 kubectl debug target -it --copy-to=target-copy --image=busybox --container=debug-container --attach=false --profile=restricted -n ${ns_name} "${kube_flags[@]:?}"
374 # Post-Conditions
375 kube::test::get_object_assert "pod -n ${ns_name}" "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:target-copy:'
376 kube::test::get_object_assert "pod/target-copy -n ${ns_name}" '{{range.spec.containers}}{{.name}}:{{end}}' 'target:debug-container:'
377 kube::test::get_object_assert "pod/target-copy -n ${ns_name}" '{{range.spec.containers}}{{.image}}:{{end}}' "busybox:busybox:"
378 # Clean up
379 kubectl delete pod target target-copy -n "${ns_name}" "${kube_flags[@]:?}"
380
381 # Clean up restricted namespace
382 kubectl delete namespace "${ns_name}"
383
384 set +o nounset
385 set +o errexit
386}
387
388run_kubectl_debug_restricted_node_tests() {
389 set -o nounset
390 set -o errexit
391
392 create_and_use_new_namespace
393 kube::log::status "Testing kubectl debug profile restricted (node)"
394
395 ### Debug node with restricted profile
396 # Pre-Condition: node exists
397 kube::test::get_object_assert nodes "{{range.items}}{{${id_field:?}}}:{{end}}" '127.0.0.1:'
398 # Restricted profile just works in not restricted namespace
399 # Command: create a new node debugger pod
400 output_message=$(kubectl debug --profile restricted node/127.0.0.1 --image=busybox --attach=false "${kube_flags[@]:?}" -- true)
401 kube::test::if_has_not_string "${output_message}" 'forbidden: violates PodSecurity'
402 # Post-Conditions
403 kube::test::get_object_assert pod "{{(len .items)}}" '1'
404 debugger=$(kubectl get pod -o go-template="{{(index .items 0)${id_field:?}}}")
405 kube::test::if_has_string "${output_message:?}" "${debugger:?}"
406 kube::test::get_object_assert "pod/${debugger:?}" "{{${image_field:?}}}" 'busybox'
407 kube::test::get_object_assert "pod/${debugger:?}" '{{.spec.nodeName}}' '127.0.0.1'
408 kube::test::get_object_assert "pod/${debugger:?}" '{{.spec.hostIPC}}' '<no value>'
409 kube::test::get_object_assert "pod/${debugger:?}" '{{.spec.hostNetwork}}' '<no value>'
410 kube::test::get_object_assert "pod/${debugger:?}" '{{.spec.hostPID}}' '<no value>'
411 kube::test::get_object_assert "pod/${debugger:?}" '{{index .spec.containers 0 "securityContext" "allowPrivilegeEscalation"}}' 'false'
412 kube::test::get_object_assert "pod/${debugger:?}" '{{index .spec.containers 0 "securityContext" "capabilities" "drop"}}' '\[ALL\]'
413 kube::test::get_object_assert "pod/${debugger:?}" '{{if (index (index .spec.containers 0) "securityContext" "capabilities" "add") }}:{{end}}' ''
414 kube::test::get_object_assert "pod/${debugger:?}" '{{index .spec.containers 0 "securityContext" "runAsNonRoot"}}' 'true'
415 kube::test::get_object_assert "pod/${debugger:?}" '{{index .spec.containers 0 "securityContext" "seccompProfile" "type"}}' 'RuntimeDefault'
416 # Clean up
417 # pod.spec.nodeName is set by kubectl debug node which causes the delete to hang,
418 # presumably waiting for a kubelet that's not present. Force the delete.
419 kubectl delete --force pod "${debugger:?}" "${kube_flags[@]:?}"
420
421 ns_name="namespace-restricted"
422 # Command: create namespace and add a label
423 kubectl create namespace "${ns_name}"
424 kubectl label namespace "${ns_name}" pod-security.kubernetes.io/enforce=restricted
425 output_message=$(kubectl get namespaces "${ns_name}" --show-labels)
426 kube::test::if_has_string "${output_message}" 'pod-security.kubernetes.io/enforce=restricted'
427
428 ### Debug node with restricted profile (restricted namespace)
429 # Pre-Condition: node exists
430 kube::test::get_object_assert nodes "{{range.items}}{{${id_field:?}}}:{{end}}" '127.0.0.1:'
431 # Restricted profile works in restricted namespace
432 # Command: create a new node debugger pod
433 output_message=$(kubectl debug --profile restricted node/127.0.0.1 --image=busybox --attach=false -n ${ns_name} "${kube_flags[@]:?}" -- true)
434 kube::test::if_has_not_string "${output_message}" 'forbidden: violates PodSecurity'
435 # Post-Conditions
436 kube::test::get_object_assert "pod -n ${ns_name}" "{{(len .items)}}" '1'
437 debugger=$(kubectl get pod -n ${ns_name} -o go-template="{{(index .items 0)${id_field:?}}}")
438 kube::test::if_has_string "${output_message:?}" "${debugger:?}"
439 kube::test::get_object_assert "pod/${debugger:?} -n ${ns_name}" "{{${image_field:?}}}" 'busybox'
440 kube::test::get_object_assert "pod/${debugger:?} -n ${ns_name}" '{{.spec.nodeName}}' '127.0.0.1'
441 kube::test::get_object_assert "pod/${debugger:?} -n ${ns_name}" '{{.spec.hostIPC}}' '<no value>'
442 kube::test::get_object_assert "pod/${debugger:?} -n ${ns_name}" '{{.spec.hostNetwork}}' '<no value>'
443 kube::test::get_object_assert "pod/${debugger:?} -n ${ns_name}" '{{.spec.hostPID}}' '<no value>'
444 kube::test::get_object_assert "pod/${debugger:?} -n ${ns_name}" '{{index .spec.containers 0 "securityContext" "allowPrivilegeEscalation"}}' 'false'
445 kube::test::get_object_assert "pod/${debugger:?} -n ${ns_name}" '{{index .spec.containers 0 "securityContext" "capabilities" "drop"}}' '\[ALL\]'
446 kube::test::get_object_assert "pod/${debugger:?} -n ${ns_name}" '{{if (index (index .spec.containers 0) "securityContext" "capabilities" "add") }}:{{end}}' ''
447 kube::test::get_object_assert "pod/${debugger:?} -n ${ns_name}" '{{index .spec.containers 0 "securityContext" "runAsNonRoot"}}' 'true'
448 kube::test::get_object_assert "pod/${debugger:?} -n ${ns_name}" '{{index .spec.containers 0 "securityContext" "seccompProfile" "type"}}' 'RuntimeDefault'
449 # Clean up
450 # pod.spec.nodeName is set by kubectl debug node which causes the delete to hang,
451 # presumably waiting for a kubelet that's not present. Force the delete.
452 kubectl delete --force pod "${debugger:?}" -n ${ns_name} "${kube_flags[@]:?}"
453
454 # Clean up restricted namespace
455 kubectl delete namespace "${ns_name}"
456
457 set +o nounset
458 set +o errexit
459}
460
461run_kubectl_debug_netadmin_tests() {
462 set -o nounset
463 set -o errexit
464
465 create_and_use_new_namespace
466 kube::log::status "Testing kubectl debug profile netadmin"
467
468 ### Pod Troubleshooting by ephemeral containers with netadmin profile
469 # Pre-Condition: Pod "nginx" is created
470 kubectl run target "--image=${IMAGE_NGINX:?}" "${kube_flags[@]:?}"
471 kube::test::get_object_assert pod "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:'
472 # Command: add a new debug container with netadmin profile
473 output_message=$(kubectl debug target -it --image=busybox --attach=false -c debug-container --profile=netadmin "${kube_flags[@]:?}")
474 # Post-Conditions
475 kube::test::get_object_assert pod/target '{{range.spec.ephemeralContainers}}{{.name}}:{{end}}' 'debug-container:'
476 kube::test::get_object_assert pod/target '{{(index (index .spec.ephemeralContainers 0).securityContext.capabilities.add)}}' '\[NET_ADMIN NET_RAW\]'
477 # Clean up
478 kubectl delete pod target "${kube_flags[@]:?}"
479
480 ### Pod Troubleshooting by pod copy with netadmin profile
481 # Pre-Condition: Pod "nginx" is created
482 kubectl run target "--image=${IMAGE_NGINX:?}" "${kube_flags[@]:?}"
483 kube::test::get_object_assert pod "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:'
484 # Command: create a copy of target with a new debug container
485 kubectl debug target -it --copy-to=target-copy --image=busybox --container=debug-container --attach=false --profile=netadmin "${kube_flags[@]:?}"
486 # Post-Conditions
487 kube::test::get_object_assert pod "{{range.items}}{{${id_field:?}}}:{{end}}" 'target:target-copy:'
488 kube::test::get_object_assert pod/target-copy '{{range.spec.containers}}{{.name}}:{{end}}' 'target:debug-container:'
489 kube::test::get_object_assert pod/target-copy '{{range.spec.containers}}{{.image}}:{{end}}' "${IMAGE_NGINX:?}:busybox:"
490 kube::test::get_object_assert pod/target-copy '{{.spec.shareProcessNamespace}}' 'true'
491 kube::test::get_object_assert pod/target-copy '{{(index (index .spec.containers 1).securityContext.capabilities.add)}}' '\[NET_ADMIN NET_RAW\]'
492 # Clean up
493 kubectl delete pod target target-copy "${kube_flags[@]:?}"
494
495 set +o nounset
496 set +o errexit
497}
498
499run_kubectl_debug_netadmin_node_tests() {
500 set -o nounset
501 set -o errexit
502
503 create_and_use_new_namespace
504 kube::log::status "Testing kubectl debug profile netadmin (node)"
505
506 ### Debug node with netadmin profile
507 # Pre-Condition: node exists
508 kube::test::get_object_assert nodes "{{range.items}}{{${id_field:?}}}:{{end}}" '127.0.0.1:'
509 # Command: create a new node debugger pod
510 output_message=$(kubectl debug --profile netadmin node/127.0.0.1 --image=busybox --attach=false "${kube_flags[@]:?}" -- true)
511 # Post-Conditions
512 kube::test::get_object_assert pod "{{(len .items)}}" '1'
513 debugger=$(kubectl get pod -o go-template="{{(index .items 0)${id_field:?}}}")
514 kube::test::if_has_string "${output_message:?}" "${debugger:?}"
515 kube::test::get_object_assert "pod/${debugger:?}" "{{${image_field:?}}}" 'busybox'
516 kube::test::get_object_assert "pod/${debugger:?}" '{{.spec.nodeName}}' '127.0.0.1'
517 kube::test::get_object_assert "pod/${debugger:?}" '{{.spec.hostNetwork}}' 'true'
518 kube::test::get_object_assert "pod/${debugger:?}" '{{.spec.hostPID}}' 'true'
519 kube::test::get_object_assert "pod/${debugger:?}" '{{index .spec.containers 0 "securityContext" "capabilities" "add"}}' '\[NET_ADMIN NET_RAW\]'
520 # Clean up
521 # pod.spec.nodeName is set by kubectl debug node which causes the delete to hang,
522 # presumably waiting for a kubelet that's not present. Force the delete.
523 kubectl delete --force pod "${debugger:?}" "${kube_flags[@]:?}"
524
525 set +o nounset
526 set +o errexit
527}
View as plain text