From 7170cbb0c2d8a5dfacf0131f66243b553eaf5fd9 Mon Sep 17 00:00:00 2001
From: shuting
Date: Sat, 27 Jan 2024 21:00:22 +0800
Subject: [PATCH] feat:Webhook config per policy (#9483)
* add spec.webhookConfigurations
Signed-off-by: ShutingZhao
* update crd
Signed-off-by: ShutingZhao
* configure webhook
Signed-off-by: ShutingZhao
* register webhook handler
Signed-off-by: ShutingZhao
* skip storing finegrained policies in cache
Signed-off-by: ShutingZhao
* update resource validate handler
Signed-off-by: ShutingZhao
* updates
Signed-off-by: ShutingZhao
* enable mutate resource handler for fine-grained policies
Signed-off-by: ShutingZhao
* fix: tests
Signed-off-by: ShutingZhao
---------
Signed-off-by: ShutingZhao
---
api/kyverno/v1/common_types.go | 8 +
api/kyverno/v1/spec_types.go | 18 ++
api/kyverno/v1/zz_generated.deepcopy.go | 27 ++
api/kyverno/v2beta1/common_types.go | 8 +
api/kyverno/v2beta1/spec_types.go | 9 +
api/kyverno/v2beta1/zz_generated.deepcopy.go | 26 ++
.../kyverno/charts/crds/templates/crds.yaml | 184 +++++++++++++
.../data/crds/kyverno.io_clusterpolicies.yaml | 92 +++++++
.../data/crds/kyverno.io_policies.yaml | 92 +++++++
config/crds/kyverno.io_clusterpolicies.yaml | 92 +++++++
config/crds/kyverno.io_policies.yaml | 92 +++++++
config/install-latest-testing.yaml | 184 +++++++++++++
docs/user/crd/index.html | 158 +++++++++++
.../applyconfigurations/kyverno/v1/spec.go | 9 +
.../kyverno/v1/webhookconfiguration.go | 45 ++++
.../kyverno/v2beta1/spec.go | 9 +
.../kyverno/v2beta1/webhookconfiguration.go | 45 ++++
pkg/client/applyconfigurations/utils.go | 4 +
pkg/config/config.go | 2 +
pkg/controllers/policycache/controller.go | 2 +-
pkg/controllers/webhook/controller.go | 245 ++++++++++--------
pkg/controllers/webhook/utils.go | 45 +++-
pkg/controllers/webhook/utils_test.go | 4 +-
pkg/validation/policy/validate.go | 4 +
pkg/webhooks/handlers/admission.go | 4 +
pkg/webhooks/handlers/types.go | 2 +
pkg/webhooks/resource/handlers.go | 85 +++++-
pkg/webhooks/server.go | 2 +
28 files changed, 1371 insertions(+), 126 deletions(-)
create mode 100644 pkg/client/applyconfigurations/kyverno/v1/webhookconfiguration.go
create mode 100644 pkg/client/applyconfigurations/kyverno/v2beta1/webhookconfiguration.go
diff --git a/api/kyverno/v1/common_types.go b/api/kyverno/v1/common_types.go
index d4ec8deaa5..2dfb8bca38 100644
--- a/api/kyverno/v1/common_types.go
+++ b/api/kyverno/v1/common_types.go
@@ -7,6 +7,7 @@ import (
"github.com/kyverno/kyverno/pkg/engine/variables/regex"
"github.com/sigstore/k8s-manifest-sigstore/pkg/k8smanifest"
admissionv1 "k8s.io/api/admission/v1"
+ admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
"k8s.io/api/admissionregistration/v1alpha1"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
@@ -49,6 +50,13 @@ const (
Descending ForeachOrder = "Descending"
)
+// WebhookConfiguration specifies the configuration for Kubernetes admission webhookconfiguration.
+type WebhookConfiguration struct {
+ // MatchCondition configures admission webhook matchConditions.
+ // +optional
+ MatchConditions []admissionregistrationv1.MatchCondition `json:"matchConditions,omitempty" yaml:"matchConditions,omitempty"`
+}
+
// AnyAllConditions consists of conditions wrapped denoting a logical criteria to be fulfilled.
// AnyConditions get fulfilled when at least one of its sub-conditions passes.
// AllConditions get fulfilled only when all of its sub-conditions pass.
diff --git a/api/kyverno/v1/spec_types.go b/api/kyverno/v1/spec_types.go
index 41bbdcf02c..d1d6f75d78 100644
--- a/api/kyverno/v1/spec_types.go
+++ b/api/kyverno/v1/spec_types.go
@@ -5,6 +5,7 @@ import (
"fmt"
"github.com/kyverno/kyverno/pkg/toggle"
+ admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/validation/field"
@@ -121,6 +122,15 @@ type Spec struct {
// Defaults to "false" if not specified.
// +optional
UseServerSideApply bool `json:"useServerSideApply,omitempty" yaml:"useServerSideApply,omitempty"`
+
+ // WebhookConfiguration specifies the custom configuration for Kubernetes admission webhookconfiguration.
+ // Requires Kubernetes 1.27 or later.
+ // +optional
+ WebhookConfiguration *WebhookConfiguration `json:"webhookConfiguration,omitempty" yaml:"webhookConfiguration,omitempty"`
+}
+
+func (s *Spec) CustomWebhookConfiguration() bool {
+ return s.WebhookConfiguration != nil
}
func (s *Spec) SetRules(rules []Rule) {
@@ -257,6 +267,14 @@ func (s *Spec) GetFailurePolicy(ctx context.Context) FailurePolicyType {
return *s.FailurePolicy
}
+// GetMatchConditions returns matchConditions in webhookConfiguration
+func (s *Spec) GetMatchConditions() []admissionregistrationv1.MatchCondition {
+ if s.WebhookConfiguration != nil {
+ return s.WebhookConfiguration.MatchConditions
+ }
+ return nil
+}
+
// GetFailurePolicy returns the failure policy to be applied
func (s *Spec) GetApplyRules() ApplyRulesType {
if s.ApplyRules == nil {
diff --git a/api/kyverno/v1/zz_generated.deepcopy.go b/api/kyverno/v1/zz_generated.deepcopy.go
index 90f8f017c6..0fee540f54 100755
--- a/api/kyverno/v1/zz_generated.deepcopy.go
+++ b/api/kyverno/v1/zz_generated.deepcopy.go
@@ -23,6 +23,7 @@ package v1
import (
k8smanifest "github.com/sigstore/k8s-manifest-sigstore/pkg/k8smanifest"
+ admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
v1alpha1 "k8s.io/api/admissionregistration/v1alpha1"
rbacv1 "k8s.io/api/rbac/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
@@ -1408,6 +1409,11 @@ func (in *Spec) DeepCopyInto(out *Spec) {
*out = new(bool)
**out = **in
}
+ if in.WebhookConfiguration != nil {
+ in, out := &in.WebhookConfiguration, &out.WebhookConfiguration
+ *out = new(WebhookConfiguration)
+ (*in).DeepCopyInto(*out)
+ }
return
}
@@ -1632,3 +1638,24 @@ func (in *Variable) DeepCopy() *Variable {
in.DeepCopyInto(out)
return out
}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *WebhookConfiguration) DeepCopyInto(out *WebhookConfiguration) {
+ *out = *in
+ if in.MatchConditions != nil {
+ in, out := &in.MatchConditions, &out.MatchConditions
+ *out = make([]admissionregistrationv1.MatchCondition, len(*in))
+ copy(*out, *in)
+ }
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WebhookConfiguration.
+func (in *WebhookConfiguration) DeepCopy() *WebhookConfiguration {
+ if in == nil {
+ return nil
+ }
+ out := new(WebhookConfiguration)
+ in.DeepCopyInto(out)
+ return out
+}
diff --git a/api/kyverno/v2beta1/common_types.go b/api/kyverno/v2beta1/common_types.go
index 4dc822afd8..d3ae3b5037 100644
--- a/api/kyverno/v2beta1/common_types.go
+++ b/api/kyverno/v2beta1/common_types.go
@@ -2,10 +2,18 @@ package v2beta1
import (
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
+ admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
)
+// WebhookConfiguration specifies the configuration for Kubernetes admission webhookconfiguration.
+type WebhookConfiguration struct {
+ // MatchCondition configures admission webhook matchConditions.
+ // +optional
+ MatchConditions []admissionregistrationv1.MatchCondition `json:"matchConditions,omitempty" yaml:"matchConditions,omitempty"`
+}
+
// Validation defines checks to be performed on matching resources.
type Validation struct {
// Message specifies a custom message to be displayed on failure.
diff --git a/api/kyverno/v2beta1/spec_types.go b/api/kyverno/v2beta1/spec_types.go
index 9b4772a419..05854b02e7 100644
--- a/api/kyverno/v2beta1/spec_types.go
+++ b/api/kyverno/v2beta1/spec_types.go
@@ -82,6 +82,15 @@ type Spec struct {
// Defaults to "false" if not specified.
// +optional
UseServerSideApply bool `json:"useServerSideApply,omitempty" yaml:"useServerSideApply,omitempty"`
+
+ // WebhookConfiguration specifies the custom configuration for Kubernetes admission webhookconfiguration.
+ // Requires Kubernetes 1.27 or later.
+ // +optional
+ WebhookConfiguration *WebhookConfiguration `json:"webhookConfiguration,omitempty" yaml:"webhookConfiguration,omitempty"`
+}
+
+func (s *Spec) CustomWebhookConfiguration() bool {
+ return s.WebhookConfiguration != nil
}
func (s *Spec) SetRules(rules []Rule) {
diff --git a/api/kyverno/v2beta1/zz_generated.deepcopy.go b/api/kyverno/v2beta1/zz_generated.deepcopy.go
index 1c0ca94bc8..f1ae0b0da5 100755
--- a/api/kyverno/v2beta1/zz_generated.deepcopy.go
+++ b/api/kyverno/v2beta1/zz_generated.deepcopy.go
@@ -810,6 +810,11 @@ func (in *Spec) DeepCopyInto(out *Spec) {
*out = new(bool)
**out = **in
}
+ if in.WebhookConfiguration != nil {
+ in, out := &in.WebhookConfiguration, &out.WebhookConfiguration
+ *out = new(WebhookConfiguration)
+ (*in).DeepCopyInto(*out)
+ }
return
}
@@ -875,3 +880,24 @@ func (in *Validation) DeepCopy() *Validation {
in.DeepCopyInto(out)
return out
}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *WebhookConfiguration) DeepCopyInto(out *WebhookConfiguration) {
+ *out = *in
+ if in.MatchConditions != nil {
+ in, out := &in.MatchConditions, &out.MatchConditions
+ *out = make([]admissionregistrationv1.MatchCondition, len(*in))
+ copy(*out, *in)
+ }
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WebhookConfiguration.
+func (in *WebhookConfiguration) DeepCopy() *WebhookConfiguration {
+ if in == nil {
+ return nil
+ }
+ out := new(WebhookConfiguration)
+ in.DeepCopyInto(out)
+ return out
+}
diff --git a/charts/kyverno/charts/crds/templates/crds.yaml b/charts/kyverno/charts/crds/templates/crds.yaml
index 66946c7aa8..abece2432b 100644
--- a/charts/kyverno/charts/crds/templates/crds.yaml
+++ b/charts/kyverno/charts/crds/templates/crds.yaml
@@ -14420,6 +14420,52 @@ spec:
type: array
type: object
type: array
+ webhookConfiguration:
+ description: WebhookConfiguration specifies the custom configuration
+ for Kubernetes admission webhookconfiguration. Requires Kubernetes
+ 1.27 or later.
+ properties:
+ matchConditions:
+ description: MatchCondition configures admission webhook matchConditions.
+ items:
+ description: MatchCondition represents a condition which must
+ by fulfilled for a request to be sent to a webhook.
+ properties:
+ expression:
+ description: "Expression represents the expression which
+ will be evaluated by CEL. Must evaluate to bool. CEL expressions
+ have access to the contents of the AdmissionRequest and
+ Authorizer, organized into CEL variables: \n 'object'
+ - The object from the incoming request. The value is null
+ for DELETE requests. 'oldObject' - The existing object.
+ The value is null for CREATE requests. 'request' - Attributes
+ of the admission request(/pkg/apis/admission/types.go#AdmissionRequest).
+ 'authorizer' - A CEL Authorizer. May be used to perform
+ authorization checks for the principal (user or service
+ account) of the request. See https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz
+ 'authorizer.requestResource' - A CEL ResourceCheck constructed
+ from the 'authorizer' and configured with the request
+ resource. Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
+ \n Required."
+ type: string
+ name:
+ description: "Name is an identifier for this match condition,
+ used for strategic merging of MatchConditions, as well
+ as providing an identifier for logging purposes. A good
+ name should be descriptive of the associated expression.
+ Name must be a qualified name consisting of alphanumeric
+ characters, '-', '_' or '.', and must start and end with
+ an alphanumeric character (e.g. 'MyName', or 'my.name',
+ \ or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')
+ with an optional DNS subdomain prefix and '/' (e.g. 'example.com/MyName')
+ \n Required."
+ type: string
+ required:
+ - expression
+ - name
+ type: object
+ type: array
+ type: object
webhookTimeoutSeconds:
description: WebhookTimeoutSeconds specifies the maximum time in seconds
allowed to apply this policy. After the configured time expires,
@@ -23196,6 +23242,52 @@ spec:
type: array
type: object
type: array
+ webhookConfiguration:
+ description: WebhookConfiguration specifies the custom configuration
+ for Kubernetes admission webhookconfiguration. Requires Kubernetes
+ 1.27 or later.
+ properties:
+ matchConditions:
+ description: MatchCondition configures admission webhook matchConditions.
+ items:
+ description: MatchCondition represents a condition which must
+ by fulfilled for a request to be sent to a webhook.
+ properties:
+ expression:
+ description: "Expression represents the expression which
+ will be evaluated by CEL. Must evaluate to bool. CEL expressions
+ have access to the contents of the AdmissionRequest and
+ Authorizer, organized into CEL variables: \n 'object'
+ - The object from the incoming request. The value is null
+ for DELETE requests. 'oldObject' - The existing object.
+ The value is null for CREATE requests. 'request' - Attributes
+ of the admission request(/pkg/apis/admission/types.go#AdmissionRequest).
+ 'authorizer' - A CEL Authorizer. May be used to perform
+ authorization checks for the principal (user or service
+ account) of the request. See https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz
+ 'authorizer.requestResource' - A CEL ResourceCheck constructed
+ from the 'authorizer' and configured with the request
+ resource. Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
+ \n Required."
+ type: string
+ name:
+ description: "Name is an identifier for this match condition,
+ used for strategic merging of MatchConditions, as well
+ as providing an identifier for logging purposes. A good
+ name should be descriptive of the associated expression.
+ Name must be a qualified name consisting of alphanumeric
+ characters, '-', '_' or '.', and must start and end with
+ an alphanumeric character (e.g. 'MyName', or 'my.name',
+ \ or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')
+ with an optional DNS subdomain prefix and '/' (e.g. 'example.com/MyName')
+ \n Required."
+ type: string
+ required:
+ - expression
+ - name
+ type: object
+ type: array
+ type: object
webhookTimeoutSeconds:
description: WebhookTimeoutSeconds specifies the maximum time in seconds
allowed to apply this policy. After the configured time expires,
@@ -32272,6 +32364,52 @@ spec:
type: array
type: object
type: array
+ webhookConfiguration:
+ description: WebhookConfiguration specifies the custom configuration
+ for Kubernetes admission webhookconfiguration. Requires Kubernetes
+ 1.27 or later.
+ properties:
+ matchConditions:
+ description: MatchCondition configures admission webhook matchConditions.
+ items:
+ description: MatchCondition represents a condition which must
+ by fulfilled for a request to be sent to a webhook.
+ properties:
+ expression:
+ description: "Expression represents the expression which
+ will be evaluated by CEL. Must evaluate to bool. CEL expressions
+ have access to the contents of the AdmissionRequest and
+ Authorizer, organized into CEL variables: \n 'object'
+ - The object from the incoming request. The value is null
+ for DELETE requests. 'oldObject' - The existing object.
+ The value is null for CREATE requests. 'request' - Attributes
+ of the admission request(/pkg/apis/admission/types.go#AdmissionRequest).
+ 'authorizer' - A CEL Authorizer. May be used to perform
+ authorization checks for the principal (user or service
+ account) of the request. See https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz
+ 'authorizer.requestResource' - A CEL ResourceCheck constructed
+ from the 'authorizer' and configured with the request
+ resource. Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
+ \n Required."
+ type: string
+ name:
+ description: "Name is an identifier for this match condition,
+ used for strategic merging of MatchConditions, as well
+ as providing an identifier for logging purposes. A good
+ name should be descriptive of the associated expression.
+ Name must be a qualified name consisting of alphanumeric
+ characters, '-', '_' or '.', and must start and end with
+ an alphanumeric character (e.g. 'MyName', or 'my.name',
+ \ or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')
+ with an optional DNS subdomain prefix and '/' (e.g. 'example.com/MyName')
+ \n Required."
+ type: string
+ required:
+ - expression
+ - name
+ type: object
+ type: array
+ type: object
webhookTimeoutSeconds:
description: WebhookTimeoutSeconds specifies the maximum time in seconds
allowed to apply this policy. After the configured time expires,
@@ -41050,6 +41188,52 @@ spec:
type: array
type: object
type: array
+ webhookConfiguration:
+ description: WebhookConfiguration specifies the custom configuration
+ for Kubernetes admission webhookconfiguration. Requires Kubernetes
+ 1.27 or later.
+ properties:
+ matchConditions:
+ description: MatchCondition configures admission webhook matchConditions.
+ items:
+ description: MatchCondition represents a condition which must
+ by fulfilled for a request to be sent to a webhook.
+ properties:
+ expression:
+ description: "Expression represents the expression which
+ will be evaluated by CEL. Must evaluate to bool. CEL expressions
+ have access to the contents of the AdmissionRequest and
+ Authorizer, organized into CEL variables: \n 'object'
+ - The object from the incoming request. The value is null
+ for DELETE requests. 'oldObject' - The existing object.
+ The value is null for CREATE requests. 'request' - Attributes
+ of the admission request(/pkg/apis/admission/types.go#AdmissionRequest).
+ 'authorizer' - A CEL Authorizer. May be used to perform
+ authorization checks for the principal (user or service
+ account) of the request. See https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz
+ 'authorizer.requestResource' - A CEL ResourceCheck constructed
+ from the 'authorizer' and configured with the request
+ resource. Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
+ \n Required."
+ type: string
+ name:
+ description: "Name is an identifier for this match condition,
+ used for strategic merging of MatchConditions, as well
+ as providing an identifier for logging purposes. A good
+ name should be descriptive of the associated expression.
+ Name must be a qualified name consisting of alphanumeric
+ characters, '-', '_' or '.', and must start and end with
+ an alphanumeric character (e.g. 'MyName', or 'my.name',
+ \ or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')
+ with an optional DNS subdomain prefix and '/' (e.g. 'example.com/MyName')
+ \n Required."
+ type: string
+ required:
+ - expression
+ - name
+ type: object
+ type: array
+ type: object
webhookTimeoutSeconds:
description: WebhookTimeoutSeconds specifies the maximum time in seconds
allowed to apply this policy. After the configured time expires,
diff --git a/cmd/cli/kubectl-kyverno/data/crds/kyverno.io_clusterpolicies.yaml b/cmd/cli/kubectl-kyverno/data/crds/kyverno.io_clusterpolicies.yaml
index e001acdffd..ccda23a704 100644
--- a/cmd/cli/kubectl-kyverno/data/crds/kyverno.io_clusterpolicies.yaml
+++ b/cmd/cli/kubectl-kyverno/data/crds/kyverno.io_clusterpolicies.yaml
@@ -4469,6 +4469,52 @@ spec:
type: array
type: object
type: array
+ webhookConfiguration:
+ description: WebhookConfiguration specifies the custom configuration
+ for Kubernetes admission webhookconfiguration. Requires Kubernetes
+ 1.27 or later.
+ properties:
+ matchConditions:
+ description: MatchCondition configures admission webhook matchConditions.
+ items:
+ description: MatchCondition represents a condition which must
+ by fulfilled for a request to be sent to a webhook.
+ properties:
+ expression:
+ description: "Expression represents the expression which
+ will be evaluated by CEL. Must evaluate to bool. CEL expressions
+ have access to the contents of the AdmissionRequest and
+ Authorizer, organized into CEL variables: \n 'object'
+ - The object from the incoming request. The value is null
+ for DELETE requests. 'oldObject' - The existing object.
+ The value is null for CREATE requests. 'request' - Attributes
+ of the admission request(/pkg/apis/admission/types.go#AdmissionRequest).
+ 'authorizer' - A CEL Authorizer. May be used to perform
+ authorization checks for the principal (user or service
+ account) of the request. See https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz
+ 'authorizer.requestResource' - A CEL ResourceCheck constructed
+ from the 'authorizer' and configured with the request
+ resource. Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
+ \n Required."
+ type: string
+ name:
+ description: "Name is an identifier for this match condition,
+ used for strategic merging of MatchConditions, as well
+ as providing an identifier for logging purposes. A good
+ name should be descriptive of the associated expression.
+ Name must be a qualified name consisting of alphanumeric
+ characters, '-', '_' or '.', and must start and end with
+ an alphanumeric character (e.g. 'MyName', or 'my.name',
+ \ or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')
+ with an optional DNS subdomain prefix and '/' (e.g. 'example.com/MyName')
+ \n Required."
+ type: string
+ required:
+ - expression
+ - name
+ type: object
+ type: array
+ type: object
webhookTimeoutSeconds:
description: WebhookTimeoutSeconds specifies the maximum time in seconds
allowed to apply this policy. After the configured time expires,
@@ -13245,6 +13291,52 @@ spec:
type: array
type: object
type: array
+ webhookConfiguration:
+ description: WebhookConfiguration specifies the custom configuration
+ for Kubernetes admission webhookconfiguration. Requires Kubernetes
+ 1.27 or later.
+ properties:
+ matchConditions:
+ description: MatchCondition configures admission webhook matchConditions.
+ items:
+ description: MatchCondition represents a condition which must
+ by fulfilled for a request to be sent to a webhook.
+ properties:
+ expression:
+ description: "Expression represents the expression which
+ will be evaluated by CEL. Must evaluate to bool. CEL expressions
+ have access to the contents of the AdmissionRequest and
+ Authorizer, organized into CEL variables: \n 'object'
+ - The object from the incoming request. The value is null
+ for DELETE requests. 'oldObject' - The existing object.
+ The value is null for CREATE requests. 'request' - Attributes
+ of the admission request(/pkg/apis/admission/types.go#AdmissionRequest).
+ 'authorizer' - A CEL Authorizer. May be used to perform
+ authorization checks for the principal (user or service
+ account) of the request. See https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz
+ 'authorizer.requestResource' - A CEL ResourceCheck constructed
+ from the 'authorizer' and configured with the request
+ resource. Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
+ \n Required."
+ type: string
+ name:
+ description: "Name is an identifier for this match condition,
+ used for strategic merging of MatchConditions, as well
+ as providing an identifier for logging purposes. A good
+ name should be descriptive of the associated expression.
+ Name must be a qualified name consisting of alphanumeric
+ characters, '-', '_' or '.', and must start and end with
+ an alphanumeric character (e.g. 'MyName', or 'my.name',
+ \ or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')
+ with an optional DNS subdomain prefix and '/' (e.g. 'example.com/MyName')
+ \n Required."
+ type: string
+ required:
+ - expression
+ - name
+ type: object
+ type: array
+ type: object
webhookTimeoutSeconds:
description: WebhookTimeoutSeconds specifies the maximum time in seconds
allowed to apply this policy. After the configured time expires,
diff --git a/cmd/cli/kubectl-kyverno/data/crds/kyverno.io_policies.yaml b/cmd/cli/kubectl-kyverno/data/crds/kyverno.io_policies.yaml
index 47f889a79e..7e7b7527a2 100644
--- a/cmd/cli/kubectl-kyverno/data/crds/kyverno.io_policies.yaml
+++ b/cmd/cli/kubectl-kyverno/data/crds/kyverno.io_policies.yaml
@@ -4470,6 +4470,52 @@ spec:
type: array
type: object
type: array
+ webhookConfiguration:
+ description: WebhookConfiguration specifies the custom configuration
+ for Kubernetes admission webhookconfiguration. Requires Kubernetes
+ 1.27 or later.
+ properties:
+ matchConditions:
+ description: MatchCondition configures admission webhook matchConditions.
+ items:
+ description: MatchCondition represents a condition which must
+ by fulfilled for a request to be sent to a webhook.
+ properties:
+ expression:
+ description: "Expression represents the expression which
+ will be evaluated by CEL. Must evaluate to bool. CEL expressions
+ have access to the contents of the AdmissionRequest and
+ Authorizer, organized into CEL variables: \n 'object'
+ - The object from the incoming request. The value is null
+ for DELETE requests. 'oldObject' - The existing object.
+ The value is null for CREATE requests. 'request' - Attributes
+ of the admission request(/pkg/apis/admission/types.go#AdmissionRequest).
+ 'authorizer' - A CEL Authorizer. May be used to perform
+ authorization checks for the principal (user or service
+ account) of the request. See https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz
+ 'authorizer.requestResource' - A CEL ResourceCheck constructed
+ from the 'authorizer' and configured with the request
+ resource. Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
+ \n Required."
+ type: string
+ name:
+ description: "Name is an identifier for this match condition,
+ used for strategic merging of MatchConditions, as well
+ as providing an identifier for logging purposes. A good
+ name should be descriptive of the associated expression.
+ Name must be a qualified name consisting of alphanumeric
+ characters, '-', '_' or '.', and must start and end with
+ an alphanumeric character (e.g. 'MyName', or 'my.name',
+ \ or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')
+ with an optional DNS subdomain prefix and '/' (e.g. 'example.com/MyName')
+ \n Required."
+ type: string
+ required:
+ - expression
+ - name
+ type: object
+ type: array
+ type: object
webhookTimeoutSeconds:
description: WebhookTimeoutSeconds specifies the maximum time in seconds
allowed to apply this policy. After the configured time expires,
@@ -13248,6 +13294,52 @@ spec:
type: array
type: object
type: array
+ webhookConfiguration:
+ description: WebhookConfiguration specifies the custom configuration
+ for Kubernetes admission webhookconfiguration. Requires Kubernetes
+ 1.27 or later.
+ properties:
+ matchConditions:
+ description: MatchCondition configures admission webhook matchConditions.
+ items:
+ description: MatchCondition represents a condition which must
+ by fulfilled for a request to be sent to a webhook.
+ properties:
+ expression:
+ description: "Expression represents the expression which
+ will be evaluated by CEL. Must evaluate to bool. CEL expressions
+ have access to the contents of the AdmissionRequest and
+ Authorizer, organized into CEL variables: \n 'object'
+ - The object from the incoming request. The value is null
+ for DELETE requests. 'oldObject' - The existing object.
+ The value is null for CREATE requests. 'request' - Attributes
+ of the admission request(/pkg/apis/admission/types.go#AdmissionRequest).
+ 'authorizer' - A CEL Authorizer. May be used to perform
+ authorization checks for the principal (user or service
+ account) of the request. See https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz
+ 'authorizer.requestResource' - A CEL ResourceCheck constructed
+ from the 'authorizer' and configured with the request
+ resource. Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
+ \n Required."
+ type: string
+ name:
+ description: "Name is an identifier for this match condition,
+ used for strategic merging of MatchConditions, as well
+ as providing an identifier for logging purposes. A good
+ name should be descriptive of the associated expression.
+ Name must be a qualified name consisting of alphanumeric
+ characters, '-', '_' or '.', and must start and end with
+ an alphanumeric character (e.g. 'MyName', or 'my.name',
+ \ or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')
+ with an optional DNS subdomain prefix and '/' (e.g. 'example.com/MyName')
+ \n Required."
+ type: string
+ required:
+ - expression
+ - name
+ type: object
+ type: array
+ type: object
webhookTimeoutSeconds:
description: WebhookTimeoutSeconds specifies the maximum time in seconds
allowed to apply this policy. After the configured time expires,
diff --git a/config/crds/kyverno.io_clusterpolicies.yaml b/config/crds/kyverno.io_clusterpolicies.yaml
index e001acdffd..ccda23a704 100644
--- a/config/crds/kyverno.io_clusterpolicies.yaml
+++ b/config/crds/kyverno.io_clusterpolicies.yaml
@@ -4469,6 +4469,52 @@ spec:
type: array
type: object
type: array
+ webhookConfiguration:
+ description: WebhookConfiguration specifies the custom configuration
+ for Kubernetes admission webhookconfiguration. Requires Kubernetes
+ 1.27 or later.
+ properties:
+ matchConditions:
+ description: MatchCondition configures admission webhook matchConditions.
+ items:
+ description: MatchCondition represents a condition which must
+ by fulfilled for a request to be sent to a webhook.
+ properties:
+ expression:
+ description: "Expression represents the expression which
+ will be evaluated by CEL. Must evaluate to bool. CEL expressions
+ have access to the contents of the AdmissionRequest and
+ Authorizer, organized into CEL variables: \n 'object'
+ - The object from the incoming request. The value is null
+ for DELETE requests. 'oldObject' - The existing object.
+ The value is null for CREATE requests. 'request' - Attributes
+ of the admission request(/pkg/apis/admission/types.go#AdmissionRequest).
+ 'authorizer' - A CEL Authorizer. May be used to perform
+ authorization checks for the principal (user or service
+ account) of the request. See https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz
+ 'authorizer.requestResource' - A CEL ResourceCheck constructed
+ from the 'authorizer' and configured with the request
+ resource. Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
+ \n Required."
+ type: string
+ name:
+ description: "Name is an identifier for this match condition,
+ used for strategic merging of MatchConditions, as well
+ as providing an identifier for logging purposes. A good
+ name should be descriptive of the associated expression.
+ Name must be a qualified name consisting of alphanumeric
+ characters, '-', '_' or '.', and must start and end with
+ an alphanumeric character (e.g. 'MyName', or 'my.name',
+ \ or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')
+ with an optional DNS subdomain prefix and '/' (e.g. 'example.com/MyName')
+ \n Required."
+ type: string
+ required:
+ - expression
+ - name
+ type: object
+ type: array
+ type: object
webhookTimeoutSeconds:
description: WebhookTimeoutSeconds specifies the maximum time in seconds
allowed to apply this policy. After the configured time expires,
@@ -13245,6 +13291,52 @@ spec:
type: array
type: object
type: array
+ webhookConfiguration:
+ description: WebhookConfiguration specifies the custom configuration
+ for Kubernetes admission webhookconfiguration. Requires Kubernetes
+ 1.27 or later.
+ properties:
+ matchConditions:
+ description: MatchCondition configures admission webhook matchConditions.
+ items:
+ description: MatchCondition represents a condition which must
+ by fulfilled for a request to be sent to a webhook.
+ properties:
+ expression:
+ description: "Expression represents the expression which
+ will be evaluated by CEL. Must evaluate to bool. CEL expressions
+ have access to the contents of the AdmissionRequest and
+ Authorizer, organized into CEL variables: \n 'object'
+ - The object from the incoming request. The value is null
+ for DELETE requests. 'oldObject' - The existing object.
+ The value is null for CREATE requests. 'request' - Attributes
+ of the admission request(/pkg/apis/admission/types.go#AdmissionRequest).
+ 'authorizer' - A CEL Authorizer. May be used to perform
+ authorization checks for the principal (user or service
+ account) of the request. See https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz
+ 'authorizer.requestResource' - A CEL ResourceCheck constructed
+ from the 'authorizer' and configured with the request
+ resource. Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
+ \n Required."
+ type: string
+ name:
+ description: "Name is an identifier for this match condition,
+ used for strategic merging of MatchConditions, as well
+ as providing an identifier for logging purposes. A good
+ name should be descriptive of the associated expression.
+ Name must be a qualified name consisting of alphanumeric
+ characters, '-', '_' or '.', and must start and end with
+ an alphanumeric character (e.g. 'MyName', or 'my.name',
+ \ or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')
+ with an optional DNS subdomain prefix and '/' (e.g. 'example.com/MyName')
+ \n Required."
+ type: string
+ required:
+ - expression
+ - name
+ type: object
+ type: array
+ type: object
webhookTimeoutSeconds:
description: WebhookTimeoutSeconds specifies the maximum time in seconds
allowed to apply this policy. After the configured time expires,
diff --git a/config/crds/kyverno.io_policies.yaml b/config/crds/kyverno.io_policies.yaml
index 47f889a79e..7e7b7527a2 100644
--- a/config/crds/kyverno.io_policies.yaml
+++ b/config/crds/kyverno.io_policies.yaml
@@ -4470,6 +4470,52 @@ spec:
type: array
type: object
type: array
+ webhookConfiguration:
+ description: WebhookConfiguration specifies the custom configuration
+ for Kubernetes admission webhookconfiguration. Requires Kubernetes
+ 1.27 or later.
+ properties:
+ matchConditions:
+ description: MatchCondition configures admission webhook matchConditions.
+ items:
+ description: MatchCondition represents a condition which must
+ by fulfilled for a request to be sent to a webhook.
+ properties:
+ expression:
+ description: "Expression represents the expression which
+ will be evaluated by CEL. Must evaluate to bool. CEL expressions
+ have access to the contents of the AdmissionRequest and
+ Authorizer, organized into CEL variables: \n 'object'
+ - The object from the incoming request. The value is null
+ for DELETE requests. 'oldObject' - The existing object.
+ The value is null for CREATE requests. 'request' - Attributes
+ of the admission request(/pkg/apis/admission/types.go#AdmissionRequest).
+ 'authorizer' - A CEL Authorizer. May be used to perform
+ authorization checks for the principal (user or service
+ account) of the request. See https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz
+ 'authorizer.requestResource' - A CEL ResourceCheck constructed
+ from the 'authorizer' and configured with the request
+ resource. Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
+ \n Required."
+ type: string
+ name:
+ description: "Name is an identifier for this match condition,
+ used for strategic merging of MatchConditions, as well
+ as providing an identifier for logging purposes. A good
+ name should be descriptive of the associated expression.
+ Name must be a qualified name consisting of alphanumeric
+ characters, '-', '_' or '.', and must start and end with
+ an alphanumeric character (e.g. 'MyName', or 'my.name',
+ \ or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')
+ with an optional DNS subdomain prefix and '/' (e.g. 'example.com/MyName')
+ \n Required."
+ type: string
+ required:
+ - expression
+ - name
+ type: object
+ type: array
+ type: object
webhookTimeoutSeconds:
description: WebhookTimeoutSeconds specifies the maximum time in seconds
allowed to apply this policy. After the configured time expires,
@@ -13248,6 +13294,52 @@ spec:
type: array
type: object
type: array
+ webhookConfiguration:
+ description: WebhookConfiguration specifies the custom configuration
+ for Kubernetes admission webhookconfiguration. Requires Kubernetes
+ 1.27 or later.
+ properties:
+ matchConditions:
+ description: MatchCondition configures admission webhook matchConditions.
+ items:
+ description: MatchCondition represents a condition which must
+ by fulfilled for a request to be sent to a webhook.
+ properties:
+ expression:
+ description: "Expression represents the expression which
+ will be evaluated by CEL. Must evaluate to bool. CEL expressions
+ have access to the contents of the AdmissionRequest and
+ Authorizer, organized into CEL variables: \n 'object'
+ - The object from the incoming request. The value is null
+ for DELETE requests. 'oldObject' - The existing object.
+ The value is null for CREATE requests. 'request' - Attributes
+ of the admission request(/pkg/apis/admission/types.go#AdmissionRequest).
+ 'authorizer' - A CEL Authorizer. May be used to perform
+ authorization checks for the principal (user or service
+ account) of the request. See https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz
+ 'authorizer.requestResource' - A CEL ResourceCheck constructed
+ from the 'authorizer' and configured with the request
+ resource. Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
+ \n Required."
+ type: string
+ name:
+ description: "Name is an identifier for this match condition,
+ used for strategic merging of MatchConditions, as well
+ as providing an identifier for logging purposes. A good
+ name should be descriptive of the associated expression.
+ Name must be a qualified name consisting of alphanumeric
+ characters, '-', '_' or '.', and must start and end with
+ an alphanumeric character (e.g. 'MyName', or 'my.name',
+ \ or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')
+ with an optional DNS subdomain prefix and '/' (e.g. 'example.com/MyName')
+ \n Required."
+ type: string
+ required:
+ - expression
+ - name
+ type: object
+ type: array
+ type: object
webhookTimeoutSeconds:
description: WebhookTimeoutSeconds specifies the maximum time in seconds
allowed to apply this policy. After the configured time expires,
diff --git a/config/install-latest-testing.yaml b/config/install-latest-testing.yaml
index e4e799170b..77a3b18b0a 100644
--- a/config/install-latest-testing.yaml
+++ b/config/install-latest-testing.yaml
@@ -14639,6 +14639,52 @@ spec:
type: array
type: object
type: array
+ webhookConfiguration:
+ description: WebhookConfiguration specifies the custom configuration
+ for Kubernetes admission webhookconfiguration. Requires Kubernetes
+ 1.27 or later.
+ properties:
+ matchConditions:
+ description: MatchCondition configures admission webhook matchConditions.
+ items:
+ description: MatchCondition represents a condition which must
+ by fulfilled for a request to be sent to a webhook.
+ properties:
+ expression:
+ description: "Expression represents the expression which
+ will be evaluated by CEL. Must evaluate to bool. CEL expressions
+ have access to the contents of the AdmissionRequest and
+ Authorizer, organized into CEL variables: \n 'object'
+ - The object from the incoming request. The value is null
+ for DELETE requests. 'oldObject' - The existing object.
+ The value is null for CREATE requests. 'request' - Attributes
+ of the admission request(/pkg/apis/admission/types.go#AdmissionRequest).
+ 'authorizer' - A CEL Authorizer. May be used to perform
+ authorization checks for the principal (user or service
+ account) of the request. See https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz
+ 'authorizer.requestResource' - A CEL ResourceCheck constructed
+ from the 'authorizer' and configured with the request
+ resource. Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
+ \n Required."
+ type: string
+ name:
+ description: "Name is an identifier for this match condition,
+ used for strategic merging of MatchConditions, as well
+ as providing an identifier for logging purposes. A good
+ name should be descriptive of the associated expression.
+ Name must be a qualified name consisting of alphanumeric
+ characters, '-', '_' or '.', and must start and end with
+ an alphanumeric character (e.g. 'MyName', or 'my.name',
+ \ or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')
+ with an optional DNS subdomain prefix and '/' (e.g. 'example.com/MyName')
+ \n Required."
+ type: string
+ required:
+ - expression
+ - name
+ type: object
+ type: array
+ type: object
webhookTimeoutSeconds:
description: WebhookTimeoutSeconds specifies the maximum time in seconds
allowed to apply this policy. After the configured time expires,
@@ -23415,6 +23461,52 @@ spec:
type: array
type: object
type: array
+ webhookConfiguration:
+ description: WebhookConfiguration specifies the custom configuration
+ for Kubernetes admission webhookconfiguration. Requires Kubernetes
+ 1.27 or later.
+ properties:
+ matchConditions:
+ description: MatchCondition configures admission webhook matchConditions.
+ items:
+ description: MatchCondition represents a condition which must
+ by fulfilled for a request to be sent to a webhook.
+ properties:
+ expression:
+ description: "Expression represents the expression which
+ will be evaluated by CEL. Must evaluate to bool. CEL expressions
+ have access to the contents of the AdmissionRequest and
+ Authorizer, organized into CEL variables: \n 'object'
+ - The object from the incoming request. The value is null
+ for DELETE requests. 'oldObject' - The existing object.
+ The value is null for CREATE requests. 'request' - Attributes
+ of the admission request(/pkg/apis/admission/types.go#AdmissionRequest).
+ 'authorizer' - A CEL Authorizer. May be used to perform
+ authorization checks for the principal (user or service
+ account) of the request. See https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz
+ 'authorizer.requestResource' - A CEL ResourceCheck constructed
+ from the 'authorizer' and configured with the request
+ resource. Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
+ \n Required."
+ type: string
+ name:
+ description: "Name is an identifier for this match condition,
+ used for strategic merging of MatchConditions, as well
+ as providing an identifier for logging purposes. A good
+ name should be descriptive of the associated expression.
+ Name must be a qualified name consisting of alphanumeric
+ characters, '-', '_' or '.', and must start and end with
+ an alphanumeric character (e.g. 'MyName', or 'my.name',
+ \ or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')
+ with an optional DNS subdomain prefix and '/' (e.g. 'example.com/MyName')
+ \n Required."
+ type: string
+ required:
+ - expression
+ - name
+ type: object
+ type: array
+ type: object
webhookTimeoutSeconds:
description: WebhookTimeoutSeconds specifies the maximum time in seconds
allowed to apply this policy. After the configured time expires,
@@ -32493,6 +32585,52 @@ spec:
type: array
type: object
type: array
+ webhookConfiguration:
+ description: WebhookConfiguration specifies the custom configuration
+ for Kubernetes admission webhookconfiguration. Requires Kubernetes
+ 1.27 or later.
+ properties:
+ matchConditions:
+ description: MatchCondition configures admission webhook matchConditions.
+ items:
+ description: MatchCondition represents a condition which must
+ by fulfilled for a request to be sent to a webhook.
+ properties:
+ expression:
+ description: "Expression represents the expression which
+ will be evaluated by CEL. Must evaluate to bool. CEL expressions
+ have access to the contents of the AdmissionRequest and
+ Authorizer, organized into CEL variables: \n 'object'
+ - The object from the incoming request. The value is null
+ for DELETE requests. 'oldObject' - The existing object.
+ The value is null for CREATE requests. 'request' - Attributes
+ of the admission request(/pkg/apis/admission/types.go#AdmissionRequest).
+ 'authorizer' - A CEL Authorizer. May be used to perform
+ authorization checks for the principal (user or service
+ account) of the request. See https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz
+ 'authorizer.requestResource' - A CEL ResourceCheck constructed
+ from the 'authorizer' and configured with the request
+ resource. Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
+ \n Required."
+ type: string
+ name:
+ description: "Name is an identifier for this match condition,
+ used for strategic merging of MatchConditions, as well
+ as providing an identifier for logging purposes. A good
+ name should be descriptive of the associated expression.
+ Name must be a qualified name consisting of alphanumeric
+ characters, '-', '_' or '.', and must start and end with
+ an alphanumeric character (e.g. 'MyName', or 'my.name',
+ \ or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')
+ with an optional DNS subdomain prefix and '/' (e.g. 'example.com/MyName')
+ \n Required."
+ type: string
+ required:
+ - expression
+ - name
+ type: object
+ type: array
+ type: object
webhookTimeoutSeconds:
description: WebhookTimeoutSeconds specifies the maximum time in seconds
allowed to apply this policy. After the configured time expires,
@@ -41271,6 +41409,52 @@ spec:
type: array
type: object
type: array
+ webhookConfiguration:
+ description: WebhookConfiguration specifies the custom configuration
+ for Kubernetes admission webhookconfiguration. Requires Kubernetes
+ 1.27 or later.
+ properties:
+ matchConditions:
+ description: MatchCondition configures admission webhook matchConditions.
+ items:
+ description: MatchCondition represents a condition which must
+ by fulfilled for a request to be sent to a webhook.
+ properties:
+ expression:
+ description: "Expression represents the expression which
+ will be evaluated by CEL. Must evaluate to bool. CEL expressions
+ have access to the contents of the AdmissionRequest and
+ Authorizer, organized into CEL variables: \n 'object'
+ - The object from the incoming request. The value is null
+ for DELETE requests. 'oldObject' - The existing object.
+ The value is null for CREATE requests. 'request' - Attributes
+ of the admission request(/pkg/apis/admission/types.go#AdmissionRequest).
+ 'authorizer' - A CEL Authorizer. May be used to perform
+ authorization checks for the principal (user or service
+ account) of the request. See https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz
+ 'authorizer.requestResource' - A CEL ResourceCheck constructed
+ from the 'authorizer' and configured with the request
+ resource. Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
+ \n Required."
+ type: string
+ name:
+ description: "Name is an identifier for this match condition,
+ used for strategic merging of MatchConditions, as well
+ as providing an identifier for logging purposes. A good
+ name should be descriptive of the associated expression.
+ Name must be a qualified name consisting of alphanumeric
+ characters, '-', '_' or '.', and must start and end with
+ an alphanumeric character (e.g. 'MyName', or 'my.name',
+ \ or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')
+ with an optional DNS subdomain prefix and '/' (e.g. 'example.com/MyName')
+ \n Required."
+ type: string
+ required:
+ - expression
+ - name
+ type: object
+ type: array
+ type: object
webhookTimeoutSeconds:
description: WebhookTimeoutSeconds specifies the maximum time in seconds
allowed to apply this policy. After the configured time expires,
diff --git a/docs/user/crd/index.html b/docs/user/crd/index.html
index bf36ef2310..c727ca77dd 100644
--- a/docs/user/crd/index.html
+++ b/docs/user/crd/index.html
@@ -293,6 +293,21 @@ If is set to “true” create & update for generate rules will use
Defaults to “false” if not specified.
+
+
+webhookConfiguration
+
+
+WebhookConfiguration
+
+
+ |
+
+(Optional)
+ WebhookConfiguration specifies the custom configuration for Kubernetes admission webhookconfiguration.
+Requires Kubernetes 1.27 or later.
+ |
+
@@ -556,6 +571,21 @@ If is set to “true” create & update for generate rules will use
Defaults to “false” if not specified.
+
+
+webhookConfiguration
+
+
+WebhookConfiguration
+
+
+ |
+
+(Optional)
+ WebhookConfiguration specifies the custom configuration for Kubernetes admission webhookconfiguration.
+Requires Kubernetes 1.27 or later.
+ |
+
@@ -3910,6 +3940,21 @@ If is set to “true” create & update for generate rules will use
Defaults to “false” if not specified.
+
+
+webhookConfiguration
+
+
+WebhookConfiguration
+
+
+ |
+
+(Optional)
+ WebhookConfiguration specifies the custom configuration for Kubernetes admission webhookconfiguration.
+Requires Kubernetes 1.27 or later.
+ |
+
@@ -4441,6 +4486,40 @@ expression evaluates to nil
+WebhookConfiguration
+
+
+(Appears on:
+Spec)
+
+
+
WebhookConfiguration specifies the configuration for Kubernetes admission webhookconfiguration.
+
+
+
kyverno.io/v1alpha2
Package v1alpha2 contains API Schema definitions for the policy v1alpha2 API group
@@ -8288,6 +8367,21 @@ If is set to “true” create & update for generate rules will use
Defaults to “false” if not specified.
+
+
+webhookConfiguration
+
+
+WebhookConfiguration
+
+
+ |
+
+(Optional)
+ WebhookConfiguration specifies the custom configuration for Kubernetes admission webhookconfiguration.
+Requires Kubernetes 1.27 or later.
+ |
+
@@ -8550,6 +8644,21 @@ If is set to “true” create & update for generate rules will use
Defaults to “false” if not specified.
+
+
+webhookConfiguration
+
+
+WebhookConfiguration
+
+
+ |
+
+(Optional)
+ WebhookConfiguration specifies the custom configuration for Kubernetes admission webhookconfiguration.
+Requires Kubernetes 1.27 or later.
+ |
+
@@ -9932,6 +10041,21 @@ If is set to “true” create & update for generate rules will use
Defaults to “false” if not specified.
+
+
+webhookConfiguration
+
+
+WebhookConfiguration
+
+
+ |
+
+(Optional)
+ WebhookConfiguration specifies the custom configuration for Kubernetes admission webhookconfiguration.
+Requires Kubernetes 1.27 or later.
+ |
+
@@ -10067,6 +10191,40 @@ CEL
+WebhookConfiguration
+
+
+(Appears on:
+Spec)
+
+
+
WebhookConfiguration specifies the configuration for Kubernetes admission webhookconfiguration.
+
+
+
reports.kyverno.io/v1
diff --git a/pkg/client/applyconfigurations/kyverno/v1/spec.go b/pkg/client/applyconfigurations/kyverno/v1/spec.go
index 1ed14a4fc8..cf6746a75f 100644
--- a/pkg/client/applyconfigurations/kyverno/v1/spec.go
+++ b/pkg/client/applyconfigurations/kyverno/v1/spec.go
@@ -38,6 +38,7 @@ type SpecApplyConfiguration struct {
GenerateExistingOnPolicyUpdate *bool `json:"generateExistingOnPolicyUpdate,omitempty"`
GenerateExisting *bool `json:"generateExisting,omitempty"`
UseServerSideApply *bool `json:"useServerSideApply,omitempty"`
+ WebhookConfiguration *WebhookConfigurationApplyConfiguration `json:"webhookConfiguration,omitempty"`
}
// SpecApplyConfiguration constructs an declarative configuration of the Spec type for use with
@@ -159,3 +160,11 @@ func (b *SpecApplyConfiguration) WithUseServerSideApply(value bool) *SpecApplyCo
b.UseServerSideApply = &value
return b
}
+
+// WithWebhookConfiguration sets the WebhookConfiguration field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the WebhookConfiguration field is set to the value of the last call.
+func (b *SpecApplyConfiguration) WithWebhookConfiguration(value *WebhookConfigurationApplyConfiguration) *SpecApplyConfiguration {
+ b.WebhookConfiguration = value
+ return b
+}
diff --git a/pkg/client/applyconfigurations/kyverno/v1/webhookconfiguration.go b/pkg/client/applyconfigurations/kyverno/v1/webhookconfiguration.go
new file mode 100644
index 0000000000..fdcd61b38e
--- /dev/null
+++ b/pkg/client/applyconfigurations/kyverno/v1/webhookconfiguration.go
@@ -0,0 +1,45 @@
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by applyconfiguration-gen. DO NOT EDIT.
+
+package v1
+
+import (
+ v1 "k8s.io/api/admissionregistration/v1"
+)
+
+// WebhookConfigurationApplyConfiguration represents an declarative configuration of the WebhookConfiguration type for use
+// with apply.
+type WebhookConfigurationApplyConfiguration struct {
+ MatchConditions []v1.MatchCondition `json:"matchConditions,omitempty"`
+}
+
+// WebhookConfigurationApplyConfiguration constructs an declarative configuration of the WebhookConfiguration type for use with
+// apply.
+func WebhookConfiguration() *WebhookConfigurationApplyConfiguration {
+ return &WebhookConfigurationApplyConfiguration{}
+}
+
+// WithMatchConditions adds the given value to the MatchConditions field in the declarative configuration
+// and returns the receiver, so that objects can be build by chaining "With" function invocations.
+// If called multiple times, values provided by each call will be appended to the MatchConditions field.
+func (b *WebhookConfigurationApplyConfiguration) WithMatchConditions(values ...v1.MatchCondition) *WebhookConfigurationApplyConfiguration {
+ for i := range values {
+ b.MatchConditions = append(b.MatchConditions, values[i])
+ }
+ return b
+}
diff --git a/pkg/client/applyconfigurations/kyverno/v2beta1/spec.go b/pkg/client/applyconfigurations/kyverno/v2beta1/spec.go
index 427aeef855..1fad94bcb4 100644
--- a/pkg/client/applyconfigurations/kyverno/v2beta1/spec.go
+++ b/pkg/client/applyconfigurations/kyverno/v2beta1/spec.go
@@ -39,6 +39,7 @@ type SpecApplyConfiguration struct {
GenerateExistingOnPolicyUpdate *bool `json:"generateExistingOnPolicyUpdate,omitempty"`
GenerateExisting *bool `json:"generateExisting,omitempty"`
UseServerSideApply *bool `json:"useServerSideApply,omitempty"`
+ WebhookConfiguration *WebhookConfigurationApplyConfiguration `json:"webhookConfiguration,omitempty"`
}
// SpecApplyConfiguration constructs an declarative configuration of the Spec type for use with
@@ -160,3 +161,11 @@ func (b *SpecApplyConfiguration) WithUseServerSideApply(value bool) *SpecApplyCo
b.UseServerSideApply = &value
return b
}
+
+// WithWebhookConfiguration sets the WebhookConfiguration field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the WebhookConfiguration field is set to the value of the last call.
+func (b *SpecApplyConfiguration) WithWebhookConfiguration(value *WebhookConfigurationApplyConfiguration) *SpecApplyConfiguration {
+ b.WebhookConfiguration = value
+ return b
+}
diff --git a/pkg/client/applyconfigurations/kyverno/v2beta1/webhookconfiguration.go b/pkg/client/applyconfigurations/kyverno/v2beta1/webhookconfiguration.go
new file mode 100644
index 0000000000..9623f7c470
--- /dev/null
+++ b/pkg/client/applyconfigurations/kyverno/v2beta1/webhookconfiguration.go
@@ -0,0 +1,45 @@
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by applyconfiguration-gen. DO NOT EDIT.
+
+package v2beta1
+
+import (
+ v1 "k8s.io/api/admissionregistration/v1"
+)
+
+// WebhookConfigurationApplyConfiguration represents an declarative configuration of the WebhookConfiguration type for use
+// with apply.
+type WebhookConfigurationApplyConfiguration struct {
+ MatchConditions []v1.MatchCondition `json:"matchConditions,omitempty"`
+}
+
+// WebhookConfigurationApplyConfiguration constructs an declarative configuration of the WebhookConfiguration type for use with
+// apply.
+func WebhookConfiguration() *WebhookConfigurationApplyConfiguration {
+ return &WebhookConfigurationApplyConfiguration{}
+}
+
+// WithMatchConditions adds the given value to the MatchConditions field in the declarative configuration
+// and returns the receiver, so that objects can be build by chaining "With" function invocations.
+// If called multiple times, values provided by each call will be appended to the MatchConditions field.
+func (b *WebhookConfigurationApplyConfiguration) WithMatchConditions(values ...v1.MatchCondition) *WebhookConfigurationApplyConfiguration {
+ for i := range values {
+ b.MatchConditions = append(b.MatchConditions, values[i])
+ }
+ return b
+}
diff --git a/pkg/client/applyconfigurations/utils.go b/pkg/client/applyconfigurations/utils.go
index 910984a366..0bffaf29ed 100644
--- a/pkg/client/applyconfigurations/utils.go
+++ b/pkg/client/applyconfigurations/utils.go
@@ -143,6 +143,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} {
return &kyvernov1.ValidationFailureActionOverrideApplyConfiguration{}
case v1.SchemeGroupVersion.WithKind("Variable"):
return &kyvernov1.VariableApplyConfiguration{}
+ case v1.SchemeGroupVersion.WithKind("WebhookConfiguration"):
+ return &kyvernov1.WebhookConfigurationApplyConfiguration{}
// Group=kyverno.io, Version=v1alpha2
case v1alpha2.SchemeGroupVersion.WithKind("AdmissionReport"):
@@ -257,6 +259,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} {
return &kyvernov2beta1.SpecApplyConfiguration{}
case v2beta1.SchemeGroupVersion.WithKind("Validation"):
return &kyvernov2beta1.ValidationApplyConfiguration{}
+ case v2beta1.SchemeGroupVersion.WithKind("WebhookConfiguration"):
+ return &kyvernov2beta1.WebhookConfigurationApplyConfiguration{}
// Group=reports.kyverno.io, Version=v1
case reportsv1.SchemeGroupVersion.WithKind("AdmissionReport"):
diff --git a/pkg/config/config.go b/pkg/config/config.go
index 5afa3ddcfa..f9ab57332b 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -74,6 +74,8 @@ const (
ReadinessServicePath = "/health/readiness"
// MetricsPath is the path for exposing metrics
MetricsPath = "/metrics"
+ // FineGrainedWebhookPath is the sub-path for fine-grained webhook configurationss
+ FineGrainedWebhookPath = "/finegrained"
)
// keys in config map
diff --git a/pkg/controllers/policycache/controller.go b/pkg/controllers/policycache/controller.go
index 915ee3dc01..519dd95cc5 100644
--- a/pkg/controllers/policycache/controller.go
+++ b/pkg/controllers/policycache/controller.go
@@ -103,7 +103,7 @@ func (c *controller) reconcile(ctx context.Context, logger logr.Logger, key, nam
}
return err
}
- if policy.AdmissionProcessingEnabled() {
+ if policy.AdmissionProcessingEnabled() && !policy.GetSpec().CustomWebhookConfiguration() {
return c.cache.Set(key, policy, c.client.Discovery())
} else {
c.cache.Unset(key)
diff --git a/pkg/controllers/webhook/controller.go b/pkg/controllers/webhook/controller.go
index 0336da9a79..95e945371b 100644
--- a/pkg/controllers/webhook/controller.go
+++ b/pkg/controllers/webhook/controller.go
@@ -634,74 +634,85 @@ func (c *controller) buildResourceMutatingWebhookConfiguration(ctx context.Conte
Webhooks: []admissionregistrationv1.MutatingWebhook{},
}
if c.watchdogCheck() {
- ignore := newWebhook(c.defaultTimeout, ignore)
- fail := newWebhook(c.defaultTimeout, fail)
- policies, err := c.getAllPolicies()
- if err != nil {
- return nil, err
- }
- c.recordPolicyState(config.MutatingWebhookConfigurationName, policies...)
- for _, p := range policies {
- if p.AdmissionProcessingEnabled() {
- spec := p.GetSpec()
- if spec.HasMutateStandard() || spec.HasVerifyImages() {
- if spec.GetFailurePolicy(ctx) == kyvernov1.Ignore {
- c.mergeWebhook(ignore, p, false)
- } else {
- c.mergeWebhook(fail, p, false)
- }
- }
- }
- }
webhookCfg := config.WebhookConfig{}
webhookCfgs := cfg.GetWebhooks()
if len(webhookCfgs) > 0 {
webhookCfg = webhookCfgs[0]
}
- if !ignore.isEmpty() {
- timeout := capTimeout(ignore.maxWebhookTimeout)
- result.Webhooks = append(
- result.Webhooks,
- admissionregistrationv1.MutatingWebhook{
- Name: config.MutatingWebhookName + "-ignore",
- ClientConfig: c.clientConfig(caBundle, config.MutatingWebhookServicePath+"/ignore"),
- Rules: ignore.buildRulesWithOperations(admissionregistrationv1.Create, admissionregistrationv1.Update),
- FailurePolicy: &ignore.failurePolicy,
- SideEffects: &noneOnDryRun,
- AdmissionReviewVersions: []string{"v1"},
- NamespaceSelector: webhookCfg.NamespaceSelector,
- ObjectSelector: webhookCfg.ObjectSelector,
- TimeoutSeconds: &timeout,
- ReinvocationPolicy: &ifNeeded,
- MatchConditions: cfg.GetMatchConditions(),
- },
- )
+
+ ignoreWebhook := newWebhook(c.defaultTimeout, ignore, cfg.GetMatchConditions())
+ failWebhook := newWebhook(c.defaultTimeout, fail, cfg.GetMatchConditions())
+ policies, err := c.getAllPolicies()
+ if err != nil {
+ return nil, err
}
- if !fail.isEmpty() {
- timeout := capTimeout(fail.maxWebhookTimeout)
- result.Webhooks = append(
- result.Webhooks,
- admissionregistrationv1.MutatingWebhook{
- Name: config.MutatingWebhookName + "-fail",
- ClientConfig: c.clientConfig(caBundle, config.MutatingWebhookServicePath+"/fail"),
- Rules: fail.buildRulesWithOperations(admissionregistrationv1.Create, admissionregistrationv1.Update),
- FailurePolicy: &fail.failurePolicy,
- SideEffects: &noneOnDryRun,
- AdmissionReviewVersions: []string{"v1"},
- NamespaceSelector: webhookCfg.NamespaceSelector,
- ObjectSelector: webhookCfg.ObjectSelector,
- TimeoutSeconds: &timeout,
- ReinvocationPolicy: &ifNeeded,
- MatchConditions: cfg.GetMatchConditions(),
- },
- )
+ var fineGrainedIgnoreList, fineGrainedFailList []*webhook
+ c.recordPolicyState(config.MutatingWebhookConfigurationName, policies...)
+ for _, p := range policies {
+ if p.AdmissionProcessingEnabled() {
+ spec := p.GetSpec()
+ if spec.HasMutateStandard() || spec.HasVerifyImages() {
+ if spec.CustomWebhookConfiguration() {
+ fineGrainedIgnore := newWebhookPerPolicy(c.defaultTimeout, ignore, cfg.GetMatchConditions(), p)
+ fineGrainedFail := newWebhookPerPolicy(c.defaultTimeout, fail, cfg.GetMatchConditions(), p)
+ if spec.GetFailurePolicy(ctx) == kyvernov1.Ignore {
+ c.mergeWebhook(fineGrainedIgnore, p, false)
+ fineGrainedIgnoreList = append(fineGrainedIgnoreList, fineGrainedIgnore)
+ } else {
+ c.mergeWebhook(fineGrainedFail, p, false)
+ fineGrainedFailList = append(fineGrainedFailList, fineGrainedFail)
+ }
+ continue
+ }
+
+ if spec.GetFailurePolicy(ctx) == kyvernov1.Ignore {
+ c.mergeWebhook(ignoreWebhook, p, false)
+ } else {
+ c.mergeWebhook(failWebhook, p, false)
+ }
+ }
+ }
}
+
+ webhooks := []*webhook{ignoreWebhook, failWebhook}
+ webhooks = append(webhooks, fineGrainedIgnoreList...)
+ webhooks = append(webhooks, fineGrainedFailList...)
+ result.Webhooks = c.buildResourceMutatingWebhookRules(caBundle, webhookCfg, &noneOnDryRun, webhooks)
} else {
c.recordPolicyState(config.MutatingWebhookConfigurationName)
}
return &result, nil
}
+func (c *controller) buildResourceMutatingWebhookRules(caBundle []byte, webhookCfg config.WebhookConfig, sideEffects *admissionregistrationv1.SideEffectClass, webhooks []*webhook) []admissionregistrationv1.MutatingWebhook {
+ var mutatingWebhooks []admissionregistrationv1.MutatingWebhook
+ for _, webhook := range webhooks {
+ if webhook.isEmpty() {
+ continue
+ }
+ failurePolicy := webhook.failurePolicy
+ timeout := capTimeout(webhook.maxWebhookTimeout)
+ name, path := webhookNameAndPath(*webhook, config.MutatingWebhookName, config.MutatingWebhookServicePath)
+ mutatingWebhooks = append(
+ mutatingWebhooks,
+ admissionregistrationv1.MutatingWebhook{
+ Name: name,
+ ClientConfig: c.clientConfig(caBundle, path),
+ Rules: webhook.buildRulesWithOperations(admissionregistrationv1.Create, admissionregistrationv1.Update),
+ FailurePolicy: &failurePolicy,
+ SideEffects: sideEffects,
+ AdmissionReviewVersions: []string{"v1"},
+ NamespaceSelector: webhookCfg.NamespaceSelector,
+ ObjectSelector: webhookCfg.ObjectSelector,
+ TimeoutSeconds: &timeout,
+ ReinvocationPolicy: &ifNeeded,
+ MatchConditions: webhook.matchConditions,
+ },
+ )
+ }
+ return mutatingWebhooks
+}
+
func (c *controller) buildDefaultResourceValidatingWebhookConfiguration(_ context.Context, cfg config.Configuration, caBundle []byte) (*admissionregistrationv1.ValidatingWebhookConfiguration, error) {
sideEffects := &none
if c.admissionReports {
@@ -760,76 +771,90 @@ func (c *controller) buildResourceValidatingWebhookConfiguration(ctx context.Con
Webhooks: []admissionregistrationv1.ValidatingWebhook{},
}
if c.watchdogCheck() {
- ignore := newWebhook(c.defaultTimeout, ignore)
- fail := newWebhook(c.defaultTimeout, fail)
- policies, err := c.getAllPolicies()
- if err != nil {
- return nil, err
- }
- c.recordPolicyState(config.ValidatingWebhookConfigurationName, policies...)
- for _, p := range policies {
- if p.AdmissionProcessingEnabled() {
- spec := p.GetSpec()
- if spec.HasValidate() || spec.HasGenerate() || spec.HasMutateExisting() || spec.HasVerifyImageChecks() || spec.HasVerifyManifests() {
- if spec.GetFailurePolicy(ctx) == kyvernov1.Ignore {
- c.mergeWebhook(ignore, p, true)
- } else {
- c.mergeWebhook(fail, p, true)
- }
- }
- }
- }
webhookCfg := config.WebhookConfig{}
webhookCfgs := cfg.GetWebhooks()
if len(webhookCfgs) > 0 {
webhookCfg = webhookCfgs[0]
}
+
+ ignoreWebhook := newWebhook(c.defaultTimeout, ignore, cfg.GetMatchConditions())
+ failWebhook := newWebhook(c.defaultTimeout, fail, cfg.GetMatchConditions())
+ policies, err := c.getAllPolicies()
+ if err != nil {
+ return nil, err
+ }
+
+ var fineGrainedIgnoreList, fineGrainedFailList []*webhook
+ c.recordPolicyState(config.ValidatingWebhookConfigurationName, policies...)
+ for _, p := range policies {
+ if p.AdmissionProcessingEnabled() {
+ spec := p.GetSpec()
+ if spec.HasValidate() || spec.HasGenerate() || spec.HasMutateExisting() || spec.HasVerifyImageChecks() || spec.HasVerifyManifests() {
+ if spec.CustomWebhookConfiguration() {
+ fineGrainedIgnore := newWebhookPerPolicy(c.defaultTimeout, ignore, cfg.GetMatchConditions(), p)
+ fineGrainedFail := newWebhookPerPolicy(c.defaultTimeout, fail, cfg.GetMatchConditions(), p)
+ if spec.GetFailurePolicy(ctx) == kyvernov1.Ignore {
+ c.mergeWebhook(fineGrainedIgnore, p, true)
+ fineGrainedIgnoreList = append(fineGrainedIgnoreList, fineGrainedIgnore)
+ } else {
+ c.mergeWebhook(fineGrainedFail, p, true)
+ fineGrainedFailList = append(fineGrainedFailList, fineGrainedFail)
+ }
+ continue
+ }
+
+ if spec.GetFailurePolicy(ctx) == kyvernov1.Ignore {
+ c.mergeWebhook(ignoreWebhook, p, true)
+ } else {
+ c.mergeWebhook(failWebhook, p, true)
+ }
+ }
+ }
+ }
+
sideEffects := &none
if c.admissionReports {
sideEffects = &noneOnDryRun
}
- if !ignore.isEmpty() {
- timeout := capTimeout(ignore.maxWebhookTimeout)
- result.Webhooks = append(
- result.Webhooks,
- admissionregistrationv1.ValidatingWebhook{
- Name: config.ValidatingWebhookName + "-ignore",
- ClientConfig: c.clientConfig(caBundle, config.ValidatingWebhookServicePath+"/ignore"),
- Rules: ignore.buildRulesWithOperations(admissionregistrationv1.Create, admissionregistrationv1.Update, admissionregistrationv1.Delete, admissionregistrationv1.Connect),
- FailurePolicy: &ignore.failurePolicy,
- SideEffects: sideEffects,
- AdmissionReviewVersions: []string{"v1"},
- NamespaceSelector: webhookCfg.NamespaceSelector,
- ObjectSelector: webhookCfg.ObjectSelector,
- TimeoutSeconds: &timeout,
- MatchConditions: cfg.GetMatchConditions(),
- },
- )
- }
- if !fail.isEmpty() {
- timeout := capTimeout(fail.maxWebhookTimeout)
- result.Webhooks = append(
- result.Webhooks,
- admissionregistrationv1.ValidatingWebhook{
- Name: config.ValidatingWebhookName + "-fail",
- ClientConfig: c.clientConfig(caBundle, config.ValidatingWebhookServicePath+"/fail"),
- Rules: fail.buildRulesWithOperations(admissionregistrationv1.Create, admissionregistrationv1.Update, admissionregistrationv1.Delete, admissionregistrationv1.Connect),
- FailurePolicy: &fail.failurePolicy,
- SideEffects: sideEffects,
- AdmissionReviewVersions: []string{"v1"},
- NamespaceSelector: webhookCfg.NamespaceSelector,
- ObjectSelector: webhookCfg.ObjectSelector,
- TimeoutSeconds: &timeout,
- MatchConditions: cfg.GetMatchConditions(),
- },
- )
- }
+
+ webhooks := []*webhook{ignoreWebhook, failWebhook}
+ webhooks = append(webhooks, fineGrainedIgnoreList...)
+ webhooks = append(webhooks, fineGrainedFailList...)
+ result.Webhooks = c.buildResourceValidatingWebhookRules(caBundle, webhookCfg, sideEffects, webhooks)
} else {
c.recordPolicyState(config.MutatingWebhookConfigurationName)
}
return &result, nil
}
+func (c *controller) buildResourceValidatingWebhookRules(caBundle []byte, webhookCfg config.WebhookConfig, sideEffects *admissionregistrationv1.SideEffectClass, webhooks []*webhook) []admissionregistrationv1.ValidatingWebhook {
+ var validatingWebhooks []admissionregistrationv1.ValidatingWebhook
+ for _, webhook := range webhooks {
+ if webhook.isEmpty() {
+ continue
+ }
+ timeout := capTimeout(webhook.maxWebhookTimeout)
+ name, path := webhookNameAndPath(*webhook, config.ValidatingWebhookName, config.ValidatingWebhookServicePath)
+ failurePolicy := webhook.failurePolicy
+ validatingWebhooks = append(
+ validatingWebhooks,
+ admissionregistrationv1.ValidatingWebhook{
+ Name: name,
+ ClientConfig: c.clientConfig(caBundle, path),
+ Rules: webhook.buildRulesWithOperations(admissionregistrationv1.Create, admissionregistrationv1.Update, admissionregistrationv1.Delete, admissionregistrationv1.Connect),
+ FailurePolicy: &failurePolicy,
+ SideEffects: sideEffects,
+ AdmissionReviewVersions: []string{"v1"},
+ NamespaceSelector: webhookCfg.NamespaceSelector,
+ ObjectSelector: webhookCfg.ObjectSelector,
+ TimeoutSeconds: &timeout,
+ MatchConditions: webhook.matchConditions,
+ },
+ )
+ }
+ return validatingWebhooks
+}
+
func (c *controller) getAllPolicies() ([]kyvernov1.PolicyInterface, error) {
var policies []kyvernov1.PolicyInterface
if cpols, err := c.cpolLister.List(labels.Everything()); err != nil {
diff --git a/pkg/controllers/webhook/utils.go b/pkg/controllers/webhook/utils.go
index 2f71a717d8..f7c51b390c 100644
--- a/pkg/controllers/webhook/utils.go
+++ b/pkg/controllers/webhook/utils.go
@@ -7,20 +7,27 @@ import (
"github.com/kyverno/kyverno/api/kyverno"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
+ "github.com/kyverno/kyverno/pkg/config"
"golang.org/x/exp/maps"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets"
+ objectmeta "k8s.io/client-go/tools/cache"
"k8s.io/utils/ptr"
)
// webhook is the instance that aggregates the GVK of existing policies
// based on group, kind, scopeType, failurePolicy and webhookTimeout
+// a fine-grained webhook is created per policy with a unique path
type webhook struct {
+ // policyMeta is set for fine-grained webhooks
+ policyMeta objectmeta.ObjectName
+
maxWebhookTimeout int32
failurePolicy admissionregistrationv1.FailurePolicyType
rules map[groupVersionScope]sets.Set[string]
+ matchConditions []admissionregistrationv1.MatchCondition
}
// groupVersionScope contains the GV and scopeType of a resource
@@ -34,14 +41,27 @@ func (gvs groupVersionScope) String() string {
return gvs.GroupVersion.String() + "/" + string(gvs.scopeType)
}
-func newWebhook(timeout int32, failurePolicy admissionregistrationv1.FailurePolicyType) *webhook {
+func newWebhook(timeout int32, failurePolicy admissionregistrationv1.FailurePolicyType, matchConditions []admissionregistrationv1.MatchCondition) *webhook {
return &webhook{
maxWebhookTimeout: timeout,
failurePolicy: failurePolicy,
rules: map[groupVersionScope]sets.Set[string]{},
+ matchConditions: matchConditions,
}
}
+func newWebhookPerPolicy(timeout int32, failurePolicy admissionregistrationv1.FailurePolicyType, matchConditions []admissionregistrationv1.MatchCondition, policy kyvernov1.PolicyInterface) *webhook {
+ webhook := newWebhook(timeout, failurePolicy, matchConditions)
+ webhook.policyMeta = objectmeta.ObjectName{
+ Namespace: policy.GetNamespace(),
+ Name: policy.GetName(),
+ }
+ if policy.GetSpec().CustomWebhookConfiguration() {
+ webhook.matchConditions = policy.GetSpec().GetMatchConditions()
+ }
+ return webhook
+}
+
func (wh *webhook) buildRulesWithOperations(ops ...admissionregistrationv1.OperationType) []admissionregistrationv1.RuleWithOperations {
var rules []admissionregistrationv1.RuleWithOperations
@@ -122,6 +142,14 @@ func (wh *webhook) isEmpty() bool {
return len(wh.rules) == 0
}
+func (wh *webhook) key(separator string) string {
+ p := wh.policyMeta
+ if p.Namespace != "" {
+ return p.Namespace + separator + p.Name
+ }
+ return p.Name
+}
+
func objectMeta(name string, annotations map[string]string, labels map[string]string, owner ...metav1.OwnerReference) metav1.ObjectMeta {
desiredLabels := make(map[string]string)
defaultLabels := map[string]string{
@@ -167,3 +195,18 @@ func capTimeout(maxWebhookTimeout int32) int32 {
}
return maxWebhookTimeout
}
+
+func webhookNameAndPath(wh webhook, baseName, basePath string) (name string, path string) {
+ if wh.failurePolicy == ignore {
+ name = baseName + "-ignore"
+ path = basePath + "/ignore"
+ } else {
+ name = baseName + "-fail"
+ path = basePath + "/fail"
+ }
+ if wh.policyMeta.Name != "" {
+ name = name + "-finegrained-" + wh.key("-")
+ path = path + config.FineGrainedWebhookPath + "/" + wh.key("/")
+ }
+ return name, path
+}
diff --git a/pkg/controllers/webhook/utils_test.go b/pkg/controllers/webhook/utils_test.go
index dc0d8f5edb..7bdc3d85a3 100644
--- a/pkg/controllers/webhook/utils_test.go
+++ b/pkg/controllers/webhook/utils_test.go
@@ -12,9 +12,9 @@ import (
)
func Test_webhook_isEmpty(t *testing.T) {
- empty := newWebhook(DefaultWebhookTimeout, admissionregistrationv1.Ignore)
+ empty := newWebhook(DefaultWebhookTimeout, admissionregistrationv1.Ignore, []admissionregistrationv1.MatchCondition{})
assert.Equal(t, empty.isEmpty(), true)
- notEmpty := newWebhook(DefaultWebhookTimeout, admissionregistrationv1.Ignore)
+ notEmpty := newWebhook(DefaultWebhookTimeout, admissionregistrationv1.Ignore, []admissionregistrationv1.MatchCondition{})
notEmpty.set(GroupVersionResourceScope{
GroupVersionResource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"},
Scope: admissionregistrationv1.NamespacedScope,
diff --git a/pkg/validation/policy/validate.go b/pkg/validation/policy/validate.go
index d8fac4b237..cfe1a8ac78 100644
--- a/pkg/validation/policy/validate.go
+++ b/pkg/validation/policy/validate.go
@@ -123,6 +123,10 @@ func Validate(policy, oldPolicy kyvernov1.PolicyInterface, client dclient.Interf
spec := policy.GetSpec()
background := spec.BackgroundProcessingEnabled()
mutateExistingOnPolicyUpdate := spec.GetMutateExistingOnPolicyUpdate()
+ if policy.GetSpec().CustomWebhookConfiguration() &&
+ !kubeutils.HigherThanKubernetesVersion(client.GetKubeClient().Discovery(), logging.GlobalLogger(), 1, 27, 0) {
+ return warnings, fmt.Errorf("custom webhook configurations are only supported in kubernetes version 1.27.0 and above")
+ }
warnings = append(warnings, checkValidationFailureAction(spec)...)
var errs field.ErrorList
diff --git a/pkg/webhooks/handlers/admission.go b/pkg/webhooks/handlers/admission.go
index 1b23812e30..d1a546aee3 100644
--- a/pkg/webhooks/handlers/admission.go
+++ b/pkg/webhooks/handlers/admission.go
@@ -8,6 +8,7 @@ import (
"time"
"github.com/go-logr/logr"
+ "github.com/julienschmidt/httprouter"
admissionv1 "k8s.io/api/admission/v1"
)
@@ -47,8 +48,11 @@ func (inner AdmissionHandler) withAdmission(logger logr.Logger) HttpHandler {
"uid", admissionReview.Request.UID,
"user", admissionReview.Request.UserInfo,
)
+
+ params := httprouter.ParamsFromContext(request.Context())
admissionRequest := AdmissionRequest{
AdmissionRequest: *admissionReview.Request,
+ URLParams: params.ByName("policy"),
}
admissionResponse := inner(request.Context(), logger, admissionRequest, startTime)
admissionReview.Response = &admissionResponse
diff --git a/pkg/webhooks/handlers/types.go b/pkg/webhooks/handlers/types.go
index 03a98b7a4b..e023d51698 100644
--- a/pkg/webhooks/handlers/types.go
+++ b/pkg/webhooks/handlers/types.go
@@ -23,6 +23,8 @@ type AdmissionRequest struct {
// GroupVersionKind is the top level GVK.
GroupVersionKind schema.GroupVersionKind
+
+ URLParams string
}
type AdmissionResponse = admissionv1.AdmissionResponse
diff --git a/pkg/webhooks/resource/handlers.go b/pkg/webhooks/resource/handlers.go
index bfd485d581..5fb701f450 100644
--- a/pkg/webhooks/resource/handlers.go
+++ b/pkg/webhooks/resource/handlers.go
@@ -3,6 +3,8 @@ package resource
import (
"context"
"errors"
+ "fmt"
+ "strings"
"time"
"github.com/go-logr/logr"
@@ -101,16 +103,13 @@ func NewHandlers(
func (h *resourceHandlers) Validate(ctx context.Context, logger logr.Logger, request handlers.AdmissionRequest, failurePolicy string, startTime time.Time) handlers.AdmissionResponse {
kind := request.Kind.Kind
- logger = logger.WithValues("kind", kind)
+ logger = logger.WithValues("kind", kind).WithValues("URLParams", request.URLParams)
logger.V(4).Info("received an admission request in validating webhook")
- // timestamp at which this admission request got triggered
- gvr := schema.GroupVersionResource(request.Resource)
- policies := filterPolicies(ctx, failurePolicy, h.pCache.GetPolicies(policycache.ValidateEnforce, gvr, request.SubResource, request.Namespace)...)
- mutatePolicies := filterPolicies(ctx, failurePolicy, h.pCache.GetPolicies(policycache.Mutate, gvr, request.SubResource, request.Namespace)...)
- generatePolicies := filterPolicies(ctx, failurePolicy, h.pCache.GetPolicies(policycache.Generate, gvr, request.SubResource, request.Namespace)...)
- imageVerifyValidatePolicies := filterPolicies(ctx, failurePolicy, h.pCache.GetPolicies(policycache.VerifyImagesValidate, gvr, request.SubResource, request.Namespace)...)
- policies = append(policies, imageVerifyValidatePolicies...)
+ policies, mutatePolicies, generatePolicies, _, err := h.retrieveAndCategorizePolicies(ctx, logger, request, failurePolicy, false)
+ if err != nil {
+ return errorResponse(logger, request.UID, err, "failed to fetch policy with key")
+ }
if len(policies) == 0 && len(mutatePolicies) == 0 && len(generatePolicies) == 0 {
logger.V(4).Info("no policies matched admission request")
@@ -143,11 +142,13 @@ func (h *resourceHandlers) Validate(ctx context.Context, logger logr.Logger, req
func (h *resourceHandlers) Mutate(ctx context.Context, logger logr.Logger, request handlers.AdmissionRequest, failurePolicy string, startTime time.Time) handlers.AdmissionResponse {
kind := request.Kind.Kind
- logger = logger.WithValues("kind", kind)
+ logger = logger.WithValues("kind", kind).WithValues("URLParams", request.URLParams)
logger.V(4).Info("received an admission request in mutating webhook")
- gvr := schema.GroupVersionResource(request.Resource)
- mutatePolicies := filterPolicies(ctx, failurePolicy, h.pCache.GetPolicies(policycache.Mutate, gvr, request.SubResource, request.Namespace)...)
- verifyImagesPolicies := filterPolicies(ctx, failurePolicy, h.pCache.GetPolicies(policycache.VerifyImagesMutate, gvr, request.SubResource, request.Namespace)...)
+
+ _, mutatePolicies, _, verifyImagesPolicies, err := h.retrieveAndCategorizePolicies(ctx, logger, request, failurePolicy, true)
+ if err != nil {
+ return errorResponse(logger, request.UID, err, "failed to fetch policy with key")
+ }
if len(mutatePolicies) == 0 && len(verifyImagesPolicies) == 0 {
logger.V(4).Info("no policies matched mutate admission request")
return admissionutils.ResponseSuccess(request.UID)
@@ -184,6 +185,66 @@ func (h *resourceHandlers) Mutate(ctx context.Context, logger logr.Logger, reque
return admissionutils.MutationResponse(request.UID, patch, warnings...)
}
+func (h *resourceHandlers) retrieveAndCategorizePolicies(
+ ctx context.Context, logger logr.Logger, request handlers.AdmissionRequest, failurePolicy string, mutation bool) (
+ []kyvernov1.PolicyInterface, []kyvernov1.PolicyInterface, []kyvernov1.PolicyInterface, []kyvernov1.PolicyInterface, error,
+) {
+ var policies, mutatePolicies, generatePolicies, imageVerifyValidatePolicies []kyvernov1.PolicyInterface
+ if request.URLParams == "" {
+ gvr := schema.GroupVersionResource(request.Resource)
+ policies = filterPolicies(ctx, failurePolicy, h.pCache.GetPolicies(policycache.ValidateEnforce, gvr, request.SubResource, request.Namespace)...)
+ mutatePolicies = filterPolicies(ctx, failurePolicy, h.pCache.GetPolicies(policycache.Mutate, gvr, request.SubResource, request.Namespace)...)
+ generatePolicies = filterPolicies(ctx, failurePolicy, h.pCache.GetPolicies(policycache.Generate, gvr, request.SubResource, request.Namespace)...)
+ if mutation {
+ imageVerifyValidatePolicies = filterPolicies(ctx, failurePolicy, h.pCache.GetPolicies(policycache.VerifyImagesMutate, gvr, request.SubResource, request.Namespace)...)
+ } else {
+ imageVerifyValidatePolicies = filterPolicies(ctx, failurePolicy, h.pCache.GetPolicies(policycache.VerifyImagesValidate, gvr, request.SubResource, request.Namespace)...)
+ policies = append(policies, imageVerifyValidatePolicies...)
+ }
+ } else {
+ meta := strings.Split(request.URLParams, "/")
+ polName := meta[1]
+ polNamespace := ""
+
+ if len(meta) >= 3 {
+ polNamespace = meta[1]
+ polName = meta[2]
+ }
+
+ var policy kyvernov1.PolicyInterface
+ var err error
+ if polNamespace == "" {
+ policy, err = h.cpolLister.Get(polName)
+ } else {
+ policy, err = h.polLister.Policies(polNamespace).Get(polName)
+ }
+ if err != nil {
+ return nil, nil, nil, nil, fmt.Errorf("key %s/%s: %v", polNamespace, polName, err)
+ }
+
+ filteredPolicies := filterPolicies(ctx, failurePolicy, policy)
+ if len(filteredPolicies) == 0 {
+ logger.V(4).Info("no policy found with key", "namespace", polNamespace, "name", polName)
+ return nil, nil, nil, nil, nil
+ }
+ policy = filteredPolicies[0]
+ spec := policy.GetSpec()
+ if spec.HasValidate() {
+ policies = append(policies, policy)
+ }
+ if spec.HasGenerate() {
+ generatePolicies = append(generatePolicies, policy)
+ }
+ if spec.HasMutate() {
+ mutatePolicies = append(mutatePolicies, policy)
+ }
+ if spec.HasVerifyImages() {
+ policies = append(policies, policy)
+ }
+ }
+ return policies, mutatePolicies, generatePolicies, imageVerifyValidatePolicies, nil
+}
+
func filterPolicies(ctx context.Context, failurePolicy string, policies ...kyvernov1.PolicyInterface) []kyvernov1.PolicyInterface {
var results []kyvernov1.PolicyInterface
for _, policy := range policies {
diff --git a/pkg/webhooks/server.go b/pkg/webhooks/server.go
index 42f90efea8..64bcac7f57 100644
--- a/pkg/webhooks/server.go
+++ b/pkg/webhooks/server.go
@@ -285,4 +285,6 @@ func registerWebhookHandlers(
mux.HandlerFunc("POST", basePath, builder(all).ToHandlerFunc(name))
mux.HandlerFunc("POST", basePath+"/ignore", builder(ignore).ToHandlerFunc(name))
mux.HandlerFunc("POST", basePath+"/fail", builder(fail).ToHandlerFunc(name))
+ mux.HandlerFunc("POST", basePath+"/ignore"+config.FineGrainedWebhookPath+"/*policy", builder(ignore).ToHandlerFunc(name))
+ mux.HandlerFunc("POST", basePath+"/fail"+config.FineGrainedWebhookPath+"/*policy", builder(fail).ToHandlerFunc(name))
}