Skip to content

Commit

Permalink
[feat] namespace deletion protection
Browse files Browse the repository at this point in the history
Signed-off-by: Vacant2333 <vacant2333@gmail.com>
  • Loading branch information
Vacant2333 authored and Vacant2333 committed Oct 17, 2023
1 parent 5135e8f commit f915995
Show file tree
Hide file tree
Showing 9 changed files with 139 additions and 0 deletions.
17 changes: 17 additions & 0 deletions artifacts/deploy/webhook-configuration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -237,3 +237,20 @@ webhooks:
sideEffects: None
admissionReviewVersions: [ "v1" ]
timeoutSeconds: 3
- name: resourcedeletionprotection.karmada.io
rules:
- operations: ["DELETE"]
apiGroups: ["*"]
apiVersions: ["*"]
resources: ["*"]
scope: "*"
clientConfig:
url: https://karmada-webhook.karmada-system.svc:443/validate-resourcedeletionprotection
caBundle: {{caBundle}}
objectSelector:
matchExpressions:
- { key: "resourcetemplate.karmada.io/deletion-protected", operator: "Exists" }
failurePolicy: Fail
sideEffects: None
admissionReviewVersions: [ "v1" ]
timeoutSeconds: 3
17 changes: 17 additions & 0 deletions charts/karmada/templates/_karmada_webhook_configuration.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -213,4 +213,21 @@ webhooks:
sideEffects: None
admissionReviewVersions: [ "v1" ]
timeoutSeconds: 3
- name: resourcedeletionprotection.karmada.io
rules:
- operations: ["DELETE"]
apiGroups: ["*"]
apiVersions: ["*"]
resources: ["*"]
scope: "*"
clientConfig:
url: https://{{ $name }}-webhook.{{ $namespace }}.svc:443/validate-resourcedeletionprotection
{{- include "karmada.webhook.caBundle" . | nindent 6 }}
objectSelector:
matchExpressions:
- { key: "resourcetemplate.karmada.io/deletion-protected", operator: "Exists" }
failurePolicy: Fail
sideEffects: None
admissionReviewVersions: [ "v1" ]
timeoutSeconds: 3
{{- end -}}
2 changes: 2 additions & 0 deletions cmd/webhook/app/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/karmada-io/karmada/pkg/webhook/multiclusterservice"
"github.com/karmada-io/karmada/pkg/webhook/overridepolicy"
"github.com/karmada-io/karmada/pkg/webhook/propagationpolicy"
"github.com/karmada-io/karmada/pkg/webhook/resourcedeletionprotection"
"github.com/karmada-io/karmada/pkg/webhook/resourceinterpretercustomization"
"github.com/karmada-io/karmada/pkg/webhook/work"
)
Expand Down Expand Up @@ -139,6 +140,7 @@ func Run(ctx context.Context, opts *options.Options) error {
hookServer.Register("/validate-multiclusteringress", &webhook.Admission{Handler: &multiclusteringress.ValidatingAdmission{Decoder: decoder}})
hookServer.Register("/validate-multiclusterservice", &webhook.Admission{Handler: &multiclusterservice.ValidatingAdmission{Decoder: decoder}})
hookServer.Register("/mutate-federatedhpa", &webhook.Admission{Handler: &federatedhpa.MutatingAdmission{Decoder: decoder}})
hookServer.Register("/validate-resourcedeletionprotection", &webhook.Admission{Handler: &resourcedeletionprotection.ValidatingAdmission{Decoder: decoder}})
hookServer.WebhookMux().Handle("/readyz/", http.StripPrefix("/readyz/", &healthz.Handler{}))

// blocks until the context is done.
Expand Down
17 changes: 17 additions & 0 deletions operator/pkg/karmadaresource/webhookconfiguration/manifests.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,5 +245,22 @@ webhooks:
sideEffects: None
admissionReviewVersions: [ "v1" ]
timeoutSeconds: 3
- name: resourcedeletionprotection.karmada.io
rules:
- operations: ["DELETE"]
apiGroups: ["*"]
apiVersions: ["*"]
resources: ["*"]
scope: "*"
clientConfig:
url: https://{{ .Service }}.{{ .Namespace }}.svc:443/validate-resourcedeletionprotection
caBundle: {{ .CaBundle }}
objectSelector:
matchExpressions:
- { key: "resourcetemplate.karmada.io/deletion-protected", operator: "Exists" }
failurePolicy: Fail
sideEffects: None
admissionReviewVersions: [ "v1" ]
timeoutSeconds: 3
`
)
8 changes: 8 additions & 0 deletions pkg/apis/work/v1alpha2/well_known_constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,14 @@ const (
// E.g. "resourcetemplate.karmada.io/managed-annotations: bar,foo".
// Note: the keys will be sorted in alphabetical order.
ManagedAnnotation = "resourcetemplate.karmada.io/managed-annotations"

// DeletionProtectionLabelKey If a user assigns the DeletionProtectionLabelKey label to a specific resource,
// and the value of this label is DeletionProtectionAlways, then deletion requests
// for this resource will be denied.
// In the current design, only the Value set to 'Always' will be protected,
// Additional options will be added here in the future.
DeletionProtectionLabelKey = "resourcetemplate.karmada.io/deletion-protected"
DeletionProtectionAlways = "Always"
)

// Define eviction reasons.
Expand Down
17 changes: 17 additions & 0 deletions pkg/karmadactl/cmdinit/karmada/webhook_configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,23 @@ webhooks:
sideEffects: None
admissionReviewVersions: [ "v1" ]
timeoutSeconds: 3
- name: resourcedeletionprotection.karmada.io
rules:
- operations: ["DELETE"]
apiGroups: ["*"]
apiVersions: ["*"]
resources: ["*"]
scope: "*"
clientConfig:
url: https://karmada-webhook.%[1]s.svc:443/validate-resourcedeletionprotection
caBundle: %[2]s
objectSelector:
matchExpressions:
- { key: "resourcetemplate.karmada.io/deletion-protected", operator: "Exists" }
failurePolicy: Fail
sideEffects: None
admissionReviewVersions: [ "v1" ]
timeoutSeconds: 3
`, systemNamespace, caBundle)
}

