diff --git a/pkg/controllers/report/utils/events.go b/pkg/controllers/report/utils/events.go index c454f2aa1e..222af092c9 100644 --- a/pkg/controllers/report/utils/events.go +++ b/pkg/controllers/report/utils/events.go @@ -36,7 +36,7 @@ func generateExceptionEvents(log logr.Logger, ers ...engineapi.EngineResponse) ( for i, ruleResp := range er.PolicyResponse.Rules { isException := ruleResp.Exception != nil if ruleResp.Status == engineapi.RuleStatusSkip && isException { - eventInfos = append(eventInfos, event.NewPolicyExceptionEvents(er, &er.PolicyResponse.Rules[i])...) + eventInfos = append(eventInfos, event.NewPolicyExceptionEvents(er, &er.PolicyResponse.Rules[i], event.PolicyController)...) } } } diff --git a/pkg/event/events.go b/pkg/event/events.go index eaa939964c..ee128c7ce5 100644 --- a/pkg/event/events.go +++ b/pkg/event/events.go @@ -123,7 +123,7 @@ func NewBackgroundSuccessEvent(policy, rule string, source Source, r *unstructur return events } -func NewPolicyExceptionEvents(engineResponse engineapi.EngineResponse, ruleResp *engineapi.RuleResponse) []Info { +func NewPolicyExceptionEvents(engineResponse engineapi.EngineResponse, ruleResp *engineapi.RuleResponse, source Source) []Info { exceptionName, exceptionNamespace := ruleResp.Exception.GetName(), ruleResp.Exception.GetNamespace() policyMessage := fmt.Sprintf("resource %s was skipped from rule %s due to policy exception %s/%s", resourceKey(engineResponse.PatchedResource), ruleResp.Name, exceptionNamespace, exceptionName) var exceptionMessage string @@ -138,6 +138,7 @@ func NewPolicyExceptionEvents(engineResponse engineapi.EngineResponse, ruleResp Namespace: engineResponse.Policy.GetNamespace(), Reason: PolicySkipped, Message: policyMessage, + Source: source, } exceptionEvent := Info{ Kind: "PolicyException", @@ -145,6 +146,7 @@ func NewPolicyExceptionEvents(engineResponse engineapi.EngineResponse, ruleResp Namespace: exceptionNamespace, Reason: PolicySkipped, Message: exceptionMessage, + Source: source, } return []Info{policyEvent, exceptionEvent} } diff --git a/pkg/webhooks/utils/event.go b/pkg/webhooks/utils/event.go index f37c52005f..f7395af6c4 100644 --- a/pkg/webhooks/utils/event.go +++ b/pkg/webhooks/utils/event.go @@ -34,7 +34,7 @@ func GenerateEvents(engineResponses []engineapi.EngineResponse, blocked bool) [] for i, ruleResp := range er.PolicyResponse.Rules { isException := ruleResp.Exception != nil if ruleResp.Status == engineapi.RuleStatusSkip && !blocked && isException { - events = append(events, event.NewPolicyExceptionEvents(er, &er.PolicyResponse.Rules[i])...) + events = append(events, event.NewPolicyExceptionEvents(er, &er.PolicyResponse.Rules[i], event.AdmissionController)...) } } } else if !er.IsSkipped() { diff --git a/test/conformance/kuttl/exceptions/events-creation/01-policy.yaml b/test/conformance/kuttl/exceptions/events-creation/01-policy.yaml new file mode 100644 index 0000000000..b088ed7601 --- /dev/null +++ b/test/conformance/kuttl/exceptions/events-creation/01-policy.yaml @@ -0,0 +1,6 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +apply: +- policy.yaml +assert: +- policy-assert.yaml diff --git a/test/conformance/kuttl/exceptions/events-creation/02-exception.yaml b/test/conformance/kuttl/exceptions/events-creation/02-exception.yaml new file mode 100644 index 0000000000..2fa5cb808e --- /dev/null +++ b/test/conformance/kuttl/exceptions/events-creation/02-exception.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: policy-exception-events-creation-polex-ns +--- +apiVersion: kyverno.io/v2alpha1 +kind: PolicyException +metadata: + name: policy-exception-allow-latest + namespace: policy-exception-events-creation-polex-ns +spec: + exceptions: + - policyName: disallow-latest-tag-events-creation + ruleNames: + - validate-image-tag + match: + any: + - resources: + namespaces: + - policy-exception-events-creation-ns diff --git a/test/conformance/kuttl/exceptions/events-creation/03-manifests.yaml b/test/conformance/kuttl/exceptions/events-creation/03-manifests.yaml new file mode 100644 index 0000000000..8fc90f127d --- /dev/null +++ b/test/conformance/kuttl/exceptions/events-creation/03-manifests.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: policy-exception-events-creation-ns +--- +apiVersion: v1 +kind: Pod +metadata: + name: policy-exception-events-creation-pod + namespace: policy-exception-events-creation-ns +spec: + containers: + - image: nginx + name: nginx + diff --git a/test/conformance/kuttl/exceptions/events-creation/04-sleep.yaml b/test/conformance/kuttl/exceptions/events-creation/04-sleep.yaml new file mode 100644 index 0000000000..fe3b8abbcb --- /dev/null +++ b/test/conformance/kuttl/exceptions/events-creation/04-sleep.yaml @@ -0,0 +1,5 @@ +# A command can only run a single command, not a pipeline and not a script. The program called must exist on the system where the test is run. +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: sleep 3 \ No newline at end of file diff --git a/test/conformance/kuttl/exceptions/events-creation/05-assert.yaml b/test/conformance/kuttl/exceptions/events-creation/05-assert.yaml new file mode 100644 index 0000000000..edbe51fa77 --- /dev/null +++ b/test/conformance/kuttl/exceptions/events-creation/05-assert.yaml @@ -0,0 +1,26 @@ +apiVersion: v1 +involvedObject: + apiVersion: kyverno.io/v2alpha1 + kind: PolicyException + name: policy-exception-allow-latest + namespace: policy-exception-events-creation-polex-ns +kind: Event +metadata: + namespace: policy-exception-events-creation-polex-ns +reason: PolicySkipped +source: + component: kyverno-admission +type: Normal +--- +apiVersion: v1 +involvedObject: + apiVersion: kyverno.io/v1 + kind: ClusterPolicy + name: disallow-latest-tag-events-creation +kind: Event +metadata: + namespace: default +reason: PolicySkipped +source: + component: kyverno-admission +type: Normal diff --git a/test/conformance/kuttl/exceptions/events-creation/README.md b/test/conformance/kuttl/exceptions/events-creation/README.md new file mode 100644 index 0000000000..e0e79f97db --- /dev/null +++ b/test/conformance/kuttl/exceptions/events-creation/README.md @@ -0,0 +1,14 @@ +## Description + +This test checks the events are generated properly for policyexceptions. + +## Steps + +1. - Create a cluster policy + - Assert the policy becomes ready +1. - Create a policy exception for the cluster policy created above but for a specific namespace +1. - Try to create a pod, expecting two events are created, one for the clusterpolicy, another is for policyexception + +## Reference Issue(s) + +https://github.com/kyverno/kyverno/issues/6469 diff --git a/test/conformance/kuttl/exceptions/events-creation/policy-assert.yaml b/test/conformance/kuttl/exceptions/events-creation/policy-assert.yaml new file mode 100644 index 0000000000..94acb8259d --- /dev/null +++ b/test/conformance/kuttl/exceptions/events-creation/policy-assert.yaml @@ -0,0 +1,9 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: disallow-latest-tag-events-creation +status: + conditions: + - reason: Succeeded + status: "True" + type: Ready diff --git a/test/conformance/kuttl/exceptions/events-creation/policy.yaml b/test/conformance/kuttl/exceptions/events-creation/policy.yaml new file mode 100644 index 0000000000..b7841813c9 --- /dev/null +++ b/test/conformance/kuttl/exceptions/events-creation/policy.yaml @@ -0,0 +1,29 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: disallow-latest-tag-events-creation + annotations: + policies.kyverno.io/title: Disallow Latest Tag + policies.kyverno.io/category: Best Practices + policies.kyverno.io/severity: medium + policies.kyverno.io/subject: Pod + policies.kyverno.io/description: >- + The ':latest' tag is mutable and can lead to unexpected errors if the + image changes. A best practice is to use an immutable tag that maps to + a specific version of an application Pod. This policy validates that the image + specifies a tag and that it is not called `latest`. +spec: + validationFailureAction: enforce + background: true + rules: + - name: validate-image-tag + match: + resources: + kinds: + - Pod + validate: + message: "An image tag is required (:latest is not allowed)" + pattern: + spec: + containers: + - image: "!*:latest & *:*" \ No newline at end of file