diff --git a/pkg/engine/validation.go b/pkg/engine/validation.go index 0cd89e09da..2daadb08a9 100644 --- a/pkg/engine/validation.go +++ b/pkg/engine/validation.go @@ -17,7 +17,7 @@ import ( ) //Validate applies validation rules from policy on the resource -func Validate(policyContext PolicyContext) (resp response.EngineResponse) { +func Validate(policyContext PolicyContext) response.EngineResponse { startTime := time.Now() policy := policyContext.Policy newR := policyContext.NewResource @@ -29,39 +29,22 @@ func Validate(policyContext PolicyContext) (resp response.EngineResponse) { // policy information logger.V(4).Info("start processing", "startTime", startTime) - // Process new & old resource - if reflect.DeepEqual(oldR, unstructured.Unstructured{}) { - // Create Mode - // Operate on New Resource only - resp := validateResource(logger, ctx, policy, newR, admissionInfo) - startResultResponse(resp, policy, newR) - defer endResultResponse(logger, resp, startTime) - // set PatchedResource with origin resource if empty - // in order to create policy violation - if reflect.DeepEqual(resp.PatchedResource, unstructured.Unstructured{}) { - resp.PatchedResource = newR - } - return *resp + var resp *response.EngineResponse + // handling delete requests + if reflect.DeepEqual(newR, unstructured.Unstructured{}) { + resp = validateResource(logger, ctx, policy, oldR, admissionInfo, true) + } else { + resp = validateResource(logger, ctx, policy, newR, admissionInfo, false) } - // Update Mode - // Operate on New and Old Resource only - // New resource - oldResponse := validateResource(logger, ctx, policy, oldR, admissionInfo) - newResponse := validateResource(logger, ctx, policy, newR, admissionInfo) - // if the old and new response is same then return empty response - if !isSameResponse(oldResponse, newResponse) { - // there are changes send response - startResultResponse(newResponse, policy, newR) - defer endResultResponse(logger, newResponse, startTime) - if reflect.DeepEqual(newResponse.PatchedResource, unstructured.Unstructured{}) { - newResponse.PatchedResource = newR - } - return *newResponse + startResultResponse(resp, policy, newR) + defer endResultResponse(logger, resp, startTime) + // set PatchedResource with origin resource if empty + // in order to create policy violation + if reflect.DeepEqual(resp.PatchedResource, unstructured.Unstructured{}) { + resp.PatchedResource = newR } - // if there are no changes with old and new response then sent empty response - // skip processing - return response.EngineResponse{} + return *resp } func startResultResponse(resp *response.EngineResponse, policy kyverno.ClusterPolicy, newR unstructured.Unstructured) { @@ -85,7 +68,7 @@ func incrementAppliedCount(resp *response.EngineResponse) { resp.PolicyResponse.RulesAppliedCount++ } -func validateResource(log logr.Logger, ctx context.EvalInterface, policy kyverno.ClusterPolicy, resource unstructured.Unstructured, admissionInfo kyverno.RequestInfo) *response.EngineResponse { +func validateResource(log logr.Logger, ctx context.EvalInterface, policy kyverno.ClusterPolicy, resource unstructured.Unstructured, admissionInfo kyverno.RequestInfo, isDelete bool) *response.EngineResponse { resp := &response.EngineResponse{} for _, rule := range policy.Spec.Rules { if !rule.HasValidate() { @@ -123,11 +106,14 @@ func validateResource(log logr.Logger, ctx context.EvalInterface, policy kyverno continue } - if rule.Validation.Pattern != nil || rule.Validation.AnyPattern != nil { - ruleResponse := validatePatterns(log, ctx, resource, rule) - incrementAppliedCount(resp) - resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse) + if !isDelete { + if rule.Validation.Pattern != nil || rule.Validation.AnyPattern != nil { + ruleResponse := validatePatterns(log, ctx, resource, rule) + incrementAppliedCount(resp) + resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse) + } } + } return resp } diff --git a/pkg/webhookconfig/resource.go b/pkg/webhookconfig/resource.go index 050517da0a..7a91a24af5 100644 --- a/pkg/webhookconfig/resource.go +++ b/pkg/webhookconfig/resource.go @@ -100,7 +100,7 @@ func (wrc *WebhookRegistrationClient) constructDebugValidatingWebhookConfig(caDa "*/*", "*", "*", - []admregapi.OperationType{admregapi.Create, admregapi.Update}, + []admregapi.OperationType{admregapi.Create, admregapi.Update, admregapi.Delete}, ), }, } @@ -124,7 +124,7 @@ func (wrc *WebhookRegistrationClient) constructValidatingWebhookConfig(caData [] "*/*", "*", "*", - []admregapi.OperationType{admregapi.Create, admregapi.Update}, + []admregapi.OperationType{admregapi.Create, admregapi.Update, admregapi.Delete}, ), }, } diff --git a/pkg/webhooks/server.go b/pkg/webhooks/server.go index 23e8ccd6e8..0e3fd35847 100644 --- a/pkg/webhooks/server.go +++ b/pkg/webhooks/server.go @@ -8,6 +8,7 @@ import ( "fmt" "io/ioutil" "net/http" + "strings" "time" v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1" @@ -171,13 +172,19 @@ func (ws *WebhookServer) handlerFunc(handler func(request *v1beta1.AdmissionRequ // Do not process the admission requests for kinds that are in filterKinds for filtering request := admissionReview.Request - if filter { - if !ws.configHandler.ToFilter(request.Kind.Kind, request.Namespace, request.Name) { + + if !isValidUsername(request.UserInfo.Username) { + admissionReview.Response = &v1beta1.AdmissionResponse{Allowed: true} + } else { + if filter { + if !ws.configHandler.ToFilter(request.Kind.Kind, request.Namespace, request.Name) { + admissionReview.Response = handler(request) + } + } else { admissionReview.Response = handler(request) } - } else { - admissionReview.Response = handler(request) } + admissionReview.Response.UID = request.UID responseJSON, err := json.Marshal(admissionReview) @@ -193,6 +200,15 @@ func (ws *WebhookServer) handlerFunc(handler func(request *v1beta1.AdmissionRequ } } +func isValidUsername(username string) bool { + if strings.HasPrefix(username, "system") { + if !strings.HasPrefix(username, "system:serviceaccount") { + return false + } + } + return true +} + func (ws *WebhookServer) resourceMutation(request *v1beta1.AdmissionRequest) *v1beta1.AdmissionResponse { logger := ws.log.WithValues("uid", request.UID, "kind", request.Kind.Kind, "namespace", request.Namespace, "name", request.Name, "operation", request.Operation) policies, err := ws.pMetaStore.ListAll()