github.com/oam-dev/kubevela@v1.9.11/pkg/resourcekeeper/admission.go (about) 1 /* 2 Copyright 2021 The KubeVela 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 resourcekeeper 18 19 import ( 20 "context" 21 "fmt" 22 "strings" 23 24 "github.com/pkg/errors" 25 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 26 27 "github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1" 28 ) 29 30 var ( 31 // AllowCrossNamespaceResource indicates whether application can apply resources into other namespaces 32 AllowCrossNamespaceResource = true 33 // AllowResourceTypes if not empty, application can only apply resources with specified types 34 AllowResourceTypes = "" 35 ) 36 37 // AdmissionCheck check whether resources dispatch/deletion is admitted 38 func (h *resourceKeeper) AdmissionCheck(ctx context.Context, manifests []*unstructured.Unstructured) error { 39 for _, handler := range []ResourceAdmissionHandler{ 40 &NamespaceAdmissionHandler{app: h.app}, 41 &ResourceTypeAdmissionHandler{}, 42 } { 43 if err := handler.Validate(ctx, manifests); err != nil { 44 return err 45 } 46 } 47 return nil 48 } 49 50 // ResourceAdmissionHandler defines the handler to validate the admission of resource operation 51 type ResourceAdmissionHandler interface { 52 Validate(ctx context.Context, manifests []*unstructured.Unstructured) error 53 } 54 55 // NamespaceAdmissionHandler defines the handler to validate if the resource namespace is valid to be dispatch/delete 56 type NamespaceAdmissionHandler struct { 57 app *v1beta1.Application 58 } 59 60 // Validate check if cross namespace is available 61 func (h *NamespaceAdmissionHandler) Validate(_ context.Context, manifests []*unstructured.Unstructured) error { 62 if !AllowCrossNamespaceResource { 63 for _, manifest := range manifests { 64 if manifest.GetNamespace() != h.app.GetNamespace() { 65 return errors.Errorf("forbidden resource: %s %s/%s is outside the namespace of application", manifest.GetKind(), manifest.GetNamespace(), manifest.GetName()) 66 } 67 } 68 } 69 return nil 70 } 71 72 // ResourceTypeAdmissionHandler defines the handler to validate if the resource type is valid to be dispatch/delete 73 type ResourceTypeAdmissionHandler struct { 74 initialized bool 75 isWhiteList bool 76 resourceTypeMap map[string]struct{} 77 } 78 79 // Validate check if resource type is valid 80 func (h *ResourceTypeAdmissionHandler) Validate(_ context.Context, manifests []*unstructured.Unstructured) error { 81 if AllowResourceTypes != "" { 82 if !h.initialized { 83 h.initialized = true 84 h.resourceTypeMap = make(map[string]struct{}) 85 if strings.HasPrefix(AllowResourceTypes, "whitelist:") { 86 for _, t := range strings.Split(strings.TrimPrefix(AllowResourceTypes, "whitelist:"), ",") { 87 h.isWhiteList = true 88 h.resourceTypeMap[t] = struct{}{} 89 } 90 } 91 if strings.HasPrefix(AllowResourceTypes, "blacklist:") { 92 for _, t := range strings.Split(strings.TrimPrefix(AllowResourceTypes, "blacklist:"), ",") { 93 h.isWhiteList = false 94 h.resourceTypeMap[t] = struct{}{} 95 } 96 } 97 } 98 for _, manifest := range manifests { 99 gvk := manifest.GetObjectKind().GroupVersionKind() 100 resourceType := fmt.Sprintf("%s.%s", manifest.GetKind(), gvk.Version) 101 if gvk.Group != "" { 102 resourceType += "." + gvk.Group 103 } 104 _, found := h.resourceTypeMap[resourceType] 105 if h.isWhiteList != found { 106 return errors.Errorf("forbidden resource: type (%s) of resource %s/%s is not allowed", manifest.GetKind(), manifest.GetNamespace(), manifest.GetName()) 107 } 108 } 109 } 110 return nil 111 }