diff --git a/pkg/event/msgbuilder.go b/pkg/event/msgbuilder.go index ea897ab07f..61db77033f 100644 --- a/pkg/event/msgbuilder.go +++ b/pkg/event/msgbuilder.go @@ -17,6 +17,8 @@ const ( FPolicyApplyBlockCreate FPolicyApplyBlockUpdate FPolicyBlockResourceUpdate + FPolicyApplyFailed + FResourcePolicyFailed ) func (k MsgKey) String() string { @@ -28,6 +30,8 @@ func (k MsgKey) String() string { "Resource %s creation blocked by rule(s) %s", "Rule(s) '%s' of policy '%s' blocked update of the resource", "Resource %s update blocked by rule(s) %s", + "Rule(s) '%s' failed to apply on resource %s", + "Rule(s) '%s' of policy '%s' failed to apply on the resource", }[k] } diff --git a/pkg/webhooks/mutation.go b/pkg/webhooks/mutation.go index cb23ca2703..dfaa8c2fa7 100644 --- a/pkg/webhooks/mutation.go +++ b/pkg/webhooks/mutation.go @@ -89,9 +89,15 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest, resou // generate violation when response fails pvInfos := policyviolation.GeneratePVsFromEngineResponse(engineResponses) ws.pvGenerator.Add(pvInfos...) - + // REPORTING EVENTS + // Scenario 1: + // some/all policies failed to apply on the resource. a policy volation is generated. + // create an event on the resource and the policy that failed + // Scenario 2: + // all policies were applied succesfully. + // create an event on the resource // ADD EVENTS - events := generateEvents(engineResponses, (request.Operation == v1beta1.Update)) + events := generateEvents(engineResponses, false, (request.Operation == v1beta1.Update)) ws.eventGen.Add(events...) // debug info diff --git a/pkg/webhooks/report.go b/pkg/webhooks/report.go index f18946fc51..035a60688e 100644 --- a/pkg/webhooks/report.go +++ b/pkg/webhooks/report.go @@ -6,82 +6,21 @@ import ( kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" "github.com/nirmata/kyverno/pkg/engine/response" - "github.com/golang/glog" "github.com/nirmata/kyverno/pkg/event" ) //generateEvents generates event info for the engine responses -func generateEvents(engineResponses []response.EngineResponse, onUpdate bool) []event.Info { +func generateEvents(engineResponses []response.EngineResponse, blocked, onUpdate bool) []event.Info { var events []event.Info - if !isResponseSuccesful(engineResponses) { - for _, er := range engineResponses { - if er.IsSuccesful() { - // dont create events on success - continue - } - // default behavior is audit - reason := event.PolicyViolation - if er.PolicyResponse.ValidationFailureAction == Enforce { - reason = event.RequestBlocked - } - failedRules := er.GetFailedRules() - filedRulesStr := strings.Join(failedRules, ";") - if onUpdate { - var e event.Info - // UPDATE - // event on resource - e = event.NewEvent( - er.PolicyResponse.Resource.Kind, - er.PolicyResponse.Resource.APIVersion, - er.PolicyResponse.Resource.Namespace, - er.PolicyResponse.Resource.Name, - reason.String(), - event.AdmissionController, - event.FPolicyApplyBlockUpdate, - filedRulesStr, - er.PolicyResponse.Policy, - ) - glog.V(4).Infof("UPDATE event on resource %s/%s/%s with policy %s", er.PolicyResponse.Resource.Kind, er.PolicyResponse.Resource.Namespace, er.PolicyResponse.Resource.Name, er.PolicyResponse.Policy) - events = append(events, e) - - // event on policy - e = event.NewEvent( - "ClusterPolicy", - kyverno.SchemeGroupVersion.String(), - "", - er.PolicyResponse.Policy, - reason.String(), - event.AdmissionController, - event.FPolicyBlockResourceUpdate, - er.PolicyResponse.Resource.GetKey(), - filedRulesStr, - ) - glog.V(4).Infof("UPDATE event on policy %s", er.PolicyResponse.Policy) - events = append(events, e) - - } else { - // CREATE - // event on policy - e := event.NewEvent( - "ClusterPolicy", - kyverno.SchemeGroupVersion.String(), - "", - er.PolicyResponse.Policy, - reason.String(), - event.AdmissionController, - event.FPolicyApplyBlockCreate, - er.PolicyResponse.Resource.GetKey(), - filedRulesStr, - ) - glog.V(4).Infof("CREATE event on policy %s", er.PolicyResponse.Policy) - events = append(events, e) - } + // Scenario 1 + // - Admission-Response is SUCCESS && CREATE + // - All policies were succesfully + // - report event on resources + if isResponseSuccesful(engineResponses) { + if !onUpdate { + // we only report events on CREATE requests + return events } - return events - } - if !onUpdate { - // All policies were applied successfully - // CREATE for _, er := range engineResponses { successRules := er.GetSuccessRules() successRulesStr := strings.Join(successRules, ";") @@ -99,7 +38,84 @@ func generateEvents(engineResponses []response.EngineResponse, onUpdate bool) [] ) events = append(events, e) } - + return events } + + // Scneario 2 + // - Admission-Response is BLOCKED + // - report event of policy is in enforce mode and failed to apply + if blocked { + for _, er := range engineResponses { + if er.IsSuccesful() { + // do not create event on polices that were succesfuly + continue + } + if er.PolicyResponse.ValidationFailureAction != Enforce { + // do not create event on "audit" policy + continue + } + // Rules that failed + failedRules := er.GetFailedRules() + filedRulesStr := strings.Join(failedRules, ";") + // Event on Policy + e := event.NewEvent( + "ClusterPolicy", + kyverno.SchemeGroupVersion.String(), + "", + er.PolicyResponse.Policy, + event.RequestBlocked.String(), + event.AdmissionController, + event.FPolicyBlockResourceUpdate, + er.PolicyResponse.Resource.GetKey(), + filedRulesStr, + ) + events = append(events, e) + } + return events + } + + // Scenario 3 + // - Admission-Response is SUCCESS + // - Some/All policies failed (policy violations generated) + // - report event on policy that failed + // - report event on resource that failed + + for _, er := range engineResponses { + if er.IsSuccesful() { + // do not create event on polices that were succesfuly + continue + } + // Rules that failed + failedRules := er.GetFailedRules() + filedRulesStr := strings.Join(failedRules, ";") + // Event on the policy + e := event.NewEvent( + "ClusterPolicy", + kyverno.SchemeGroupVersion.String(), + "", + er.PolicyResponse.Policy, + event.PolicyFailed.String(), + event.AdmissionController, + event.FPolicyApplyFailed, + filedRulesStr, + er.PolicyResponse.Resource.GetKey(), + ) + events = append(events, e) + // Event on the resource + // event on resource + e = event.NewEvent( + er.PolicyResponse.Resource.Kind, + er.PolicyResponse.Resource.APIVersion, + er.PolicyResponse.Resource.Namespace, + er.PolicyResponse.Resource.Name, + event.PolicyViolation.String(), + event.AdmissionController, + event.FResourcePolicyFailed, + filedRulesStr, + er.PolicyResponse.Policy, + ) + events = append(events, e) + } + return events } diff --git a/pkg/webhooks/validation.go b/pkg/webhooks/validation.go index 5f8051ff0f..b539bfef9d 100644 --- a/pkg/webhooks/validation.go +++ b/pkg/webhooks/validation.go @@ -87,8 +87,20 @@ func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest, pol // If Validation fails then reject the request // no violations will be created on "enforce" - // the event will be reported on owner by k8s blocked := toBlockResource(engineResponses) + + // REPORTING EVENTS + // Scenario 1: + // resource is blocked, as there is a policy in "enforce" mode that failed. + // create an event on the policy to inform the resource request was blocked + // Scenario 2: + // some/all policies failed to apply on the resource. a policy volation is generated. + // create an event on the resource and the policy that failed + // Scenario 3: + // all policies were applied succesfully. + // create an event on the resource + events := generateEvents(engineResponses, blocked, (request.Operation == v1beta1.Update)) + ws.eventGen.Add(events...) if blocked { glog.V(4).Infof("resource %s/%s/%s is blocked\n", newR.GetKind(), newR.GetNamespace(), newR.GetName()) return false, getEnforceFailureErrorMsg(engineResponses) @@ -98,9 +110,6 @@ func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest, pol // violations are created with resource on "audit" pvInfos := policyviolation.GeneratePVsFromEngineResponse(engineResponses) ws.pvGenerator.Add(pvInfos...) - // ADD EVENTS - events := generateEvents(engineResponses, (request.Operation == v1beta1.Update)) - ws.eventGen.Add(events...) // report time end glog.V(4).Infof("report: %v %s/%s/%s", time.Since(reportTime), request.Kind, request.Namespace, request.Name) return true, ""