Repository: kyverno/kyverno
Pull request #12946: add support for auditAnnotations in ivpols
Author: login: fjogeleit
Labels: name: cherry-pick-required
name: cherry-pick-completed
description: The PR was cherry-picked (or merged) to required release branches
name: size:XL
description: This PR changes 500-999 lines, ignoring generated files.
Created: 2025-04-29T06:38:34Z | Merged: 2025-04-29T11:45:18Z

## Explanation

Support AuditAnnotations in ivpols

## Related issue

<!--
Please link the GitHub issue this pull request resolves in the format of `Closes #1234`. If you discussed this change
with a maintainer, please mention her/him using the `@` syntax (e.g. `@JimBugwadia`).

If this change neither resolves an existing issue nor has sign-off from one of the maintainers, there is a
chance substantial changes will be requested or that the changes will be rejected.

You can discuss changes with maintainers in the [Kyverno Slack Channel](https://kubernetes.slack.com/).
-->

## Milestone of this PR
<!--

Add the milestone label by commenting `/milestone 1.2.3`.

-->

## Documentation (required for features)

My PR contains new or altered behavior to Kyverno. 
- [ ] I have sent the draft PR to add or update [the documentation](https://github.com/kyverno/website) and the link is:
  <!-- Uncomment to link to the PR -->
  <!-- https://github.com/kyverno/website/pull/123 -->

## What type of PR is this

<!--

> Uncomment only one ` /kind <>` line, hit enter to put that in a new line, and remove leading white spaces from that line:
>
> /kind api-change
> /kind bug
> /kind cleanup
> /kind design
> /kind documentation
> /kind failing-test
> /kind feature
-->

## Proposed Changes

<!--
Describe the big picture of your changes here to communicate to the maintainers why we should accept this pull request. 

***NOTE***: If this PR results in new or altered behavior which is user facing, you **MUST** read and follow the steps outlined in the [PR documentation guide](pr_documentation.md) and add Proof Manifests as defined below.
-->

### Proof Manifests

<!--
Read and follow the [PR documentation guide](https://github.com/kyverno/kyverno/blob/main/.github/pr_documentation.md) for more details first. This section is for pasting your YAML manifests (Kubernetes resources and Kyverno policies) and Kyverno CLI test manifests which allow maintainers to prove the intended functionality is achieved by your PR. Please use proper fenced code block formatting, for example:

# Kubernetes resource

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: roles-dictionary
  namespace: default
data:
  allowed-roles: "[\"cluster-admin\", \"cluster-operator\", \"tenant-admin\"]"
```

# Kyverno CLI test manifest (please see docs for latest manifest format at https://kyverno.io/docs/kyverno-cli/). See kyverno/policies for complete examples of all related test files.

```yaml
name: prepend-image-registry
policies:
  - prepend_image_registry.yaml
resources:
  - resource.yaml
variables: values.yaml
results:
  - policy: prepend-registry
    rule: prepend-registry-containers
    resource: mypod
    # if mutate rule
    patchedResource: patchedResource01.yaml
    kind: Pod
    result: pass
```
-->

## Checklist

<!--
Put an `x` in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of
them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code.
-->

- [ ] I have read the [contributing guidelines](https://github.com/kyverno/kyverno/blob/main/CONTRIBUTING.md).
- [ ] I have read the [PR documentation guide](https://github.com/kyverno/kyverno/blob/main/.github/pr_documentation.md) and followed the process including adding proof manifests to this PR.
- [ ] This is a bug fix and I have added unit tests that prove my fix is effective.
- [ ] This is a feature and I have added CLI tests that are applicable.
- [ ] My PR needs to be cherry picked to a specific release branch which is <replace>.
- [ ] My PR contains new or altered behavior to Kyverno and
  - [ ] CLI support should be added and my PR doesn't contain that functionality.

## Further Comments

<!--
If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution
you did and what alternatives you considered, etc...
-->


Linked issue #1234: [BUG] Error reporting for openAPISchema validation
**Describe the bug**
Per [this](https://github.com/kyverno/kyverno/issues/954#issuecomment-722015854) discussion, Kyverno keeps logging errors when a CRD does not have openAPI schema defined.

>Kyverno should have a mode where we can quiet this down in some way.. or it should simply not fail here.

We should turn the error log into a leveled info log, only log out the error during the policy validation - when a policy is defined on a custom resource that does not have openAPISchema.

Linked issue comments: user: login: realshuting
created_at: 2020-11-12T19:03:00Z
body: Related issue reported in Kyverno Slack: https://kubernetes.slack.com/archives/CLGR9BJU9/p1605207195190800?thread_ts=1605191779.161900&cid=CLGR9BJU9
author_association: MEMBER
user: login: Raboldar
created_at: 2020-11-12T21:48:05Z
body: I get a similar error : 
```
[60]\n\nValidationError(org.projectcalico.crd.v1.IPAMBlock.spec.allocations): unknown object type \"nil\" in org.projectcalico.crd.v1.IPAMBlock.spec.allocations[61]\n\nValidationError(org.projectcalico.crd.v1.IPAMBlock.spec.allocations): unknown object type \"nil\" in org.projectcalico.crd.v1.IPAMBlock.spec.allocations[62]\n\nValidationError(org.projectcalico.crd.v1.IPAMBlock.spec.allocations): unknown object type \"nil\" in org.projectcalico.crd.v1.IPAMBlock.spec.allocations[63]" "action"="mutate" "operation"="UPDATE" "resource"="IPAMBlock/192-168-86-0-26" "policy"="insert-container"
I1112 20:43:33.501452       1 mutation.go:78] WebhookServer "msg"="mutation rules from policy applied successfully" "action"="mutate" "operation"="UPDATE" "resource"="default/Deployment/hello-kube" "policy"="insert-container" "rules"=["insert-container"]
```
I'm trying to deploy the following: 
```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-kube 
  labels:
    app: bar 
    service: front 
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello-kube
      service: front 
  template:
    metadata:
      labels:
        app: hello-kube  
        service: front 
    spec:
      containers:
      - name: hello-kube 
        image: paulbouwer/hello-kubernetes:1.8
        ports:
        - containerPort: 8080
          name: http 
```
This is the Kyverno policy that i applied previously:
```
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: kyverno-admin-generate
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: kyverno:generatecontroller # clusterRole defined above, to manage generated resources
subjects:
- kind: ServiceAccount
  name: kyverno-service-account # default kyverno serviceAccount
  namespace: kyverno
```
```
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: insert-container
spec:
  rules:
    - name: insert-container
      match:
        resources:
          kinds:
          - Deployment
      mutate:
        overlay:
          spec:
            template:
              spec:
                topologySpreadConstraints:
                - maxSkew: 1
                  topologyKey: topology.psud.nc/datacenter 
                  whenUnsatisfiable: DoNotSchedule
                  labelSelector:
                    matchLabels:
                      app: bar
```
Calico :
The pods get an IP and can communicate. 

author_association: NONE
user: login: kacejot
created_at: 2021-02-18T00:32:32Z
body: I see three possible ways to resolve it:
- We could leave the things as they are.
    Pros: we keep compatibility with openapi standards without adding specific validation for 3rd-party CRDs. And we don't need to do anything.
    Cons: 3rd-party CRD that violate openAPI will have error on validation.
- We could change logging logic as Shuting proposes.
    Pros/Cons: specific 3rd-party CRD support, which is good for audience coverage, but not product architecture.
    Pros: Easy to do.
- We could change validation logic by adding support of 3rd party CRD right there.
    Pros: specific 3rd-party CRD support
    Cons: Complex task;

Personally I like the second way, where the logging process should be updated.
I will look more at alternatives and comment back.
author_association: CONTRIBUTOR
user: login: JimBugwadia
created_at: 2021-02-19T17:30:34Z
body: @kacejot - this sounds good to me. Please proceed.
author_association: MEMBER
user: login: kacejot
created_at: 2021-02-23T02:44:45Z
body: After additional research I came up with oneliner solution. I have implemented it and started testing.
I have set up calico over my cluster and its CRD already had OpenAPIv3 schema, so I wasn't able to reproduce this issue anymore. When I tried to recreate old CRD without OpenAPIv3 schema, Kubernetes declined my try saying:
```
The CustomResourceDefinition "globalnetworkpolicies.crd.projectcalico.org" is invalid: 
* spec.versions[0].schema.openAPIV3Schema: Required value: schemas are required
```

But anyway, the problem was that Kyverno tried to validate the resource with empty schema. I have added check for this case. I will push my changes to separate branch, but there is no sense to merge it until we have stable reproduce. I will try to downgrade my Kubernetes version to November 2020 and try again.
author_association: CONTRIBUTOR
user: login: JimBugwadia
created_at: 2021-02-23T05:36:52Z
body: @kacejot - Calico was one example but seems like we would have this issue anytime a CRD does not have openAPI schema defined, right?
author_association: MEMBER
user: login: realshuting
created_at: 2021-02-23T06:50:21Z
body: @kacejot check this comment - https://github.com/kyverno/kyverno/issues/1234#issuecomment-726276476, `HelmRelease` is another CRD that we can use to reproduce the issue.
author_association: MEMBER
user: login: kacejot
created_at: 2021-02-25T00:13:39Z
body: cc: @realshuting @JimBugwadia 

I have installed Helm Operator (without flux) and wrote [some instructions](https://github.com/kyverno/kyverno/wiki/How-to-install-Helm-Operator) how to do this, because I was encountering lots of difficulties and it should help someone who want to reproduce this issue.

So, I have added HelmRelease custom resource much like it is described in [slack thread]( https://kubernetes.slack.com/archives/CLGR9BJU9/p1605207195190800?thread_ts=1605191779.161900&cid=CLGR9BJU9):
```yaml
apiVersion: helm.fluxcd.io/v1
kind: HelmRelease
metadata:
  name: azure-arc-sample
  namespace: default
spec:
  releaseName: arc-k8s-demo
  chart:
    git: https://github.com/Azure/arc-helm-demo
    ref: master
    path: charts/azure-arc-sample
  values:
    serviceName: arc-k8s-demo
```
Also I created the same policy as is in the thread:
```yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata: 
  name: add-labels
spec: 
  background: false
  rules:
  - name: add-ns-label
    match:
      resources:
        kinds:
        - Namespace
        name: "epi-*"
    mutate:
      patchStrategicMerge:
        metadata:
          labels:
            name: "{{ request.object.metadata.name }}"
```
And created sample namespace:
```
kubectl create namespace epi-sample
```
All worked fine and there is no errors in logs.
author_association: CONTRIBUTOR
user: login: JimBugwadia
created_at: 2021-03-02T16:15:43Z
body: @realshuting are you able to reproduce this?
author_association: MEMBER
user: login: realshuting
created_at: 2021-03-02T19:49:41Z
body: No I cannot reproduce the issue with `HelmRelease`.

We had suppressed the error log in [this](https://github.com/kyverno/kyverno/pull/1255/files#diff-51a43f2d1bdcedd38e4b4b122ed9bda070cdbbc3ce65ed04f87b88f13646b065R69) PR, if I apply [`machinehealthchecks.cluster.x-k8s.io`](https://github.com/kyverno/kyverno/issues/954#issue-645905828), I can see the error in level 4:
```
I0302 19:38:38.852973       1 mutation.go:77] WebhookServer "msg"="validation error" "action"="mutate" "operation"="UPDATE" "resource"="CustomResourceDefinition/machinehealthchecks.cluster.x-k8s.io" "error"="ValidationError(io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceDefinition.spec.conversion): unknown field \"webhook\" in io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceConversion\n\nValidationError(io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceDefinition.spec.versions[0].additionalPrinterColumns[0]): unknown field \"jsonPath\" in io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceColumnDefinition\n\nValidationError(io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceDefinition.spec.versions[0].additionalPrinterColumns[0]): missing required field \"JSONPath\" in io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceColumnDefinition\n\nValidationError(io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceDefinition.spec.versions[0].additionalPrinterColumns[1]): unknown field \"jsonPath\" in io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceColumnDefinition\n\nValidationError(io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceDefinition.spec.versions[0].additionalPrinterColumns[1]): missing required field \"JSONPath\" in io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceColumnDefinition\n\nValidationError(io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceDefinition.spec.versions[0].additionalPrinterColumns[2]): unknown field \"jsonPath\" in io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceColumnDefinition\n\nValidationError(io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceDefinition.spec.versions[0].additionalPrinterColumns[2]): missing required field \"JSONPath\" in io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceColumnDefinition" "policy"="add-labels"
```

We still need to -
>log out the error during the policy validation - when a policy is defined on the custom resource that does not have openAPISchema.
author_association: MEMBER
user: login: JimBugwadia
created_at: 2021-03-19T05:33:07Z
body: @kacejot - are you planning on submitting a PR for this?
author_association: MEMBER
user: login: kacejot
created_at: 2021-03-19T17:43:08Z
body: @JimBugwadia, not for the current release. I was working on other issues. I think I will apply Shuting's comments on the next release
author_association: CONTRIBUTOR
user: login: realshuting
created_at: 2021-03-22T22:19:29Z
body: >log out the error during the policy validation - when a policy is defined on the custom resource that does not have openAPISchema.

It seems we already do it - https://github.com/kyverno/kyverno/issues/1218#issuecomment-799734944:
```
E0315 19:48:52.649398       1 crdSync.go:146]  "msg"="could not parse crd schema" "error"="crd schema has no properties"  "name"="Task"
```

author_association: MEMBER
user: login: realshuting
created_at: 2021-03-22T22:19:54Z
body: Closing this issue.
Please feel free to reopen if this can be reproduced.
author_association: MEMBER
user: login: awoodobvio
created_at: 2022-01-23T21:44:27Z
body: @realshuting 

We are seeing something similar to this with version 1.5.3 and the "IstioOperator" crd.  Not sure if this warrants opening the bug again, but I found this while searching for some way to suppress the log output and it seems related.  We have no policies running against IstioOperator or CRD objects in the cluster.

That has a schema that looks like this:

``` yaml
schema:
      openAPIV3Schema:
        type: object
        x-kubernetes-preserve-unknown-fields: true
