diff --git a/pkg/webhook/validatingwebhook/validate.go b/pkg/webhook/validatingwebhook/validate.go index 8a119100..523ae8cd 100644 --- a/pkg/webhook/validatingwebhook/validate.go +++ b/pkg/webhook/validatingwebhook/validate.go @@ -1,12 +1,20 @@ package validatingwebhook import ( + "context" "encoding/json" + "html" + "strings" + toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" + userv1 "github.com/openshift/api/user/v1" + "github.com/pkg/errors" admissionv1 "k8s.io/api/admission/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/apimachinery/pkg/types" + runtimeClient "sigs.k8s.io/controller-runtime/pkg/client" logf "sigs.k8s.io/controller-runtime/pkg/log" ) @@ -18,6 +26,37 @@ var ( log = logf.Log.WithName("validating_webhook") ) +func allowIfNonSandboxUser(body []byte, client *runtimeClient.Client) []byte { + admReview := admissionv1.AdmissionReview{} + if _, _, err := deserializer.Decode(body, nil, &admReview); err != nil { + // sanitize the body + escapedBody := html.EscapeString(string(body)) + log.Error(err, "unable to deserialize the admission review object", "body", escapedBody) + return denyAdmissionRequest(admReview, errors.Wrapf(err, "unable to deserialize the admission review object - body: %v", escapedBody)) + } + requestingUsername := admReview.Request.UserInfo.Username + // allow admission request if the user is a system user + if strings.HasPrefix(requestingUsername, "system:") { + return allowAdmissionRequest(admReview) + } + //check if the requesting user is a sandbox user + requestingUser := &userv1.User{} + err := (*client).Get(context.TODO(), types.NamespacedName{ + Name: admReview.Request.UserInfo.Username, + }, requestingUser) + + if err != nil { + log.Error(err, "unable to find the user requesting creation of the "+admReview.Request.Kind.Kind+" resource", "username", admReview.Request.UserInfo.Username) + return denyAdmissionRequest(admReview, errors.Errorf("unable to find the user requesting the creation of the %s resource", admReview.Request.Kind.Kind)) + } + if requestingUser.GetLabels()[toolchainv1alpha1.ProviderLabelKey] == toolchainv1alpha1.ProviderLabelValue { + log.Info("sandbox user is trying to create a "+admReview.Request.Kind.Kind, "AdmissionReview", admReview) + return denyAdmissionRequest(admReview, errors.Errorf("this is a Dev Sandbox enforced restriction. you are trying to create a %s resource, which is not allowed", admReview.Request.Kind.Kind)) + } + // at this point, it is clear the user isn't a sandbox user, allow request + return allowAdmissionRequest(admReview) +} + func denyAdmissionRequest(admReview admissionv1.AdmissionReview, err error) []byte { response := &admissionv1.AdmissionResponse{ Allowed: false, diff --git a/pkg/webhook/validatingwebhook/validate_checluster_request.go b/pkg/webhook/validatingwebhook/validate_checluster_request.go index 607bd857..6dbe1257 100644 --- a/pkg/webhook/validatingwebhook/validate_checluster_request.go +++ b/pkg/webhook/validatingwebhook/validate_checluster_request.go @@ -1,18 +1,9 @@ package validatingwebhook import ( - "context" - "html" "io" "net/http" - "strings" - toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" - - userv1 "github.com/openshift/api/user/v1" - "github.com/pkg/errors" - admissionv1 "k8s.io/api/admission/v1" - "k8s.io/apimachinery/pkg/types" runtimeClient "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -44,32 +35,5 @@ func (v CheClusterRequestValidator) HandleValidate(w http.ResponseWriter, r *htt func (v CheClusterRequestValidator) validate(body []byte) []byte { log.Info("incoming request", "body", string(body)) - admReview := admissionv1.AdmissionReview{} - if _, _, err := deserializer.Decode(body, nil, &admReview); err != nil { - // sanitize the body - escapedBody := html.EscapeString(string(body)) - log.Error(err, "unable to deserialize the admission review object", "body", escapedBody) - return denyAdmissionRequest(admReview, errors.Wrapf(err, "unable to deserialize the admission review object - body: %v", escapedBody)) - } - requestingUsername := admReview.Request.UserInfo.Username - // allow admission request if the user is a system user - if strings.HasPrefix(requestingUsername, "system:") { - return allowAdmissionRequest(admReview) - } - //check if the requesting user is a sandbox user - requestingUser := &userv1.User{} - err := v.Client.Get(context.TODO(), types.NamespacedName{ - Name: admReview.Request.UserInfo.Username, - }, requestingUser) - - if err != nil { - log.Error(err, "unable to find the user requesting creation of the CheCluster resource", "username", admReview.Request.UserInfo.Username) - return denyAdmissionRequest(admReview, errors.New("unable to find the user requesting the creation of the CheCluster resource")) - } - if requestingUser.GetLabels()[toolchainv1alpha1.ProviderLabelKey] == toolchainv1alpha1.ProviderLabelValue { - log.Info("sandbox user is trying to create a CheCluster", "AdmissionReview", admReview) - return denyAdmissionRequest(admReview, errors.New("this is a Dev Sandbox enforced restriction. you are trying to create a CheCluster resource, which is not allowed")) - } - // at this point, it is clear the user isn't a sandbox user, allow request - return allowAdmissionRequest(admReview) + return allowIfNonSandboxUser(body, &v.Client) } diff --git a/pkg/webhook/validatingwebhook/validate_k8simagepuller_request.go b/pkg/webhook/validatingwebhook/validate_k8simagepuller_request.go index 061d3f75..db285563 100644 --- a/pkg/webhook/validatingwebhook/validate_k8simagepuller_request.go +++ b/pkg/webhook/validatingwebhook/validate_k8simagepuller_request.go @@ -1,18 +1,9 @@ package validatingwebhook import ( - "context" - "html" "io" "net/http" - "strings" - toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" - - userv1 "github.com/openshift/api/user/v1" - "github.com/pkg/errors" - admissionv1 "k8s.io/api/admission/v1" - "k8s.io/apimachinery/pkg/types" runtimeClient "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -44,32 +35,5 @@ func (v K8sImagePullerRequestValidator) HandleValidate(w http.ResponseWriter, r func (v K8sImagePullerRequestValidator) validate(body []byte) []byte { log.Info("incoming request", "body", string(body)) - admReview := admissionv1.AdmissionReview{} - if _, _, err := deserializer.Decode(body, nil, &admReview); err != nil { - // sanitize the body - escapedBody := html.EscapeString(string(body)) - log.Error(err, "unable to deserialize the admission review object", "body", escapedBody) - return denyAdmissionRequest(admReview, errors.Wrapf(err, "unable to deserialize the admission review object - body: %v", escapedBody)) - } - requestingUsername := admReview.Request.UserInfo.Username - // allow admission request if the user is a system user - if strings.HasPrefix(requestingUsername, "system:") { - return allowAdmissionRequest(admReview) - } - //check if the requesting user is a sandbox user - requestingUser := &userv1.User{} - err := v.Client.Get(context.TODO(), types.NamespacedName{ - Name: admReview.Request.UserInfo.Username, - }, requestingUser) - - if err != nil { - log.Error(err, "unable to find the user requesting creation of the KubernetesImagePuller resource", "username", admReview.Request.UserInfo.Username) - return denyAdmissionRequest(admReview, errors.New("unable to find the user requesting the creation of the KubernetesImagePuller resource")) - } - if requestingUser.GetLabels()[toolchainv1alpha1.ProviderLabelKey] == toolchainv1alpha1.ProviderLabelValue { - log.Info("sandbox user is trying to create a KubernetesImagePuller", "AdmissionReview", admReview) - return denyAdmissionRequest(admReview, errors.New("this is a Dev Sandbox enforced restriction. you are trying to create a KubernetesImagePuller resource, which is not allowed")) - } - // at this point, it is clear the user isn't a sandbox user, allow request - return allowAdmissionRequest(admReview) + return allowIfNonSandboxUser(body, &v.Client) }