Expand Down
File renamed without changes.
File renamed without changes.
61 changes: 61 additions & 0 deletions pkg/webhook/resourcedeletionprotection/validating.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
Copyright 2023 The Karmada Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package resourcedeletionprotection

import (
"context"
"fmt"
"net/http"

admissionv1 "k8s.io/api/admission/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/klog/v2"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"

"github.com/karmada-io/karmada/pkg/apis/work/v1alpha2"
)

// ValidatingAdmission validates resource templates to ensure those protected resources are not delectable.
type ValidatingAdmission struct {
Decoder *admission.Decoder
}

// Check if our ValidatingAdmission implements necessary interface
var _ admission.Handler = &ValidatingAdmission{}

// Handle implements admission.Handler interface.
// It yields a response to an AdmissionRequest.
func (v *ValidatingAdmission) Handle(_ context.Context, req admission.Request) admission.Response {
if req.Operation != admissionv1.Delete {
// We only care about the Delete operation.
return admission.Allowed("")
}

// Parse the uncertain type resource object
obj := &unstructured.Unstructured{}
if err := v.Decoder.DecodeRaw(req.OldObject, obj); err != nil {
return admission.Errored(http.StatusBadRequest, err)
}

klog.V(2).Infof("Validating ResourceDeletionProtection for resource: Kind:%s Name:%s Namespace:%s", req.Kind.Kind, obj.GetName(), obj.GetNamespace())

if value, ok := obj.GetLabels()[v1alpha2.DeletionProtectionLabelKey]; ok {
// In normal, requests will be processed here.
// Only v1alpha2.DeletionProtectionAlways value will be denied
if value == v1alpha2.DeletionProtectionAlways {
return admission.Denied(fmt.Sprintf("This resource is protected, please make sure to remove the label: %s", v1alpha2.DeletionProtectionLabelKey))
}
}
return admission.Allowed("")
}

0 comments on commit f915995

Please sign in to comment.