Skip to content

Commit

Permalink
[controller] Add a webhook to validate storage class operations
Browse files Browse the repository at this point in the history
Signed-off-by: Viktor Kramarenko <viktor.kramarenko@flant.com>
  • Loading branch information
ViktorKram committed Apr 25, 2024
1 parent b28b8ee commit 04375ed
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 0 deletions.
1 change: 1 addition & 0 deletions images/webhooks/src/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ func main() {
mux := http.NewServeMux()
mux.Handle("/pod-scheduler-mutation", pscmWhHandler)
mux.Handle("/storage-class-update", scuWhHandler)
http.HandleFunc("/sc-validate", validators.ValidateSCOperation)
mux.HandleFunc("/healthz", httpHandlerHealthz)

logger.Infof("Listening on %s", port)
Expand Down
63 changes: 63 additions & 0 deletions images/webhooks/src/validators/scOperationsValidator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package validators

import (
"encoding/json"
"k8s.io/api/admission/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/klog/v2"
"net/http"
)

const (
localCSIProvisioner = "local.csi.storage.deckhouse.io"
)

func ValidateSCOperation(w http.ResponseWriter, r *http.Request) {
arReview := v1beta1.AdmissionReview{}
if err := json.NewDecoder(r.Body).Decode(&arReview); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
} else if arReview.Request == nil {
http.Error(w, "invalid request body", http.StatusBadRequest)
return
}

raw := arReview.Request.Object.Raw

arReview.Response = &v1beta1.AdmissionResponse{
UID: arReview.Request.UID,
Allowed: true,
}

var jsonData map[string]interface{}
err := json.Unmarshal(raw, &jsonData)
if err != nil {
http.Error(w, "invalid request body", http.StatusBadRequest)
return
}

if jsonData["provisioner"] == localCSIProvisioner {
if arReview.Request.UserInfo.Username == "system:serviceaccount:d8-sds-local-volume:sds-local-volume-controller" {
arReview.Response.Allowed = true
klog.Infof("Incoming request approved (%s)", string(raw))
} else if arReview.Request.Operation == "DELETE" {
arReview.Response.Allowed = true
klog.Infof("Incoming request approved (%s)", string(raw))
} else {
arReview.Response.Allowed = false
arReview.Response.Result = &metav1.Status{
Message: "Manual operations with this StorageClass is prohibited. Please use LocalStorageClass instead.",
}
klog.Infof("Incoming request denied: Manual operations with this StorageClass is prohibited. Please use LocalStorageClass instead (%s)", string(raw))
}
} else {
arReview.Response.Allowed = true
}

w.Header().Set("Content-Type", "application/json")
err = json.NewEncoder(w).Encode(&arReview)
if err != nil {
http.Error(w, "invalid response body", http.StatusInternalServerError)
return
}
}
23 changes: 23 additions & 0 deletions templates/webhooks/webhook.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,26 @@ webhooks:
admissionReviewVersions: ["v1", "v1beta1"]
sideEffects: None
timeoutSeconds: 5
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: "d8-{{ .Chart.Name }}-sc-validation"
webhooks:
- name: "d8-{{ .Chart.Name }}-sc-validation.storage.deckhouse.io"
rules:
- apiGroups: ["storage.k8s.io"]
apiVersions: ["v1"]
operations: ["*"]
resources: ["storageclasses"]
scope: "Cluster"
clientConfig:
service:
namespace: "d8-{{ .Chart.Name }}"
name: "webhooks"
path: "/sc-validate"
caBundle: |
{{ .Values.sdsLocalVolume.internal.customWebhookCert.ca }}
admissionReviewVersions: ["v1", "v1beta1"]
sideEffects: None
timeoutSeconds: 5

0 comments on commit 04375ed

Please sign in to comment.