From d4a5f3becae48c3b7335f6fd25b051a0af8ef542 Mon Sep 17 00:00:00 2001 From: Pandry <17499836+Pandry@users.noreply.github.com> Date: Wed, 16 Feb 2022 12:12:12 +0100 Subject: [PATCH] fix: validate regex patterns in annotations #510 --- main.go | 2 +- .../tenant/forbidden_annotations_regex.go | 76 +++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 pkg/webhook/tenant/forbidden_annotations_regex.go diff --git a/main.go b/main.go index a0405648..02bb99bb 100644 --- a/main.go +++ b/main.go @@ -205,7 +205,7 @@ func main() { route.PVC(pvc.Handler()), route.Service(service.Handler()), route.NetworkPolicy(utils.InCapsuleGroups(cfg, networkpolicy.Handler())), - route.Tenant(tenant.NameHandler(), tenant.RoleBindingRegexHandler(), tenant.IngressClassRegexHandler(), tenant.StorageClassRegexHandler(), tenant.ContainerRegistryRegexHandler(), tenant.HostnameRegexHandler(), tenant.FreezedEmitter(), tenant.ServiceAccountNameHandler()), + route.Tenant(tenant.NameHandler(), tenant.RoleBindingRegexHandler(), tenant.IngressClassRegexHandler(), tenant.StorageClassRegexHandler(), tenant.ContainerRegistryRegexHandler(), tenant.HostnameRegexHandler(), tenant.FreezedEmitter(), tenant.ServiceAccountNameHandler(), tenant.ForbiddenAnnotationsRegexHandler()), route.OwnerReference(utils.InCapsuleGroups(cfg, ownerreference.Handler(cfg))), route.Cordoning(tenant.CordoningHandler(cfg), tenant.ResourceCounterHandler()), route.Node(utils.InCapsuleGroups(cfg, node.UserMetadataHandler(cfg, kubeVersion))), diff --git a/pkg/webhook/tenant/forbidden_annotations_regex.go b/pkg/webhook/tenant/forbidden_annotations_regex.go new file mode 100644 index 00000000..0ef937cc --- /dev/null +++ b/pkg/webhook/tenant/forbidden_annotations_regex.go @@ -0,0 +1,76 @@ +// Copyright 2020-2021 Clastix Labs +// SPDX-License-Identifier: Apache-2.0 + +package tenant + +import ( + "context" + "regexp" + + "k8s.io/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + + capsulev1beta1 "github.com/clastix/capsule/api/v1beta1" + capsulewebhook "github.com/clastix/capsule/pkg/webhook" + "github.com/clastix/capsule/pkg/webhook/utils" +) + +type forbiddenAnnotationsRegexHandler struct { +} + +func ForbiddenAnnotationsRegexHandler() capsulewebhook.Handler { + return &forbiddenAnnotationsRegexHandler{} +} + +func (h *forbiddenAnnotationsRegexHandler) validate(decoder *admission.Decoder, req admission.Request) *admission.Response { + tenant := &capsulev1beta1.Tenant{} + if err := decoder.Decode(req, tenant); err != nil { + return utils.ErroredResponse(err) + } + + if tenant.Annotations == nil { + return nil + } + + annotationsToCheck := []string{ + capsulev1beta1.ForbiddenNamespaceAnnotationsRegexpAnnotation, + capsulev1beta1.ForbiddenNamespaceLabelsRegexpAnnotation, + } + + for _, annotation := range annotationsToCheck { + if _, err := regexp.Compile(tenant.Annotations[annotation]); err != nil { + response := admission.Denied("unable to compile " + annotation + " regex annotation") + + return &response + } + } + + return nil +} + +func (h *forbiddenAnnotationsRegexHandler) OnCreate(_ client.Client, decoder *admission.Decoder, _ record.EventRecorder) capsulewebhook.Func { + return func(ctx context.Context, req admission.Request) *admission.Response { + if err := h.validate(decoder, req); err != nil { + return err + } + + return nil + } +} + +func (h *forbiddenAnnotationsRegexHandler) OnDelete(client.Client, *admission.Decoder, record.EventRecorder) capsulewebhook.Func { + return func(context.Context, admission.Request) *admission.Response { + return nil + } +} + +func (h *forbiddenAnnotationsRegexHandler) OnUpdate(client client.Client, decoder *admission.Decoder, recorder record.EventRecorder) capsulewebhook.Func { + return func(ctx context.Context, req admission.Request) *admission.Response { + if response := h.validate(decoder, req); response != nil { + return response + } + + return nil + } +}