k8s.io/kubernetes@v1.29.3/test/cmd/debug.sh (about) 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 17 set -o errexit 18 set -o nounset 19 set -o pipefail 20 21 run_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 95 run_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 128 run_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 173 run_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 208 run_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 253 run_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 286 run_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 388 run_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 461 run_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 499 run_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 }