```

This results in the following log message being continuously sent:

``` log
E0123 21:43:14.364473       1 crdSync.go:179]  "msg"="could not parse crd schema" "error"="crd schema has no properties" "name"="IstioOperator"
```

**Entire CRD definition is below:**

``` yaml
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  annotations:
  labels:
    release: istio
  name: istiooperators.install.istio.io
spec:
  conversion:
    strategy: None
  group: install.istio.io
  names:
    kind: IstioOperator
    listKind: IstioOperatorList
    plural: istiooperators
    shortNames:
    - iop
    - io
    singular: istiooperator
  scope: Namespaced
  versions:
  - additionalPrinterColumns:
    - description: Istio control plane revision
      jsonPath: .spec.revision
      name: Revision
      type: string
    - description: IOP current state
      jsonPath: .status.status
      name: Status
      type: string
    - description: 'CreationTimestamp is a timestamp representing the server time
        when this object was created. It is not guaranteed to be set in happens-before
        order across separate operations. Clients may not set this value. It is represented
        in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for
        lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata'
      jsonPath: .metadata.creationTimestamp
      name: Age
      type: date
    name: v1alpha1
    schema:
      openAPIV3Schema:
        type: object
        x-kubernetes-preserve-unknown-fields: true
    served: true
    storage: true
    subresources:
      status: {}
