From 0873a9fc02ed595ef20d78ca7146e61b44f92af3 Mon Sep 17 00:00:00 2001 From: Md Sahil <85174511+MdSahil-oss@users.noreply.github.com> Date: Thu, 20 Apr 2023 12:36:13 +0530 Subject: [PATCH] Support for Context vars in cleanup (#6084) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added Context in CleanupPolicySpec Signed-off-by: MdSahil-oss * Added context.go file with loadVariable() Signed-off-by: MdSahil-oss * Added loadAPIData() in context.go and called from handlers.go Signed-off-by: MdSahil-oss * Added conditionals for not supported context variables Signed-off-by: MdSahil-oss * Reverted versions in CRDs Signed-off-by: MdSahil-oss * Reverted CRDs to v0.11.1 Signed-off-by: MdSahil-oss * Imported fmt in handlers.go Signed-off-by: MdSahil-oss * Added Context in CleanupPolicySpec Signed-off-by: MdSahil-oss * Added context.go file with loadVariable() Signed-off-by: MdSahil-oss * Added loadAPIData() in context.go and called from handlers.go Signed-off-by: MdSahil-oss * Added conditionals for not supported context variables Signed-off-by: MdSahil-oss * Reverted versions in CRDs Signed-off-by: MdSahil-oss * Reverted CRDs to v0.11.1 Signed-off-by: MdSahil-oss * Imported fmt in handlers.go Signed-off-by: MdSahil-oss * Removed duplicate import Signed-off-by: MdSahil-oss * make verify-codegen Signed-off-by: MdSahil-oss * Updated kuttl test Signed-off-by: MdSahil-oss * Fixed kuttl failure Signed-off-by: MdSahil-oss * moved policy check to validation Signed-off-by: MdSahil-oss * Reused functions Signed-off-by: MdSahil-oss * Added kuttl test Signed-off-by: MdSahil-oss * Added more configMap Signed-off-by: MdSahil-oss * removed unecessary check Signed-off-by: MdSahil-oss * auto codegen Signed-off-by: MdSahil-oss * updated codegen Signed-off-by: MdSahil-oss * Renamed ApplyJMESPath() to applyJMESPath() Signed-off-by: MdSahil-oss --------- Signed-off-by: MdSahil-oss Co-authored-by: shuting Co-authored-by: Chip Zoller Co-authored-by: Charles-Edouard Brétéché --- api/kyverno/v2alpha1/cleanup_policy_types.go | 17 ++ api/kyverno/v2alpha1/zz_generated.deepcopy.go | 12 +- charts/kyverno/templates/crds/crds.yaml | 238 ++++++++++++++++++ .../handlers/cleanup/handlers.go | 19 +- config/crds/kyverno.io_cleanuppolicies.yaml | 119 +++++++++ .../kyverno.io_clustercleanuppolicies.yaml | 119 +++++++++ config/install-latest-testing.yaml | 238 ++++++++++++++++++ docs/user/crd/index.html | 43 ++++ pkg/validation/cleanuppolicy/validate.go | 2 +- .../clusterpolicy/cleanup-pod/policy.yaml | 20 +- .../context-cleanup-pod/01-rbac.yaml | 4 + .../context-cleanup-pod/02-pod.yaml | 6 + .../context-cleanup-pod/03-policy.yaml | 6 + .../context-cleanup-pod/04-sleep.yaml | 4 + .../context-cleanup-pod/05-check.yaml | 4 + .../context-cleanup-pod/pod-assert.yaml | 5 + .../context-cleanup-pod/pod.yaml | 9 + .../context-cleanup-pod/policy.yaml | 28 +++ .../context-cleanup-pod/rbac.yaml | 26 ++ .../01-cleanup-policy.yaml | 7 + .../cleanuppolicy-with-configmap.yaml | 25 ++ .../cleanuppolicy-with-image-registry.yaml | 24 ++ 22 files changed, 961 insertions(+), 14 deletions(-) create mode 100644 test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/01-rbac.yaml create mode 100644 test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/02-pod.yaml create mode 100644 test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/03-policy.yaml create mode 100644 test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/04-sleep.yaml create mode 100644 test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/05-check.yaml create mode 100644 test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/pod-assert.yaml create mode 100644 test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/pod.yaml create mode 100644 test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/policy.yaml create mode 100644 test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/rbac.yaml create mode 100644 test/conformance/kuttl/cleanup/validation/not-supported-attributes-in-context/01-cleanup-policy.yaml create mode 100644 test/conformance/kuttl/cleanup/validation/not-supported-attributes-in-context/cleanuppolicy-with-configmap.yaml create mode 100644 test/conformance/kuttl/cleanup/validation/not-supported-attributes-in-context/cleanuppolicy-with-image-registry.yaml diff --git a/api/kyverno/v2alpha1/cleanup_policy_types.go b/api/kyverno/v2alpha1/cleanup_policy_types.go index 479249d0c8..d33c2aada6 100644 --- a/api/kyverno/v2alpha1/cleanup_policy_types.go +++ b/api/kyverno/v2alpha1/cleanup_policy_types.go @@ -148,6 +148,10 @@ type ClusterCleanupPolicyList struct { // CleanupPolicySpec stores specifications for selecting resources that the user needs to delete // and schedule when the matching resources needs deleted. type CleanupPolicySpec struct { + // Context defines variables and data sources that can be used during rule execution. + // +optional + Context []kyvernov1.ContextEntry `json:"context,omitempty" yaml:"context,omitempty"` + // MatchResources defines when cleanuppolicy should be applied. The match // criteria can include resource information (e.g. kind, name, namespace, labels) // and admission review request information like the user name or role. @@ -175,6 +179,8 @@ type CleanupPolicyStatus struct { // Validate implements programmatic validation func (p *CleanupPolicySpec) Validate(path *field.Path, clusterResources sets.Set[string], namespaced bool) (errs field.ErrorList) { + // Write context validation code here by following other validations. + errs = append(errs, ValidateContext(path.Child("context"), p.Context)...) errs = append(errs, ValidateSchedule(path.Child("schedule"), p.Schedule)...) if userInfoErrs := p.MatchResources.ValidateNoUserInfo(path.Child("match")); len(userInfoErrs) != 0 { errs = append(errs, userInfoErrs...) @@ -192,6 +198,17 @@ func (p *CleanupPolicySpec) Validate(path *field.Path, clusterResources sets.Set return errs } +func ValidateContext(path *field.Path, context []kyvernov1.ContextEntry) (errs field.ErrorList) { + for _, entry := range context { + if entry.ImageRegistry != nil { + errs = append(errs, field.Invalid(path, context, "ImageRegistry is not allowed in CleanUp Policy")) + } else if entry.ConfigMap != nil { + errs = append(errs, field.Invalid(path, context, "ConfigMap is not allowed in CleanUp Policy")) + } + } + return errs +} + // ValidateSchedule validates whether the schedule specified is in proper cron format or not. func ValidateSchedule(path *field.Path, schedule string) (errs field.ErrorList) { if _, err := cron.ParseStandard(schedule); err != nil { diff --git a/api/kyverno/v2alpha1/zz_generated.deepcopy.go b/api/kyverno/v2alpha1/zz_generated.deepcopy.go index 7a1fb2b4c8..2a1750ffe8 100644 --- a/api/kyverno/v2alpha1/zz_generated.deepcopy.go +++ b/api/kyverno/v2alpha1/zz_generated.deepcopy.go @@ -22,8 +22,9 @@ limitations under the License. package v2alpha1 import ( + v1 "github.com/kyverno/kyverno/api/kyverno/v1" "github.com/kyverno/kyverno/api/kyverno/v2beta1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" ) @@ -89,6 +90,13 @@ func (in *CleanupPolicyList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CleanupPolicySpec) DeepCopyInto(out *CleanupPolicySpec) { *out = *in + if in.Context != nil { + in, out := &in.Context, &out.Context + *out = make([]v1.ContextEntry, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } in.MatchResources.DeepCopyInto(&out.MatchResources) if in.ExcludeResources != nil { in, out := &in.ExcludeResources, &out.ExcludeResources @@ -117,7 +125,7 @@ func (in *CleanupPolicyStatus) DeepCopyInto(out *CleanupPolicyStatus) { *out = *in if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) + *out = make([]metav1.Condition, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } diff --git a/charts/kyverno/templates/crds/crds.yaml b/charts/kyverno/templates/crds/crds.yaml index 86889db5a6..6933952a5f 100644 --- a/charts/kyverno/templates/crds/crds.yaml +++ b/charts/kyverno/templates/crds/crds.yaml @@ -778,6 +778,125 @@ spec: type: object type: array type: object + context: + description: Context defines variables and data sources that can be + used during rule execution. + items: + description: ContextEntry adds variables and data sources to a rule + Context. Either a ConfigMap reference or a APILookup must be provided. + properties: + apiCall: + description: APICall is an HTTP request to the Kubernetes API + server, or other JSON web service. The data returned is stored + in the context with the name for the context entry. + properties: + jmesPath: + description: JMESPath is an optional JSON Match Expression + that can be used to transform the JSON response returned + from the server. For example a JMESPath of "items | length(@)" + applied to the API server response for the URLPath "/apis/apps/v1/deployments" + will return the total count of deployments across all + namespaces. + type: string + service: + description: Service is an API call to a JSON web service + properties: + caBundle: + description: CABundle is a PEM encoded CA bundle which + will be used to validate the server certificate. + type: string + data: + description: Data specifies the POST data sent to the + server. + items: + description: RequestData contains the HTTP POST data + properties: + key: + description: Key is a unique identifier for the + data value + type: string + value: + description: Value is the data value + x-kubernetes-preserve-unknown-fields: true + required: + - key + - value + type: object + type: array + requestType: + default: GET + description: Method is the HTTP request type (GET or + POST). + enum: + - GET + - POST + type: string + urlPath: + description: URL is the JSON web service URL. The typical + format is `https://{service}.{namespace}:{port}/{path}`. + type: string + required: + - requestType + - urlPath + type: object + urlPath: + description: URLPath is the URL path to be used in the HTTP + GET request to the Kubernetes API server (e.g. "/api/v1/namespaces" + or "/apis/apps/v1/deployments"). The format required + is the same format used by the `kubectl get --raw` command. + type: string + type: object + configMap: + description: ConfigMap is the ConfigMap reference. + properties: + name: + description: Name is the ConfigMap name. + type: string + namespace: + description: Namespace is the ConfigMap namespace. + type: string + required: + - name + type: object + imageRegistry: + description: ImageRegistry defines requests to an OCI/Docker + V2 registry to fetch image details. + properties: + jmesPath: + description: JMESPath is an optional JSON Match Expression + that can be used to transform the ImageData struct returned + as a result of processing the image reference. + type: string + reference: + description: 'Reference is image reference to a container + image in the registry. Example: ghcr.io/kyverno/kyverno:latest' + type: string + required: + - reference + type: object + name: + description: Name is the variable name. + type: string + variable: + description: Variable defines an arbitrary JMESPath context + variable that can be defined inline. + properties: + default: + description: Default is an optional arbitrary JSON object + that the variable may take if the JMESPath expression + evaluates to nil + x-kubernetes-preserve-unknown-fields: true + jmesPath: + description: JMESPath is an optional JMESPath Expression + that can be used to transform the variable. + type: string + value: + description: Value is any arbitrary JSON object representable + in YAML or JSON form. + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + type: array exclude: description: ExcludeResources defines when cleanuppolicy should not be applied. The exclude criteria can include resource information @@ -2529,6 +2648,125 @@ spec: type: object type: array type: object + context: + description: Context defines variables and data sources that can be + used during rule execution. + items: + description: ContextEntry adds variables and data sources to a rule + Context. Either a ConfigMap reference or a APILookup must be provided. + properties: + apiCall: + description: APICall is an HTTP request to the Kubernetes API + server, or other JSON web service. The data returned is stored + in the context with the name for the context entry. + properties: + jmesPath: + description: JMESPath is an optional JSON Match Expression + that can be used to transform the JSON response returned + from the server. For example a JMESPath of "items | length(@)" + applied to the API server response for the URLPath "/apis/apps/v1/deployments" + will return the total count of deployments across all + namespaces. + type: string + service: + description: Service is an API call to a JSON web service + properties: + caBundle: + description: CABundle is a PEM encoded CA bundle which + will be used to validate the server certificate. + type: string + data: + description: Data specifies the POST data sent to the + server. + items: + description: RequestData contains the HTTP POST data + properties: + key: + description: Key is a unique identifier for the + data value + type: string + value: + description: Value is the data value + x-kubernetes-preserve-unknown-fields: true + required: + - key + - value + type: object + type: array + requestType: + default: GET + description: Method is the HTTP request type (GET or + POST). + enum: + - GET + - POST + type: string + urlPath: + description: URL is the JSON web service URL. The typical + format is `https://{service}.{namespace}:{port}/{path}`. + type: string + required: + - requestType + - urlPath + type: object + urlPath: + description: URLPath is the URL path to be used in the HTTP + GET request to the Kubernetes API server (e.g. "/api/v1/namespaces" + or "/apis/apps/v1/deployments"). The format required + is the same format used by the `kubectl get --raw` command. + type: string + type: object + configMap: + description: ConfigMap is the ConfigMap reference. + properties: + name: + description: Name is the ConfigMap name. + type: string + namespace: + description: Namespace is the ConfigMap namespace. + type: string + required: + - name + type: object + imageRegistry: + description: ImageRegistry defines requests to an OCI/Docker + V2 registry to fetch image details. + properties: + jmesPath: + description: JMESPath is an optional JSON Match Expression + that can be used to transform the ImageData struct returned + as a result of processing the image reference. + type: string + reference: + description: 'Reference is image reference to a container + image in the registry. Example: ghcr.io/kyverno/kyverno:latest' + type: string + required: + - reference + type: object + name: + description: Name is the variable name. + type: string + variable: + description: Variable defines an arbitrary JMESPath context + variable that can be defined inline. + properties: + default: + description: Default is an optional arbitrary JSON object + that the variable may take if the JMESPath expression + evaluates to nil + x-kubernetes-preserve-unknown-fields: true + jmesPath: + description: JMESPath is an optional JMESPath Expression + that can be used to transform the variable. + type: string + value: + description: Value is any arbitrary JSON object representable + in YAML or JSON form. + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + type: array exclude: description: ExcludeResources defines when cleanuppolicy should not be applied. The exclude criteria can include resource information diff --git a/cmd/cleanup-controller/handlers/cleanup/handlers.go b/cmd/cleanup-controller/handlers/cleanup/handlers.go index aaa1c2c17a..9e8ef79233 100644 --- a/cmd/cleanup-controller/handlers/cleanup/handlers.go +++ b/cmd/cleanup-controller/handlers/cleanup/handlers.go @@ -10,6 +10,7 @@ import ( kyvernov2alpha1listers "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v2alpha1" "github.com/kyverno/kyverno/pkg/clients/dclient" "github.com/kyverno/kyverno/pkg/config" + engineapi "github.com/kyverno/kyverno/pkg/engine/api" enginecontext "github.com/kyverno/kyverno/pkg/engine/context" "github.com/kyverno/kyverno/pkg/engine/jmespath" "github.com/kyverno/kyverno/pkg/event" @@ -112,6 +113,22 @@ func (h *handlers) executePolicy(ctx context.Context, logger logr.Logger, policy kinds := sets.New(spec.MatchResources.GetKinds()...) debug := logger.V(4) var errs []error + enginectx := enginecontext.NewContext(h.jp) + + if spec.Context != nil { + for _, entry := range spec.Context { + if entry.APICall != nil { + if err := engineapi.LoadAPIData(ctx, h.jp, logger, entry, enginectx, h.client); err != nil { + return err + } + } else if entry.Variable != nil { + if err := engineapi.LoadVariable(logger, h.jp, entry, enginectx); err != nil { + return err + } + } + } + } + for kind := range kinds { commonLabels := []attribute.KeyValue{ attribute.String("policy_type", policy.GetKind()), @@ -185,7 +202,7 @@ func (h *handlers) executePolicy(ctx context.Context, logger logr.Logger, policy } // check conditions if spec.Conditions != nil { - enginectx := enginecontext.NewContext(h.jp) + enginectx.Reset() if err := enginectx.AddTargetResource(resource.Object); err != nil { debug.Error(err, "failed to add resource in context") errs = append(errs, err) diff --git a/config/crds/kyverno.io_cleanuppolicies.yaml b/config/crds/kyverno.io_cleanuppolicies.yaml index d4bdb7cd9d..053b4baffc 100644 --- a/config/crds/kyverno.io_cleanuppolicies.yaml +++ b/config/crds/kyverno.io_cleanuppolicies.yaml @@ -131,6 +131,125 @@ spec: type: object type: array type: object + context: + description: Context defines variables and data sources that can be + used during rule execution. + items: + description: ContextEntry adds variables and data sources to a rule + Context. Either a ConfigMap reference or a APILookup must be provided. + properties: + apiCall: + description: APICall is an HTTP request to the Kubernetes API + server, or other JSON web service. The data returned is stored + in the context with the name for the context entry. + properties: + jmesPath: + description: JMESPath is an optional JSON Match Expression + that can be used to transform the JSON response returned + from the server. For example a JMESPath of "items | length(@)" + applied to the API server response for the URLPath "/apis/apps/v1/deployments" + will return the total count of deployments across all + namespaces. + type: string + service: + description: Service is an API call to a JSON web service + properties: + caBundle: + description: CABundle is a PEM encoded CA bundle which + will be used to validate the server certificate. + type: string + data: + description: Data specifies the POST data sent to the + server. + items: + description: RequestData contains the HTTP POST data + properties: + key: + description: Key is a unique identifier for the + data value + type: string + value: + description: Value is the data value + x-kubernetes-preserve-unknown-fields: true + required: + - key + - value + type: object + type: array + requestType: + default: GET + description: Method is the HTTP request type (GET or + POST). + enum: + - GET + - POST + type: string + urlPath: + description: URL is the JSON web service URL. The typical + format is `https://{service}.{namespace}:{port}/{path}`. + type: string + required: + - requestType + - urlPath + type: object + urlPath: + description: URLPath is the URL path to be used in the HTTP + GET request to the Kubernetes API server (e.g. "/api/v1/namespaces" + or "/apis/apps/v1/deployments"). The format required + is the same format used by the `kubectl get --raw` command. + type: string + type: object + configMap: + description: ConfigMap is the ConfigMap reference. + properties: + name: + description: Name is the ConfigMap name. + type: string + namespace: + description: Namespace is the ConfigMap namespace. + type: string + required: + - name + type: object + imageRegistry: + description: ImageRegistry defines requests to an OCI/Docker + V2 registry to fetch image details. + properties: + jmesPath: + description: JMESPath is an optional JSON Match Expression + that can be used to transform the ImageData struct returned + as a result of processing the image reference. + type: string + reference: + description: 'Reference is image reference to a container + image in the registry. Example: ghcr.io/kyverno/kyverno:latest' + type: string + required: + - reference + type: object + name: + description: Name is the variable name. + type: string + variable: + description: Variable defines an arbitrary JMESPath context + variable that can be defined inline. + properties: + default: + description: Default is an optional arbitrary JSON object + that the variable may take if the JMESPath expression + evaluates to nil + x-kubernetes-preserve-unknown-fields: true + jmesPath: + description: JMESPath is an optional JMESPath Expression + that can be used to transform the variable. + type: string + value: + description: Value is any arbitrary JSON object representable + in YAML or JSON form. + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + type: array exclude: description: ExcludeResources defines when cleanuppolicy should not be applied. The exclude criteria can include resource information diff --git a/config/crds/kyverno.io_clustercleanuppolicies.yaml b/config/crds/kyverno.io_clustercleanuppolicies.yaml index fb26632a27..c109cb65c7 100644 --- a/config/crds/kyverno.io_clustercleanuppolicies.yaml +++ b/config/crds/kyverno.io_clustercleanuppolicies.yaml @@ -131,6 +131,125 @@ spec: type: object type: array type: object + context: + description: Context defines variables and data sources that can be + used during rule execution. + items: + description: ContextEntry adds variables and data sources to a rule + Context. Either a ConfigMap reference or a APILookup must be provided. + properties: + apiCall: + description: APICall is an HTTP request to the Kubernetes API + server, or other JSON web service. The data returned is stored + in the context with the name for the context entry. + properties: + jmesPath: + description: JMESPath is an optional JSON Match Expression + that can be used to transform the JSON response returned + from the server. For example a JMESPath of "items | length(@)" + applied to the API server response for the URLPath "/apis/apps/v1/deployments" + will return the total count of deployments across all + namespaces. + type: string + service: + description: Service is an API call to a JSON web service + properties: + caBundle: + description: CABundle is a PEM encoded CA bundle which + will be used to validate the server certificate. + type: string + data: + description: Data specifies the POST data sent to the + server. + items: + description: RequestData contains the HTTP POST data + properties: + key: + description: Key is a unique identifier for the + data value + type: string + value: + description: Value is the data value + x-kubernetes-preserve-unknown-fields: true + required: + - key + - value + type: object + type: array + requestType: + default: GET + description: Method is the HTTP request type (GET or + POST). + enum: + - GET + - POST + type: string + urlPath: + description: URL is the JSON web service URL. The typical + format is `https://{service}.{namespace}:{port}/{path}`. + type: string + required: + - requestType + - urlPath + type: object + urlPath: + description: URLPath is the URL path to be used in the HTTP + GET request to the Kubernetes API server (e.g. "/api/v1/namespaces" + or "/apis/apps/v1/deployments"). The format required + is the same format used by the `kubectl get --raw` command. + type: string + type: object + configMap: + description: ConfigMap is the ConfigMap reference. + properties: + name: + description: Name is the ConfigMap name. + type: string + namespace: + description: Namespace is the ConfigMap namespace. + type: string + required: + - name + type: object + imageRegistry: + description: ImageRegistry defines requests to an OCI/Docker + V2 registry to fetch image details. + properties: + jmesPath: + description: JMESPath is an optional JSON Match Expression + that can be used to transform the ImageData struct returned + as a result of processing the image reference. + type: string + reference: + description: 'Reference is image reference to a container + image in the registry. Example: ghcr.io/kyverno/kyverno:latest' + type: string + required: + - reference + type: object + name: + description: Name is the variable name. + type: string + variable: + description: Variable defines an arbitrary JMESPath context + variable that can be defined inline. + properties: + default: + description: Default is an optional arbitrary JSON object + that the variable may take if the JMESPath expression + evaluates to nil + x-kubernetes-preserve-unknown-fields: true + jmesPath: + description: JMESPath is an optional JMESPath Expression + that can be used to transform the variable. + type: string + value: + description: Value is any arbitrary JSON object representable + in YAML or JSON form. + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + type: array exclude: description: ExcludeResources defines when cleanuppolicy should not be applied. The exclude criteria can include resource information diff --git a/config/install-latest-testing.yaml b/config/install-latest-testing.yaml index 7b346141a3..d82d5a49da 100644 --- a/config/install-latest-testing.yaml +++ b/config/install-latest-testing.yaml @@ -971,6 +971,125 @@ spec: type: object type: array type: object + context: + description: Context defines variables and data sources that can be + used during rule execution. + items: + description: ContextEntry adds variables and data sources to a rule + Context. Either a ConfigMap reference or a APILookup must be provided. + properties: + apiCall: + description: APICall is an HTTP request to the Kubernetes API + server, or other JSON web service. The data returned is stored + in the context with the name for the context entry. + properties: + jmesPath: + description: JMESPath is an optional JSON Match Expression + that can be used to transform the JSON response returned + from the server. For example a JMESPath of "items | length(@)" + applied to the API server response for the URLPath "/apis/apps/v1/deployments" + will return the total count of deployments across all + namespaces. + type: string + service: + description: Service is an API call to a JSON web service + properties: + caBundle: + description: CABundle is a PEM encoded CA bundle which + will be used to validate the server certificate. + type: string + data: + description: Data specifies the POST data sent to the + server. + items: + description: RequestData contains the HTTP POST data + properties: + key: + description: Key is a unique identifier for the + data value + type: string + value: + description: Value is the data value + x-kubernetes-preserve-unknown-fields: true + required: + - key + - value + type: object + type: array + requestType: + default: GET + description: Method is the HTTP request type (GET or + POST). + enum: + - GET + - POST + type: string + urlPath: + description: URL is the JSON web service URL. The typical + format is `https://{service}.{namespace}:{port}/{path}`. + type: string + required: + - requestType + - urlPath + type: object + urlPath: + description: URLPath is the URL path to be used in the HTTP + GET request to the Kubernetes API server (e.g. "/api/v1/namespaces" + or "/apis/apps/v1/deployments"). The format required + is the same format used by the `kubectl get --raw` command. + type: string + type: object + configMap: + description: ConfigMap is the ConfigMap reference. + properties: + name: + description: Name is the ConfigMap name. + type: string + namespace: + description: Namespace is the ConfigMap namespace. + type: string + required: + - name + type: object + imageRegistry: + description: ImageRegistry defines requests to an OCI/Docker + V2 registry to fetch image details. + properties: + jmesPath: + description: JMESPath is an optional JSON Match Expression + that can be used to transform the ImageData struct returned + as a result of processing the image reference. + type: string + reference: + description: 'Reference is image reference to a container + image in the registry. Example: ghcr.io/kyverno/kyverno:latest' + type: string + required: + - reference + type: object + name: + description: Name is the variable name. + type: string + variable: + description: Variable defines an arbitrary JMESPath context + variable that can be defined inline. + properties: + default: + description: Default is an optional arbitrary JSON object + that the variable may take if the JMESPath expression + evaluates to nil + x-kubernetes-preserve-unknown-fields: true + jmesPath: + description: JMESPath is an optional JMESPath Expression + that can be used to transform the variable. + type: string + value: + description: Value is any arbitrary JSON object representable + in YAML or JSON form. + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + type: array exclude: description: ExcludeResources defines when cleanuppolicy should not be applied. The exclude criteria can include resource information @@ -2722,6 +2841,125 @@ spec: type: object type: array type: object + context: + description: Context defines variables and data sources that can be + used during rule execution. + items: + description: ContextEntry adds variables and data sources to a rule + Context. Either a ConfigMap reference or a APILookup must be provided. + properties: + apiCall: + description: APICall is an HTTP request to the Kubernetes API + server, or other JSON web service. The data returned is stored + in the context with the name for the context entry. + properties: + jmesPath: + description: JMESPath is an optional JSON Match Expression + that can be used to transform the JSON response returned + from the server. For example a JMESPath of "items | length(@)" + applied to the API server response for the URLPath "/apis/apps/v1/deployments" + will return the total count of deployments across all + namespaces. + type: string + service: + description: Service is an API call to a JSON web service + properties: + caBundle: + description: CABundle is a PEM encoded CA bundle which + will be used to validate the server certificate. + type: string + data: + description: Data specifies the POST data sent to the + server. + items: + description: RequestData contains the HTTP POST data + properties: + key: + description: Key is a unique identifier for the + data value + type: string + value: + description: Value is the data value + x-kubernetes-preserve-unknown-fields: true + required: + - key + - value + type: object + type: array + requestType: + default: GET + description: Method is the HTTP request type (GET or + POST). + enum: + - GET + - POST + type: string + urlPath: + description: URL is the JSON web service URL. The typical + format is `https://{service}.{namespace}:{port}/{path}`. + type: string + required: + - requestType + - urlPath + type: object + urlPath: + description: URLPath is the URL path to be used in the HTTP + GET request to the Kubernetes API server (e.g. "/api/v1/namespaces" + or "/apis/apps/v1/deployments"). The format required + is the same format used by the `kubectl get --raw` command. + type: string + type: object + configMap: + description: ConfigMap is the ConfigMap reference. + properties: + name: + description: Name is the ConfigMap name. + type: string + namespace: + description: Namespace is the ConfigMap namespace. + type: string + required: + - name + type: object + imageRegistry: + description: ImageRegistry defines requests to an OCI/Docker + V2 registry to fetch image details. + properties: + jmesPath: + description: JMESPath is an optional JSON Match Expression + that can be used to transform the ImageData struct returned + as a result of processing the image reference. + type: string + reference: + description: 'Reference is image reference to a container + image in the registry. Example: ghcr.io/kyverno/kyverno:latest' + type: string + required: + - reference + type: object + name: + description: Name is the variable name. + type: string + variable: + description: Variable defines an arbitrary JMESPath context + variable that can be defined inline. + properties: + default: + description: Default is an optional arbitrary JSON object + that the variable may take if the JMESPath expression + evaluates to nil + x-kubernetes-preserve-unknown-fields: true + jmesPath: + description: JMESPath is an optional JMESPath Expression + that can be used to transform the variable. + type: string + value: + description: Value is any arbitrary JSON object representable + in YAML or JSON form. + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + type: array exclude: description: ExcludeResources defines when cleanuppolicy should not be applied. The exclude criteria can include resource information diff --git a/docs/user/crd/index.html b/docs/user/crd/index.html index 48b5010140..2837f1b7e2 100644 --- a/docs/user/crd/index.html +++ b/docs/user/crd/index.html @@ -1154,6 +1154,7 @@ string ForEachValidation, Rule, TargetResourceSpec, +CleanupPolicySpec, Rule)

@@ -4970,6 +4971,20 @@ CleanupPolicySpec + + + +
+context
+ + +[]ContextEntry + + +
+(Optional) +

Context defines variables and data sources that can be used during rule execution.

+
match
@@ -5105,6 +5120,20 @@ CleanupPolicySpec + + + + + + + +
+context
+ + +[]ContextEntry + + +
+(Optional) +

Context defines variables and data sources that can be used during rule execution.

+
match
@@ -5309,6 +5338,20 @@ and schedule when the matching resources needs deleted.

+context
+ + +[]ContextEntry + + +
+(Optional) +

Context defines variables and data sources that can be used during rule execution.

+
match
diff --git a/pkg/validation/cleanuppolicy/validate.go b/pkg/validation/cleanuppolicy/validate.go index ec160bac4a..a48853e70f 100644 --- a/pkg/validation/cleanuppolicy/validate.go +++ b/pkg/validation/cleanuppolicy/validate.go @@ -102,4 +102,4 @@ func validateVariables(logger logr.Logger, policy kyvernov2alpha1.CleanupPolicyI return nil } -var allowedVariables = regexp.MustCompile(`target\.|images\.|([a-z_0-9]+\()[^{}]`) +var allowedVariables = regexp.MustCompile(`([a-z_0-9]+)|(target\.|images\.|([a-z_0-9]+\()[^{}])`) diff --git a/test/conformance/kuttl/cleanup/clusterpolicy/cleanup-pod/policy.yaml b/test/conformance/kuttl/cleanup/clusterpolicy/cleanup-pod/policy.yaml index 44e0f0fdb1..c379b27860 100644 --- a/test/conformance/kuttl/cleanup/clusterpolicy/cleanup-pod/policy.yaml +++ b/test/conformance/kuttl/cleanup/clusterpolicy/cleanup-pod/policy.yaml @@ -5,16 +5,16 @@ metadata: spec: match: any: - - resources: - kinds: - - Pod + - resources: + kinds: + - Pod conditions: all: - - key: "{{ target.metadata.name }}" - operator: Equals - value: example - - key: "{{ target.metadata.namespace }}" - operator: Equals - value: default + - key: "{{ target.metadata.name }}" + operator: Equals + value: example + - key: "{{ target.metadata.namespace }}" + operator: Equals + value: default ## execute every minute - schedule: "*/1 * * * *" + schedule: "*/1 * * * *" \ No newline at end of file diff --git a/test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/01-rbac.yaml b/test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/01-rbac.yaml new file mode 100644 index 0000000000..170a96da85 --- /dev/null +++ b/test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/01-rbac.yaml @@ -0,0 +1,4 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +apply: +- rbac.yaml diff --git a/test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/02-pod.yaml b/test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/02-pod.yaml new file mode 100644 index 0000000000..3e1752d840 --- /dev/null +++ b/test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/02-pod.yaml @@ -0,0 +1,6 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +apply: +- pod.yaml +assert: +- pod-assert.yaml diff --git a/test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/03-policy.yaml b/test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/03-policy.yaml new file mode 100644 index 0000000000..a2918426aa --- /dev/null +++ b/test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/03-policy.yaml @@ -0,0 +1,6 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +apply: +- policy.yaml +assert: +- policy.yaml diff --git a/test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/04-sleep.yaml b/test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/04-sleep.yaml new file mode 100644 index 0000000000..799c8968c8 --- /dev/null +++ b/test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/04-sleep.yaml @@ -0,0 +1,4 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: sleep 5 diff --git a/test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/05-check.yaml b/test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/05-check.yaml new file mode 100644 index 0000000000..7916be6554 --- /dev/null +++ b/test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/05-check.yaml @@ -0,0 +1,4 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +error: +- pod-assert.yaml diff --git a/test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/pod-assert.yaml b/test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/pod-assert.yaml new file mode 100644 index 0000000000..99bac5fb09 --- /dev/null +++ b/test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/pod-assert.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: Pod +metadata: + name: example + namespace: default diff --git a/test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/pod.yaml b/test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/pod.yaml new file mode 100644 index 0000000000..91b8d5074d --- /dev/null +++ b/test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/pod.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Pod +metadata: + name: example + namespace: default +spec: + containers: + - image: nginx:latest + name: example diff --git a/test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/policy.yaml b/test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/policy.yaml new file mode 100644 index 0000000000..99f37b435e --- /dev/null +++ b/test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/policy.yaml @@ -0,0 +1,28 @@ +apiVersion: kyverno.io/v2alpha1 +kind: ClusterCleanupPolicy +metadata: + name: cleanup-pod +spec: + context: + - name: varNamespace + apiCall: + urlPath: "/api/v1/namespaces/default" + jmesPath: metadata.name + - name: varname + variable: + value: "example" + match: + any: + - resources: + kinds: + - Pod + conditions: + all: + - key: "{{ target.metadata.name }}" + operator: Equals + value: "{{ varname }}" + - key: "{{ target.metadata.namespace }}" + operator: Equals + value: "{{ varNamespace }}" + ## execute every minute + schedule: "*/1 * * * *" diff --git a/test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/rbac.yaml b/test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/rbac.yaml new file mode 100644 index 0000000000..a9af733222 --- /dev/null +++ b/test/conformance/kuttl/cleanup/clusterpolicy/context-cleanup-pod/rbac.yaml @@ -0,0 +1,26 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: test-cleanup-pod +rules: +- apiGroups: + - "" + resources: + - pods + verbs: + - delete + - list + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: test-cleanup-pod +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: test-cleanup-pod +subjects: +- kind: ServiceAccount + name: kyverno-cleanup-controller + namespace: kyverno diff --git a/test/conformance/kuttl/cleanup/validation/not-supported-attributes-in-context/01-cleanup-policy.yaml b/test/conformance/kuttl/cleanup/validation/not-supported-attributes-in-context/01-cleanup-policy.yaml new file mode 100644 index 0000000000..0dbd6ff48f --- /dev/null +++ b/test/conformance/kuttl/cleanup/validation/not-supported-attributes-in-context/01-cleanup-policy.yaml @@ -0,0 +1,7 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +apply: + - file: cleanuppolicy-with-image-registry.yaml + shouldFail: true + - file: cleanuppolicy-with-configmap.yaml + shouldFail: true diff --git a/test/conformance/kuttl/cleanup/validation/not-supported-attributes-in-context/cleanuppolicy-with-configmap.yaml b/test/conformance/kuttl/cleanup/validation/not-supported-attributes-in-context/cleanuppolicy-with-configmap.yaml new file mode 100644 index 0000000000..b120e7582c --- /dev/null +++ b/test/conformance/kuttl/cleanup/validation/not-supported-attributes-in-context/cleanuppolicy-with-configmap.yaml @@ -0,0 +1,25 @@ +apiVersion: kyverno.io/v2alpha1 +kind: ClusterCleanupPolicy +metadata: + name: cleanup-pod +spec: + context: + - name: configData + configMap: + name: some-config-map + namespace: default + match: + any: + - resources: + kinds: + - Pod + conditions: + all: + - key: "{{ target.metadata.name }}" + operator: Equals + value: example + - key: "{{ target.metadata.namespace }}" + operator: Equals + value: default + ## execute every minute + schedule: "*/1 * * * *" diff --git a/test/conformance/kuttl/cleanup/validation/not-supported-attributes-in-context/cleanuppolicy-with-image-registry.yaml b/test/conformance/kuttl/cleanup/validation/not-supported-attributes-in-context/cleanuppolicy-with-image-registry.yaml new file mode 100644 index 0000000000..2ddd825c57 --- /dev/null +++ b/test/conformance/kuttl/cleanup/validation/not-supported-attributes-in-context/cleanuppolicy-with-image-registry.yaml @@ -0,0 +1,24 @@ +apiVersion: kyverno.io/v2alpha1 +kind: ClusterCleanupPolicy +metadata: + name: cleanup-pod +spec: + context: + - name: imageData + imageRegistry: + reference: "ghcr.io/kyverno/kyverno" + match: + any: + - resources: + kinds: + - Pod + conditions: + all: + - key: "{{ target.metadata.name }}" + operator: Equals + value: "example" + - key: "{{ target.metadata.namespace }}" + operator: Equals + value: default + ## execute every minute + schedule: "*/1 * * * *"