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