```

author_association: NONE
user: login: JimBugwadia
created_at: 2022-01-24T02:57:43Z
body: Is this reproducible with 1.6.x? I believe it was fixed, but would be good to verify.
author_association: MEMBER

Diff:
diff --git a/api/policies.kyverno.io/v1alpha1/imagevalidating_policy.go b/api/policies.kyverno.io/v1alpha1/imagevalidating_policy.go
index df6f13db1bd3..3805da991b82 100644
--- a/api/policies.kyverno.io/v1alpha1/imagevalidating_policy.go
+++ b/api/policies.kyverno.io/v1alpha1/imagevalidating_policy.go
@@ -141,6 +141,14 @@ type ImageValidatingPolicySpec struct {
 	// +kubebuilder:validation:Enum=Ignore;Fail
 	FailurePolicy *admissionregistrationv1.FailurePolicyType `json:"failurePolicy"`
 
+	// auditAnnotations contains CEL expressions which are used to produce audit
+	// annotations for the audit event of the API request.
+	// validations and auditAnnotations may not both be empty; a least one of validations or auditAnnotations is
+	// required.
+	// +listType=atomic
+	// +optional
+	AuditAnnotations []admissionregistrationv1.AuditAnnotation `json:"auditAnnotations,omitempty"`
+
 	// ValidationAction specifies the action to be taken when the matched resource violates the policy.
 	// Required.
 	// +listType=set
diff --git a/api/policies.kyverno.io/v1alpha1/zz_generated.deepcopy.go b/api/policies.kyverno.io/v1alpha1/zz_generated.deepcopy.go
index 2afd3412d59a..6045aebb2dd4 100644
--- a/api/policies.kyverno.io/v1alpha1/zz_generated.deepcopy.go
+++ b/api/policies.kyverno.io/v1alpha1/zz_generated.deepcopy.go
@@ -468,6 +468,11 @@ func (in *ImageValidatingPolicySpec) DeepCopyInto(out *ImageValidatingPolicySpec
 		*out = new(admissionregistrationv1.FailurePolicyType)
 		**out = **in
 	}
+	if in.AuditAnnotations != nil {
+		in, out := &in.AuditAnnotations, &out.AuditAnnotations
+		*out = make([]admissionregistrationv1.AuditAnnotation, len(*in))
+		copy(*out, *in)
+	}
 	if in.ValidationAction != nil {
 		in, out := &in.ValidationAction, &out.ValidationAction
 		*out = make([]admissionregistrationv1.ValidationAction, len(*in))
diff --git a/charts/kyverno/charts/crds/templates/policies.kyverno.io/policies.kyverno.io_imagevalidatingpolicies.yaml b/charts/kyverno/charts/crds/templates/policies.kyverno.io/policies.kyverno.io_imagevalidatingpolicies.yaml
index 5a99c405e606..22fc1162bea0 100644
--- a/charts/kyverno/charts/crds/templates/policies.kyverno.io/policies.kyverno.io_imagevalidatingpolicies.yaml
+++ b/charts/kyverno/charts/crds/templates/policies.kyverno.io/policies.kyverno.io_imagevalidatingpolicies.yaml
@@ -351,6 +351,58 @@ spec:
                   - name
                   type: object
                 type: array
+              auditAnnotations:
+                description: |-
+                  auditAnnotations contains CEL expressions which are used to produce audit
+                  annotations for the audit event of the API request.
+                  validations and auditAnnotations may not both be empty; a least one of validations or auditAnnotations is
+                  required.
+                items:
+                  description: AuditAnnotation describes how to produce an audit annotation
+                    for an API request.
+                  properties:
+                    key:
+                      description: |-
+                        key specifies the audit annotation key. The audit annotation keys of
+                        a ValidatingAdmissionPolicy must be unique. The key must be a qualified
+                        name ([A-Za-z0-9][-A-Za-z0-9_.]*) no more than 63 bytes in length.
+
+                        The key is combined with the resource name of the
+                        ValidatingAdmissionPolicy to construct an audit annotation key:
+                        "{ValidatingAdmissionPolicy name}/{key}".
+
+                        If an admission webhook uses the same resource name as this ValidatingAdmissionPolicy
+                        and the same audit annotation key, the annotation key will be identical.
+                        In this case, the first annotation written with the key will be included
+                        in the audit event and all subsequent annotations with the same key
+                        will be discarded.
+
+                        Required.
+                      type: string
+                    valueExpression:
+                      description: |-
+                        valueExpression represents the expression which is evaluated by CEL to
+                        produce an audit annotation value. The expression must evaluate to either
+                        a string or null value. If the expression evaluates to a string, the
+                        audit annotation is included with the string value. If the expression
+                        evaluates to null or empty string the audit annotation will be omitted.
+                        The valueExpression may be no longer than 5kb in length.
+                        If the result of the valueExpression is more than 10kb in length, it
+                        will be truncated to 10kb.
+
+                        If multiple ValidatingAdmissionPolicyBinding resources match an
+                        API request, then the valueExpression will be evaluated for
+                        each binding. All unique values produced by the valueExpressions
+                        will be joined together in a comma-separated list.
+
+                        Required.
+                      type: string
+                  required:
+                  - key
+                  - valueExpression
+                  type: object
+                type: array
+                x-kubernetes-list-type: atomic
               autogen:
                 description: AutogenConfiguration defines the configuration for the
                   generation controller.
@@ -1348,6 +1400,58 @@ spec:
                                 - name
                                 type: object
                               type: array
+                            auditAnnotations:
+                              description: |-
+                                auditAnnotations contains CEL expressions which are used to produce audit
+                                annotations for the audit event of the API request.
+                                validations and auditAnnotations may not both be empty; a least one of validations or auditAnnotations is
+                                required.
+                              items:
+                                description: AuditAnnotation describes how to produce
+                                  an audit annotation for an API request.
+                                properties:
+                                  key:
+                                    description: |-
+                                      key specifies the audit annotation key. The audit annotation keys of
+                                      a ValidatingAdmissionPolicy must be unique. The key must be a qualified
+                                      name ([A-Za-z0-9][-A-Za-z0-9_.]*) no more than 63 bytes in length.
+
+                                      The key is combined with the resource name of the
+                                      ValidatingAdmissionPolicy to construct an audit annotation key:
+                                      "{ValidatingAdmissionPolicy name}/{key}".
+
+                                      If an admission webhook uses the same resource name as this ValidatingAdmissionPolicy
+                                      and the same audit annotation key, the annotation key will be identical.
+                                      In this case, the first annotation written with the key will be included
+                                      in the audit event and all subsequent annotations with the same key
+                                      will be discarded.
+
+                                      Required.
+                                    type: string
+                                  valueExpression:
+                                    description: |-
+                                      valueExpression represents the expression which is evaluated by CEL to
+                                      produce an audit annotation value. The expression must evaluate to either
+                                      a string or null value. If the expression evaluates to a string, the
+                                      audit annotation is included with the string value. If the expression
+                                      evaluates to null or empty string the audit annotation will be omitted.
+                                      The valueExpression may be no longer than 5kb in length.
+                                      If the result of the valueExpression is more than 10kb in length, it
+                                      will be truncated to 10kb.
+
+                                      If multiple ValidatingAdmissionPolicyBinding resources match an
+                                      API request, then the valueExpression will be evaluated for
+                                      each binding. All unique values produced by the valueExpressions
+                                      will be joined together in a comma-separated list.
+
+                                      Required.
+                                    type: string
+                                required:
+                                - key
+                                - valueExpression
+                                type: object
+                              type: array
+                              x-kubernetes-list-type: atomic
                             autogen:
                               description: AutogenConfiguration defines the configuration
                                 for the generation controller.
diff --git a/cmd/cli/kubectl-kyverno/commands/apply/command.go b/cmd/cli/kubectl-kyverno/commands/apply/command.go
index c163d347efb0..54a9e266ae89 100644
--- a/cmd/cli/kubectl-kyverno/commands/apply/command.go
+++ b/cmd/cli/kubectl-kyverno/commands/apply/command.go
@@ -581,7 +581,7 @@ func (c *ApplyCommandConfig) applyImageValidatingPolicies(
 				}
 			} else {
 				resp.PolicyResponse.Rules = []engineapi.RuleResponse{
-					*engineapi.RuleFail(p, engineapi.ImageVerify, rslt.Message, nil),
+					*engineapi.RuleFail(p, engineapi.ImageVerify, rslt.Message, rslt.AuditAnnotations),
 				}
 			}
 			resp = resp.WithPolicy(engineapi.NewImageValidatingPolicy(pMap[p]))
diff --git a/cmd/cli/kubectl-kyverno/data/crds/policies.kyverno.io_imagevalidatingpolicies.yaml b/cmd/cli/kubectl-kyverno/data/crds/policies.kyverno.io_imagevalidatingpolicies.yaml
index 313a18d49af4..3c23655fcd79 100644
--- a/cmd/cli/kubectl-kyverno/data/crds/policies.kyverno.io_imagevalidatingpolicies.yaml
+++ b/cmd/cli/kubectl-kyverno/data/crds/policies.kyverno.io_imagevalidatingpolicies.yaml
@@ -345,6 +345,58 @@ spec:
                   - name
                   type: object
                 type: array
+              auditAnnotations:
+                description: |-
+                  auditAnnotations contains CEL expressions which are used to produce audit
+                  annotations for the audit event of the API request.
+                  validations and auditAnnotations may not both be empty; a least one of validations or auditAnnotations is
+                  required.
+                items:
+                  description: AuditAnnotation describes how to produce an audit annotation
+                    for an API request.
+                  properties:
+                    key:
+                      description: |-
+                        key specifies the audit annotation key. The audit annotation keys of
+                        a ValidatingAdmissionPolicy must be unique. The key must be a qualified
+                        name ([A-Za-z0-9][-A-Za-z0-9_.]*) no more than 63 bytes in length.
+
+                        The key is combined with the resource name of the
+                        ValidatingAdmissionPolicy to construct an audit annotation key:
+                        "{ValidatingAdmissionPolicy name}/{key}".
+
+                        If an admission webhook uses the same resource name as this ValidatingAdmissionPolicy
+                        and the same audit annotation key, the annotation key will be identical.
+                        In this case, the first annotation written with the key will be included
+                        in the audit event and all subsequent annotations with the same key
+                        will be discarded.
+
+                        Required.
+                      type: string
+                    valueExpression:
+                      description: |-
+                        valueExpression represents the expression which is evaluated by CEL to
+                        produce an audit annotation value. The expression must evaluate to either
+                        a string or null value. If the expression evaluates to a string, the
+                        audit annotation is included with the string value. If the expression
+                        evaluates to null or empty string the audit annotation will be omitted.
+                        The valueExpression may be no longer than 5kb in length.
+                        If the result of the valueExpression is more than 10kb in length, it
+                        will be truncated to 10kb.
+
+                        If multiple ValidatingAdmissionPolicyBinding resources match an
+                        API request, then the valueExpression will be evaluated for
+                        each binding. All unique values produced by the valueExpressions
+                        will be joined together in a comma-separated list.
+
+                        Required.
+                      type: string
+                  required:
+                  - key
+                  - valueExpression
+                  type: object
+                type: array
+                x-kubernetes-list-type: atomic
               autogen:
                 description: AutogenConfiguration defines the configuration for the
                   generation controller.
@@ -1342,6 +1394,58 @@ spec:
                                 - name
                                 type: object
                               type: array
+                            auditAnnotations:
+                              description: |-
+                                auditAnnotations contains CEL expressions which are used to produce audit
+                                annotations for the audit event of the API request.
+                                validations and auditAnnotations may not both be empty; a least one of validations or auditAnnotations is
+                                required.
+                              items:
+                                description: AuditAnnotation describes how to produce
+                                  an audit annotation for an API request.
+                                properties:
+                                  key:
+                                    description: |-
+                                      key specifies the audit annotation key. The audit annotation keys of
+                                      a ValidatingAdmissionPolicy must be unique. The key must be a qualified
+                                      name ([A-Za-z0-9][-A-Za-z0-9_.]*) no more than 63 bytes in length.
+
+                                      The key is combined with the resource name of the
+                                      ValidatingAdmissionPolicy to construct an audit annotation key:
+                                      "{ValidatingAdmissionPolicy name}/{key}".
+
+                                      If an admission webhook uses the same resource name as this ValidatingAdmissionPolicy
+                                      and the same audit annotation key, the annotation key will be identical.
+                                      In this case, the first annotation written with the key will be included
+                                      in the audit event and all subsequent annotations with the same key
+                                      will be discarded.
+
+                                      Required.
+                                    type: string
+                                  valueExpression:
+                                    description: |-
+                                      valueExpression represents the expression which is evaluated by CEL to
+                                      produce an audit annotation value. The expression must evaluate to either
+                                      a string or null value. If the expression evaluates to a string, the
+                                      audit annotation is included with the string value. If the expression
+                                      evaluates to null or empty string the audit annotation will be omitted.
+                                      The valueExpression may be no longer than 5kb in length.
+                                      If the result of the valueExpression is more than 10kb in length, it
+                                      will be truncated to 10kb.
+
+                                      If multiple ValidatingAdmissionPolicyBinding resources match an
+                                      API request, then the valueExpression will be evaluated for
+                                      each binding. All unique values produced by the valueExpressions
+                                      will be joined together in a comma-separated list.
+
+                                      Required.
+                                    type: string
+                                required:
+                                - key
+                                - valueExpression
+                                type: object
+                              type: array
+                              x-kubernetes-list-type: atomic
                             autogen:
                               description: AutogenConfiguration defines the configuration
                                 for the generation controller.
diff --git a/config/crds/policies.kyverno.io/policies.kyverno.io_imagevalidatingpolicies.yaml b/config/crds/policies.kyverno.io/policies.kyverno.io_imagevalidatingpolicies.yaml
index 313a18d49af4..3c23655fcd79 100644
--- a/config/crds/policies.kyverno.io/policies.kyverno.io_imagevalidatingpolicies.yaml
+++ b/config/crds/policies.kyverno.io/policies.kyverno.io_imagevalidatingpolicies.yaml
@@ -345,6 +345,58 @@ spec:
                   - name
                   type: object
                 type: array
+              auditAnnotations:
+                description: |-
+                  auditAnnotations contains CEL expressions which are used to produce audit
+                  annotations for the audit event of the API request.
+                  validations and auditAnnotations may not both be empty; a least one of validations or auditAnnotations is
+                  required.
+                items:
+                  description: AuditAnnotation describes how to produce an audit annotation
+                    for an API request.
+                  properties:
+                    key:
+                      description: |-
+                        key specifies the audit annotation key. The audit annotation keys of
+                        a ValidatingAdmissionPolicy must be unique. The key must be a qualified
+                        name ([A-Za-z0-9][-A-Za-z0-9_.]*) no more than 63 bytes in length.
+
+                        The key is combined with the resource name of the
+                        ValidatingAdmissionPolicy to construct an audit annotation key:
+                        "{ValidatingAdmissionPolicy name}/{key}".
+
+                        If an admission webhook uses the same resource name as this ValidatingAdmissionPolicy
+                        and the same audit annotation key, the annotation key will be identical.
+                        In this case, the first annotation written with the key will be included
+                        in the audit event and all subsequent annotations with the same key
+                        will be discarded.
+
+                        Required.
+                      type: string
+                    valueExpression:
+                      description: |-
+                        valueExpression represents the expression which is evaluated by CEL to
+                        produce an audit annotation value. The expression must evaluate to either
+                        a string or null value. If the expression evaluates to a string, the
+                        audit annotation is included with the string value. If the expression
+                        evaluates to null or empty string the audit annotation will be omitted.
+                        The valueExpression may be no longer than 5kb in length.
+                        If the result of the valueExpression is more than 10kb in length, it
+                        will be truncated to 10kb.
+
+                        If multiple ValidatingAdmissionPolicyBinding resources match an
+                        API request, then the valueExpression will be evaluated for
+                        each binding. All unique values produced by the valueExpressions
+                        will be joined together in a comma-separated list.
+
+                        Required.
+                      type: string
+                  required:
+                  - key
+                  - valueExpression
+                  type: object
+                type: array
+                x-kubernetes-list-type: atomic
               autogen:
                 description: AutogenConfiguration defines the configuration for the
                   generation controller.
@@ -1342,6 +1394,58 @@ spec:
                                 - name
                                 type: object
                               type: array
+                            auditAnnotations:
+                              description: |-
+                                auditAnnotations contains CEL expressions which are used to produce audit
+                                annotations for the audit event of the API request.
+                                validations and auditAnnotations may not both be empty; a least one of validations or auditAnnotations is
+                                required.
+                              items:
+                                description: AuditAnnotation describes how to produce
+                                  an audit annotation for an API request.
+                                properties:
+                                  key:
+                                    description: |-
+                                      key specifies the audit annotation key. The audit annotation keys of
+                                      a ValidatingAdmissionPolicy must be unique. The key must be a qualified
+                                      name ([A-Za-z0-9][-A-Za-z0-9_.]*) no more than 63 bytes in length.
+
+                                      The key is combined with the resource name of the
+                                      ValidatingAdmissionPolicy to construct an audit annotation key:
+                                      "{ValidatingAdmissionPolicy name}/{key}".
+
+                                      If an admission webhook uses the same resource name as this ValidatingAdmissionPolicy
+                                      and the same audit annotation key, the annotation key will be identical.
+                                      In this case, the first annotation written with the key will be included
+                                      in the audit event and all subsequent annotations with the same key
+                                      will be discarded.
+
+                                      Required.
+                                    type: string
+                                  valueExpression:
+                                    description: |-
+                                      valueExpression represents the expression which is evaluated by CEL to
+                                      produce an audit annotation value. The expression must evaluate to either
+                                      a string or null value. If the expression evaluates to a string, the
+                                      audit annotation is included with the string value. If the expression
+                                      evaluates to null or empty string the audit annotation will be omitted.
+                                      The valueExpression may be no longer than 5kb in length.
+                                      If the result of the valueExpression is more than 10kb in length, it
+                                      will be truncated to 10kb.
+
+                                      If multiple ValidatingAdmissionPolicyBinding resources match an
+                                      API request, then the valueExpression will be evaluated for
+                                      each binding. All unique values produced by the valueExpressions
+                                      will be joined together in a comma-separated list.
+
+                                      Required.
+                                    type: string
+                                required:
+                                - key
+                                - valueExpression
+                                type: object
+                              type: array
+                              x-kubernetes-list-type: atomic
                             autogen:
                               description: AutogenConfiguration defines the configuration
                                 for the generation controller.
diff --git a/config/install-latest-testing.yaml b/config/install-latest-testing.yaml
index eba1535a2ba9..db1a83b17695 100644
--- a/config/install-latest-testing.yaml
+++ b/config/install-latest-testing.yaml
@@ -48833,6 +48833,58 @@ spec:
                   - name
                   type: object
                 type: array
+              auditAnnotations:
+                description: |-
+                  auditAnnotations contains CEL expressions which are used to produce audit
+                  annotations for the audit event of the API request.
+                  validations and auditAnnotations may not both be empty; a least one of validations or auditAnnotations is
+                  required.
+                items:
+                  description: AuditAnnotation describes how to produce an audit annotation
+                    for an API request.
+                  properties:
+                    key:
+                      description: |-
+                        key specifies the audit annotation key. The audit annotation keys of
+                        a ValidatingAdmissionPolicy must be unique. The key must be a qualified
+                        name ([A-Za-z0-9][-A-Za-z0-9_.]*) no more than 63 bytes in length.
+
+                        The key is combined with the resource name of the
+                        ValidatingAdmissionPolicy to construct an audit annotation key:
+                        "{ValidatingAdmissionPolicy name}/{key}".
+
+                        If an admission webhook uses the same resource name as this ValidatingAdmissionPolicy
+                        and the same audit annotation key, the annotation key will be identical.
+                        In this case, the first annotation written with the key will be included
+                        in the audit event and all subsequent annotations with the same key
+                        will be discarded.
+
+                        Required.
+                      type: string
+                    valueExpression:
+                      description: |-
+                        valueExpression represents the expression which is evaluated by CEL to
+                        produce an audit annotation value. The expression must evaluate to either
+                        a string or null value. If the expression evaluates to a string, the
+                        audit annotation is included with the string value. If the expression
+                        evaluates to null or empty string the audit annotation will be omitted.
+                        The valueExpression may be no longer than 5kb in length.
+                        If the result of the valueExpression is more than 10kb in length, it
+                        will be truncated to 10kb.
+
+                        If multiple ValidatingAdmissionPolicyBinding resources match an
+                        API request, then the valueExpression will be evaluated for
+                        each binding. All unique values produced by the valueExpressions
+                        will be joined together in a comma-separated list.
+
+                        Required.
+                      type: string
+                  required:
+                  - key
+                  - valueExpression
+                  type: object
+                type: array
+                x-kubernetes-list-type: atomic
               autogen:
                 description: AutogenConfiguration defines the configuration for the
                   generation controller.
@@ -49830,6 +49882,58 @@ spec:
                                 - name
                                 type: object
                               type: array
+                            auditAnnotations:
+                              description: |-
+                                auditAnnotations contains CEL expressions which are used to produce audit
+                                annotations for the audit event of the API request.
+                                validations and auditAnnotations may not both be empty; a least one of validations or auditAnnotations is
+                                required.
+                              items:
+                                description: AuditAnnotation describes how to produce
+                                  an audit annotation for an API request.
+                                properties:
+                                  key:
+                                    description: |-
+                                      key specifies the audit annotation key. The audit annotation keys of
+                                      a ValidatingAdmissionPolicy must be unique. The key must be a qualified
+                                      name ([A-Za-z0-9][-A-Za-z0-9_.]*) no more than 63 bytes in length.
+
+                                      The key is combined with the resource name of the
+                                      ValidatingAdmissionPolicy to construct an audit annotation key:
+                                      "{ValidatingAdmissionPolicy name}/{key}".
+
+                                      If an admission webhook uses the same resource name as this ValidatingAdmissionPolicy
+                                      and the same audit annotation key, the annotation key will be identical.
+                                      In this case, the first annotation written with the key will be included
+                                      in the audit event and all subsequent annotations with the same key
+                                      will be discarded.
+
+                                      Required.
+                                    type: string
+                                  valueExpression:
+                                    description: |-
+                                      valueExpression represents the expression which is evaluated by CEL to
+                                      produce an audit annotation value. The expression must evaluate to either
+                                      a string or null value. If the expression evaluates to a string, the
+                                      audit annotation is included with the string value. If the expression
+                                      evaluates to null or empty string the audit annotation will be omitted.
+                                      The valueExpression may be no longer than 5kb in length.
+                                      If the result of the valueExpression is more than 10kb in length, it
+                                      will be truncated to 10kb.
+
+                                      If multiple ValidatingAdmissionPolicyBinding resources match an
+                                      API request, then the valueExpression will be evaluated for
+                                      each binding. All unique values produced by the valueExpressions
+                                      will be joined together in a comma-separated list.
+
+                                      Required.
+                                    type: string
+                                required:
+                                - key
+                                - valueExpression
+                                type: object
+                              type: array
+                              x-kubernetes-list-type: atomic
                             autogen:
                               description: AutogenConfiguration defines the configuration
                                 for the generation controller.
diff --git a/docs/user/crd/index.html b/docs/user/crd/index.html
index 53c80b8e5269..3431e27472d8 100644
--- a/docs/user/crd/index.html
+++ b/docs/user/crd/index.html
@@ -10269,6 +10269,23 @@ <h3 id="policies.kyverno.io/v1alpha1.ImageValidatingPolicy">ImageValidatingPolic
 </tr>
 <tr>
 <td>
+<code>auditAnnotations</code><br/>
+<em>
+<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#auditannotation-v1-admissionregistration">
+[]Kubernetes admissionregistration/v1.AuditAnnotation
+</a>
+</em>
+</td>
+<td>
+<em>(Optional)</em>
+<p>auditAnnotations contains CEL expressions which are used to produce audit
+annotations for the audit event of the API request.
+validations and auditAnnotations may not both be empty; a least one of validations or auditAnnotations is
+required.</p>
+</td>
+</tr>
+<tr>
+<td>
 <code>validationActions</code><br/>
 <em>
 <a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#validationaction-v1-admissionregistration">
@@ -11718,6 +11735,23 @@ <h3 id="policies.kyverno.io/v1alpha1.ImageValidatingPolicySpec">ImageValidatingP
 </tr>
 <tr>
 <td>
+<code>auditAnnotations</code><br/>
+<em>
+<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#auditannotation-v1-admissionregistration">
+[]Kubernetes admissionregistration/v1.AuditAnnotation
+</a>
+</em>
+</td>
+<td>
+<em>(Optional)</em>
+<p>auditAnnotations contains CEL expressions which are used to produce audit
+annotations for the audit event of the API request.
+validations and auditAnnotations may not both be empty; a least one of validations or auditAnnotations is
+required.</p>
+</td>
+</tr>
+<tr>
+<td>
 <code>validationActions</code><br/>
 <em>
 <a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#validationaction-v1-admissionregistration">
diff --git a/docs/user/crd/kyverno_cel_policies.v1alpha1.html b/docs/user/crd/kyverno_cel_policies.v1alpha1.html
index 998c7c97c858..f553203e1d81 100644
--- a/docs/user/crd/kyverno_cel_policies.v1alpha1.html
+++ b/docs/user/crd/kyverno_cel_policies.v1alpha1.html
@@ -193,6 +193,36 @@ <H3 id="policies-kyverno-io-v1alpha1-ImageValidatingPolicy">ImageValidatingPolic
   
     
     
+      <tr>
+        <td><code>auditAnnotations</code>
+          
+          </br>
+
+          
+          
+            
+              <span style="font-family: monospace">[]admissionregistration/v1.AuditAnnotation</span>
+            
+          
+        </td>
+        <td>
+          
+
+          <p>auditAnnotations contains CEL expressions which are used to produce audit
+annotations for the audit event of the API request.
+validations and auditAnnotations may not both be empty; a least one of validations or auditAnnotations is
+required.</p>
+
+
+          
+
+          
+        </td>
+      </tr>
+    
+  
+    
+    
       <tr>
         <td><code>validationActions</code>
           
@@ -3087,6 +3117,36 @@ <H3 id="policies-kyverno-io-v1alpha1-ImageValidatingPolicySpec">ImageValidatingP
   
     
     
+      <tr>
+        <td><code>auditAnnotations</code>
+          
+          </br>
+
+          
+          
+            
+              <span style="font-family: monospace">[]admissionregistration/v1.AuditAnnotation</span>
+            
+          
+        </td>
+        <td>
+          
+
+          <p>auditAnnotations contains CEL expressions which are used to produce audit
+annotations for the audit event of the API request.
+validations and auditAnnotations may not both be empty; a least one of validations or auditAnnotations is
+required.</p>
+
+
+          
+
+          
+        </td>
+      </tr>
+    
+  
+    
+    
       <tr>
         <td><code>validationActions</code>
           
diff --git a/pkg/cel/policies/ivpol/engine/engine.go b/pkg/cel/policies/ivpol/engine/engine.go
index c0ec1d683821..c801ab3aa29f 100644
--- a/pkg/cel/policies/ivpol/engine/engine.go
+++ b/pkg/cel/policies/ivpol/engine/engine.go
@@ -244,7 +244,7 @@ func (e *engineImpl) handleMutation(
 					} else if result.Result {
 						response.Result = *engineapi.RulePass(ruleName, engineapi.ImageVerify, "success", nil)
 					} else {
-						response.Result = *engineapi.RuleFail(ruleName, engineapi.ImageVerify, result.Message, nil)
+						response.Result = *engineapi.RuleFail(ruleName, engineapi.ImageVerify, result.Message, result.AuditAnnotations)
 					}
 				}
 			}
diff --git a/pkg/imageverification/evaluator/compiler.go b/pkg/imageverification/evaluator/compiler.go
index 0dafc50a18f8..c619f6c64068 100644
--- a/pkg/imageverification/evaluator/compiler.go
+++ b/pkg/imageverification/evaluator/compiler.go
@@ -130,7 +130,7 @@ func (c *compiler) Compile(ivpolicy *policiesv1alpha1.ImageValidatingPolicy, exc
 		}
 	}
 
-	verifications := make([]engine.Validation, 0, len(ivpolicy.Spec.Validations))
+	validations := make([]engine.Validation, 0, len(ivpolicy.Spec.Validations))
 	{
 		path := path.Child("validations")
 		for i, rule := range ivpolicy.Spec.Validations {
@@ -139,7 +139,20 @@ func (c *compiler) Compile(ivpolicy *policiesv1alpha1.ImageValidatingPolicy, exc
 			if errs != nil {
 				return nil, append(allErrs, errs...)
 			}
-			verifications = append(verifications, program)
+			validations = append(validations, program)
+		}
+	}
+
+	auditAnnotations := make(map[string]cel.Program, len(ivpolicy.Spec.AuditAnnotations))
+	{
+		path := path.Child("auditAnnotations")
+		for i, auditAnnotation := range ivpolicy.Spec.AuditAnnotations {
+			path := path.Index(i)
+			program, errs := engine.CompileAuditAnnotation(path, env, auditAnnotation)
+			if errs != nil {
+				return nil, append(allErrs, errs...)
+			}
+			auditAnnotations[auditAnnotation.Key] = program
 		}
 	}
 
@@ -163,7 +176,8 @@ func (c *compiler) Compile(ivpolicy *policiesv1alpha1.ImageValidatingPolicy, exc
 		failurePolicy:        ivpolicy.GetFailurePolicy(),
 		matchConditions:      matchConditions,
 		matchImageReferences: matchImageReferences,
-		verifications:        verifications,
+		validations:          validations,
+		auditAnnotations:     auditAnnotations,
 		imageExtractors:      imageExtractors,
 		attestors:            compiledAttestors,
 		attestorList:         ivpolvar.GetAttestors(ivpolicy.Spec.Attestors),
diff --git a/pkg/imageverification/evaluator/policy.go b/pkg/imageverification/evaluator/policy.go
index 0375b172e778..62d3dc20171d 100644
--- a/pkg/imageverification/evaluator/policy.go
+++ b/pkg/imageverification/evaluator/policy.go
@@ -29,11 +29,12 @@ import (
 )
 
 type EvaluationResult struct {
-	Error      error
-	Message    string
-	Index      int
-	Result     bool
-	Exceptions []*policiesv1alpha1.PolicyException
+	Error            error
+	Message          string
+	Index            int
+	Result           bool
+	AuditAnnotations map[string]string
+	Exceptions       []*policiesv1alpha1.PolicyException
 }
 
 type CompiledPolicy interface {
@@ -44,11 +45,12 @@ type compiledPolicy struct {
 	failurePolicy        admissionregistrationv1.FailurePolicyType
 	matchConditions      []cel.Program
 	matchImageReferences []*match.CompiledMatch
-	verifications        []engine.Validation
+	validations          []engine.Validation
 	imageExtractors      []*variables.CompiledImageExtractor
 	attestors            []*variables.CompiledAttestor
 	attestorList         map[string]string
 	attestationList      map[string]string
+	auditAnnotations     map[string]cel.Program
 	creds                *v1alpha1.Credentials
 	exceptions           []engine.Exception
 	variables            map[string]cel.Program
@@ -149,7 +151,7 @@ func (c *compiledPolicy) Evaluate(ctx context.Context, ictx imagedataloader.Imag
 	if err := ictx.AddImages(ctx, imgList, imageverify.GetRemoteOptsFromPolicy(c.creds)...); err != nil {
 		return nil, err
 	}
-	for i, v := range c.verifications {
+	for i, v := range c.validations {
 		out, _, err := v.Program.ContextEval(ctx, data)
 		if err != nil {
 			return nil, err
@@ -166,11 +168,25 @@ func (c *compiledPolicy) Evaluate(ctx context.Context, ictx imagedataloader.Imag
 					message = msg
 				}
 			}
+			auditAnnotations := make(map[string]string, 0)
+			for key, annotation := range c.auditAnnotations {
+				out, _, err := annotation.ContextEval(ctx, data)
+				if err != nil {
+					return nil, fmt.Errorf("failed to evaluate auditAnnotation '%s': %w", key, err)
+				}
+				// evaluate only when rule fails
+				if outcome, err := utils.ConvertToNative[string](out); err == nil && outcome != "" {
+					auditAnnotations[key] = outcome
+				} else if err != nil {
+					return nil, fmt.Errorf("failed to convert auditAnnotation '%s' expression: %w", key, err)
+				}
+			}
 			return &EvaluationResult{
-				Result:  outcome,
-				Message: message,
-				Index:   i,
-				Error:   err,
+				Result:           outcome,
+				Message:          message,
+				AuditAnnotations: auditAnnotations,
+				Index:            i,
+				Error:            err,
 			}, nil
 		} else if err != nil {
 			return &EvaluationResult{Error: err}, nil
diff --git a/test/conformance/chainsaw/image-validating-policies/report/admission/policy.yaml b/test/conformance/chainsaw/image-validating-policies/report/admission/policy.yaml
index e0d3a26656a5..8fe87692891d 100644
--- a/test/conformance/chainsaw/image-validating-policies/report/admission/policy.yaml
+++ b/test/conformance/chainsaw/image-validating-policies/report/admission/policy.yaml
@@ -23,6 +23,10 @@ spec:
     - expression: >-
         images.containers.map(image, verifyImageSignatures(image, [attestors.notary])).all(e, e > 0)
       message: failed to verify image with notary cert
+  auditAnnotations:
+    - key: label
+      valueExpression: >-
+        has(object.metadata.labels) && 'env' in object.metadata.labels ? string(object.metadata.labels['env']) : ''
   webhookConfiguration:
     timeoutSeconds: 20
   failurePolicy: Ignore
diff --git a/test/conformance/chainsaw/image-validating-policies/report/admission/report.yaml b/test/conformance/chainsaw/image-validating-policies/report/admission/report.yaml
index 940450416b89..5469585cafdb 100644
--- a/test/conformance/chainsaw/image-validating-policies/report/admission/report.yaml
+++ b/test/conformance/chainsaw/image-validating-policies/report/admission/report.yaml
@@ -17,6 +17,8 @@ results:
   result: fail
   scored: true
   source: KyvernoImageValidatingPolicy
+  properties:
+    label: prod
 summary:
   error: 0
   fail: 1


Reviews:
user: login: MariamFahmy98
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T06:55:15Z
user: login: eddycharly
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-29T07:14:33Z
user: login: eddycharly
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-29T07:38:16Z
user: login: fjogeleit
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-29T07:46:37Z
user: login: eddycharly
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-29T08:07:09Z

Review comments:
diff_hunk: @@ -417,13 +417,13 @@ KUBE_CHART_VERSION          ?= ">=1.25.0-0"
 codegen-api-register: ## Generate API types registrations
 codegen-api-register: $(REGISTER_GEN)
 	@echo Generate registration... >&2
-	@$(REGISTER_GEN) --go-header-file=./scripts/boilerplate.go.txt --output-file zz_generated.register.go ./api/...
+	@$(REGISTER_GEN) --go-header-file=./scripts/boilerplate.go.txt --output-file-base zz_generated.register ./api/...
path: Makefile
user: login: eddycharly
body: --output-file-base doesn't exist in newer version of the tooling.

run `make clean-tools` and `make codegen-all` it should fix your issue
created_at: 2025-04-29T07:14:32Z
author_association: MEMBER
diff_hunk: @@ -1813,6 +1813,10 @@
         {
           "groupVersion": "flowcontrol.apiserver.k8s.io/v1",
           "version": "v1"
+        },
path: cmd/cli/kubectl-kyverno/data/api-group-resources.json
user: login: eddycharly
body: This file shouldn't have changed, I will update the makefile to pop an ephemeral cluster instead of using the underlying one, sorry.
created_at: 2025-04-29T07:38:16Z
author_association: MEMBER
diff_hunk: @@ -1813,6 +1813,10 @@
         {
           "groupVersion": "flowcontrol.apiserver.k8s.io/v1",
           "version": "v1"
+        },
path: cmd/cli/kubectl-kyverno/data/api-group-resources.json
user: login: fjogeleit
body: removed the changes
created_at: 2025-04-29T07:46:37Z
author_association: MEMBER

PR comments:
user: login: codecov[bot]
created_at: 2025-04-29T06:54:40Z
body: ## [Codecov](https://app.codecov.io/gh/kyverno/kyverno/pull/12946?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kyverno) Report
Attention: Patch coverage is `45.45455%` with `18 lines` in your changes missing coverage. Please review.
> Project coverage is 15.21%. Comparing base [(`de62c22`)](https://app.codecov.io/gh/kyverno/kyverno/commit/de62c2239ddacb279c12009c4dffa83e2320256d?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kyverno) to head [(`f662a1b`)](https://app.codecov.io/gh/kyverno/kyverno/commit/f662a1beb10437e193ea8e1ae4927e8a97c04704?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kyverno).
> Report is 4 commits behind head on main.

| [Files with missing lines](https://app.codecov.io/gh/kyverno/kyverno/pull/12946?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kyverno) | Patch % | Lines |
|---|---|---|
| [pkg/imageverification/evaluator/policy.go](https://app.codecov.io/gh/kyverno/kyverno/pull/12946?src=pr&el=tree&filepath=pkg%2Fimageverification%2Fevaluator%2Fpolicy.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kyverno#diff-cGtnL2ltYWdldmVyaWZpY2F0aW9uL2V2YWx1YXRvci9wb2xpY3kuZ28=) | 41.17% | [9 Missing and 1 partial :warning: ](https://app.codecov.io/gh/kyverno/kyverno/pull/12946?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kyverno) |
| [pkg/imageverification/evaluator/compiler.go](https://app.codecov.io/gh/kyverno/kyverno/pull/12946?src=pr&el=tree&filepath=pkg%2Fimageverification%2Fevaluator%2Fcompiler.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kyverno#diff-cGtnL2ltYWdldmVyaWZpY2F0aW9uL2V2YWx1YXRvci9jb21waWxlci5nbw==) | 50.00% | [6 Missing and 1 partial :warning: ](https://app.codecov.io/gh/kyverno/kyverno/pull/12946?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kyverno) |
| [pkg/cel/policies/ivpol/engine/engine.go](https://app.codecov.io/gh/kyverno/kyverno/pull/12946?src=pr&el=tree&filepath=pkg%2Fcel%2Fpolicies%2Fivpol%2Fengine%2Fengine.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kyverno#diff-cGtnL2NlbC9wb2xpY2llcy9pdnBvbC9lbmdpbmUvZW5naW5lLmdv) | 0.00% | [1 Missing :warning: ](https://app.codecov.io/gh/kyverno/kyverno/pull/12946?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kyverno) |

<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff           @@
##             main   #12946   +/-   ##
=======================================
  Coverage   15.21%   15.21%           
=======================================
  Files         922      922           
  Lines      100166   100189   +23     
=======================================
+ Hits        15241    15247    +6     
- Misses      83202    83217   +15     
- Partials     1723     1725    +2     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/kyverno/kyverno/pull/12946?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kyverno).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kyverno).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE
user: login: eddycharly
created_at: 2025-04-29T15:04:06Z
body: /cherry-pick release-1.14
author_association: MEMBER