k8s.io/kubernetes@v1.29.3/test/images/agnhost/webhook/pods.go (about) 1 /* 2 Copyright 2018 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package webhook 18 19 import ( 20 "fmt" 21 "strings" 22 23 "k8s.io/api/admission/v1" 24 corev1 "k8s.io/api/core/v1" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/klog/v2" 27 ) 28 29 const ( 30 podsInitContainerPatch string = `[ 31 {"op":"add","path":"/spec/initContainers","value":[{"image":"webhook-added-image","name":"webhook-added-init-container","resources":{}}]} 32 ]` 33 podsSidecarPatch string = `[ 34 {"op":"add", "path":"/spec/containers/-","value":{"image":"%v","name":"webhook-added-sidecar","resources":{}}} 35 ]` 36 ) 37 38 // only allow pods to pull images from specific registry. 39 func admitPods(ar v1.AdmissionReview) *v1.AdmissionResponse { 40 klog.V(2).Info("admitting pods") 41 podResource := metav1.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"} 42 if ar.Request.Resource != podResource { 43 err := fmt.Errorf("expect resource to be %s", podResource) 44 klog.Error(err) 45 return toV1AdmissionResponse(err) 46 } 47 48 raw := ar.Request.Object.Raw 49 pod := corev1.Pod{} 50 deserializer := codecs.UniversalDeserializer() 51 if _, _, err := deserializer.Decode(raw, nil, &pod); err != nil { 52 klog.Error(err) 53 return toV1AdmissionResponse(err) 54 } 55 reviewResponse := v1.AdmissionResponse{} 56 reviewResponse.Allowed = true 57 58 var msg string 59 if v, ok := pod.Labels["webhook-e2e-test"]; ok { 60 if v == "webhook-disallow" { 61 reviewResponse.Allowed = false 62 msg = msg + "the pod contains unwanted label; " 63 } 64 if v == "wait-forever" { 65 reviewResponse.Allowed = false 66 msg = msg + "the pod response should not be sent; " 67 <-make(chan int) // Sleep forever - no one sends to this channel 68 } 69 } 70 for _, container := range pod.Spec.Containers { 71 if strings.Contains(container.Name, "webhook-disallow") { 72 reviewResponse.Allowed = false 73 msg = msg + "the pod contains unwanted container name; " 74 } 75 } 76 if !reviewResponse.Allowed { 77 reviewResponse.Result = &metav1.Status{Message: strings.TrimSpace(msg)} 78 } 79 return &reviewResponse 80 } 81 82 func mutatePods(ar v1.AdmissionReview) *v1.AdmissionResponse { 83 shouldPatchPod := func(pod *corev1.Pod) bool { 84 if pod.Name != "webhook-to-be-mutated" { 85 return false 86 } 87 return !hasContainer(pod.Spec.InitContainers, "webhook-added-init-container") 88 } 89 return applyPodPatch(ar, shouldPatchPod, podsInitContainerPatch) 90 } 91 92 func mutatePodsSidecar(ar v1.AdmissionReview) *v1.AdmissionResponse { 93 if sidecarImage == "" { 94 return &v1.AdmissionResponse{ 95 Allowed: false, 96 Result: &metav1.Status{ 97 Status: "Failure", 98 Message: "No image specified by the sidecar-image parameter", 99 Code: 500, 100 }, 101 } 102 } 103 shouldPatchPod := func(pod *corev1.Pod) bool { 104 return !hasContainer(pod.Spec.Containers, "webhook-added-sidecar") 105 } 106 return applyPodPatch(ar, shouldPatchPod, fmt.Sprintf(podsSidecarPatch, sidecarImage)) 107 } 108 109 func hasContainer(containers []corev1.Container, containerName string) bool { 110 for _, container := range containers { 111 if container.Name == containerName { 112 return true 113 } 114 } 115 return false 116 } 117 118 func applyPodPatch(ar v1.AdmissionReview, shouldPatchPod func(*corev1.Pod) bool, patch string) *v1.AdmissionResponse { 119 klog.V(2).Info("mutating pods") 120 podResource := metav1.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"} 121 if ar.Request.Resource != podResource { 122 klog.Errorf("expect resource to be %s", podResource) 123 return nil 124 } 125 126 raw := ar.Request.Object.Raw 127 pod := corev1.Pod{} 128 deserializer := codecs.UniversalDeserializer() 129 if _, _, err := deserializer.Decode(raw, nil, &pod); err != nil { 130 klog.Error(err) 131 return toV1AdmissionResponse(err) 132 } 133 reviewResponse := v1.AdmissionResponse{} 134 reviewResponse.Allowed = true 135 if shouldPatchPod(&pod) { 136 reviewResponse.Patch = []byte(patch) 137 pt := v1.PatchTypeJSONPatch 138 reviewResponse.PatchType = &pt 139 } 140 return &reviewResponse 141 } 142 143 // denySpecificAttachment denies `kubectl attach to-be-attached-pod -i -c=container1" 144 // or equivalent client requests. 145 func denySpecificAttachment(ar v1.AdmissionReview) *v1.AdmissionResponse { 146 klog.V(2).Info("handling attaching pods") 147 if ar.Request.Name != "to-be-attached-pod" { 148 return &v1.AdmissionResponse{Allowed: true} 149 } 150 podResource := metav1.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"} 151 if e, a := podResource, ar.Request.Resource; e != a { 152 err := fmt.Errorf("expect resource to be %s, got %s", e, a) 153 klog.Error(err) 154 return toV1AdmissionResponse(err) 155 } 156 if e, a := "attach", ar.Request.SubResource; e != a { 157 err := fmt.Errorf("expect subresource to be %s, got %s", e, a) 158 klog.Error(err) 159 return toV1AdmissionResponse(err) 160 } 161 162 raw := ar.Request.Object.Raw 163 podAttachOptions := corev1.PodAttachOptions{} 164 deserializer := codecs.UniversalDeserializer() 165 if _, _, err := deserializer.Decode(raw, nil, &podAttachOptions); err != nil { 166 klog.Error(err) 167 return toV1AdmissionResponse(err) 168 } 169 klog.V(2).Info(fmt.Sprintf("podAttachOptions=%#v\n", podAttachOptions)) 170 if !podAttachOptions.Stdin || podAttachOptions.Container != "container1" { 171 return &v1.AdmissionResponse{Allowed: true} 172 } 173 return &v1.AdmissionResponse{ 174 Allowed: false, 175 Result: &metav1.Status{ 176 Message: "attaching to pod 'to-be-attached-pod' is not allowed", 177 }, 178 } 179 }