k8s.io/apiserver@v0.31.1/pkg/admission/plugin/webhook/predicates/rules/rules.go (about) 1 /* 2 Copyright 2017 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 rules 18 19 import ( 20 "strings" 21 22 "k8s.io/api/admissionregistration/v1" 23 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 "k8s.io/apimachinery/pkg/runtime/schema" 25 "k8s.io/apiserver/pkg/admission" 26 ) 27 28 // Matcher determines if the Attr matches the Rule. 29 type Matcher struct { 30 Rule v1.RuleWithOperations 31 Attr admission.Attributes 32 } 33 34 // Matches returns if the Attr matches the Rule. 35 func (r *Matcher) Matches() bool { 36 return r.scope() && 37 r.operation() && 38 r.group() && 39 r.version() && 40 r.resource() 41 } 42 43 func exactOrWildcard(items []string, requested string) bool { 44 for _, item := range items { 45 if item == "*" { 46 return true 47 } 48 if item == requested { 49 return true 50 } 51 } 52 53 return false 54 } 55 56 var namespaceResource = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "namespaces"} 57 58 func (r *Matcher) scope() bool { 59 if r.Rule.Scope == nil || *r.Rule.Scope == v1.AllScopes { 60 return true 61 } 62 // attr.GetNamespace() is set to the name of the namespace for requests of the namespace object itself. 63 switch *r.Rule.Scope { 64 case v1.NamespacedScope: 65 // first make sure that we are not requesting a namespace object (namespace objects are cluster-scoped) 66 return r.Attr.GetResource() != namespaceResource && r.Attr.GetNamespace() != metav1.NamespaceNone 67 case v1.ClusterScope: 68 // also return true if the request is for a namespace object (namespace objects are cluster-scoped) 69 return r.Attr.GetResource() == namespaceResource || r.Attr.GetNamespace() == metav1.NamespaceNone 70 default: 71 return false 72 } 73 } 74 75 func (r *Matcher) group() bool { 76 return exactOrWildcard(r.Rule.APIGroups, r.Attr.GetResource().Group) 77 } 78 79 func (r *Matcher) version() bool { 80 return exactOrWildcard(r.Rule.APIVersions, r.Attr.GetResource().Version) 81 } 82 83 func (r *Matcher) operation() bool { 84 attrOp := r.Attr.GetOperation() 85 for _, op := range r.Rule.Operations { 86 if op == v1.OperationAll { 87 return true 88 } 89 // The constants are the same such that this is a valid cast (and this 90 // is tested). 91 if op == v1.OperationType(attrOp) { 92 return true 93 } 94 } 95 return false 96 } 97 98 func splitResource(resSub string) (res, sub string) { 99 parts := strings.SplitN(resSub, "/", 2) 100 if len(parts) == 2 { 101 return parts[0], parts[1] 102 } 103 return parts[0], "" 104 } 105 106 func (r *Matcher) resource() bool { 107 opRes, opSub := r.Attr.GetResource().Resource, r.Attr.GetSubresource() 108 for _, res := range r.Rule.Resources { 109 res, sub := splitResource(res) 110 resMatch := res == "*" || res == opRes 111 subMatch := sub == "*" || sub == opSub 112 if resMatch && subMatch { 113 return true 114 } 115 } 116 return false 117 } 118 119 // IsExemptAdmissionConfigurationResource determines if an admission.Attributes object is describing 120 // the admission of a ValidatingWebhookConfiguration or a MutatingWebhookConfiguration or a ValidatingAdmissionPolicy or a ValidatingAdmissionPolicyBinding 121 func IsExemptAdmissionConfigurationResource(attr admission.Attributes) bool { 122 gvk := attr.GetKind() 123 if gvk.Group == "admissionregistration.k8s.io" { 124 if gvk.Kind == "ValidatingWebhookConfiguration" || gvk.Kind == "MutatingWebhookConfiguration" || gvk.Kind == "ValidatingAdmissionPolicy" || gvk.Kind == "ValidatingAdmissionPolicyBinding" { 125 return true 126 } 127 } 128 return false 129 }