1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-31 03:45:17 +00:00

feat: mutate existing resources (#3669)

* feat: mutate existing, replace GR by UR in webhook server (#3601)

* add attributes for post mutation

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* add UR informer to webhook server

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* - replace gr with ur in the webhook server; - create ur for mutateExsiting policies

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* replace gr by ur across entire packages

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* add YAMLs

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* update api docs & fix unit tests

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* add UR deletion handler

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* add api docs for v1beta1

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* fix clientset method

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* fix v1beta1 client registration

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* feat: mutate existing - generates UR for admission requests (#3623)

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* replace with UR in policy controller generate rules (#3635)

Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com>

* - enable mutate engine to process mutateExisting rules; - add unit tests

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* implemented ur background reconciliation for mutateExisting policies

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* fix webhook update error

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* temporary comment out new unit tests

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* feat: mutate existing, replace GR by UR in webhook server (#3601)

* add attributes for post mutation

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* add UR informer to webhook server

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* - replace gr with ur in the webhook server; - create ur for mutateExsiting policies

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* replace gr by ur across entire packages

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* fix missing policy.kyverno.io/policy-name label (#3599)

Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com>

* refactor cli code from pkg to cmd (#3591)

* refactor cli code from pkg to cmd

Signed-off-by: Mritunjay Sharma <mritunjaysharma394@gmail.com>

* fixes in imports

Signed-off-by: Mritunjay Sharma <mritunjaysharma394@gmail.com>

* fixes tests

Signed-off-by: Mritunjay Sharma <mritunjaysharma394@gmail.com>

* fixed conflicts

Signed-off-by: Mritunjay Sharma <mritunjaysharma394@gmail.com>

* moved non-commands to utils

Signed-off-by: Mritunjay Sharma <mritunjaysharma394@gmail.com>

Co-authored-by: Vyankatesh Kudtarkar <vyankateshkd@gmail.com>

* add YAMLs

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* update api docs & fix unit tests

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* add UR deletion handler

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* add api docs for v1beta1

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* fix clientset method

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* add-kms-libraries for cosign (#3603)

* add-kms-libraries

Signed-off-by: anushkamittal20 <anumittal4641@gmail.com>

* Shifted providers to cosign package

Signed-off-by: anushkamittal20 <anumittal4641@gmail.com>
Signed-off-by: ShutingZhao <shuting@nirmata.com>

* Add support for custom image extractors (#3596)

Signed-off-by: Sambhav Kothari <skothari44@bloomberg.net>

* Update vulnerable dependencies (#3577)

Signed-off-by: Shubham Gupta <shubham.gupta2956@gmail.com>

Co-authored-by: Jim Bugwadia <jim@nirmata.com>
Signed-off-by: ShutingZhao <shuting@nirmata.com>

* fix v1beta1 client registration

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* feat: mutate existing - generates UR for admission requests (#3623)

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* updating version in Chart.yaml (#3618)

* updatimg version in Chart.yaml

Signed-off-by: Prateeknandle <prateeknandle@gmail.com>

* changes from, make gen-helm

Signed-off-by: Prateeknandle <prateeknandle@gmail.com>

Co-authored-by: Vyankatesh Kudtarkar <vyankateshkd@gmail.com>
Signed-off-by: ShutingZhao <shuting@nirmata.com>

* Allow kyverno-policies to have preconditions defined (#3606)

* Allow kyverno-policies to have preconditions defined

Signed-off-by: Trey Dockendorf <tdockendorf@osc.edu>

* Fix docs

Signed-off-by: Trey Dockendorf <tdockendorf@osc.edu>
Signed-off-by: ShutingZhao <shuting@nirmata.com>

* replace with UR in policy controller generate rules (#3635)

Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com>
Signed-off-by: ShutingZhao <shuting@nirmata.com>

* - enable mutate engine to process mutateExisting rules; - add unit tests

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* implemented ur background reconciliation for mutateExisting policies

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* fix webhook update error

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* temporary comment out new unit tests

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* Image verify attestors (#3614)

* fix logs

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* fix logs

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* support multiple attestors

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* rm CLI tests (not currently supported)

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* apply attestor repo

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* fix linter issues

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* fix entryError assignment

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* fix tests

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* format

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* add intermediary certs

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* Allow defining imagePullSecrets (#3633)

* Allow defining imagePullSecrets

Signed-off-by: Trey Dockendorf <tdockendorf@osc.edu>

* Use dict for imagePullSecrets

Signed-off-by: Trey Dockendorf <tdockendorf@osc.edu>

* Simplify how imagePullSecrets is defined

Signed-off-by: Trey Dockendorf <tdockendorf@osc.edu>
Signed-off-by: ShutingZhao <shuting@nirmata.com>

* Fix race condition in pCache (#3632)

* fix race condition in pCache

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* refact: remove unused Run function from generate (#3638)

Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com>

* Remove helm mode setting (#3628)

Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>
Signed-off-by: ShutingZhao <shuting@nirmata.com>

* refactor: image utils (#3630)

Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>
Signed-off-by: ShutingZhao <shuting@nirmata.com>

* -resolve lift comments; -fix informer sync issue

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* refact the update request cleanup controller

Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com>

* - fix delete request for mutateExisting; - fix context variable substitution; - improve logging

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* - enable events; - add last applied annotation

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* enable mutate existing on policy creation

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* update autogen code

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* merge main

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* add unit tests

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* address list comments

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* update api docs

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* fix "Implicit memory aliasing in for loop"

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* remove unused definitions

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* update api docs

Signed-off-by: ShutingZhao <shuting@nirmata.com>

Co-authored-by: Prateek Pandey <prateek.pandey@nirmata.com>
Co-authored-by: Mritunjay Kumar Sharma <mritunjaysharma394@gmail.com>
Co-authored-by: Vyankatesh Kudtarkar <vyankateshkd@gmail.com>
Co-authored-by: Anushka Mittal <55237170+anushkamittal20@users.noreply.github.com>
Co-authored-by: Sambhav Kothari <sambhavs.email@gmail.com>
Co-authored-by: Shubham Gupta <shubham.gupta2956@gmail.com>
Co-authored-by: Jim Bugwadia <jim@nirmata.com>
Co-authored-by: Prateek Nandle <56027872+Prateeknandle@users.noreply.github.com>
Co-authored-by: treydock <tdockendorf@osc.edu>
Co-authored-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>
This commit is contained in:
shuting 2022-04-25 20:20:40 +08:00 committed by GitHub
parent cbf93ff004
commit 2a656f6de0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
82 changed files with 4239 additions and 1191 deletions

View file

@ -156,6 +156,7 @@ generate-api-docs: gen-crd-api-reference-docs ## Generate api reference docs
rm -rf docs/crd
mkdir docs/crd
gen-crd-api-reference-docs -v 6 -api-dir ./api/kyverno/v1alpha2 -config docs/config.json -template-dir docs/template -out-file docs/crd/v1alpha2/index.html
gen-crd-api-reference-docs -v 6 -api-dir ./api/kyverno/v1beta1 -config docs/config.json -template-dir docs/template -out-file docs/crd/v1beta1/index.html
gen-crd-api-reference-docs -v 6 -api-dir ./api/kyverno/v1 -config docs/config.json -template-dir docs/template -out-file docs/crd/v1/index.html
.PHONY: verify-api-docs

View file

@ -215,6 +215,18 @@ type ResourceFilter struct {
// Mutation defines how resource are modified.
type Mutation struct {
// mutateExisting controls whether to mutate existing resource ONLY
// The existing resources will be mutated ONLY if set to "true".
// Otherwise all resources including admission requests are mutated.
// Optional. Defaults to "false" if not specified.
// +optional
MutateExisting bool `json:"mutateExisting,omitempty" yaml:"mutatingExisting,omitempty"`
// Targets defines the target resources to be mutated.
// +optional
Targets []TargetMutation `json:"targets,omitempty" yaml:"targets,omitempty"`
// PatchStrategicMerge is a strategic merge patch used to modify resources.
// See https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/
// and https://kubectl.docs.kubernetes.io/references/kustomize/patchesstrategicmerge/.
@ -231,6 +243,12 @@ type Mutation struct {
ForEachMutation []*ForEachMutation `json:"foreach,omitempty" yaml:"foreach,omitempty"`
}
type TargetMutation struct {
// ResourceSpec specifies the target resource information.
// +optional
ResourceSpec `json:",omitempty" yaml:",omitempty"`
}
func (m *Mutation) GetPatchStrategicMerge() apiextensions.JSON {
return FromJSON(m.RawPatchStrategicMerge)
}

View file

@ -17,12 +17,12 @@ type ResourceDescription struct {
// Name is the name of the resource. The name supports wildcard characters
// "*" (matches zero or many characters) and "?" (at least one character).
// NOTE: "Name" is being deprecated in favor of "Names".
// +optional
Name string `json:"name,omitempty" yaml:"name,omitempty"`
// Names are the names of the resources. Each name supports wildcard characters
// "*" (matches zero or many characters) and "?" (at least one character).
// NOTE: "Name" is being deprecated in favor of "Names".
// +optional
Names []string `json:"names,omitempty" yaml:"names,omitempty"`

View file

@ -87,6 +87,11 @@ func (r *Rule) HasGenerate() bool {
return !reflect.DeepEqual(r.Generation, Generation{})
}
// IsMutatingExisting checks if the mutate rule applies to existing resources
func (r *Rule) IsMutateExisting() bool {
return r.Mutation.Targets != nil
}
func (r *Rule) GetAnyAllConditions() apiextensions.JSON {
return FromJSON(r.RawAnyAllConditions)
}

View file

@ -14,7 +14,7 @@ type ValidationFailureAction string
const (
// Enforce blocks the request on failure
Enforce ValidationFailureAction = "enforce"
// Audit indicates not to block the request on failure, but report failiures as policy violations
// Audit indicates not to block the request on failure, but report failures as policy violations
Audit ValidationFailureAction = "audit"
)

View file

@ -745,6 +745,11 @@ func (in *MatchResources) DeepCopy() *MatchResources {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Mutation) DeepCopyInto(out *Mutation) {
*out = *in
if in.Targets != nil {
in, out := &in.Targets, &out.Targets
*out = make([]TargetMutation, len(*in))
copy(*out, *in)
}
if in.RawPatchStrategicMerge != nil {
in, out := &in.RawPatchStrategicMerge, &out.RawPatchStrategicMerge
*out = new(apiextensionsv1.JSON)
@ -1110,6 +1115,22 @@ func (in *StaticKeyAttestor) DeepCopy() *StaticKeyAttestor {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TargetMutation) DeepCopyInto(out *TargetMutation) {
*out = *in
out.ResourceSpec = in.ResourceSpec
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TargetMutation.
func (in *TargetMutation) DeepCopy() *TargetMutation {
if in == nil {
return nil
}
out := new(TargetMutation)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *UserInfo) DeepCopyInto(out *UserInfo) {
*out = *in

View file

@ -0,0 +1,21 @@
/*
Copyright 2020 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.
*/
// Package v1beta1 contains API Schema definitions for the policy v1alpha1 API group
// +k8s:deepcopy-gen=package
// +kubebuilder:object:generate=true
// +groupName=kyverno.io
package v1beta1

View file

@ -52,7 +52,7 @@ type UpdateRequestStatus struct {
// +kubebuilder:printcolumn:name="ResourceNamespace",type="string",JSONPath=".spec.resource.namespace"
// +kubebuilder:printcolumn:name="status",type="string",JSONPath=".status.state"
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
// +kubebuilder:resource:shortName=gr
// +kubebuilder:resource:shortName=ur
type UpdateRequest struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
@ -65,8 +65,19 @@ type UpdateRequest struct {
Status UpdateRequestStatus `json:"status,omitempty"`
}
type RequestType string
const (
Mutate RequestType = "mutate"
Generate RequestType = "generate"
)
// UpdateRequestSpec stores the request specification.
type UpdateRequestSpec struct {
// Type represents request type for background processing
// +kubebuilder:validation:Enum=mutate;generate
Type RequestType `json:"requestType,omitempty" yaml:"requestType,omitempty"`
// Specifies the name of the policy.
Policy string `json:"policy" yaml:"policy"`
@ -139,3 +150,7 @@ type UpdateRequestList struct {
func init() {
SchemeBuilder.Register(&UpdateRequest{}, &UpdateRequestList{})
}
func (s *UpdateRequestSpec) GetRequestType() RequestType {
return s.Type
}

View file

@ -5,7 +5,6 @@ metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.8.0
config.kubernetes.io/index: '1'
internal.config.kubernetes.io/index: '1'
creationTimestamp: null
labels:
app.kubernetes.io/component: kyverno
@ -155,10 +154,10 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -281,10 +280,10 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -402,10 +401,10 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -585,10 +584,10 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -711,10 +710,10 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -832,10 +831,10 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -1082,12 +1081,34 @@ spec:
x-kubernetes-preserve-unknown-fields: true
type: object
type: array
mutateExisting:
description: mutateExisting controls whether to mutate existing resource ONLY The existing resources will be mutated ONLY if set to "true". Otherwise all resources including admission requests are mutated. Optional. Defaults to "false" if not specified.
type: boolean
patchStrategicMerge:
description: PatchStrategicMerge is a strategic merge patch used to modify resources. See https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/ and https://kubectl.docs.kubernetes.io/references/kustomize/patchesstrategicmerge/.
x-kubernetes-preserve-unknown-fields: true
patchesJson6902:
description: PatchesJSON6902 is a list of RFC 6902 JSON Patch declarations used to modify resources. See https://tools.ietf.org/html/rfc6902 and https://kubectl.docs.kubernetes.io/references/kustomize/patchesjson6902/.
type: string
targets:
description: Targets defines the target resources to be mutated.
items:
properties:
apiVersion:
description: APIVersion specifies resource apiVersion.
type: string
kind:
description: Kind specifies resource kind.
type: string
name:
description: Name specifies the resource name.
maxLength: 63
type: string
namespace:
description: Namespace specifies resource namespace.
type: string
type: object
type: array
type: object
name:
description: Name is a label to identify the rule, It must be unique within the policy.
@ -1661,10 +1682,10 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -1787,10 +1808,10 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -1908,10 +1929,10 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -2091,10 +2112,10 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -2217,10 +2238,10 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -2338,10 +2359,10 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -2588,12 +2609,34 @@ spec:
x-kubernetes-preserve-unknown-fields: true
type: object
type: array
mutateExisting:
description: mutateExisting controls whether to mutate existing resource ONLY The existing resources will be mutated ONLY if set to "true". Otherwise all resources including admission requests are mutated. Optional. Defaults to "false" if not specified.
type: boolean
patchStrategicMerge:
description: PatchStrategicMerge is a strategic merge patch used to modify resources. See https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/ and https://kubectl.docs.kubernetes.io/references/kustomize/patchesstrategicmerge/.
x-kubernetes-preserve-unknown-fields: true
patchesJson6902:
description: PatchesJSON6902 is a list of RFC 6902 JSON Patch declarations used to modify resources. See https://tools.ietf.org/html/rfc6902 and https://kubectl.docs.kubernetes.io/references/kustomize/patchesjson6902/.
type: string
targets:
description: Targets defines the target resources to be mutated.
items:
properties:
apiVersion:
description: APIVersion specifies resource apiVersion.
type: string
kind:
description: Kind specifies resource kind.
type: string
name:
description: Name specifies the resource name.
maxLength: 63
type: string
namespace:
description: Namespace specifies resource namespace.
type: string
type: object
type: array
type: object
name:
description: Name is a label to identify the rule, It must be unique within the policy.
@ -3000,7 +3043,6 @@ metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.8.0
config.kubernetes.io/index: '2'
internal.config.kubernetes.io/index: '2'
creationTimestamp: null
labels:
app.kubernetes.io/component: kyverno
@ -3272,7 +3314,6 @@ metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.8.0
config.kubernetes.io/index: '3'
internal.config.kubernetes.io/index: '3'
creationTimestamp: null
labels:
app.kubernetes.io/component: kyverno
@ -3544,7 +3585,6 @@ metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.8.0
config.kubernetes.io/index: '4'
internal.config.kubernetes.io/index: '4'
creationTimestamp: null
labels:
app.kubernetes.io/component: kyverno
@ -3728,7 +3768,6 @@ metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.8.0
config.kubernetes.io/index: '5'
internal.config.kubernetes.io/index: '5'
creationTimestamp: null
labels:
app.kubernetes.io/component: kyverno
@ -3878,10 +3917,10 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -4004,10 +4043,10 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -4125,10 +4164,10 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -4308,10 +4347,10 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -4434,10 +4473,10 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -4555,10 +4594,10 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -4805,12 +4844,34 @@ spec:
x-kubernetes-preserve-unknown-fields: true
type: object
type: array
mutateExisting:
description: mutateExisting controls whether to mutate existing resource ONLY The existing resources will be mutated ONLY if set to "true". Otherwise all resources including admission requests are mutated. Optional. Defaults to "false" if not specified.
type: boolean
patchStrategicMerge:
description: PatchStrategicMerge is a strategic merge patch used to modify resources. See https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/ and https://kubectl.docs.kubernetes.io/references/kustomize/patchesstrategicmerge/.
x-kubernetes-preserve-unknown-fields: true
patchesJson6902:
description: PatchesJSON6902 is a list of RFC 6902 JSON Patch declarations used to modify resources. See https://tools.ietf.org/html/rfc6902 and https://kubectl.docs.kubernetes.io/references/kustomize/patchesjson6902/.
type: string
targets:
description: Targets defines the target resources to be mutated.
items:
properties:
apiVersion:
description: APIVersion specifies resource apiVersion.
type: string
kind:
description: Kind specifies resource kind.
type: string
name:
description: Name specifies the resource name.
maxLength: 63
type: string
namespace:
description: Namespace specifies resource namespace.
type: string
type: object
type: array
type: object
name:
description: Name is a label to identify the rule, It must be unique within the policy.
@ -5384,10 +5445,10 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -5510,10 +5571,10 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -5631,10 +5692,10 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -5814,10 +5875,10 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -5940,10 +6001,10 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -6061,10 +6122,10 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character). NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each name supports wildcard characters "*" (matches zero or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -6311,12 +6372,34 @@ spec:
x-kubernetes-preserve-unknown-fields: true
type: object
type: array
mutateExisting:
description: mutateExisting controls whether to mutate existing resource ONLY The existing resources will be mutated ONLY if set to "true". Otherwise all resources including admission requests are mutated. Optional. Defaults to "false" if not specified.
type: boolean
patchStrategicMerge:
description: PatchStrategicMerge is a strategic merge patch used to modify resources. See https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/ and https://kubectl.docs.kubernetes.io/references/kustomize/patchesstrategicmerge/.
x-kubernetes-preserve-unknown-fields: true
patchesJson6902:
description: PatchesJSON6902 is a list of RFC 6902 JSON Patch declarations used to modify resources. See https://tools.ietf.org/html/rfc6902 and https://kubectl.docs.kubernetes.io/references/kustomize/patchesjson6902/.
type: string
targets:
description: Targets defines the target resources to be mutated.
items:
properties:
apiVersion:
description: APIVersion specifies resource apiVersion.
type: string
kind:
description: Kind specifies resource kind.
type: string
name:
description: Name specifies the resource name.
maxLength: 63
type: string
namespace:
description: Namespace specifies resource namespace.
type: string
type: object
type: array
type: object
name:
description: Name is a label to identify the rule, It must be unique within the policy.
@ -6723,7 +6806,6 @@ metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.8.0
config.kubernetes.io/index: '6'
internal.config.kubernetes.io/index: '6'
creationTimestamp: null
labels:
app.kubernetes.io/component: kyverno
@ -6995,7 +7077,6 @@ metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.8.0
config.kubernetes.io/index: '7'
internal.config.kubernetes.io/index: '7'
creationTimestamp: null
labels:
app.kubernetes.io/component: kyverno
@ -7260,4 +7341,191 @@ status:
plural: ""
conditions: []
storedVersions: []
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.8.0
config.kubernetes.io/index: '8'
creationTimestamp: null
labels:
app.kubernetes.io/component: kyverno
app.kubernetes.io/instance: kyverno
app.kubernetes.io/name: kyverno
app.kubernetes.io/part-of: kyverno
app.kubernetes.io/version: latest
name: updaterequests.kyverno.io
spec:
group: kyverno.io
names:
kind: UpdateRequest
listKind: UpdateRequestList
plural: updaterequests
shortNames:
- ur
singular: updaterequest
scope: Namespaced
versions:
- additionalPrinterColumns:
- jsonPath: .spec.policy
name: Policy
type: string
- jsonPath: .spec.resource.kind
name: ResourceKind
type: string
- jsonPath: .spec.resource.name
name: ResourceName
type: string
- jsonPath: .spec.resource.namespace
name: ResourceNamespace
type: string
- jsonPath: .status.state
name: status
type: string
- jsonPath: .metadata.creationTimestamp
name: Age
type: date
name: v1beta1
schema:
openAPIV3Schema:
description: UpdateRequestStatus is a request to process mutate and generate rules in background.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: Spec is the information to identify the update request.
properties:
context:
description: Context ...
properties:
admissionRequestInfo:
description: AdmissionRequestInfoObject stores the admission request and operation details
properties:
admissionRequest:
type: string
operation:
description: Operation is the type of resource operation being checked for admission control
type: string
type: object
userInfo:
description: RequestInfo contains permission info carried in an admission request.
properties:
clusterRoles:
description: ClusterRoles is a list of possible clusterRoles send the request.
items:
type: string
nullable: true
type: array
roles:
description: Roles is a list of possible role send the request.
items:
type: string
nullable: true
type: array
userInfo:
description: UserInfo is the userInfo carried in the admission request.
properties:
extra:
additionalProperties:
description: ExtraValue masks the value so protobuf can generate
items:
type: string
type: array
description: Any additional information provided by the authenticator.
type: object
groups:
description: The names of groups this user is a part of.
items:
type: string
type: array
uid:
description: A unique value that identifies this user across time. If this user is deleted and another user by the same name is added, they will have different UIDs.
type: string
username:
description: The name that uniquely identifies this user among all active users.
type: string
type: object
type: object
type: object
policy:
description: Specifies the name of the policy.
type: string
requestType:
description: Type represents request type for background processing
enum:
- mutate
- generate
type: string
resource:
description: ResourceSpec is the information to identify the update request.
properties:
apiVersion:
description: APIVersion specifies resource apiVersion.
type: string
kind:
description: Kind specifies resource kind.
type: string
name:
description: Name specifies the resource name.
maxLength: 63
type: string
namespace:
description: Namespace specifies resource namespace.
type: string
type: object
required:
- context
- policy
- resource
type: object
status:
description: Status contains statistics related to update request.
properties:
generatedResources:
description: This will track the resources that are updated by the generate Policy. Will be used during clean up resources.
items:
description: ResourceSpec contains information to identify a resource.
properties:
apiVersion:
description: APIVersion specifies resource apiVersion.
type: string
kind:
description: Kind specifies resource kind.
type: string
name:
description: Name specifies the resource name.
maxLength: 63
type: string
namespace:
description: Namespace specifies resource namespace.
type: string
type: object
type: array
message:
description: Specifies request status message.
type: string
state:
description: State represents state of the generate request.
type: string
required:
- state
type: object
type: object
served: true
storage: true
subresources:
status: {}
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []
{{- end }}

View file

@ -8,7 +8,7 @@ import (
"time"
"github.com/go-git/go-billy/v5/memfs"
v1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/common"
sanitizederror "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/sanitizedError"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/store"
@ -246,7 +246,7 @@ func applyCommandHelper(resourcePaths []string, userInfoPath string, cluster boo
}
// get the user info as request info from a different file
var userInfo v1.RequestInfo
var userInfo v1beta1.RequestInfo
if userInfoPath != "" {
userInfo, err = common.GetUserInfoFromPath(fs, userInfoPath, false, "")
if err != nil {

View file

@ -17,6 +17,7 @@ import (
"github.com/go-git/go-billy/v5/memfs"
"github.com/kataras/tablewriter"
v1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/api/kyverno/v1beta1"
report "github.com/kyverno/kyverno/api/policyreport/v1alpha2"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/common"
sanitizederror "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/sanitizedError"
@ -750,7 +751,7 @@ func applyPoliciesFromPath(fs billy.Filesystem, policyBytes []byte, isGit bool,
}
// get the user info as request info from a different file
var userInfo v1.RequestInfo
var userInfo v1beta1.RequestInfo
if userInfoFile != "" {
userInfo, err = common.GetUserInfoFromPath(fs, userInfoFile, isGit, policyResourcePath)
if err != nil {

View file

@ -13,21 +13,21 @@ import (
"reflect"
"strings"
"github.com/kyverno/kyverno/pkg/autogen"
"github.com/kyverno/kyverno/pkg/engine/variables"
jsonpatch "github.com/evanphx/json-patch/v5"
"github.com/go-git/go-billy/v5"
"github.com/go-logr/logr"
v1 "github.com/kyverno/kyverno/api/kyverno/v1"
v1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
report "github.com/kyverno/kyverno/api/policyreport/v1alpha2"
sanitizederror "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/sanitizedError"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/store"
"github.com/kyverno/kyverno/pkg/autogen"
client "github.com/kyverno/kyverno/pkg/dclient"
"github.com/kyverno/kyverno/pkg/engine"
"github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/response"
ut "github.com/kyverno/kyverno/pkg/engine/utils"
"github.com/kyverno/kyverno/pkg/engine/variables"
"github.com/kyverno/kyverno/pkg/policymutation"
"github.com/kyverno/kyverno/pkg/policyreport"
"github.com/kyverno/kyverno/pkg/utils"
@ -442,7 +442,7 @@ func MutatePolicies(policies []v1.PolicyInterface) ([]v1.PolicyInterface, error)
// ApplyPolicyOnResource - function to apply policy on resource
func ApplyPolicyOnResource(policy v1.PolicyInterface, resource *unstructured.Unstructured,
mutateLogPath string, mutateLogPathIsDir bool, variables map[string]string, userInfo v1.RequestInfo, policyReport bool,
mutateLogPath string, mutateLogPathIsDir bool, variables map[string]string, userInfo v1beta1.RequestInfo, policyReport bool,
namespaceSelectorMap map[string]map[string]string, stdin bool, rc *ResultCounts,
printPatchResource bool) ([]*response.EngineResponse, policyreport.Info, error) {
@ -595,7 +595,7 @@ OuterLoop:
JSONContext: context.NewContext(),
NamespaceLabels: namespaceLabels,
}
generateResponse := engine.Generate(policyContext)
generateResponse := engine.ApplyBackgroundChecks(policyContext)
if generateResponse != nil {
engineResponses = append(engineResponses, generateResponse)
}
@ -1051,8 +1051,8 @@ func GetPatchedResourceFromPath(fs billy.Filesystem, path string, isGit bool, po
}
//GetUserInfoFromPath - get the request info as user info from a given path
func GetUserInfoFromPath(fs billy.Filesystem, path string, isGit bool, policyResourcePath string) (v1.RequestInfo, error) {
userInfo := &v1.RequestInfo{}
func GetUserInfoFromPath(fs billy.Filesystem, path string, isGit bool, policyResourcePath string) (v1beta1.RequestInfo, error) {
userInfo := &v1beta1.RequestInfo{}
if isGit {
filep, err := fs.Open(filepath.Join(policyResourcePath, path))

View file

@ -3,7 +3,7 @@ package common
import (
"testing"
v1 "github.com/kyverno/kyverno/api/kyverno/v1"
v1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/toggle"
ut "github.com/kyverno/kyverno/pkg/utils"
"gotest.tools/assert"
@ -100,7 +100,7 @@ func Test_NamespaceSelector(t *testing.T) {
for _, tc := range testcases {
policyArray, _ := ut.GetPolicy(tc.policy)
resourceArray, _ := GetResource(tc.resource)
ApplyPolicyOnResource(policyArray[0], resourceArray[0], "", false, nil, v1.RequestInfo{}, false, tc.namespaceSelectorMap, false, rc, false)
ApplyPolicyOnResource(policyArray[0], resourceArray[0], "", false, nil, v1beta1.RequestInfo{}, false, tc.namespaceSelectorMap, false, rc, false)
assert.Equal(t, int64(rc.Pass), int64(tc.result.Pass))
assert.Equal(t, int64(rc.Fail), int64(tc.result.Fail))
// TODO: autogen rules seem to not be present when autogen internals is disabled

View file

@ -43,7 +43,7 @@ import (
"github.com/kyverno/kyverno/pkg/version"
"github.com/kyverno/kyverno/pkg/webhookconfig"
"github.com/kyverno/kyverno/pkg/webhooks"
webhookgenerate "github.com/kyverno/kyverno/pkg/webhooks/generate"
webhookgenerate "github.com/kyverno/kyverno/pkg/webhooks/updaterequest"
)
const resyncPeriod = 15 * time.Minute
@ -137,10 +137,6 @@ func main() {
}
// KYVERNO CRD CLIENT
// access CRD resources
// - ClusterPolicy, Policy
// - ClusterPolicyReport, PolicyReport
// - GenerateRequest
pclient, err := kyvernoclient.NewForConfig(clientConfig)
if err != nil {
setupLog.Error(err, "Failed to create client")
@ -192,12 +188,7 @@ func main() {
cosign.ImageSignatureRepository = imageSignatureRepository
}
// KYVERNO CRD INFORMER
// watches CRD resources:
// - ClusterPolicy, Policy
// - ClusterPolicyReport, PolicyReport
// - GenerateRequest
// - ClusterReportChangeRequest, ReportChangeRequest
// KYVERNO CRD INFORMERS
pInformer := kyvernoinformer.NewSharedInformerFactoryWithOptions(pclient, policyControllerResyncPeriod)
// EVENT GENERATOR
@ -312,6 +303,7 @@ func main() {
pInformer.Kyverno().V1().ClusterPolicies(),
pInformer.Kyverno().V1().Policies(),
pInformer.Kyverno().V1().GenerateRequests(),
pInformer.Kyverno().V1beta1().UpdateRequests(),
configData,
eventGenerator,
reportReqGen,
@ -328,7 +320,11 @@ func main() {
}
// GENERATE REQUEST GENERATOR
grgen := webhookgenerate.NewGenerator(pclient, pInformer.Kyverno().V1().GenerateRequests(), stopCh, log.Log.WithName("GenerateRequestGenerator"))
grgen := webhookgenerate.NewGenerator(pclient,
pInformer.Kyverno().V1().GenerateRequests(),
pInformer.Kyverno().V1beta1().UpdateRequests(),
stopCh,
log.Log.WithName("UpdateRequestGenerator"))
// GENERATE CONTROLLER
// - applies generate rules on resources based on generate requests created by webhook
@ -339,9 +335,10 @@ func main() {
pInformer.Kyverno().V1().ClusterPolicies(),
pInformer.Kyverno().V1().Policies(),
pInformer.Kyverno().V1().GenerateRequests(),
pInformer.Kyverno().V1beta1().UpdateRequests(),
eventGenerator,
kubeInformer.Core().V1().Namespaces(),
log.Log.WithName("GenerateController"),
log.Log.WithName("BackgroundController"),
configData,
)
if err != nil {
@ -358,6 +355,7 @@ func main() {
pInformer.Kyverno().V1().ClusterPolicies(),
pInformer.Kyverno().V1().Policies(),
pInformer.Kyverno().V1().GenerateRequests(),
pInformer.Kyverno().V1beta1().UpdateRequests(),
kubeInformer.Core().V1().Namespaces(),
log.Log.WithName("GenerateCleanUpController"),
)
@ -399,7 +397,7 @@ func main() {
os.Exit(1)
}
registerWrapperRetry := common.RetryFunc(time.Second, webhookRegistrationTimeout, webhookCfg.Register, setupLog)
registerWrapperRetry := common.RetryFunc(time.Second, webhookRegistrationTimeout, webhookCfg.Register, "failed to register webhook", setupLog)
registerWebhookConfigurations := func() {
certManager.InitTLSPemPair()
webhookCfg.Start()
@ -460,6 +458,7 @@ func main() {
client,
tlsPair,
pInformer.Kyverno().V1().GenerateRequests(),
pInformer.Kyverno().V1beta1().UpdateRequests(),
pInformer.Kyverno().V1().ClusterPolicies(),
kubeInformer.Rbac().V1().RoleBindings(),
kubeInformer.Rbac().V1().ClusterRoleBindings(),

View file

@ -7,5 +7,6 @@ resources:
- ./kyverno.io_generaterequests.yaml
- ./kyverno.io_policies.yaml
- ./kyverno.io_reportchangerequests.yaml
- ./kyverno.io_updaterequests.yaml
- ./wgpolicyk8s.io_clusterpolicyreports.yaml
- ./wgpolicyk8s.io_policyreports.yaml

View file

@ -198,17 +198,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -413,17 +413,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -624,15 +624,15 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name
supports wildcard characters "*" (matches zero or
many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -909,17 +909,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -1124,17 +1124,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -1335,15 +1335,15 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name
supports wildcard characters "*" (matches zero or
many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -1730,6 +1730,13 @@ spec:
x-kubernetes-preserve-unknown-fields: true
type: object
type: array
mutateExisting:
description: mutateExisting controls whether to mutate existing
resource ONLY The existing resources will be mutated ONLY
if set to "true". Otherwise all resources including admission
requests are mutated. Optional. Defaults to "false" if
not specified.
type: boolean
patchStrategicMerge:
description: PatchStrategicMerge is a strategic merge patch
used to modify resources. See https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/
@ -1740,6 +1747,26 @@ spec:
Patch declarations used to modify resources. See https://tools.ietf.org/html/rfc6902
and https://kubectl.docs.kubernetes.io/references/kustomize/patchesjson6902/.
type: string
targets:
description: Targets defines the target resources to be
mutated.
items:
properties:
apiVersion:
description: APIVersion specifies resource apiVersion.
type: string
kind:
description: Kind specifies resource kind.
type: string
name:
description: Name specifies the resource name.
maxLength: 63
type: string
namespace:
description: Namespace specifies resource namespace.
type: string
type: object
type: array
type: object
name:
description: Name is a label to identify the rule, It must be
@ -2636,17 +2663,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -2851,17 +2878,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -3062,15 +3089,15 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name
supports wildcard characters "*" (matches zero or
many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -3347,17 +3374,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -3562,17 +3589,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -3773,15 +3800,15 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name
supports wildcard characters "*" (matches zero or
many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -4168,6 +4195,13 @@ spec:
x-kubernetes-preserve-unknown-fields: true
type: object
type: array
mutateExisting:
description: mutateExisting controls whether to mutate existing
resource ONLY The existing resources will be mutated ONLY
if set to "true". Otherwise all resources including admission
requests are mutated. Optional. Defaults to "false" if
not specified.
type: boolean
patchStrategicMerge:
description: PatchStrategicMerge is a strategic merge patch
used to modify resources. See https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/
@ -4178,6 +4212,26 @@ spec:
Patch declarations used to modify resources. See https://tools.ietf.org/html/rfc6902
and https://kubectl.docs.kubernetes.io/references/kustomize/patchesjson6902/.
type: string
targets:
description: Targets defines the target resources to be
mutated.
items:
properties:
apiVersion:
description: APIVersion specifies resource apiVersion.
type: string
kind:
description: Kind specifies resource kind.
type: string
name:
description: Name specifies the resource name.
maxLength: 63
type: string
namespace:
description: Namespace specifies resource namespace.
type: string
type: object
type: array
type: object
name:
description: Name is a label to identify the rule, It must be

View file

@ -199,17 +199,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -414,17 +414,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -625,15 +625,15 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name
supports wildcard characters "*" (matches zero or
many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -910,17 +910,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -1125,17 +1125,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -1336,15 +1336,15 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name
supports wildcard characters "*" (matches zero or
many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -1731,6 +1731,13 @@ spec:
x-kubernetes-preserve-unknown-fields: true
type: object
type: array
mutateExisting:
description: mutateExisting controls whether to mutate existing
resource ONLY The existing resources will be mutated ONLY
if set to "true". Otherwise all resources including admission
requests are mutated. Optional. Defaults to "false" if
not specified.
type: boolean
patchStrategicMerge:
description: PatchStrategicMerge is a strategic merge patch
used to modify resources. See https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/
@ -1741,6 +1748,26 @@ spec:
Patch declarations used to modify resources. See https://tools.ietf.org/html/rfc6902
and https://kubectl.docs.kubernetes.io/references/kustomize/patchesjson6902/.
type: string
targets:
description: Targets defines the target resources to be
mutated.
items:
properties:
apiVersion:
description: APIVersion specifies resource apiVersion.
type: string
kind:
description: Kind specifies resource kind.
type: string
name:
description: Name specifies the resource name.
maxLength: 63
type: string
namespace:
description: Namespace specifies resource namespace.
type: string
type: object
type: array
type: object
name:
description: Name is a label to identify the rule, It must be
@ -2638,17 +2665,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -2853,17 +2880,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -3064,15 +3091,15 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name
supports wildcard characters "*" (matches zero or
many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -3349,17 +3376,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -3564,17 +3591,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -3775,15 +3802,15 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name
supports wildcard characters "*" (matches zero or
many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -4170,6 +4197,13 @@ spec:
x-kubernetes-preserve-unknown-fields: true
type: object
type: array
mutateExisting:
description: mutateExisting controls whether to mutate existing
resource ONLY The existing resources will be mutated ONLY
if set to "true". Otherwise all resources including admission
requests are mutated. Optional. Defaults to "false" if
not specified.
type: boolean
patchStrategicMerge:
description: PatchStrategicMerge is a strategic merge patch
used to modify resources. See https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/
@ -4180,6 +4214,26 @@ spec:
Patch declarations used to modify resources. See https://tools.ietf.org/html/rfc6902
and https://kubectl.docs.kubernetes.io/references/kustomize/patchesjson6902/.
type: string
targets:
description: Targets defines the target resources to be
mutated.
items:
properties:
apiVersion:
description: APIVersion specifies resource apiVersion.
type: string
kind:
description: Kind specifies resource kind.
type: string
name:
description: Name specifies the resource name.
maxLength: 63
type: string
namespace:
description: Namespace specifies resource namespace.
type: string
type: object
type: array
type: object
name:
description: Name is a label to identify the rule, It must be

View file

@ -13,7 +13,7 @@ spec:
listKind: UpdateRequestList
plural: updaterequests
shortNames:
- gr
- ur
singular: updaterequest
scope: Namespaced
versions:
@ -123,6 +123,12 @@ spec:
policy:
description: Specifies the name of the policy.
type: string
requestType:
description: Type represents request type for background processing
enum:
- mutate
- generate
type: string
resource:
description: ResourceSpec is the information to identify the update
request.

View file

@ -215,17 +215,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -430,17 +430,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -641,15 +641,15 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name
supports wildcard characters "*" (matches zero or
many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -926,17 +926,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -1141,17 +1141,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -1352,15 +1352,15 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name
supports wildcard characters "*" (matches zero or
many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -1747,6 +1747,13 @@ spec:
x-kubernetes-preserve-unknown-fields: true
type: object
type: array
mutateExisting:
description: mutateExisting controls whether to mutate existing
resource ONLY The existing resources will be mutated ONLY
if set to "true". Otherwise all resources including admission
requests are mutated. Optional. Defaults to "false" if
not specified.
type: boolean
patchStrategicMerge:
description: PatchStrategicMerge is a strategic merge patch
used to modify resources. See https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/
@ -1757,6 +1764,26 @@ spec:
Patch declarations used to modify resources. See https://tools.ietf.org/html/rfc6902
and https://kubectl.docs.kubernetes.io/references/kustomize/patchesjson6902/.
type: string
targets:
description: Targets defines the target resources to be
mutated.
items:
properties:
apiVersion:
description: APIVersion specifies resource apiVersion.
type: string
kind:
description: Kind specifies resource kind.
type: string
name:
description: Name specifies the resource name.
maxLength: 63
type: string
namespace:
description: Namespace specifies resource namespace.
type: string
type: object
type: array
type: object
name:
description: Name is a label to identify the rule, It must be
@ -2653,17 +2680,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -2868,17 +2895,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -3079,15 +3106,15 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name
supports wildcard characters "*" (matches zero or
many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -3364,17 +3391,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -3579,17 +3606,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -3790,15 +3817,15 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name
supports wildcard characters "*" (matches zero or
many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -4185,6 +4212,13 @@ spec:
x-kubernetes-preserve-unknown-fields: true
type: object
type: array
mutateExisting:
description: mutateExisting controls whether to mutate existing
resource ONLY The existing resources will be mutated ONLY
if set to "true". Otherwise all resources including admission
requests are mutated. Optional. Defaults to "false" if
not specified.
type: boolean
patchStrategicMerge:
description: PatchStrategicMerge is a strategic merge patch
used to modify resources. See https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/
@ -4195,6 +4229,26 @@ spec:
Patch declarations used to modify resources. See https://tools.ietf.org/html/rfc6902
and https://kubectl.docs.kubernetes.io/references/kustomize/patchesjson6902/.
type: string
targets:
description: Targets defines the target resources to be
mutated.
items:
properties:
apiVersion:
description: APIVersion specifies resource apiVersion.
type: string
kind:
description: Kind specifies resource kind.
type: string
name:
description: Name specifies the resource name.
maxLength: 63
type: string
namespace:
description: Namespace specifies resource namespace.
type: string
type: object
type: array
type: object
name:
description: Name is a label to identify the rule, It must be
@ -5981,17 +6035,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -6196,17 +6250,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -6407,15 +6461,15 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name
supports wildcard characters "*" (matches zero or
many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -6692,17 +6746,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -6907,17 +6961,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -7118,15 +7172,15 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name
supports wildcard characters "*" (matches zero or
many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -7513,6 +7567,13 @@ spec:
x-kubernetes-preserve-unknown-fields: true
type: object
type: array
mutateExisting:
description: mutateExisting controls whether to mutate existing
resource ONLY The existing resources will be mutated ONLY
if set to "true". Otherwise all resources including admission
requests are mutated. Optional. Defaults to "false" if
not specified.
type: boolean
patchStrategicMerge:
description: PatchStrategicMerge is a strategic merge patch
used to modify resources. See https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/
@ -7523,6 +7584,26 @@ spec:
Patch declarations used to modify resources. See https://tools.ietf.org/html/rfc6902
and https://kubectl.docs.kubernetes.io/references/kustomize/patchesjson6902/.
type: string
targets:
description: Targets defines the target resources to be
mutated.
items:
properties:
apiVersion:
description: APIVersion specifies resource apiVersion.
type: string
kind:
description: Kind specifies resource kind.
type: string
name:
description: Name specifies the resource name.
maxLength: 63
type: string
namespace:
description: Namespace specifies resource namespace.
type: string
type: object
type: array
type: object
name:
description: Name is a label to identify the rule, It must be
@ -8420,17 +8501,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -8635,17 +8716,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -8846,15 +8927,15 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name
supports wildcard characters "*" (matches zero or
many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -9131,17 +9212,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -9346,17 +9427,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -9557,15 +9638,15 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name
supports wildcard characters "*" (matches zero or
many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -9952,6 +10033,13 @@ spec:
x-kubernetes-preserve-unknown-fields: true
type: object
type: array
mutateExisting:
description: mutateExisting controls whether to mutate existing
resource ONLY The existing resources will be mutated ONLY
if set to "true". Otherwise all resources including admission
requests are mutated. Optional. Defaults to "false" if
not specified.
type: boolean
patchStrategicMerge:
description: PatchStrategicMerge is a strategic merge patch
used to modify resources. See https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/
@ -9962,6 +10050,26 @@ spec:
Patch declarations used to modify resources. See https://tools.ietf.org/html/rfc6902
and https://kubectl.docs.kubernetes.io/references/kustomize/patchesjson6902/.
type: string
targets:
description: Targets defines the target resources to be
mutated.
items:
properties:
apiVersion:
description: APIVersion specifies resource apiVersion.
type: string
kind:
description: Kind specifies resource kind.
type: string
name:
description: Name specifies the resource name.
maxLength: 63
type: string
namespace:
description: Namespace specifies resource namespace.
type: string
type: object
type: array
type: object
name:
description: Name is a label to identify the rule, It must be
@ -11342,6 +11450,210 @@ status:
conditions: []
storedVersions: []
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.8.0
creationTimestamp: null
labels:
app.kubernetes.io/component: kyverno
app.kubernetes.io/instance: kyverno
app.kubernetes.io/name: kyverno
app.kubernetes.io/part-of: kyverno
app.kubernetes.io/version: latest
name: updaterequests.kyverno.io
spec:
group: kyverno.io
names:
kind: UpdateRequest
listKind: UpdateRequestList
plural: updaterequests
shortNames:
- ur
singular: updaterequest
scope: Namespaced
versions:
- additionalPrinterColumns:
- jsonPath: .spec.policy
name: Policy
type: string
- jsonPath: .spec.resource.kind
name: ResourceKind
type: string
- jsonPath: .spec.resource.name
name: ResourceName
type: string
- jsonPath: .spec.resource.namespace
name: ResourceNamespace
type: string
- jsonPath: .status.state
name: status
type: string
- jsonPath: .metadata.creationTimestamp
name: Age
type: date
name: v1beta1
schema:
openAPIV3Schema:
description: UpdateRequestStatus is a request to process mutate and generate
rules in background.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: Spec is the information to identify the update request.
properties:
context:
description: Context ...
properties:
admissionRequestInfo:
description: AdmissionRequestInfoObject stores the admission request
and operation details
properties:
admissionRequest:
type: string
operation:
description: Operation is the type of resource operation being
checked for admission control
type: string
type: object
userInfo:
description: RequestInfo contains permission info carried in an
admission request.
properties:
clusterRoles:
description: ClusterRoles is a list of possible clusterRoles
send the request.
items:
type: string
nullable: true
type: array
roles:
description: Roles is a list of possible role send the request.
items:
type: string
nullable: true
type: array
userInfo:
description: UserInfo is the userInfo carried in the admission
request.
properties:
extra:
additionalProperties:
description: ExtraValue masks the value so protobuf
can generate
items:
type: string
type: array
description: Any additional information provided by the
authenticator.
type: object
groups:
description: The names of groups this user is a part of.
items:
type: string
type: array
uid:
description: A unique value that identifies this user
across time. If this user is deleted and another user
by the same name is added, they will have different
UIDs.
type: string
username:
description: The name that uniquely identifies this user
among all active users.
type: string
type: object
type: object
type: object
policy:
description: Specifies the name of the policy.
type: string
requestType:
description: Type represents request type for background processing
enum:
- mutate
- generate
type: string
resource:
description: ResourceSpec is the information to identify the update
request.
properties:
apiVersion:
description: APIVersion specifies resource apiVersion.
type: string
kind:
description: Kind specifies resource kind.
type: string
name:
description: Name specifies the resource name.
maxLength: 63
type: string
namespace:
description: Namespace specifies resource namespace.
type: string
type: object
required:
- context
- policy
- resource
type: object
status:
description: Status contains statistics related to update request.
properties:
generatedResources:
description: This will track the resources that are updated by the
generate Policy. Will be used during clean up resources.
items:
description: ResourceSpec contains information to identify a resource.
properties:
apiVersion:
description: APIVersion specifies resource apiVersion.
type: string
kind:
description: Kind specifies resource kind.
type: string
name:
description: Name specifies the resource name.
maxLength: 63
type: string
namespace:
description: Namespace specifies resource namespace.
type: string
type: object
type: array
message:
description: Specifies request status message.
type: string
state:
description: State represents state of the generate request.
type: string
required:
- state
type: object
type: object
served: true
storage: true
subresources:
status: {}
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []
---
apiVersion: v1
kind: ServiceAccount
metadata:
@ -11586,6 +11898,8 @@ rules:
- clusterpolicies/status
- generaterequests
- generaterequests/status
- updaterequests
- updaterequests/status
- reportchangerequests
- reportchangerequests/status
- clusterreportchangerequests

View file

@ -204,17 +204,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -419,17 +419,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -630,15 +630,15 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name
supports wildcard characters "*" (matches zero or
many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -915,17 +915,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -1130,17 +1130,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -1341,15 +1341,15 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name
supports wildcard characters "*" (matches zero or
many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -1736,6 +1736,13 @@ spec:
x-kubernetes-preserve-unknown-fields: true
type: object
type: array
mutateExisting:
description: mutateExisting controls whether to mutate existing
resource ONLY The existing resources will be mutated ONLY
if set to "true". Otherwise all resources including admission
requests are mutated. Optional. Defaults to "false" if
not specified.
type: boolean
patchStrategicMerge:
description: PatchStrategicMerge is a strategic merge patch
used to modify resources. See https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/
@ -1746,6 +1753,26 @@ spec:
Patch declarations used to modify resources. See https://tools.ietf.org/html/rfc6902
and https://kubectl.docs.kubernetes.io/references/kustomize/patchesjson6902/.
type: string
targets:
description: Targets defines the target resources to be
mutated.
items:
properties:
apiVersion:
description: APIVersion specifies resource apiVersion.
type: string
kind:
description: Kind specifies resource kind.
type: string
name:
description: Name specifies the resource name.
maxLength: 63
type: string
namespace:
description: Namespace specifies resource namespace.
type: string
type: object
type: array
type: object
name:
description: Name is a label to identify the rule, It must be
@ -2642,17 +2669,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -2857,17 +2884,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -3068,15 +3095,15 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name
supports wildcard characters "*" (matches zero or
many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -3353,17 +3380,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -3568,17 +3595,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -3779,15 +3806,15 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name
supports wildcard characters "*" (matches zero or
many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -4174,6 +4201,13 @@ spec:
x-kubernetes-preserve-unknown-fields: true
type: object
type: array
mutateExisting:
description: mutateExisting controls whether to mutate existing
resource ONLY The existing resources will be mutated ONLY
if set to "true". Otherwise all resources including admission
requests are mutated. Optional. Defaults to "false" if
not specified.
type: boolean
patchStrategicMerge:
description: PatchStrategicMerge is a strategic merge patch
used to modify resources. See https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/
@ -4184,6 +4218,26 @@ spec:
Patch declarations used to modify resources. See https://tools.ietf.org/html/rfc6902
and https://kubectl.docs.kubernetes.io/references/kustomize/patchesjson6902/.
type: string
targets:
description: Targets defines the target resources to be
mutated.
items:
properties:
apiVersion:
description: APIVersion specifies resource apiVersion.
type: string
kind:
description: Kind specifies resource kind.
type: string
name:
description: Name specifies the resource name.
maxLength: 63
type: string
namespace:
description: Namespace specifies resource namespace.
type: string
type: object
type: array
type: object
name:
description: Name is a label to identify the rule, It must be
@ -5946,17 +6000,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -6161,17 +6215,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -6372,15 +6426,15 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name
supports wildcard characters "*" (matches zero or
many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -6657,17 +6711,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -6872,17 +6926,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -7083,15 +7137,15 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name
supports wildcard characters "*" (matches zero or
many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -7478,6 +7532,13 @@ spec:
x-kubernetes-preserve-unknown-fields: true
type: object
type: array
mutateExisting:
description: mutateExisting controls whether to mutate existing
resource ONLY The existing resources will be mutated ONLY
if set to "true". Otherwise all resources including admission
requests are mutated. Optional. Defaults to "false" if
not specified.
type: boolean
patchStrategicMerge:
description: PatchStrategicMerge is a strategic merge patch
used to modify resources. See https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/
@ -7488,6 +7549,26 @@ spec:
Patch declarations used to modify resources. See https://tools.ietf.org/html/rfc6902
and https://kubectl.docs.kubernetes.io/references/kustomize/patchesjson6902/.
type: string
targets:
description: Targets defines the target resources to be
mutated.
items:
properties:
apiVersion:
description: APIVersion specifies resource apiVersion.
type: string
kind:
description: Kind specifies resource kind.
type: string
name:
description: Name specifies the resource name.
maxLength: 63
type: string
namespace:
description: Namespace specifies resource namespace.
type: string
type: object
type: array
type: object
name:
description: Name is a label to identify the rule, It must be
@ -8385,17 +8466,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -8600,17 +8681,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -8811,15 +8892,15 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name
supports wildcard characters "*" (matches zero or
many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -9096,17 +9177,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -9311,17 +9392,17 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource.
description: 'Name is the name of the resource.
The name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character). NOTE: "Name" is being deprecated
in favor of "Names".'
type: string
names:
description: Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one
character).
items:
type: string
type: array
@ -9522,15 +9603,15 @@ spec:
type: string
type: array
name:
description: Name is the name of the resource. The name
supports wildcard characters "*" (matches zero or
many characters) and "?" (at least one character).
description: 'Name is the name of the resource. The
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
type: string
names:
description: 'Names are the names of the resources.
Each name supports wildcard characters "*" (matches
zero or many characters) and "?" (at least one character).
NOTE: "Name" is being deprecated in favor of "Names".'
description: Names are the names of the resources. Each
name supports wildcard characters "*" (matches zero
or many characters) and "?" (at least one character).
items:
type: string
type: array
@ -9917,6 +9998,13 @@ spec:
x-kubernetes-preserve-unknown-fields: true
type: object
type: array
mutateExisting:
description: mutateExisting controls whether to mutate existing
resource ONLY The existing resources will be mutated ONLY
if set to "true". Otherwise all resources including admission
requests are mutated. Optional. Defaults to "false" if
not specified.
type: boolean
patchStrategicMerge:
description: PatchStrategicMerge is a strategic merge patch
used to modify resources. See https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/
@ -9927,6 +10015,26 @@ spec:
Patch declarations used to modify resources. See https://tools.ietf.org/html/rfc6902
and https://kubectl.docs.kubernetes.io/references/kustomize/patchesjson6902/.
type: string
targets:
description: Targets defines the target resources to be
mutated.
items:
properties:
apiVersion:
description: APIVersion specifies resource apiVersion.
type: string
kind:
description: Kind specifies resource kind.
type: string
name:
description: Name specifies the resource name.
maxLength: 63
type: string
namespace:
description: Namespace specifies resource namespace.
type: string
type: object
type: array
type: object
name:
description: Name is a label to identify the rule, It must be
@ -11295,6 +11403,204 @@ status:
conditions: []
storedVersions: []
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.8.0
creationTimestamp: null
name: updaterequests.kyverno.io
spec:
group: kyverno.io
names:
kind: UpdateRequest
listKind: UpdateRequestList
plural: updaterequests
shortNames:
- ur
singular: updaterequest
scope: Namespaced
versions:
- additionalPrinterColumns:
- jsonPath: .spec.policy
name: Policy
type: string
- jsonPath: .spec.resource.kind
name: ResourceKind
type: string
- jsonPath: .spec.resource.name
name: ResourceName
type: string
- jsonPath: .spec.resource.namespace
name: ResourceNamespace
type: string
- jsonPath: .status.state
name: status
type: string
- jsonPath: .metadata.creationTimestamp
name: Age
type: date
name: v1beta1
schema:
openAPIV3Schema:
description: UpdateRequestStatus is a request to process mutate and generate
rules in background.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: Spec is the information to identify the update request.
properties:
context:
description: Context ...
properties:
admissionRequestInfo:
description: AdmissionRequestInfoObject stores the admission request
and operation details
properties:
admissionRequest:
type: string
operation:
description: Operation is the type of resource operation being
checked for admission control
type: string
type: object
userInfo:
description: RequestInfo contains permission info carried in an
admission request.
properties:
clusterRoles:
description: ClusterRoles is a list of possible clusterRoles
send the request.
items:
type: string
nullable: true
type: array
roles:
description: Roles is a list of possible role send the request.
items:
type: string
nullable: true
type: array
userInfo:
description: UserInfo is the userInfo carried in the admission
request.
properties:
extra:
additionalProperties:
description: ExtraValue masks the value so protobuf
can generate
items:
type: string
type: array
description: Any additional information provided by the
authenticator.
type: object
groups:
description: The names of groups this user is a part of.
items:
type: string
type: array
uid:
description: A unique value that identifies this user
across time. If this user is deleted and another user
by the same name is added, they will have different
UIDs.
type: string
username:
description: The name that uniquely identifies this user
among all active users.
type: string
type: object
type: object
type: object
policy:
description: Specifies the name of the policy.
type: string
requestType:
description: Type represents request type for background processing
enum:
- mutate
- generate
type: string
resource:
description: ResourceSpec is the information to identify the update
request.
properties:
apiVersion:
description: APIVersion specifies resource apiVersion.
type: string
kind:
description: Kind specifies resource kind.
type: string
name:
description: Name specifies the resource name.
maxLength: 63
type: string
namespace:
description: Namespace specifies resource namespace.
type: string
type: object
required:
- context
- policy
- resource
type: object
status:
description: Status contains statistics related to update request.
properties:
generatedResources:
description: This will track the resources that are updated by the
generate Policy. Will be used during clean up resources.
items:
description: ResourceSpec contains information to identify a resource.
properties:
apiVersion:
description: APIVersion specifies resource apiVersion.
type: string
kind:
description: Kind specifies resource kind.
type: string
name:
description: Name specifies the resource name.
maxLength: 63
type: string
namespace:
description: Namespace specifies resource namespace.
type: string
type: object
type: array
message:
description: Specifies request status message.
type: string
state:
description: State represents state of the generate request.
type: string
required:
- state
type: object
type: object
served: true
storage: true
subresources:
status: {}
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []
---
apiVersion: v1
kind: ServiceAccount
metadata:
@ -11494,6 +11800,8 @@ rules:
- clusterpolicies/status
- generaterequests
- generaterequests/status
- updaterequests
- updaterequests/status
- reportchangerequests
- reportchangerequests/status
- clusterreportchangerequests

View file

@ -15,6 +15,8 @@ rules:
- clusterpolicies/status
- generaterequests
- generaterequests/status
- updaterequests
- updaterequests/status
- reportchangerequests
- reportchangerequests/status
- clusterreportchangerequests

View file

@ -209,8 +209,8 @@ string
<td>
<code>conditions</code></br>
<em>
<a href="#kyverno.io/v1.*./api/kyverno/v1.AnyAllConditions">
[]*./api/kyverno/v1.AnyAllConditions
<a href="#kyverno.io/v1.*github.com/realshuting/kyverno/api/kyverno/v1.AnyAllConditions">
[]*github.com/realshuting/kyverno/api/kyverno/v1.AnyAllConditions
</a>
</em>
</td>
@ -330,8 +330,8 @@ value N, then N must be less than or equal to the size of entries, and at least
<td>
<code>entries</code></br>
<em>
<a href="#kyverno.io/v1.*./api/kyverno/v1.Attestor">
[]*./api/kyverno/v1.Attestor
<a href="#kyverno.io/v1.*github.com/realshuting/kyverno/api/kyverno/v1.Attestor">
[]*github.com/realshuting/kyverno/api/kyverno/v1.Attestor
</a>
</em>
</td>
@ -1573,8 +1573,8 @@ Deprecated.</p>
<td>
<code>attestors</code></br>
<em>
<a href="#kyverno.io/v1.*./api/kyverno/v1.AttestorSet">
[]*./api/kyverno/v1.AttestorSet
<a href="#kyverno.io/v1.*github.com/realshuting/kyverno/api/kyverno/v1.AttestorSet">
[]*github.com/realshuting/kyverno/api/kyverno/v1.AttestorSet
</a>
</em>
</td>
@ -1586,8 +1586,8 @@ Deprecated.</p>
<td>
<code>attestations</code></br>
<em>
<a href="#kyverno.io/v1.*./api/kyverno/v1.Attestation">
[]*./api/kyverno/v1.Attestation
<a href="#kyverno.io/v1.*github.com/realshuting/kyverno/api/kyverno/v1.Attestation">
[]*github.com/realshuting/kyverno/api/kyverno/v1.Attestation
</a>
</em>
</td>
@ -1832,6 +1832,35 @@ Please specify under &ldquo;any&rdquo; or &ldquo;all&rdquo; instead.</p>
<tbody>
<tr>
<td>
<code>mutateExisting</code></br>
<em>
bool
</em>
</td>
<td>
<em>(Optional)</em>
<p>mutateExisting controls whether to mutate existing resource ONLY
The existing resources will be mutated ONLY if set to &ldquo;true&rdquo;.
Otherwise all resources including admission requests are mutated.
Optional. Defaults to &ldquo;false&rdquo; if not specified.</p>
</td>
</tr>
<tr>
<td>
<code>targets</code></br>
<em>
<a href="#kyverno.io/v1.TargetMutation">
[]TargetMutation
</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>Targets defines the target resources to be mutated.</p>
</td>
</tr>
<tr>
<td>
<code>patchStrategicMerge</code></br>
<em>
k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.JSON
@ -1861,8 +1890,8 @@ See <a href="https://tools.ietf.org/html/rfc6902">https://tools.ietf.org/html/rf
<td>
<code>foreach</code></br>
<em>
<a href="#kyverno.io/v1.*./api/kyverno/v1.ForEachMutation">
[]*./api/kyverno/v1.ForEachMutation
<a href="#kyverno.io/v1.*github.com/realshuting/kyverno/api/kyverno/v1.ForEachMutation">
[]*github.com/realshuting/kyverno/api/kyverno/v1.ForEachMutation
</a>
</em>
</td>
@ -2218,7 +2247,8 @@ string
<td>
<em>(Optional)</em>
<p>Name is the name of the resource. The name supports wildcard characters
&ldquo;*&rdquo; (matches zero or many characters) and &ldquo;?&rdquo; (at least one character).</p>
&ldquo;*&rdquo; (matches zero or many characters) and &ldquo;?&rdquo; (at least one character).
NOTE: &ldquo;Name&rdquo; is being deprecated in favor of &ldquo;Names&rdquo;.</p>
</td>
</tr>
<tr>
@ -2231,8 +2261,7 @@ string
<td>
<em>(Optional)</em>
<p>Names are the names of the resources. Each name supports wildcard characters
&ldquo;*&rdquo; (matches zero or many characters) and &ldquo;?&rdquo; (at least one character).
NOTE: &ldquo;Name&rdquo; is being deprecated in favor of &ldquo;Names&rdquo;.</p>
&ldquo;*&rdquo; (matches zero or many characters) and &ldquo;?&rdquo; (at least one character).</p>
</td>
</tr>
<tr>
@ -2344,7 +2373,7 @@ ResourceDescription
</table>
<hr />
<h3 id="kyverno.io/v1.ResourceFilters">ResourceFilters
(<code>[]./api/kyverno/v1.ResourceFilter</code> alias)</p></h3>
(<code>[]github.com/realshuting/kyverno/api/kyverno/v1.ResourceFilter</code> alias)</p></h3>
<p>
(<em>Appears on:</em>
<a href="#kyverno.io/v1.MatchResources">MatchResources</a>)
@ -2358,7 +2387,8 @@ ResourceDescription
(<em>Appears on:</em>
<a href="#kyverno.io/v1.GenerateRequestSpec">GenerateRequestSpec</a>,
<a href="#kyverno.io/v1.GenerateRequestStatus">GenerateRequestStatus</a>,
<a href="#kyverno.io/v1.Generation">Generation</a>)
<a href="#kyverno.io/v1.Generation">Generation</a>,
<a href="#kyverno.io/v1.TargetMutation">TargetMutation</a>)
</p>
<p>
<p>ResourceSpec contains information to identify a resource.</p>
@ -2572,8 +2602,8 @@ Generation
<td>
<code>verifyImages</code></br>
<em>
<a href="#kyverno.io/v1.*./api/kyverno/v1.ImageVerification">
[]*./api/kyverno/v1.ImageVerification
<a href="#kyverno.io/v1.*github.com/realshuting/kyverno/api/kyverno/v1.ImageVerification">
[]*github.com/realshuting/kyverno/api/kyverno/v1.ImageVerification
</a>
</em>
</td>
@ -2766,6 +2796,39 @@ If not provided, the system roots are used.</p>
</tbody>
</table>
<hr />
<h3 id="kyverno.io/v1.TargetMutation">TargetMutation
</h3>
<p>
(<em>Appears on:</em>
<a href="#kyverno.io/v1.Mutation">Mutation</a>)
</p>
<p>
</p>
<table class="table table-striped">
<thead class="thead-dark">
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>ResourceSpec</code></br>
<em>
<a href="#kyverno.io/v1.ResourceSpec">
ResourceSpec
</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>ResourceSpec specifies the target resource information.</p>
</td>
</tr>
</tbody>
</table>
<hr />
<h3 id="kyverno.io/v1.UserInfo">UserInfo
</h3>
<p>
@ -2858,8 +2921,8 @@ string
<td>
<code>foreach</code></br>
<em>
<a href="#kyverno.io/v1.*./api/kyverno/v1.ForEachValidation">
[]*./api/kyverno/v1.ForEachValidation
<a href="#kyverno.io/v1.*github.com/realshuting/kyverno/api/kyverno/v1.ForEachValidation">
[]*github.com/realshuting/kyverno/api/kyverno/v1.ForEachValidation
</a>
</em>
</td>

436
docs/crd/v1beta1/index.html Normal file
View file

@ -0,0 +1,436 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<title>Kyverno API</title>
<style>
.bg-blue {
color: #ffffff;
background-color: #1589dd;
}
</style>
</head>
<body>
<div class="container">
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<a class="navbar-brand" href="#"><p><b>Packages : </b></p></a>
<ul style="list-style:none">
<li>
<a href="#kyverno.io%2fv1beta1"><b style="color: white">kyverno.io/v1beta1</b></a>
</li>
</ul>
</nav>
<h2 id="kyverno.io/v1beta1">kyverno.io/v1beta1</h2>
<p>
<p>Package v1beta1 contains API Schema definitions for the policy v1alpha1 API group</p>
</p>
Resource Types:
<ul></ul>
<hr />
<h3 id="kyverno.io/v1beta1.AdmissionRequestInfoObject">AdmissionRequestInfoObject
</h3>
<p>
(<em>Appears on:</em>
<a href="#kyverno.io/v1beta1.UpdateRequestSpecContext">UpdateRequestSpecContext</a>)
</p>
<p>
<p>AdmissionRequestInfoObject stores the admission request and operation details</p>
</p>
<table class="table table-striped">
<thead class="thead-dark">
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>admissionRequest</code></br>
<em>
string
</em>
</td>
<td>
<em>(Optional)</em>
</td>
</tr>
<tr>
<td>
<code>operation</code></br>
<em>
<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#operation-v1-admission">
Kubernetes admission/v1.Operation
</a>
</em>
</td>
<td>
<em>(Optional)</em>
</td>
</tr>
</tbody>
</table>
<hr />
<h3 id="kyverno.io/v1beta1.RequestInfo">RequestInfo
</h3>
<p>
(<em>Appears on:</em>
<a href="#kyverno.io/v1beta1.UpdateRequestSpecContext">UpdateRequestSpecContext</a>)
</p>
<p>
<p>RequestInfo contains permission info carried in an admission request.</p>
</p>
<table class="table table-striped">
<thead class="thead-dark">
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>roles</code></br>
<em>
[]string
</em>
</td>
<td>
<em>(Optional)</em>
<p>Roles is a list of possible role send the request.</p>
</td>
</tr>
<tr>
<td>
<code>clusterRoles</code></br>
<em>
[]string
</em>
</td>
<td>
<em>(Optional)</em>
<p>ClusterRoles is a list of possible clusterRoles send the request.</p>
</td>
</tr>
<tr>
<td>
<code>userInfo</code></br>
<em>
<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#userinfo-v1-authentication">
Kubernetes authentication/v1.UserInfo
</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>UserInfo is the userInfo carried in the admission request.</p>
</td>
</tr>
</tbody>
</table>
<hr />
<h3 id="kyverno.io/v1beta1.RequestType">RequestType
(<code>string</code> alias)</p></h3>
<p>
(<em>Appears on:</em>
<a href="#kyverno.io/v1beta1.UpdateRequestSpec">UpdateRequestSpec</a>)
</p>
<p>
</p>
<h3 id="kyverno.io/v1beta1.UpdateRequest">UpdateRequest
</h3>
<p>
<p>UpdateRequestStatus is a request to process mutate and generate rules in background.</p>
</p>
<table class="table table-striped">
<thead class="thead-dark">
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>metadata</code></br>
<em>
<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#objectmeta-v1-meta">
Kubernetes meta/v1.ObjectMeta
</a>
</em>
</td>
<td>
Refer to the Kubernetes API documentation for the fields of the
<code>metadata</code> field.
</td>
</tr>
<tr>
<td>
<code>spec</code></br>
<em>
<a href="#kyverno.io/v1beta1.UpdateRequestSpec">
UpdateRequestSpec
</a>
</em>
</td>
<td>
<p>Spec is the information to identify the update request.</p>
<br/>
<br/>
<table class="table table-striped">
<tr>
<td>
<code>requestType</code></br>
<em>
<a href="#kyverno.io/v1beta1.RequestType">
RequestType
</a>
</em>
</td>
<td>
<p>Type represents request type for background processing</p>
</td>
</tr>
<tr>
<td>
<code>policy</code></br>
<em>
string
</em>
</td>
<td>
<p>Specifies the name of the policy.</p>
</td>
</tr>
<tr>
<td>
<code>resource</code></br>
<em>
github.com/kyverno/kyverno/api/kyverno/v1.ResourceSpec
</em>
</td>
<td>
<p>ResourceSpec is the information to identify the update request.</p>
</td>
</tr>
<tr>
<td>
<code>context</code></br>
<em>
<a href="#kyverno.io/v1beta1.UpdateRequestSpecContext">
UpdateRequestSpecContext
</a>
</em>
</td>
<td>
<p>Context &hellip;</p>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<code>status</code></br>
<em>
<a href="#kyverno.io/v1beta1.UpdateRequestStatus">
UpdateRequestStatus
</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>Status contains statistics related to update request.</p>
</td>
</tr>
</tbody>
</table>
<hr />
<h3 id="kyverno.io/v1beta1.UpdateRequestSpec">UpdateRequestSpec
</h3>
<p>
(<em>Appears on:</em>
<a href="#kyverno.io/v1beta1.UpdateRequest">UpdateRequest</a>)
</p>
<p>
<p>UpdateRequestSpec stores the request specification.</p>
</p>
<table class="table table-striped">
<thead class="thead-dark">
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>requestType</code></br>
<em>
<a href="#kyverno.io/v1beta1.RequestType">
RequestType
</a>
</em>
</td>
<td>
<p>Type represents request type for background processing</p>
</td>
</tr>
<tr>
<td>
<code>policy</code></br>
<em>
string
</em>
</td>
<td>
<p>Specifies the name of the policy.</p>
</td>
</tr>
<tr>
<td>
<code>resource</code></br>
<em>
github.com/kyverno/kyverno/api/kyverno/v1.ResourceSpec
</em>
</td>
<td>
<p>ResourceSpec is the information to identify the update request.</p>
</td>
</tr>
<tr>
<td>
<code>context</code></br>
<em>
<a href="#kyverno.io/v1beta1.UpdateRequestSpecContext">
UpdateRequestSpecContext
</a>
</em>
</td>
<td>
<p>Context &hellip;</p>
</td>
</tr>
</tbody>
</table>
<hr />
<h3 id="kyverno.io/v1beta1.UpdateRequestSpecContext">UpdateRequestSpecContext
</h3>
<p>
(<em>Appears on:</em>
<a href="#kyverno.io/v1beta1.UpdateRequestSpec">UpdateRequestSpec</a>)
</p>
<p>
<p>UpdateRequestSpecContext stores the context to be shared.</p>
</p>
<table class="table table-striped">
<thead class="thead-dark">
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>userInfo</code></br>
<em>
<a href="#kyverno.io/v1beta1.RequestInfo">
RequestInfo
</a>
</em>
</td>
<td>
<em>(Optional)</em>
</td>
</tr>
<tr>
<td>
<code>admissionRequestInfo</code></br>
<em>
<a href="#kyverno.io/v1beta1.AdmissionRequestInfoObject">
AdmissionRequestInfoObject
</a>
</em>
</td>
<td>
<em>(Optional)</em>
</td>
</tr>
</tbody>
</table>
<hr />
<h3 id="kyverno.io/v1beta1.UpdateRequestState">UpdateRequestState
(<code>string</code> alias)</p></h3>
<p>
(<em>Appears on:</em>
<a href="#kyverno.io/v1beta1.UpdateRequestStatus">UpdateRequestStatus</a>)
</p>
<p>
<p>UpdateRequestState defines the state of request.</p>
</p>
<h3 id="kyverno.io/v1beta1.UpdateRequestStatus">UpdateRequestStatus
</h3>
<p>
(<em>Appears on:</em>
<a href="#kyverno.io/v1beta1.UpdateRequest">UpdateRequest</a>)
</p>
<p>
<p>UpdateRequestStatus defines the observed state of UpdateRequest</p>
</p>
<table class="table table-striped">
<thead class="thead-dark">
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>state</code></br>
<em>
<a href="#kyverno.io/v1beta1.UpdateRequestState">
UpdateRequestState
</a>
</em>
</td>
<td>
<p>State represents state of the generate request.</p>
</td>
</tr>
<tr>
<td>
<code>message</code></br>
<em>
string
</em>
</td>
<td>
<em>(Optional)</em>
<p>Specifies request status message.</p>
</td>
</tr>
<tr>
<td>
<code>generatedResources</code></br>
<em>
[]github.com/kyverno/kyverno/api/kyverno/v1.ResourceSpec
</em>
</td>
<td>
<p>This will track the resources that are updated by the generate Policy.
Will be used during clean up resources.</p>
</td>
</tr>
</tbody>
</table>
<hr />
</div>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</body>
</html>

1
go.mod
View file

@ -21,6 +21,7 @@ require (
github.com/go-logr/logr v1.2.2
github.com/google/go-containerregistry v0.8.1-0.20220209165246-a44adc326839
github.com/google/go-containerregistry/pkg/authn/kubernetes v0.0.0-20220301182634-bfe2ffc6b6bd
github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible
github.com/googleapis/gnostic v0.5.5
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
github.com/in-toto/in-toto-golang v0.3.4-0.20211211042327-af1f9fb822bf

View file

@ -0,0 +1,118 @@
package common
import (
"encoding/json"
"fmt"
"reflect"
"github.com/go-logr/logr"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/config"
dclient "github.com/kyverno/kyverno/pkg/dclient"
"github.com/kyverno/kyverno/pkg/engine"
"github.com/kyverno/kyverno/pkg/engine/context"
utils "github.com/kyverno/kyverno/pkg/utils"
admissionv1 "k8s.io/api/admission/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
func NewBackgroundContext(dclient *dclient.Client, ur *urkyverno.UpdateRequest,
policy kyverno.PolicyInterface, trigger *unstructured.Unstructured,
cfg config.Interface, namespaceLabels map[string]string, logger logr.Logger) (*engine.PolicyContext, bool, error) {
ctx := context.NewContext()
requestString := ur.Spec.Context.AdmissionRequestInfo.AdmissionRequest
var request admissionv1.AdmissionRequest
err := json.Unmarshal([]byte(requestString), &request)
if err != nil {
logger.Error(err, "error parsing the request string")
}
if err := ctx.AddRequest(&request); err != nil {
logger.Error(err, "failed to load request in context")
return nil, false, err
}
new, old, err := utils.ExtractResources(nil, &request)
if err != nil {
logger.Error(err, "failed to load request in context")
return nil, false, err
}
if !reflect.DeepEqual(new, unstructured.Unstructured{}) {
if !check(&new, trigger) {
err := fmt.Errorf("resources don't match")
logger.Error(err, "", "resource", ur.Spec.Resource)
return nil, false, err
}
}
if trigger == nil {
trigger = &old
}
err = ctx.AddResource(trigger.Object)
if err != nil {
logger.Error(err, "failed to load resource in context")
return nil, false, err
}
err = ctx.AddOldResource(old.Object)
if err != nil {
logger.Error(err, "failed to load resource in context")
return nil, false, err
}
err = ctx.AddUserInfo(ur.Spec.Context.UserRequestInfo)
if err != nil {
logger.Error(err, "failed to load SA in context")
return nil, false, err
}
err = ctx.AddServiceAccount(ur.Spec.Context.UserRequestInfo.AdmissionUserInfo.Username)
if err != nil {
logger.Error(err, "failed to load UserInfo in context")
return nil, false, err
}
if err := ctx.AddImageInfos(trigger); err != nil {
logger.Error(err, "unable to add image info to variables context")
}
policyContext := &engine.PolicyContext{
NewResource: *trigger,
OldResource: old,
Policy: policy,
AdmissionInfo: ur.Spec.Context.UserRequestInfo,
ExcludeGroupRole: cfg.GetExcludeGroupRole(),
ExcludeResourceFunc: cfg.ToFilter,
JSONContext: ctx,
NamespaceLabels: namespaceLabels,
Client: dclient,
AdmissionOperation: false,
}
return policyContext, false, nil
}
func check(admissionRsc, existingRsc *unstructured.Unstructured) bool {
if existingRsc == nil {
return admissionRsc == nil
}
if admissionRsc.GetName() != existingRsc.GetName() {
return false
}
if admissionRsc.GetNamespace() != existingRsc.GetNamespace() {
return false
}
if admissionRsc.GetKind() != existingRsc.GetKind() {
return false
}
if admissionRsc.GetAPIVersion() != existingRsc.GetAPIVersion() {
return false
}
return true
}

View file

@ -0,0 +1,34 @@
package common
import (
"fmt"
"github.com/kyverno/kyverno/pkg/event"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
func FailedEvents(err error, policy, rule string, source event.Source, resource unstructured.Unstructured) []event.Info {
re := newEvent(policy, rule, source, resource)
re.Reason = event.PolicyFailed.String()
re.Message = fmt.Sprintf("policy %s/%s failed to apply to %s/%s/%s: %v", policy, rule, resource.GetKind(), resource.GetNamespace(), resource.GetName(), err)
return []event.Info{re}
}
func SucceedEvents(policy, rule string, source event.Source, resource unstructured.Unstructured) []event.Info {
re := newEvent(policy, rule, source, resource)
re.Reason = event.PolicyApplied.String()
re.Message = fmt.Sprintf("policy %s/%s applied to %s/%s/%s successfully", policy, rule, resource.GetKind(), resource.GetNamespace(), resource.GetName())
return []event.Info{re}
}
func newEvent(policy, rule string, source event.Source, resource unstructured.Unstructured) (re event.Info) {
re.Kind = resource.GetKind()
re.Namespace = resource.GetNamespace()
re.Name = resource.GetName()
re.Source = source
return
}

View file

@ -0,0 +1,55 @@
package common
import (
"fmt"
"time"
logr "github.com/go-logr/logr"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/common"
dclient "github.com/kyverno/kyverno/pkg/dclient"
v1 "k8s.io/api/admission/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
func GetResource(client *dclient.Client, urSpec urkyverno.UpdateRequestSpec, log logr.Logger) (*unstructured.Unstructured, error) {
resourceSpec := urSpec.Resource
get := func() (*unstructured.Unstructured, error) {
if resourceSpec.Kind == "Namespace" {
resourceSpec.Namespace = ""
}
resource, err := client.GetResource(resourceSpec.APIVersion, resourceSpec.Kind, resourceSpec.Namespace, resourceSpec.Name)
if err != nil {
if urSpec.Type == urkyverno.Mutate && errors.IsNotFound(err) && urSpec.Context.AdmissionRequestInfo.Operation == v1.Delete {
log.V(4).Info("trigger resource does not exist for mutateExisting rule", "operation", urSpec.Context.AdmissionRequestInfo.Operation)
return nil, nil
}
return nil, fmt.Errorf("resource %s/%s/%s/%s: %v", resourceSpec.APIVersion, resourceSpec.Kind, resourceSpec.Namespace, resourceSpec.Name, err)
}
if resource.GetDeletionTimestamp() != nil {
log.V(4).Info("trigger resource is in termination", "operation", urSpec.Context.AdmissionRequestInfo.Operation)
return nil, nil
}
return resource, nil
}
var resource *unstructured.Unstructured
var err error
retry := func() error {
resource, err = get()
return err
}
f := common.RetryFunc(time.Second, 5*time.Second, retry, "failed to get resource", log.WithName("getResource"))
if err := f(); err != nil {
return nil, err
}
log.Info("fetched trigger resource", "resourceSpec", resourceSpec)
return resource, err
}

View file

@ -2,6 +2,7 @@ package common
import (
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
jsonutils "github.com/kyverno/kyverno/pkg/utils/json"
"k8s.io/apimachinery/pkg/api/errors"
@ -10,9 +11,9 @@ import (
//StatusControlInterface provides interface to update status subresource
type StatusControlInterface interface {
Failed(gr kyverno.GenerateRequest, message string, genResources []kyverno.ResourceSpec) error
Success(gr kyverno.GenerateRequest, genResources []kyverno.ResourceSpec) error
Skip(gr kyverno.GenerateRequest, genResources []kyverno.ResourceSpec) error
Failed(ur urkyverno.UpdateRequest, message string, genResources []kyverno.ResourceSpec) error
Success(ur urkyverno.UpdateRequest, genResources []kyverno.ResourceSpec) error
Skip(gr urkyverno.UpdateRequest, genResources []kyverno.ResourceSpec) error
}
// StatusControl is default implementaation of GRStatusControlInterface
@ -21,61 +22,75 @@ type StatusControl struct {
}
//Failed sets gr status.state to failed with message
func (sc StatusControl) Failed(gr kyverno.GenerateRequest, message string, genResources []kyverno.ResourceSpec) error {
func (sc StatusControl) Failed(gr urkyverno.UpdateRequest, message string, genResources []kyverno.ResourceSpec) error {
genR := &urkyverno.UpdateRequestStatus{
State: urkyverno.Failed,
Message: message,
}
if genResources != nil {
genR.GeneratedResources = genResources
}
patch := jsonutils.NewPatch(
"/status",
"replace",
&kyverno.GenerateRequestStatus{
State: kyverno.Failed,
Message: message,
GeneratedResources: genResources, // Update Generated Resources
},
genR,
)
_, err := PatchGenerateRequest(&gr, patch, sc.Client, "status")
if err != nil && !errors.IsNotFound(err) {
log.Log.Error(err, "failed to patch generate request status", "name", gr.Name)
log.Log.Error(err, "failed to patch update request status", "name", gr.Name)
return err
}
log.Log.V(3).Info("updated generate request status", "name", gr.Name, "status", string(kyverno.Failed))
log.Log.V(3).Info("updated update request status", "name", gr.Name, "status", string(kyverno.Failed))
return nil
}
// Success sets the gr status.state to completed and clears message
func (sc StatusControl) Success(gr kyverno.GenerateRequest, genResources []kyverno.ResourceSpec) error {
func (sc StatusControl) Success(gr urkyverno.UpdateRequest, genResources []kyverno.ResourceSpec) error {
genR := &urkyverno.UpdateRequestStatus{
State: urkyverno.Completed,
Message: "",
}
if genResources != nil {
genR.GeneratedResources = genResources
}
patch := jsonutils.NewPatch(
"/status",
"replace",
&kyverno.GenerateRequestStatus{
State: kyverno.Completed,
Message: "",
GeneratedResources: genResources, // Update Generated Resources
},
genR,
)
_, err := PatchGenerateRequest(&gr, patch, sc.Client, "status")
if err != nil && !errors.IsNotFound(err) {
log.Log.Error(err, "failed to patch generate request status", "name", gr.Name)
log.Log.Error(err, "failed to patch update request status", "name", gr.Name)
return err
}
log.Log.V(3).Info("updated generate request status", "name", gr.Name, "status", string(kyverno.Completed))
log.Log.V(3).Info("updated update request status", "name", gr.Name, "status", string(kyverno.Completed))
return nil
}
// Success sets the gr status.state to completed and clears message
func (sc StatusControl) Skip(gr kyverno.GenerateRequest, genResources []kyverno.ResourceSpec) error {
func (sc StatusControl) Skip(gr urkyverno.UpdateRequest, genResources []kyverno.ResourceSpec) error {
genR := &urkyverno.UpdateRequestStatus{
State: urkyverno.Skip,
Message: "",
}
if genResources != nil {
genR.GeneratedResources = genResources
}
patch := jsonutils.NewPatch(
"/status",
"replace",
&kyverno.GenerateRequestStatus{
State: kyverno.Skip,
Message: "",
GeneratedResources: genResources, // Update Generated Resources
},
genR,
)
_, err := PatchGenerateRequest(&gr, patch, sc.Client, "status")
if err != nil && !errors.IsNotFound(err) {
log.Log.Error(err, "failed to patch generate request status", "name", gr.Name)
log.Log.Error(err, "failed to update generate request status", "name", gr.Name)
return err
}
log.Log.V(3).Info("updated generate request status", "name", gr.Name, "status", string(kyverno.Skip))
log.Log.V(3).Info("updated update request status", "name", gr.Name, "status", string(kyverno.Skip))
return nil
}

View file

@ -3,7 +3,7 @@ package common
import (
"context"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
"github.com/kyverno/kyverno/pkg/config"
jsonutils "github.com/kyverno/kyverno/pkg/utils/json"
@ -12,12 +12,12 @@ import (
)
// PatchGenerateRequest patches a generate request object
func PatchGenerateRequest(gr *kyverno.GenerateRequest, patch jsonutils.Patch, client kyvernoclient.Interface, subresources ...string) (*kyverno.GenerateRequest, error) {
func PatchGenerateRequest(gr *urkyverno.UpdateRequest, patch jsonutils.Patch, client kyvernoclient.Interface, subresources ...string) (*urkyverno.UpdateRequest, error) {
data, err := patch.ToPatchBytes()
if nil != err {
return gr, err
}
newGR, err := client.KyvernoV1().GenerateRequests(config.KyvernoNamespace).Patch(context.TODO(), gr.Name, types.JSONPatchType, data, metav1.PatchOptions{}, subresources...)
newGR, err := client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).Patch(context.TODO(), gr.Name, types.JSONPatchType, data, metav1.PatchOptions{}, subresources...)
if err != nil {
return gr, err
}

View file

@ -4,12 +4,12 @@ import (
"strconv"
"github.com/go-logr/logr"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
dclient "github.com/kyverno/kyverno/pkg/dclient"
apierrors "k8s.io/apimachinery/pkg/api/errors"
)
func (c *Controller) processGR(gr kyverno.GenerateRequest) error {
func (c *Controller) processGR(gr urkyverno.UpdateRequest) error {
logger := c.log.WithValues("kind", gr.Kind, "namespace", gr.Namespace, "name", gr.Name)
// 1- Corresponding policy has been deleted
// then we don't delete the generated resources
@ -44,7 +44,7 @@ func (c *Controller) processGR(gr kyverno.GenerateRequest) error {
return nil
}
func ownerResourceExists(log logr.Logger, client *dclient.Client, gr kyverno.GenerateRequest) bool {
func ownerResourceExists(log logr.Logger, client *dclient.Client, gr urkyverno.UpdateRequest) bool {
_, err := client.GetResource("", gr.Spec.Resource.Kind, gr.Spec.Resource.Namespace, gr.Spec.Resource.Name)
// trigger resources has been deleted
if apierrors.IsNotFound(err) {
@ -58,7 +58,7 @@ func ownerResourceExists(log logr.Logger, client *dclient.Client, gr kyverno.Gen
return true
}
func deleteGeneratedResources(log logr.Logger, client *dclient.Client, gr kyverno.GenerateRequest) error {
func deleteGeneratedResources(log logr.Logger, client *dclient.Client, gr urkyverno.UpdateRequest) error {
for _, genResource := range gr.Status.GeneratedResources {
err := client.DeleteResource("", genResource.Kind, genResource.Namespace, genResource.Name, false)
if err != nil && !apierrors.IsNotFound(err) {

View file

@ -3,14 +3,15 @@ package cleanup
import (
"time"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
"k8s.io/client-go/kubernetes"
"github.com/go-logr/logr"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/autogen"
kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
kyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1"
urkyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1beta1"
kyvernolister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1"
urkyvernolister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1beta1"
pkgCommon "github.com/kyverno/kyverno/pkg/common"
"github.com/kyverno/kyverno/pkg/config"
dclient "github.com/kyverno/kyverno/pkg/dclient"
@ -19,6 +20,7 @@ import (
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
coreinformers "k8s.io/client-go/informers/core/v1"
"k8s.io/client-go/kubernetes"
corelister "k8s.io/client-go/listers/core/v1"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
@ -55,6 +57,9 @@ type Controller struct {
// grLister can list/get generate request from the shared informer's store
grLister kyvernolister.GenerateRequestNamespaceLister
// urLister can list/get update request from the shared informer's store
urLister urkyvernolister.UpdateRequestNamespaceLister
// nsLister can list/get namespaces from the shared informer's store
nsLister corelister.NamespaceLister
@ -67,12 +72,12 @@ type Controller struct {
// grSynced returns true if the generate request store has been synced at least once
grSynced cache.InformerSynced
// urSynced returns true if the update request store has been synced at least once
urSynced cache.InformerSynced
// nsListerSynced returns true if the namespace store has been synced at least once
nsListerSynced cache.InformerSynced
// namespaceInformer for re-evaluation on namespace updates
namespaceInformer coreinformers.NamespaceInformer
// logger
log logr.Logger
}
@ -85,17 +90,17 @@ func NewController(
pInformer kyvernoinformer.ClusterPolicyInformer,
npInformer kyvernoinformer.PolicyInformer,
grInformer kyvernoinformer.GenerateRequestInformer,
urInformer urkyvernoinformer.UpdateRequestInformer,
namespaceInformer coreinformers.NamespaceInformer,
log logr.Logger,
) (*Controller, error) {
c := Controller{
kyvernoClient: kyvernoclient,
client: client,
pInformer: pInformer,
grInformer: grInformer,
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "generate-request-cleanup"),
namespaceInformer: namespaceInformer,
log: log,
kyvernoClient: kyvernoclient,
client: client,
pInformer: pInformer,
grInformer: grInformer,
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "generate-request-cleanup"),
log: log,
}
c.control = Control{client: kyvernoclient}
@ -108,6 +113,7 @@ func NewController(
c.pSynced = pInformer.Informer().HasSynced
c.npSynced = npInformer.Informer().HasSynced
c.grSynced = grInformer.Informer().HasSynced
c.urSynced = urInformer.Informer().HasSynced
c.nsListerSynced = namespaceInformer.Informer().HasSynced
return &c, nil
@ -163,24 +169,24 @@ func (c *Controller) deletePolicy(obj interface{}) {
for _, gr := range grs {
logger.V(4).Info("enqueue the gr for cleanup", "gr name", gr.Name)
c.addGR(gr)
c.addUR(gr)
}
}
}
func (c *Controller) addGR(obj interface{}) {
gr := obj.(*kyverno.GenerateRequest)
func (c *Controller) addUR(obj interface{}) {
gr := obj.(*urkyverno.UpdateRequest)
c.enqueue(gr)
}
func (c *Controller) updateGR(old, cur interface{}) {
gr := cur.(*kyverno.GenerateRequest)
func (c *Controller) updateUR(old, cur interface{}) {
gr := cur.(*urkyverno.UpdateRequest)
c.enqueue(gr)
}
func (c *Controller) deleteGR(obj interface{}) {
func (c *Controller) deleteUR(obj interface{}) {
logger := c.log
gr, ok := obj.(*kyverno.GenerateRequest)
gr, ok := obj.(*urkyverno.UpdateRequest)
if !ok {
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
if !ok {
@ -188,7 +194,7 @@ func (c *Controller) deleteGR(obj interface{}) {
return
}
_, ok = tombstone.Obj.(*kyverno.GenerateRequest)
_, ok = tombstone.Obj.(*urkyverno.UpdateRequest)
if !ok {
logger.Info("ombstone contained object that is not a Generate Request", "obj", obj)
return
@ -215,9 +221,9 @@ func (c *Controller) deleteGR(obj interface{}) {
c.enqueue(gr)
}
func (c *Controller) enqueue(gr *kyverno.GenerateRequest) {
func (c *Controller) enqueue(gr *urkyverno.UpdateRequest) {
// skip enqueueing Pending requests
if gr.Status.State == kyverno.Pending {
if gr.Status.State == urkyverno.Pending {
return
}
@ -240,7 +246,7 @@ func (c *Controller) Run(workers int, stopCh <-chan struct{}) {
logger.Info("starting")
defer logger.Info("shutting down")
if !cache.WaitForCacheSync(stopCh, c.pSynced, c.grSynced, c.npSynced) {
if !cache.WaitForCacheSync(stopCh, c.pSynced, c.grSynced, c.urSynced, c.npSynced, c.nsListerSynced) {
logger.Info("failed to sync informer cache")
return
}
@ -250,9 +256,9 @@ func (c *Controller) Run(workers int, stopCh <-chan struct{}) {
})
c.grInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: c.addGR,
UpdateFunc: c.updateGR,
DeleteFunc: c.deleteGR,
AddFunc: c.addUR,
UpdateFunc: c.updateUR,
DeleteFunc: c.deleteUR,
})
for i := 0; i < workers; i++ {
@ -320,7 +326,7 @@ func (c *Controller) syncGenerateRequest(key string) error {
if err != nil {
return err
}
gr, err := c.grLister.Get(grName)
gr, err := c.urLister.Get(grName)
if err != nil {
return err
}

View file

@ -20,5 +20,5 @@ type Control struct {
//Delete deletes the specified resource
func (c Control) Delete(gr string) error {
return c.client.KyvernoV1().GenerateRequests(config.KyvernoNamespace).Delete(context.TODO(), gr, metav1.DeleteOptions{})
return c.client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).Delete(context.TODO(), gr, metav1.DeleteOptions{})
}

View file

@ -10,29 +10,27 @@ import (
"strings"
"time"
"github.com/go-logr/logr"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/autogen"
"github.com/kyverno/kyverno/pkg/background/common"
kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
kyvernolister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1"
"github.com/kyverno/kyverno/pkg/engine/response"
"github.com/kyverno/kyverno/pkg/event"
"github.com/go-logr/logr"
pkgcommon "github.com/kyverno/kyverno/pkg/common"
"github.com/kyverno/kyverno/pkg/config"
dclient "github.com/kyverno/kyverno/pkg/dclient"
"github.com/kyverno/kyverno/pkg/engine"
"github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/response"
"github.com/kyverno/kyverno/pkg/engine/utils"
"github.com/kyverno/kyverno/pkg/engine/variables"
"github.com/kyverno/kyverno/pkg/event"
kyvernoutils "github.com/kyverno/kyverno/pkg/utils"
admissionv1 "k8s.io/api/admission/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/labels"
coreinformers "k8s.io/client-go/informers/core/v1"
corelister "k8s.io/client-go/listers/core/v1"
"k8s.io/client-go/tools/cache"
)
@ -75,7 +73,7 @@ func NewGenerateController(
npolicyLister kyvernolister.PolicyLister,
grLister kyvernolister.GenerateRequestNamespaceLister,
eventGen event.Interface,
namespaceInformer coreinformers.NamespaceInformer,
nsLister corelister.NamespaceLister,
log logr.Logger,
dynamicConfig config.Interface,
) (*GenerateController, error) {
@ -92,12 +90,12 @@ func NewGenerateController(
}
c.statusControl = common.StatusControl{Client: kyvernoClient}
c.nsLister = namespaceInformer.Lister()
c.nsLister = nsLister
return &c, nil
}
func (c *GenerateController) ProcessGR(gr *kyverno.GenerateRequest) error {
func (c *GenerateController) ProcessGR(gr *urkyverno.UpdateRequest) error {
logger := c.log.WithValues("name", gr.Name, "policy", gr.Spec.Policy, "kind", gr.Spec.Resource.Kind, "apiVersion", gr.Spec.Resource.APIVersion, "namespace", gr.Spec.Resource.Namespace, "name", gr.Spec.Resource.Name)
var err error
var resource *unstructured.Unstructured
@ -105,7 +103,7 @@ func (c *GenerateController) ProcessGR(gr *kyverno.GenerateRequest) error {
var precreatedResource bool
// 1 - Check if the resource exists
resource, err = getResource(c.client, gr.Spec.Resource, c.log)
resource, err = common.GetResource(c.client, gr.Spec, c.log)
if err != nil {
// Don't update status
// re-queueing the GR by updating the annotation
@ -142,7 +140,7 @@ func (c *GenerateController) ProcessGR(gr *kyverno.GenerateRequest) error {
if updateAnnotation {
gr.SetAnnotations(grAnnotations)
_, err := c.kyvernoClient.KyvernoV1().GenerateRequests(config.KyvernoNamespace).Update(contextdefault.TODO(), gr, metav1.UpdateOptions{})
_, err := c.kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).Update(contextdefault.TODO(), gr, metav1.UpdateOptions{})
if err != nil {
logger.Error(err, "failed to update annotation in generate request for the resource", "generate request", gr.Name)
return err
@ -169,7 +167,7 @@ func (c *GenerateController) ProcessGR(gr *kyverno.GenerateRequest) error {
}
// 3 - Report failure Events
events := failedEvents(err, *gr, *resource)
events := common.FailedEvents(err, gr.Spec.Policy, "", event.GeneratePolicyController, *resource)
c.eventGen.Add(events...)
}
@ -179,12 +177,11 @@ func (c *GenerateController) ProcessGR(gr *kyverno.GenerateRequest) error {
const doesNotApply = "policy does not apply to resource"
func (c *GenerateController) applyGenerate(resource unstructured.Unstructured, gr kyverno.GenerateRequest, namespaceLabels map[string]string) ([]kyverno.ResourceSpec, bool, error) {
func (c *GenerateController) applyGenerate(resource unstructured.Unstructured, gr urkyverno.UpdateRequest, namespaceLabels map[string]string) ([]kyverno.ResourceSpec, bool, error) {
logger := c.log.WithValues("name", gr.Name, "policy", gr.Spec.Policy, "kind", gr.Spec.Resource.Kind, "apiVersion", gr.Spec.Resource.APIVersion, "namespace", gr.Spec.Resource.Namespace, "name", gr.Spec.Resource.Name)
// Get the list of rules to be applied
// get policy
// build context
ctx := context.NewContext()
logger.V(3).Info("applying generate policy rule")
@ -211,53 +208,9 @@ func (c *GenerateController) applyGenerate(resource unstructured.Unstructured, g
return nil, false, err
}
requestString := gr.Spec.Context.AdmissionRequestInfo.AdmissionRequest
var request admissionv1.AdmissionRequest
err = json.Unmarshal([]byte(requestString), &request)
policyContext, precreatedResource, err := common.NewBackgroundContext(c.client, &gr, &policy, &resource, c.Config, namespaceLabels, logger)
if err != nil {
logger.Error(err, "error parsing the request string")
}
if gr.Spec.Context.AdmissionRequestInfo.Operation == admissionv1.Update {
request.Operation = gr.Spec.Context.AdmissionRequestInfo.Operation
}
if err := ctx.AddRequest(&request); err != nil {
logger.Error(err, "failed to load request in context")
return nil, false, err
}
err = ctx.AddResource(resource.Object)
if err != nil {
logger.Error(err, "failed to load resource in context")
return nil, false, err
}
err = ctx.AddUserInfo(gr.Spec.Context.UserRequestInfo)
if err != nil {
logger.Error(err, "failed to load SA in context")
return nil, false, err
}
err = ctx.AddServiceAccount(gr.Spec.Context.UserRequestInfo.AdmissionUserInfo.Username)
if err != nil {
logger.Error(err, "failed to load UserInfo in context")
return nil, false, err
}
if err := ctx.AddImageInfos(&resource); err != nil {
logger.Error(err, "unable to add image info to variables context")
}
policyContext := &engine.PolicyContext{
NewResource: resource,
Policy: &policy,
AdmissionInfo: gr.Spec.Context.UserRequestInfo,
ExcludeGroupRole: c.Config.GetExcludeGroupRole(),
ExcludeResourceFunc: c.Config.ToFilter,
JSONContext: ctx,
NamespaceLabels: namespaceLabels,
Client: c.client,
return nil, precreatedResource, err
}
// check if the policy still applies to the resource
@ -300,7 +253,7 @@ func (c *GenerateController) applyGenerate(resource unstructured.Unstructured, g
}
// getPolicySpec gets the policy spec from the ClusterPolicy/Policy
func (c *GenerateController) getPolicySpec(gr kyverno.GenerateRequest) (kyverno.ClusterPolicy, error) {
func (c *GenerateController) getPolicySpec(gr urkyverno.UpdateRequest) (kyverno.ClusterPolicy, error) {
var policy kyverno.ClusterPolicy
pNamespace, pName, err := cache.SplitMetaNamespaceKey(gr.Spec.Policy)
@ -328,7 +281,7 @@ func (c *GenerateController) getPolicySpec(gr kyverno.GenerateRequest) (kyverno.
}
}
func updateStatus(statusControl common.StatusControlInterface, gr kyverno.GenerateRequest, err error, genResources []kyverno.ResourceSpec, precreatedResource bool) error {
func updateStatus(statusControl common.StatusControlInterface, gr urkyverno.UpdateRequest, err error, genResources []kyverno.ResourceSpec, precreatedResource bool) error {
if err != nil {
return statusControl.Failed(gr, err.Error(), genResources)
} else if precreatedResource {
@ -339,7 +292,7 @@ func updateStatus(statusControl common.StatusControlInterface, gr kyverno.Genera
return statusControl.Success(gr, genResources)
}
func (c *GenerateController) applyGeneratePolicy(log logr.Logger, policyContext *engine.PolicyContext, gr kyverno.GenerateRequest, applicableRules []string) (genResources []kyverno.ResourceSpec, processExisting bool, err error) {
func (c *GenerateController) applyGeneratePolicy(log logr.Logger, policyContext *engine.PolicyContext, gr urkyverno.UpdateRequest, applicableRules []string) (genResources []kyverno.ResourceSpec, processExisting bool, err error) {
// Get the response as the actions to be performed on the resource
// - - substitute values
policy := policyContext.Policy
@ -417,7 +370,7 @@ func getResourceInfo(object map[string]interface{}) (kind, name, namespace, apiv
return
}
func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resource unstructured.Unstructured, ctx context.EvalInterface, policy string, gr kyverno.GenerateRequest) (kyverno.ResourceSpec, error) {
func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resource unstructured.Unstructured, ctx context.EvalInterface, policy string, gr urkyverno.UpdateRequest) (kyverno.ResourceSpec, error) {
var rdata map[string]interface{}
var err error
var mode ResourceMode

View file

@ -1,21 +0,0 @@
package generate
import (
"fmt"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/event"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
func failedEvents(err error, gr kyverno.GenerateRequest, resource unstructured.Unstructured) []event.Info {
re := event.Info{}
re.Kind = resource.GetKind()
re.Namespace = resource.GetNamespace()
re.Name = resource.GetName()
re.Reason = event.PolicyFailed.String()
re.Source = event.GeneratePolicyController
re.Message = fmt.Sprintf("policy %s failed to apply: %v", gr.Spec.Policy, err)
return []event.Info{re}
}

View file

@ -1,42 +0,0 @@
package generate
import (
"time"
logr "github.com/go-logr/logr"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/common"
dclient "github.com/kyverno/kyverno/pkg/dclient"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
func getResource(client *dclient.Client, resourceSpec kyverno.ResourceSpec, log logr.Logger) (*unstructured.Unstructured, error) {
get := func() (*unstructured.Unstructured, error) {
if resourceSpec.Kind == "Namespace" {
resourceSpec.Namespace = ""
}
resource, err := client.GetResource(resourceSpec.APIVersion, resourceSpec.Kind, resourceSpec.Namespace, resourceSpec.Name)
if err != nil {
return nil, err
}
if resource.GetDeletionTimestamp() != nil {
return nil, nil
}
return resource, nil
}
retry := func() error {
_, err := get()
return err
}
f := common.RetryFunc(time.Second, 30*time.Second, retry, log.WithName("getResource"))
if err := f(); err != nil {
return nil, err
}
return get()
}

View file

@ -0,0 +1,243 @@
package mutate
import (
"encoding/json"
"fmt"
"github.com/go-logr/logr"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/background/common"
kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
kyvernolister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1"
urlister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/config"
dclient "github.com/kyverno/kyverno/pkg/dclient"
"github.com/kyverno/kyverno/pkg/engine"
"github.com/kyverno/kyverno/pkg/engine/response"
engineUtils "github.com/kyverno/kyverno/pkg/engine/utils"
"github.com/kyverno/kyverno/pkg/event"
"github.com/kyverno/kyverno/pkg/utils"
yamlv2 "gopkg.in/yaml.v2"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
cache "k8s.io/client-go/tools/cache"
)
type MutateExistingController struct {
client *dclient.Client
// typed client for Kyverno CRDs
kyvernoClient *kyvernoclient.Clientset
// urStatusControl is used to update UR status
statusControl common.StatusControlInterface
// event generator interface
eventGen event.Interface
log logr.Logger
// urLister can list/get update request from the shared informer's store
urLister urlister.UpdateRequestNamespaceLister
// policyLister can list/get cluster policy from the shared informer's store
policyLister kyvernolister.ClusterPolicyLister
// policyLister can list/get Namespace policy from the shared informer's store
npolicyLister kyvernolister.PolicyLister
Config config.Interface
}
// NewMutateExistingController returns an instance of the MutateExistingController
func NewMutateExistingController(
kyvernoClient *kyvernoclient.Clientset,
client *dclient.Client,
policyLister kyvernolister.ClusterPolicyLister,
npolicyLister kyvernolister.PolicyLister,
urLister urlister.UpdateRequestNamespaceLister,
eventGen event.Interface,
log logr.Logger,
dynamicConfig config.Interface,
) (*MutateExistingController, error) {
c := MutateExistingController{
client: client,
kyvernoClient: kyvernoClient,
eventGen: eventGen,
log: log,
policyLister: policyLister,
npolicyLister: npolicyLister,
urLister: urLister,
Config: dynamicConfig,
}
c.statusControl = common.StatusControl{Client: kyvernoClient}
return &c, nil
}
func (c *MutateExistingController) ProcessUR(ur *urkyverno.UpdateRequest) error {
logger := c.log.WithValues("name", ur.Name, "policy", ur.Spec.Policy, "kind", ur.Spec.Resource.Kind, "apiVersion", ur.Spec.Resource.APIVersion, "namespace", ur.Spec.Resource.Namespace, "name", ur.Spec.Resource.Name)
var errs []error
policy, err := c.getPolicy(ur.Spec.Policy)
if err != nil {
logger.Error(err, "failed to get policy")
return err
}
for _, rule := range policy.GetSpec().Rules {
if !rule.IsMutateExisting() {
continue
}
trigger, err := common.GetResource(c.client, ur.Spec, c.log)
if err != nil {
logger.WithName(rule.Name).Error(err, "failed to get trigger resource")
errs = append(errs, err)
continue
}
policyContext, _, err := common.NewBackgroundContext(c.client, ur, policy, trigger, c.Config, nil, logger)
if err != nil {
logger.WithName(rule.Name).Error(err, "failed to build policy context")
errs = append(errs, err)
continue
}
er := engine.Mutate(policyContext)
for _, r := range er.PolicyResponse.Rules {
patched := r.PatchedTarget
switch r.Status {
case response.RuleStatusFail, response.RuleStatusError, response.RuleStatusWarn:
err := fmt.Errorf("failed to mutate existing resource, rule response%v: %s", r.Status, r.Message)
logger.Error(err, "")
errs = append(errs, err)
c.report(err, ur.Spec.Policy, rule.Name, patched)
case response.RuleStatusSkip:
logger.Info("mutate existing rule skipped", "rule", r.Name, "message", r.Message)
c.report(err, ur.Spec.Policy, rule.Name, patched)
case response.RuleStatusPass:
patchedNew, err := addAnnotation(policy, patched, r)
if err != nil {
logger.Error(err, "failed to apply patches")
errs = append(errs, err)
}
if patchedNew == nil {
err := fmt.Errorf("empty resource to patch")
logger.Error(err, "", "rule", r.Name, "message", r.Message)
errs = append(errs, err)
continue
}
if r.Status == response.RuleStatusPass {
_, updateErr := c.client.UpdateResource(patchedNew.GetAPIVersion(), patchedNew.GetKind(), patchedNew.GetNamespace(), patchedNew.Object, false)
if updateErr != nil {
errs = append(errs, updateErr)
logger.WithName(rule.Name).Error(updateErr, "failed to update target resource", "namespace", patchedNew.GetNamespace(), "name", patchedNew.GetName())
} else {
logger.WithName(rule.Name).V(4).Info("successfully mutated existing resource", "namespace", patchedNew.GetNamespace(), "name", patchedNew.GetName())
}
c.report(updateErr, ur.Spec.Policy, rule.Name, patched)
}
}
}
}
return updateURStatus(c.statusControl, *ur, engineUtils.CombineErrors(errs))
}
func (c *MutateExistingController) getPolicy(key string) (kyvernov1.PolicyInterface, error) {
pNamespace, pName, err := cache.SplitMetaNamespaceKey(key)
if err != nil {
return nil, err
}
if pNamespace != "" {
return c.npolicyLister.Policies(pNamespace).Get(pName)
}
return c.policyLister.Get(pName)
}
func (c *MutateExistingController) report(err error, policy, rule string, target *unstructured.Unstructured) {
var events []event.Info
if target == nil {
c.log.WithName("mutateExisting").Info("cannot generate events for empty target resource", "policy", policy, "rule", rule, "err", err.Error())
}
if err != nil {
events = common.FailedEvents(err, policy, rule, event.MutateExistingController, *target)
} else {
events = common.SucceedEvents(policy, rule, event.MutateExistingController, *target)
}
c.eventGen.Add(events...)
}
func updateURStatus(statusControl common.StatusControlInterface, ur urkyverno.UpdateRequest, err error) error {
if err != nil {
return statusControl.Failed(ur, err.Error(), nil)
}
return statusControl.Success(ur, nil)
}
func addAnnotation(policy kyvernov1.PolicyInterface, patched *unstructured.Unstructured, r response.RuleResponse) (patchedNew *unstructured.Unstructured, err error) {
if patched == nil {
return
}
patchedNew = patched
var rulePatches []utils.RulePatch
for _, patch := range r.Patches {
var patchmap map[string]interface{}
if err := json.Unmarshal(patch, &patchmap); err != nil {
return nil, fmt.Errorf("failed to parse JSON patch bytes: %v", err)
}
rp := struct {
RuleName string `json:"rulename"`
Op string `json:"op"`
Path string `json:"path"`
}{
RuleName: r.Name,
Op: patchmap["op"].(string),
Path: patchmap["path"].(string),
}
rulePatches = append(rulePatches, rp)
}
var annotationContent = make(map[string]string)
policyName := policy.GetName()
if policy.GetNamespace() != "" {
policyName = policy.GetNamespace() + "/" + policy.GetName()
}
for _, rulePatch := range rulePatches {
annotationContent[rulePatch.RuleName+"."+policyName+".kyverno.io"] = utils.OperationToPastTense[rulePatch.Op] + " " + rulePatch.Path
}
if len(annotationContent) == 0 {
return
}
result, _ := yamlv2.Marshal(annotationContent)
ann := patchedNew.GetAnnotations()
if ann == nil {
ann = make(map[string]string)
}
ann[utils.PolicyAnnotation] = string(result)
patchedNew.SetAnnotations(ann)
return
}

View file

@ -1,13 +1,23 @@
package background
import (
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/background/generate"
"github.com/kyverno/kyverno/pkg/background/mutate"
)
func (c *Controller) ProcessGR(gr *kyverno.GenerateRequest) error {
ctrl, _ := generate.NewGenerateController(c.kyvernoClient, c.client,
c.policyLister, c.npolicyLister, c.grLister, c.eventGen, c.namespaceInformer, c.log, c.Config,
)
return ctrl.ProcessGR(gr)
func (c *Controller) ProcessUR(ur *urkyverno.UpdateRequest) error {
switch ur.Spec.Type {
case urkyverno.Mutate:
ctrl, _ := mutate.NewMutateExistingController(c.kyvernoClient, c.client,
c.policyLister, c.npolicyLister, c.urLister, c.eventGen, c.log, c.Config)
return ctrl.ProcessUR(ur)
case urkyverno.Generate:
ctrl, _ := generate.NewGenerateController(c.kyvernoClient, c.client,
c.policyLister, c.npolicyLister, c.grLister, c.eventGen, c.nsLister, c.log, c.Config,
)
return ctrl.ProcessGR(ur)
}
return nil
}

View file

@ -6,11 +6,14 @@ import (
"github.com/go-logr/logr"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/autogen"
common "github.com/kyverno/kyverno/pkg/background/common"
kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
kyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1"
urkyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1beta1"
kyvernolister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1"
urlister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/config"
dclient "github.com/kyverno/kyverno/pkg/dclient"
"github.com/kyverno/kyverno/pkg/event"
@ -57,6 +60,9 @@ type Controller struct {
// grLister can list/get generate request from the shared informer's store
grLister kyvernolister.GenerateRequestNamespaceLister
// urLister can list/get update request from the shared informer's store
urLister urlister.UpdateRequestNamespaceLister
// nsLister can list/get namespaces from the shared informer's store
nsLister corelister.NamespaceLister
@ -69,8 +75,10 @@ type Controller struct {
// grSynced returns true if the Generate Request store has been synced at least once
grSynced cache.InformerSynced
// namespaceInformer for re-evaluation on namespace updates
namespaceInformer coreinformers.NamespaceInformer
// urSynced returns true if the Update Request store has been synced at least once
urSynced cache.InformerSynced
nsSynced cache.InformerSynced
log logr.Logger
@ -85,6 +93,7 @@ func NewController(
policyInformer kyvernoinformer.ClusterPolicyInformer,
npolicyInformer kyvernoinformer.PolicyInformer,
grInformer kyvernoinformer.GenerateRequestInformer,
urInformer urkyvernoinformer.UpdateRequestInformer,
eventGen event.Interface,
namespaceInformer coreinformers.NamespaceInformer,
log logr.Logger,
@ -92,14 +101,13 @@ func NewController(
) (*Controller, error) {
c := Controller{
client: client,
kyvernoClient: kyvernoClient,
policyInformer: policyInformer,
eventGen: eventGen,
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "generate-request"),
namespaceInformer: namespaceInformer,
log: log,
Config: dynamicConfig,
client: client,
kyvernoClient: kyvernoClient,
policyInformer: policyInformer,
eventGen: eventGen,
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "generate-request"),
log: log,
Config: dynamicConfig,
}
c.statusControl = common.StatusControl{Client: kyvernoClient}
@ -116,10 +124,20 @@ func NewController(
DeleteFunc: c.deleteGR,
})
c.urSynced = urInformer.Informer().HasSynced
urInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: c.addUR,
UpdateFunc: c.updateUR,
DeleteFunc: c.deleteUR,
})
c.policyLister = policyInformer.Lister()
c.npolicyLister = npolicyInformer.Lister()
c.grLister = grInformer.Lister().GenerateRequests(config.KyvernoNamespace)
c.urLister = urInformer.Lister().UpdateRequests(config.KyvernoNamespace)
c.nsLister = namespaceInformer.Lister()
c.nsSynced = namespaceInformer.Informer().HasSynced
return &c, nil
}
@ -130,7 +148,7 @@ func (c *Controller) Run(workers int, stopCh <-chan struct{}) {
defer c.queue.ShutDown()
defer c.log.Info("shutting down")
if !cache.WaitForCacheSync(stopCh, c.policySynced, c.grSynced, c.npolicySynced) {
if !cache.WaitForCacheSync(stopCh, c.policySynced, c.grSynced, c.urSynced, c.npolicySynced, c.nsSynced) {
c.log.Info("failed to sync informer cache")
return
}
@ -203,7 +221,7 @@ func (c *Controller) syncGenerateRequest(key string) error {
return err
}
gr, err := c.grLister.Get(grName)
gr, err := c.urLister.Get(grName)
if err != nil {
if apierrors.IsNotFound(err) {
return nil
@ -213,7 +231,7 @@ func (c *Controller) syncGenerateRequest(key string) error {
return err
}
return c.ProcessGR(gr)
return c.ProcessUR(gr)
}
// EnqueueGenerateRequestFromWebhook - enqueueing generate requests from webhook
@ -221,14 +239,14 @@ func (c *Controller) EnqueueGenerateRequestFromWebhook(gr *kyverno.GenerateReque
c.enqueueGenerateRequest(gr)
}
func (c *Controller) enqueueGenerateRequest(gr *kyverno.GenerateRequest) {
c.log.V(5).Info("enqueuing generate request", "gr", gr.Name)
key, err := cache.MetaNamespaceKeyFunc(gr)
func (c *Controller) enqueueGenerateRequest(obj interface{}) {
key, err := cache.MetaNamespaceKeyFunc(obj)
if err != nil {
c.log.Error(err, "failed to extract name")
return
}
c.log.V(5).Info("enqueued update request", "ur", key)
c.queue.Add(key)
}
@ -324,7 +342,66 @@ func (c *Controller) deleteGR(obj interface{}) {
}
}
logger.V(3).Info("deleting generate request", "name", gr.Name)
logger.V(3).Info("deleting update request", "name", gr.Name)
// sync Handler will remove it from the queue
c.enqueueGenerateRequest(gr)
}
func (c *Controller) addUR(obj interface{}) {
ur := obj.(*urkyverno.UpdateRequest)
c.enqueueGenerateRequest(ur)
}
func (c *Controller) updateUR(old, cur interface{}) {
oldUr := old.(*urkyverno.UpdateRequest)
curUr := cur.(*urkyverno.UpdateRequest)
if oldUr.ResourceVersion == curUr.ResourceVersion {
// Periodic resync will send update events for all known Namespace.
// Two different versions of the same replica set will always have different RVs.
return
}
// only process the ones that are in "Pending"/"Completed" state
// if the Generate Request fails due to incorrect policy, it will be requeued during policy update
if curUr.Status.State == urkyverno.Failed {
return
}
c.enqueueGenerateRequest(curUr)
}
func (c *Controller) deleteUR(obj interface{}) {
logger := c.log
gr, ok := obj.(*urkyverno.UpdateRequest)
if !ok {
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
if !ok {
logger.Info("Couldn't get object from tombstone", "obj", obj)
return
}
_, ok = tombstone.Obj.(*kyverno.GenerateRequest)
if !ok {
logger.Info("tombstone contained object that is not a Generate Request CR", "obj", obj)
return
}
}
if gr.Spec.GetRequestType() == urkyverno.Generate {
for _, resource := range gr.Status.GeneratedResources {
r, err := c.client.GetResource(resource.APIVersion, resource.Kind, resource.Namespace, resource.Name)
if err != nil && !apierrors.IsNotFound(err) {
logger.Error(err, "Generated resource is not deleted", "Resource", resource.Name)
continue
}
if r != nil && r.GetLabels()["policy.kyverno.io/synchronize"] == "enable" {
if err := c.client.DeleteResource(r.GetAPIVersion(), r.GetKind(), r.GetNamespace(), r.GetName(), false); err != nil && !apierrors.IsNotFound(err) {
logger.Error(err, "Generated resource is not deleted", "Resource", r.GetName())
}
}
}
logger.V(3).Info("deleting update request", "name", gr.Name)
}
// sync Handler will remove it from the queue
c.enqueueGenerateRequest(gr)

View file

@ -53,9 +53,9 @@ func (c *Clientset) KyvernoV1() kyvernov1.KyvernoV1Interface {
return c.kyvernoV1
}
// KyvernoV1 retrieves the KyvernoV1Client
// KyvernoV1beta1 retrieves the KyvernoV1beta1Client
func (c *Clientset) KyvernoV1beta1() kyvernov1beta1.KyvernoV1beta1Interface {
return c.KyvernoV1beta1()
return c.kyvernoV1beta1
}
// KyvernoV1alpha2 retrieves the KyvernoV1alpha2Client

View file

@ -87,7 +87,7 @@ func (c *Clientset) KyvernoV1() kyvernov1.KyvernoV1Interface {
return &fakekyvernov1.FakeKyvernoV1{Fake: &c.Fake}
}
// KyvernoV1alpha2 retrieves the KyvernoV1alpha2Client
// KyvernoV1beta1 retrieves the KyvernoV1beta1Client
func (c *Clientset) KyvernoV1beta1() kyvernov1beta1.KyvernoV1beta1Interface {
return &fakekyvernov1beta1.FakeKyvernoV1beta1{Fake: &c.Fake}
}

View file

@ -21,6 +21,7 @@ package fake
import (
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
kyvernov1alpha2 "github.com/kyverno/kyverno/api/kyverno/v1alpha2"
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
wgpolicyk8sv1alpha2 "github.com/kyverno/kyverno/api/policyreport/v1alpha2"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
@ -34,6 +35,7 @@ var codecs = serializer.NewCodecFactory(scheme)
var localSchemeBuilder = runtime.SchemeBuilder{
kyvernov1.AddToScheme,
kyvernov1beta1.AddToScheme,
kyvernov1alpha2.AddToScheme,
wgpolicyk8sv1alpha2.AddToScheme,
}

View file

@ -19,7 +19,7 @@ limitations under the License.
package v1beta1
import (
v1 "github.com/kyverno/kyverno/api/kyverno/v1"
v1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
scheme "github.com/kyverno/kyverno/pkg/client/clientset/versioned/scheme"
rest "k8s.io/client-go/rest"
)
@ -52,7 +52,7 @@ func NewForConfig(c *rest.Config) (*KyvernoV1beta1Client, error) {
}
func setConfigDefaults(config *rest.Config) error {
gv := v1.SchemeGroupVersion
gv := v1beta1.GroupVersion
config.GroupVersion = &gv
config.APIPath = "/apis"
config.NegotiatedSerializer = scheme.Codecs.WithoutConversion()

View file

@ -23,6 +23,7 @@ import (
v1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/api/kyverno/v1alpha2"
v1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
policyreportv1alpha2 "github.com/kyverno/kyverno/api/policyreport/v1alpha2"
schema "k8s.io/apimachinery/pkg/runtime/schema"
cache "k8s.io/client-go/tools/cache"
@ -62,6 +63,9 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource
case v1.SchemeGroupVersion.WithResource("policies"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Kyverno().V1().Policies().Informer()}, nil
case v1beta1.GroupVersion.WithResource("updaterequests"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Kyverno().V1beta1().UpdateRequests().Informer()}, nil
// Group=kyverno.io, Version=v1alpha2
case v1alpha2.SchemeGroupVersion.WithResource("clusterreportchangerequests"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Kyverno().V1alpha2().ClusterReportChangeRequests().Informer()}, nil

View file

@ -22,12 +22,15 @@ import (
internalinterfaces "github.com/kyverno/kyverno/pkg/client/informers/externalversions/internalinterfaces"
v1 "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1"
v1alpha2 "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1alpha2"
v1beta1 "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1beta1"
)
// Interface provides access to each of this group's versions.
type Interface interface {
// V1 provides access to shared informers for resources in V1.
V1() v1.Interface
// V1beta1 provides access to shared informers for resources in V1beta1.
V1beta1() v1beta1.Interface
// V1alpha2 provides access to shared informers for resources in V1alpha2.
V1alpha2() v1alpha2.Interface
}
@ -48,6 +51,11 @@ func (g *group) V1() v1.Interface {
return v1.New(g.factory, g.namespace, g.tweakListOptions)
}
// V1beta1 returns a new v1beta1.Interface.
func (g *group) V1beta1() v1beta1.Interface {
return v1beta1.New(g.factory, g.namespace, g.tweakListOptions)
}
// V1alpha2 returns a new v1alpha2.Interface.
func (g *group) V1alpha2() v1alpha2.Interface {
return v1alpha2.New(g.factory, g.namespace, g.tweakListOptions)

View file

@ -101,7 +101,7 @@ func VariableToJSON(key, value string) []byte {
}
// RetryFunc allows retrying a function on error within a given timeout
func RetryFunc(retryInterval, timeout time.Duration, run func() error, logger logr.Logger) func() error {
func RetryFunc(retryInterval, timeout time.Duration, run func() error, msg string, logger logr.Logger) func() error {
return func() error {
registerTimeout := time.After(timeout)
registerTicker := time.NewTicker(retryInterval)
@ -114,13 +114,13 @@ func RetryFunc(retryInterval, timeout time.Duration, run func() error, logger lo
case <-registerTicker.C:
err = run()
if err != nil {
logger.V(3).Info("Failed to register admission control webhooks", "reason", err.Error())
logger.V(3).Info(msg, "reason", err.Error())
} else {
break loop
}
case <-registerTimeout:
return errors.Wrap(err, "Timeout registering admission control webhooks")
return errors.Wrap(err, "retry times out")
}
}
return nil

143
pkg/engine/background.go Normal file
View file

@ -0,0 +1,143 @@
package engine
import (
"time"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/autogen"
"github.com/kyverno/kyverno/pkg/engine/common"
"github.com/kyverno/kyverno/pkg/engine/response"
"github.com/kyverno/kyverno/pkg/engine/variables"
"sigs.k8s.io/controller-runtime/pkg/log"
)
// ApplyBackgroundChecks checks for validity of generate and mutateExisting rules on the resource
// 1. validate variables to be substitute in the general ruleInfo (match,exclude,condition)
// - the caller has to check the ruleResponse to determine whether the path exist
// 2. returns the list of rules that are applicable on this policy and resource, if 1 succeed
func ApplyBackgroundChecks(policyContext *PolicyContext) (resp *response.EngineResponse) {
policyStartTime := time.Now()
return filterRules(policyContext, policyStartTime)
}
func filterRules(policyContext *PolicyContext, startTime time.Time) *response.EngineResponse {
kind := policyContext.NewResource.GetKind()
name := policyContext.NewResource.GetName()
namespace := policyContext.NewResource.GetNamespace()
apiVersion := policyContext.NewResource.GetAPIVersion()
resp := &response.EngineResponse{
PolicyResponse: response.PolicyResponse{
Policy: response.PolicySpec{
Name: policyContext.Policy.GetName(),
Namespace: policyContext.Policy.GetNamespace(),
},
PolicyStats: response.PolicyStats{
PolicyExecutionTimestamp: startTime.Unix(),
},
Resource: response.ResourceSpec{
Kind: kind,
Name: name,
Namespace: namespace,
APIVersion: apiVersion,
},
},
}
if policyContext.ExcludeResourceFunc(kind, namespace, name) {
log.Log.WithName("ApplyBackgroundChecks").Info("resource excluded", "kind", kind, "namespace", namespace, "name", name)
return resp
}
for _, rule := range autogen.ComputeRules(policyContext.Policy) {
if ruleResp := filterRule(rule, policyContext); ruleResp != nil {
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, *ruleResp)
}
}
return resp
}
func filterRule(rule kyverno.Rule, policyContext *PolicyContext) *response.RuleResponse {
if !rule.HasGenerate() && !rule.IsMutateExisting() {
return nil
}
ruleType := response.Mutation
if rule.HasGenerate() {
ruleType = response.Generation
}
var err error
startTime := time.Now()
policy := policyContext.Policy
newResource := policyContext.NewResource
oldResource := policyContext.OldResource
admissionInfo := policyContext.AdmissionInfo
ctx := policyContext.JSONContext
excludeGroupRole := policyContext.ExcludeGroupRole
namespaceLabels := policyContext.NamespaceLabels
logger := log.Log.WithName(string(ruleType)).WithValues("policy", policy.GetName(),
"kind", newResource.GetKind(), "namespace", newResource.GetNamespace(), "name", newResource.GetName())
if err = MatchesResourceDescription(newResource, rule, admissionInfo, excludeGroupRole, namespaceLabels, ""); err != nil {
if ruleType == response.Generation {
// if the oldResource matched, return "false" to delete GR for it
if err = MatchesResourceDescription(oldResource, rule, admissionInfo, excludeGroupRole, namespaceLabels, ""); err == nil {
return &response.RuleResponse{
Name: rule.Name,
Type: ruleType,
Status: response.RuleStatusFail,
RuleStats: response.RuleStats{
ProcessingTime: time.Since(startTime),
RuleExecutionTimestamp: startTime.Unix(),
},
}
}
}
return nil
}
policyContext.JSONContext.Checkpoint()
defer policyContext.JSONContext.Restore()
if err = LoadContext(logger, rule.Context, policyContext, rule.Name); err != nil {
logger.V(4).Info("cannot add external data to the context", "reason", err.Error())
return nil
}
ruleCopy := rule.DeepCopy()
if after, err := variables.SubstituteAllInPreconditions(logger, ctx, ruleCopy.GetAnyAllConditions()); err != nil {
logger.V(4).Info("failed to substitute vars in preconditions, skip current rule", "rule name", ruleCopy.Name)
return nil
} else {
ruleCopy.SetAnyAllConditions(after)
}
// operate on the copy of the conditions, as we perform variable substitution
copyConditions, err := common.TransformConditions(ruleCopy.GetAnyAllConditions())
if err != nil {
logger.V(4).Info("cannot copy AnyAllConditions", "reason", err.Error())
return nil
}
// evaluate pre-conditions
if !variables.EvaluateConditions(logger, ctx, copyConditions) {
logger.V(4).Info("skip rule as preconditions are not met", "rule", ruleCopy.Name)
return nil
}
// build rule Response
return &response.RuleResponse{
Name: ruleCopy.Name,
Type: ruleType,
Status: response.RuleStatusPass,
RuleStats: response.RuleStats{
ProcessingTime: time.Since(startTime),
RuleExecutionTimestamp: startTime.Unix(),
},
}
}

View file

@ -6,7 +6,7 @@ import (
"sync"
jsonpatch "github.com/evanphx/json-patch/v5"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
pkgcommon "github.com/kyverno/kyverno/pkg/common"
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
"github.com/pkg/errors"
@ -50,7 +50,7 @@ type Interface interface {
AddOldResource(data map[string]interface{}) error
// AddUserInfo merges userInfo json under kyverno.userInfo
AddUserInfo(userInfo kyverno.RequestInfo) error
AddUserInfo(userInfo urkyverno.RequestInfo) error
// AddServiceAccount merges ServiceAccount types
AddServiceAccount(userName string) error
@ -166,7 +166,7 @@ func (ctx *context) AddOldResource(data map[string]interface{}) error {
}
// AddUserInfo adds userInfo at path request.userInfo
func (ctx *context) AddUserInfo(userRequestInfo kyverno.RequestInfo) error {
func (ctx *context) AddUserInfo(userRequestInfo urkyverno.RequestInfo) error {
return addToContext(ctx, userRequestInfo, "request")
}

View file

@ -4,7 +4,7 @@ import (
"reflect"
"testing"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
authenticationv1 "k8s.io/api/authentication/v1"
)
@ -48,7 +48,7 @@ func Test_addResourceAndUserContext(t *testing.T) {
Username: "system:serviceaccount:nirmata:user1",
UID: "014fbff9a07c",
}
userRequestInfo := kyverno.RequestInfo{
userRequestInfo := urkyverno.RequestInfo{
Roles: nil,
ClusterRoles: nil,
AdmissionUserInfo: userInfo}

View file

@ -3,27 +3,15 @@ package engine
import (
"time"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/autogen"
"github.com/kyverno/kyverno/pkg/engine/common"
"k8s.io/client-go/tools/cache"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/engine/response"
"github.com/kyverno/kyverno/pkg/engine/variables"
"k8s.io/client-go/tools/cache"
"sigs.k8s.io/controller-runtime/pkg/log"
)
// Generate checks for validity of generate rule on the resource
// 1. validate variables to be substitute in the general ruleInfo (match,exclude,condition)
// - the caller has to check the ruleResponse to determine whether the path exist
// 2. returns the list of rules that are applicable on this policy and resource, if 1 succeed
func Generate(policyContext *PolicyContext) (resp *response.EngineResponse) {
policyStartTime := time.Now()
return filterRules(policyContext, policyStartTime)
}
// GenerateResponse checks for validity of generate rule on the resource
func GenerateResponse(policyContext *PolicyContext, gr kyverno.GenerateRequest) (resp *response.EngineResponse) {
func GenerateResponse(policyContext *PolicyContext, gr urkyverno.UpdateRequest) (resp *response.EngineResponse) {
policyStartTime := time.Now()
return filterGenerateRules(policyContext, gr.Spec.Policy, policyStartTime)
}
@ -69,118 +57,3 @@ func filterGenerateRules(policyContext *PolicyContext, policyNameKey string, sta
return resp
}
func filterRules(policyContext *PolicyContext, startTime time.Time) *response.EngineResponse {
kind := policyContext.NewResource.GetKind()
name := policyContext.NewResource.GetName()
namespace := policyContext.NewResource.GetNamespace()
apiVersion := policyContext.NewResource.GetAPIVersion()
resp := &response.EngineResponse{
PolicyResponse: response.PolicyResponse{
Policy: response.PolicySpec{
Name: policyContext.Policy.GetName(),
Namespace: policyContext.Policy.GetNamespace(),
},
PolicyStats: response.PolicyStats{
PolicyExecutionTimestamp: startTime.Unix(),
},
Resource: response.ResourceSpec{
Kind: kind,
Name: name,
Namespace: namespace,
APIVersion: apiVersion,
},
},
}
if policyContext.ExcludeResourceFunc(kind, namespace, name) {
log.Log.WithName("Generate").Info("resource excluded", "kind", kind, "namespace", namespace, "name", name)
return resp
}
for _, rule := range autogen.ComputeRules(policyContext.Policy) {
if ruleResp := filterRule(rule, policyContext); ruleResp != nil {
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, *ruleResp)
}
}
return resp
}
func filterRule(rule kyverno.Rule, policyContext *PolicyContext) *response.RuleResponse {
if !rule.HasGenerate() {
return nil
}
var err error
startTime := time.Now()
policy := policyContext.Policy
newResource := policyContext.NewResource
oldResource := policyContext.OldResource
admissionInfo := policyContext.AdmissionInfo
ctx := policyContext.JSONContext
excludeGroupRole := policyContext.ExcludeGroupRole
namespaceLabels := policyContext.NamespaceLabels
logger := log.Log.WithName("Generate").WithValues("policy", policy.GetName(),
"kind", newResource.GetKind(), "namespace", newResource.GetNamespace(), "name", newResource.GetName())
if err = MatchesResourceDescription(newResource, rule, admissionInfo, excludeGroupRole, namespaceLabels, ""); err != nil {
// if the oldResource matched, return "false" to delete GR for it
if err = MatchesResourceDescription(oldResource, rule, admissionInfo, excludeGroupRole, namespaceLabels, ""); err == nil {
return &response.RuleResponse{
Name: rule.Name,
Type: "Generation",
Status: response.RuleStatusFail,
RuleStats: response.RuleStats{
ProcessingTime: time.Since(startTime),
RuleExecutionTimestamp: startTime.Unix(),
},
}
}
return nil
}
policyContext.JSONContext.Checkpoint()
defer policyContext.JSONContext.Restore()
if err = LoadContext(logger, rule.Context, policyContext, rule.Name); err != nil {
logger.V(4).Info("cannot add external data to the context", "reason", err.Error())
return nil
}
ruleCopy := rule.DeepCopy()
if after, err := variables.SubstituteAllInPreconditions(logger, ctx, ruleCopy.GetAnyAllConditions()); err != nil {
logger.V(4).Info("failed to substitute vars in preconditions, skip current rule", "rule name", ruleCopy.Name)
return nil
} else {
ruleCopy.SetAnyAllConditions(after)
}
// operate on the copy of the conditions, as we perform variable substitution
copyConditions, err := common.TransformConditions(ruleCopy.GetAnyAllConditions())
if err != nil {
logger.V(4).Info("cannot copy AnyAllConditions", "reason", err.Error())
return nil
}
// evaluate pre-conditions
if !variables.EvaluateConditions(logger, ctx, copyConditions) {
logger.V(4).Info("skip rule as preconditions are not met", "rule", ruleCopy.Name)
return nil
}
// build rule Response
return &response.RuleResponse{
Name: ruleCopy.Name,
Type: "Generation",
Status: response.RuleStatusPass,
RuleStats: response.RuleStats{
ProcessingTime: time.Since(startTime),
RuleExecutionTimestamp: startTime.Unix(),
},
}
}

View file

@ -102,7 +102,7 @@ func VerifyAndPatchImages(policyContext *PolicyContext) (resp *response.EngineRe
}
func appendError(resp *response.EngineResponse, rule *v1.Rule, msg string, status response.RuleStatus) {
rr := ruleResponse(rule, response.ImageVerify, msg, status)
rr := ruleResponse(*rule, response.ImageVerify, msg, status, nil)
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, *rr)
incrementErrorCount(resp)
}
@ -168,7 +168,7 @@ func (iv *imageVerifier) verify(imageVerify *v1.ImageVerification, images map[st
if imageInfo.Digest == "" && *imageVerify.MutateDigest && ruleResp.Status == response.RuleStatusPass {
err := iv.patchDigest(path, imageInfo, digest, ruleResp)
if err != nil {
ruleResp = ruleResponse(iv.rule, response.ImageVerify, err.Error(), response.RuleStatusFail)
ruleResp = ruleResponse(*iv.rule, response.ImageVerify, err.Error(), response.RuleStatusFail, nil)
}
}
} else {
@ -177,11 +177,11 @@ func (iv *imageVerifier) verify(imageVerify *v1.ImageVerification, images map[st
digest, err := fetchImageDigest(imageInfo.String())
if err != nil {
msg := fmt.Sprintf("fetching image digest from registry error: %s", err)
ruleResp = ruleResponse(iv.rule, response.ImageVerify, msg, response.RuleStatusFail)
ruleResp = ruleResponse(*iv.rule, response.ImageVerify, msg, response.RuleStatusFail, nil)
} else {
err = iv.patchDigest(path, imageInfo, digest, ruleResp)
if err != nil {
ruleResp = ruleResponse(iv.rule, response.ImageVerify, err.Error(), response.RuleStatusFail)
ruleResp = ruleResponse(*iv.rule, response.ImageVerify, err.Error(), response.RuleStatusFail, nil)
}
}
}
@ -227,12 +227,12 @@ func (iv *imageVerifier) verifySignatures(imageVerify *v1.ImageVerification, ima
if err != nil {
iv.logger.Error(err, "failed to verify signature", "attestorSet", attestorSet)
msg := fmt.Sprintf("failed to verify signature for %s: %s", image, err.Error())
return ruleResponse(iv.rule, response.ImageVerify, msg, response.RuleStatusFail), ""
return ruleResponse(*iv.rule, response.ImageVerify, msg, response.RuleStatusFail, nil), ""
}
}
msg := fmt.Sprintf("verified image signatures for %s", image)
return ruleResponse(iv.rule, response.ImageVerify, msg, response.RuleStatusPass), digest
return ruleResponse(*iv.rule, response.ImageVerify, msg, response.RuleStatusPass, nil), digest
}
func (iv *imageVerifier) verifyAttestorSet(attestorSet *v1.AttestorSet, imageVerify *v1.ImageVerification, image, path string) (string, error) {
@ -418,7 +418,7 @@ func (iv *imageVerifier) attestImage(imageVerify *v1.ImageVerification, imageInf
statements := statementsByPredicate[ac.PredicateType]
if statements == nil {
msg := fmt.Sprintf("predicate type %s not found", ac.PredicateType)
return ruleResponse(iv.rule, response.ImageVerify, msg, response.RuleStatusFail)
return ruleResponse(*iv.rule, response.ImageVerify, msg, response.RuleStatusFail, nil)
}
for _, s := range statements {
@ -429,14 +429,14 @@ func (iv *imageVerifier) attestImage(imageVerify *v1.ImageVerification, imageInf
if !val {
msg := fmt.Sprintf("attestation checks failed for %s and predicate %s", imageInfo.String(), ac.PredicateType)
return ruleResponse(iv.rule, response.ImageVerify, msg, response.RuleStatusFail)
return ruleResponse(*iv.rule, response.ImageVerify, msg, response.RuleStatusFail, nil)
}
}
}
msg := fmt.Sprintf("attestation checks passed for %s", imageInfo.String())
iv.logger.V(2).Info(msg)
return ruleResponse(iv.rule, response.ImageVerify, msg, response.RuleStatusPass)
return ruleResponse(*iv.rule, response.ImageVerify, msg, response.RuleStatusPass, nil)
}
func buildStatementMap(statements []map[string]interface{}) map[string][]map[string]interface{} {

61
pkg/engine/loadtargets.go Normal file
View file

@ -0,0 +1,61 @@
package engine
import (
"fmt"
"github.com/go-logr/logr"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
engineUtils "github.com/kyverno/kyverno/pkg/engine/utils"
"github.com/kyverno/kyverno/pkg/engine/variables"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
func loadTargets(logger logr.Logger, targets []kyverno.TargetMutation, ctx *PolicyContext) ([]unstructured.Unstructured, error) {
targetObjects := make([]unstructured.Unstructured, len(targets))
var errors []error
for i, target := range targets {
apiversion, err := variables.SubstituteAll(logger, ctx.JSONContext, target.APIVersion)
if err != nil {
errors = append(errors, fmt.Errorf("failed to substitute variables in target[%d].APIVersion %s: %v", i, target.APIVersion, err))
continue
}
kind, err := variables.SubstituteAll(logger, ctx.JSONContext, target.Kind)
if err != nil {
errors = append(errors, fmt.Errorf("failed to substitute variables in target[%d].Kind %s: %v", i, target.Kind, err))
continue
}
name, err := variables.SubstituteAll(logger, ctx.JSONContext, target.Name)
if err != nil {
errors = append(errors, fmt.Errorf("failed to substitute variables in target[%d].Name %s: %v", i, target.Name, err))
continue
}
namespace, err := variables.SubstituteAll(logger, ctx.JSONContext, target.Namespace)
if err != nil {
errors = append(errors, fmt.Errorf("failed to substitute variables in target[%d].Namespace %s: %v", i, target.Namespace, err))
continue
}
if namespace == "" {
namespace = "default"
}
obj, err := ctx.Client.GetResource(apiversion.(string), kind.(string), namespace.(string), name.(string))
if err != nil {
errors = append(errors, fmt.Errorf("failed to get target %s/%s %s/%s : %v", apiversion, kind, namespace, name, err))
continue
}
if obj.GetKind() == "" {
obj.SetKind(kind.(string))
}
obj.SetAPIVersion(apiversion.(string))
targetObjects = append(targetObjects, *obj)
}
return targetObjects, engineUtils.CombineErrors(errors)
}

View file

@ -218,7 +218,7 @@ func assertEqStringAndData(t *testing.T, str string, data []byte) {
json.Unmarshal([]byte(str), &p1)
var p2 jsonPatch
json.Unmarshal([]byte(str), &p2)
json.Unmarshal([]byte(data), &p2)
assert.Equal(t, p1, p2)
}

View file

@ -22,16 +22,16 @@ func Mutate(policyContext *PolicyContext) (resp *response.EngineResponse) {
resp = &response.EngineResponse{
Policy: policy,
}
patchedResource := policyContext.NewResource
matchedResource := policyContext.NewResource
ctx := policyContext.JSONContext
var skippedRules []string
logger := log.Log.WithName("EngineMutate").WithValues("policy", policy.GetName(), "kind", patchedResource.GetKind(),
"namespace", patchedResource.GetNamespace(), "name", patchedResource.GetName())
logger := log.Log.WithName("EngineMutate").WithValues("policy", policy.GetName(), "kind", matchedResource.GetKind(),
"namespace", matchedResource.GetNamespace(), "name", matchedResource.GetName())
logger.V(4).Info("start mutate policy processing", "startTime", startTime)
startMutateResultResponse(resp, policy, patchedResource)
startMutateResultResponse(resp, policy, matchedResource)
defer endMutateResultResponse(logger, resp, startTime)
policyContext.JSONContext.Checkpoint()
@ -50,7 +50,7 @@ func Mutate(policyContext *PolicyContext) (resp *response.EngineResponse) {
excludeResource = policyContext.ExcludeGroupRole
}
if err = MatchesResourceDescription(patchedResource, rule, policyContext.AdmissionInfo, excludeResource, policyContext.NamespaceLabels, policyContext.Policy.GetNamespace()); err != nil {
if err = MatchesResourceDescription(matchedResource, rule, policyContext.AdmissionInfo, excludeResource, policyContext.NamespaceLabels, policyContext.Policy.GetNamespace()); err != nil {
logger.V(4).Info("rule not matched", "reason", err.Error())
skippedRules = append(skippedRules, rule.Name)
continue
@ -78,19 +78,41 @@ func Mutate(policyContext *PolicyContext) (resp *response.EngineResponse) {
}
ruleCopy := rule.DeepCopy()
var ruleResp *response.RuleResponse
if rule.Mutation.ForEachMutation != nil {
ruleResp, patchedResource = mutateForEach(ruleCopy, policyContext, patchedResource, logger)
var patchedResources []unstructured.Unstructured
if !policyContext.AdmissionOperation && rule.IsMutateExisting() {
targets, err := loadTargets(logger, ruleCopy.Mutation.Targets, policyContext)
if err != nil {
rr := ruleResponse(rule, response.Mutation, err.Error(), response.RuleStatusError, nil)
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, *rr)
} else {
patchedResources = append(patchedResources, targets...)
}
} else {
ruleResp, patchedResource = mutateResource(ruleCopy, policyContext, patchedResource, logger)
patchedResources = append(patchedResources, matchedResource)
}
if ruleResp != nil {
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, *ruleResp)
if ruleResp.Status == response.RuleStatusError {
incrementErrorCount(resp)
for _, patchedResource := range patchedResources {
if reflect.DeepEqual(patchedResource, unstructured.Unstructured{}) {
continue
}
logger.V(4).Info("apply rule to resource", "rule", rule.Name, "resource namespace", patchedResource.GetNamespace(), "resource name", patchedResource.GetName())
var ruleResp *response.RuleResponse
if rule.Mutation.ForEachMutation != nil {
ruleResp, patchedResource = mutateForEach(ruleCopy, policyContext, patchedResource, logger)
} else {
incrementAppliedCount(resp)
ruleResp, patchedResource = mutateResource(ruleCopy, policyContext, patchedResource, logger)
}
matchedResource = patchedResource
if ruleResp != nil {
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, *ruleResp)
if ruleResp.Status == response.RuleStatusError {
incrementErrorCount(resp)
} else {
incrementAppliedCount(resp)
}
}
}
}
@ -104,7 +126,7 @@ func Mutate(policyContext *PolicyContext) (resp *response.EngineResponse) {
}
}
resp.PatchedResource = patchedResource
resp.PatchedResource = matchedResource
return resp
}
@ -115,11 +137,11 @@ func mutateResource(rule *kyverno.Rule, ctx *PolicyContext, resource unstructure
}
if !preconditionsPassed {
return ruleResponse(rule, response.Mutation, "preconditions not met", response.RuleStatusSkip), resource
return ruleResponse(*rule, response.Mutation, "preconditions not met", response.RuleStatusSkip, &resource), resource
}
mutateResp := mutate.Mutate(rule, ctx.JSONContext, resource, logger)
ruleResp := buildRuleResponse(rule, mutateResp)
ruleResp := buildRuleResponse(rule, mutateResp, &mutateResp.PatchedResource)
return ruleResp, mutateResp.PatchedResource
}
@ -145,7 +167,7 @@ func mutateForEach(rule *kyverno.Rule, ctx *PolicyContext, resource unstructured
}
if !preconditionsPassed {
return ruleResponse(rule, response.Mutation, "preconditions not met", response.RuleStatusSkip), resource
return ruleResponse(*rule, response.Mutation, "preconditions not met", response.RuleStatusSkip, &patchedResource), resource
}
elements, err := evaluateList(foreach.List, ctx.JSONContext)
@ -157,7 +179,7 @@ func mutateForEach(rule *kyverno.Rule, ctx *PolicyContext, resource unstructured
mutateResp := mutateElements(rule.Name, foreach, ctx, elements, patchedResource, logger)
if mutateResp.Status == response.RuleStatusError {
logger.Error(err, "failed to mutate elements")
return buildRuleResponse(rule, mutateResp), resource
return buildRuleResponse(rule, mutateResp, nil), resource
}
if mutateResp.Status != response.RuleStatusSkip {
@ -170,10 +192,10 @@ func mutateForEach(rule *kyverno.Rule, ctx *PolicyContext, resource unstructured
}
if applyCount == 0 {
return ruleResponse(rule, response.Mutation, "0 elements processed", response.RuleStatusSkip), resource
return ruleResponse(*rule, response.Mutation, "0 elements processed", response.RuleStatusSkip, &resource), resource
}
r := ruleResponse(rule, response.Mutation, fmt.Sprintf("%d elements processed", applyCount), response.RuleStatusPass)
r := ruleResponse(*rule, response.Mutation, fmt.Sprintf("%d elements processed", applyCount), response.RuleStatusPass, &patchedResource)
r.Patches = allPatches
return r, patchedResource
}
@ -237,8 +259,8 @@ func mutateError(err error, message string) *mutate.Response {
}
}
func buildRuleResponse(rule *kyverno.Rule, mutateResp *mutate.Response) *response.RuleResponse {
resp := ruleResponse(rule, response.Mutation, mutateResp.Message, mutateResp.Status)
func buildRuleResponse(rule *kyverno.Rule, mutateResp *mutate.Response, patchedResource *unstructured.Unstructured) *response.RuleResponse {
resp := ruleResponse(*rule, response.Mutation, mutateResp.Message, mutateResp.Status, patchedResource)
if resp.Status == response.RuleStatusPass {
resp.Patches = mutateResp.Patches
resp.Message = buildSuccessMessage(mutateResp.PatchedResource)

View file

@ -7,13 +7,15 @@ import (
"testing"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/engine/response"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/store"
client "github.com/kyverno/kyverno/pkg/dclient"
"github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/response"
"github.com/kyverno/kyverno/pkg/engine/utils"
"gotest.tools/assert"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
func Test_VariableSubstitutionPatchStrategicMerge(t *testing.T) {
@ -1027,3 +1029,254 @@ func Test_foreach_order_mutation_(t *testing.T) {
}
}
}
func Test_mutate_existing_resources(t *testing.T) {
tests := []struct {
name string
policy []byte
trigger []byte
target []byte
targetList string
patches []string
}{
{
name: "test-different-trigger-target",
policy: []byte(`{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "test-post-mutation"
},
"spec": {
"rules": [
{
"name": "mutate-deploy-on-configmap-update",
"match": {
"any": [
{
"resources": {
"kinds": [
"ConfigMap"
],
"names": [
"dictionary"
],
"namespaces": [
"staging"
]
}
}
]
},
"preconditions": {
"any": [
{
"key": "{{ request.object.data.foo }}",
"operator": "Equals",
"value": "bar"
}
]
},
"mutate": {
"targets": [
{
"apiVersion": "v1",
"kind": "Deployment",
"name": "example-A",
"namespace": "staging"
}
],
"patchStrategicMerge": {
"metadata": {
"labels": {
"foo": "bar"
}
}
}
}
}
]
}
}`),
trigger: []byte(`{
"apiVersion": "v1",
"data": {
"foo": "bar"
},
"kind": "ConfigMap",
"metadata": {
"name": "dictionary",
"namespace": "staging"
}
}`),
target: []byte(`{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"name": "example-A",
"namespace": "staging",
"labels": {
"app": "nginx"
}
},
"spec": {
"replicas": 1,
"selector": {
"matchLabels": {
"app": "nginx"
}
},
"template": {
"metadata": {
"labels": {
"app": "nginx"
}
},
"spec": {
"containers": [
{
"name": "nginx",
"image": "nginx:1.14.2",
"ports": [
{
"containerPort": 80
}
]
}
]
}
}
}
}`),
targetList: "DeploymentList",
patches: []string{`{"op":"add","path":"/metadata/labels/foo","value":"bar"}`},
},
{
name: "test-same-trigger-target",
policy: []byte(`{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "test-post-mutation"
},
"spec": {
"rules": [
{
"name": "mutate-deploy-on-configmap-update",
"match": {
"any": [
{
"resources": {
"kinds": [
"ConfigMap"
],
"names": [
"dictionary"
],
"namespaces": [
"staging"
]
}
}
]
},
"preconditions": {
"any": [
{
"key": "{{ request.object.data.foo }}",
"operator": "Equals",
"value": "bar"
}
]
},
"mutate": {
"targets": [
{
"apiVersion": "v1",
"kind": "ConfigMap",
"name": "dictionary",
"namespace": "staging"
}
],
"patchStrategicMerge": {
"metadata": {
"labels": {
"foo": "bar"
}
}
}
}
}
]
}
}`),
trigger: []byte(`{
"apiVersion": "v1",
"data": {
"foo": "bar"
},
"kind": "ConfigMap",
"metadata": {
"name": "dictionary",
"namespace": "staging"
}
}`),
target: []byte(`{
"apiVersion": "v1",
"data": {
"foo": "bar"
},
"kind": "ConfigMap",
"metadata": {
"name": "dictionary",
"namespace": "staging"
}
}`),
targetList: "ComfigMapList",
patches: []string{`{"op":"add","path":"/metadata/labels","value":{"foo":"bar"}}`},
},
}
for _, test := range tests {
var policy kyverno.ClusterPolicy
err := json.Unmarshal(test.policy, &policy)
assert.NilError(t, err)
trigger, err := utils.ConvertToUnstructured(test.trigger)
assert.NilError(t, err)
target, err := utils.ConvertToUnstructured(test.target)
assert.NilError(t, err)
ctx := context.NewContext()
err = ctx.AddResource(trigger.Object)
assert.NilError(t, err)
gvrToListKind := map[schema.GroupVersionResource]string{
{Group: target.GroupVersionKind().Group, Version: target.GroupVersionKind().Version, Resource: target.GroupVersionKind().Kind}: test.targetList,
}
objects := []runtime.Object{target}
scheme := runtime.NewScheme()
dclient, err := client.NewMockClient(scheme, gvrToListKind, objects...)
assert.NilError(t, err)
dclient.SetDiscovery(client.NewFakeDiscoveryClient(nil))
_, err = dclient.GetResource(target.GetAPIVersion(), target.GetKind(), target.GetNamespace(), target.GetName())
assert.NilError(t, err)
policyContext := &PolicyContext{
Client: dclient,
Policy: &policy,
JSONContext: ctx,
NewResource: *trigger,
}
er := Mutate(policyContext)
for _, rr := range er.PolicyResponse.Rules {
assert.Equal(t, test.patches[0], string(rr.Patches[0]))
assert.Equal(t, rr.Status, response.RuleStatusPass, rr.Status)
}
}
}

View file

@ -2,6 +2,7 @@ package engine
import (
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
client "github.com/kyverno/kyverno/pkg/dclient"
"github.com/kyverno/kyverno/pkg/engine/context"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@ -22,9 +23,9 @@ type PolicyContext struct {
Element unstructured.Unstructured
// AdmissionInfo contains the admission request information
AdmissionInfo kyverno.RequestInfo
AdmissionInfo urkyverno.RequestInfo
// Dynamic client - used by generate
// Dynamic client - used for api lookups
Client *client.Client
// Config handler
@ -37,6 +38,9 @@ type PolicyContext struct {
// NamespaceLabels stores the label of namespace to be processed by namespace selector
NamespaceLabels map[string]string
// AdmissionOperation represents if the caller is from the webhook server
AdmissionOperation bool
}
func (pc *PolicyContext) Copy() *PolicyContext {

View file

@ -109,6 +109,9 @@ type RuleResponse struct {
// statistics
RuleStats `json:",inline"`
// PatchedTarget is the patched resource for mutate.targets
PatchedTarget *unstructured.Unstructured
}
//ToString ...

View file

@ -6,18 +6,17 @@ import (
"strings"
"time"
"github.com/kyverno/kyverno/pkg/engine/common"
"github.com/go-logr/logr"
wildcard "github.com/kyverno/go-wildcard"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/engine/common"
"github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/response"
"github.com/kyverno/kyverno/pkg/engine/variables"
"github.com/pkg/errors"
wildcard "github.com/kyverno/go-wildcard"
"github.com/kyverno/kyverno/pkg/engine/wildcards"
"github.com/kyverno/kyverno/pkg/utils"
"github.com/pkg/errors"
authenticationv1 "k8s.io/api/authentication/v1"
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
@ -127,7 +126,7 @@ func checkSelector(labelSelector *metav1.LabelSelector, resourceLabels map[strin
// should be: AND across attributes but an OR inside attributes that of type list
// To filter out the targeted resources with UserInfo, the check
// should be: OR (across & inside) attributes
func doesResourceMatchConditionBlock(conditionBlock kyverno.ResourceDescription, userInfo kyverno.UserInfo, admissionInfo kyverno.RequestInfo, resource unstructured.Unstructured, dynamicConfig []string, namespaceLabels map[string]string) []error {
func doesResourceMatchConditionBlock(conditionBlock kyverno.ResourceDescription, userInfo kyverno.UserInfo, admissionInfo urkyverno.RequestInfo, resource unstructured.Unstructured, dynamicConfig []string, namespaceLabels map[string]string) []error {
var errs []error
if len(conditionBlock.Kinds) > 0 {
@ -263,7 +262,7 @@ func matchSubjects(ruleSubjects []rbacv1.Subject, userInfo authenticationv1.User
}
//MatchesResourceDescription checks if the resource matches resource description of the rule or not
func MatchesResourceDescription(resourceRef unstructured.Unstructured, ruleRef kyverno.Rule, admissionInfoRef kyverno.RequestInfo, dynamicConfig []string, namespaceLabels map[string]string, policyNamespace string) error {
func MatchesResourceDescription(resourceRef unstructured.Unstructured, ruleRef kyverno.Rule, admissionInfoRef urkyverno.RequestInfo, dynamicConfig []string, namespaceLabels map[string]string, policyNamespace string) error {
rule := ruleRef.DeepCopy()
resource := *resourceRef.DeepCopy()
@ -336,7 +335,7 @@ func MatchesResourceDescription(resourceRef unstructured.Unstructured, ruleRef k
return nil
}
func matchesResourceDescriptionMatchHelper(rmr kyverno.ResourceFilter, admissionInfo kyverno.RequestInfo, resource unstructured.Unstructured, dynamicConfig []string, namespaceLabels map[string]string) []error {
func matchesResourceDescriptionMatchHelper(rmr kyverno.ResourceFilter, admissionInfo urkyverno.RequestInfo, resource unstructured.Unstructured, dynamicConfig []string, namespaceLabels map[string]string) []error {
var errs []error
if reflect.DeepEqual(admissionInfo, kyverno.RequestInfo{}) {
rmr.UserInfo = kyverno.UserInfo{}
@ -353,7 +352,7 @@ func matchesResourceDescriptionMatchHelper(rmr kyverno.ResourceFilter, admission
return errs
}
func matchesResourceDescriptionExcludeHelper(rer kyverno.ResourceFilter, admissionInfo kyverno.RequestInfo, resource unstructured.Unstructured, dynamicConfig []string, namespaceLabels map[string]string) []error {
func matchesResourceDescriptionExcludeHelper(rer kyverno.ResourceFilter, admissionInfo urkyverno.RequestInfo, resource unstructured.Unstructured, dynamicConfig []string, namespaceLabels map[string]string) []error {
var errs []error
// checking if resource matches the rule
if !reflect.DeepEqual(rer.ResourceDescription, kyverno.ResourceDescription{}) ||
@ -474,16 +473,21 @@ func evaluateList(jmesPath string, ctx context.EvalInterface) ([]interface{}, er
func ruleError(rule *kyverno.Rule, ruleType response.RuleType, msg string, err error) *response.RuleResponse {
msg = fmt.Sprintf("%s: %s", msg, err.Error())
return ruleResponse(rule, ruleType, msg, response.RuleStatusError)
return ruleResponse(*rule, ruleType, msg, response.RuleStatusError, nil)
}
func ruleResponse(rule *kyverno.Rule, ruleType response.RuleType, msg string, status response.RuleStatus) *response.RuleResponse {
return &response.RuleResponse{
func ruleResponse(rule kyverno.Rule, ruleType response.RuleType, msg string, status response.RuleStatus, patchedResource *unstructured.Unstructured) *response.RuleResponse {
resp := &response.RuleResponse{
Name: rule.Name,
Type: ruleType,
Message: msg,
Status: status,
}
if rule.Mutation.Targets != nil {
resp.PatchedTarget = patchedResource
}
return resp
}
func incrementAppliedCount(resp *response.EngineResponse) {

View file

@ -5,6 +5,7 @@ import (
"testing"
v1 "github.com/kyverno/kyverno/api/kyverno/v1"
v1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/autogen"
"github.com/kyverno/kyverno/pkg/engine/utils"
"gotest.tools/assert"
@ -14,14 +15,14 @@ import (
func TestMatchesResourceDescription(t *testing.T) {
tcs := []struct {
Description string
AdmissionInfo v1.RequestInfo
AdmissionInfo v1beta1.RequestInfo
Resource []byte
Policy []byte
areErrorsExpected bool
}{
{
Description: "Match Any matches the Pod",
AdmissionInfo: v1.RequestInfo{
AdmissionInfo: v1beta1.RequestInfo{
ClusterRoles: []string{"admin"},
},
Resource: []byte(`{
@ -106,7 +107,7 @@ func TestMatchesResourceDescription(t *testing.T) {
},
{
Description: "Match Any does not match the Pod",
AdmissionInfo: v1.RequestInfo{
AdmissionInfo: v1beta1.RequestInfo{
ClusterRoles: []string{"admin"},
},
Resource: []byte(`{
@ -191,7 +192,7 @@ func TestMatchesResourceDescription(t *testing.T) {
},
{
Description: "Match All matches the Pod",
AdmissionInfo: v1.RequestInfo{
AdmissionInfo: v1beta1.RequestInfo{
ClusterRoles: []string{"admin"},
},
Resource: []byte(`{
@ -276,7 +277,7 @@ func TestMatchesResourceDescription(t *testing.T) {
},
{
Description: "Match All does not match the Pod",
AdmissionInfo: v1.RequestInfo{
AdmissionInfo: v1beta1.RequestInfo{
ClusterRoles: []string{"admin"},
},
Resource: []byte(`{
@ -361,7 +362,7 @@ func TestMatchesResourceDescription(t *testing.T) {
},
{
Description: "Exclude Any excludes the Pod",
AdmissionInfo: v1.RequestInfo{
AdmissionInfo: v1beta1.RequestInfo{
ClusterRoles: []string{"admin"},
},
Resource: []byte(`{
@ -461,7 +462,7 @@ func TestMatchesResourceDescription(t *testing.T) {
},
{
Description: "Exclude Any does not exclude the Pod",
AdmissionInfo: v1.RequestInfo{
AdmissionInfo: v1beta1.RequestInfo{
ClusterRoles: []string{"admin"},
},
Resource: []byte(`{
@ -561,7 +562,7 @@ func TestMatchesResourceDescription(t *testing.T) {
},
{
Description: "Exclude All excludes the Pod",
AdmissionInfo: v1.RequestInfo{
AdmissionInfo: v1beta1.RequestInfo{
ClusterRoles: []string{"admin"},
},
Resource: []byte(`{
@ -661,7 +662,7 @@ func TestMatchesResourceDescription(t *testing.T) {
},
{
Description: "Exclude All does not exclude the Pod",
AdmissionInfo: v1.RequestInfo{
AdmissionInfo: v1beta1.RequestInfo{
ClusterRoles: []string{"admin"},
},
Resource: []byte(`{
@ -761,7 +762,7 @@ func TestMatchesResourceDescription(t *testing.T) {
},
{
Description: "Should match pod and not exclude it",
AdmissionInfo: v1.RequestInfo{
AdmissionInfo: v1beta1.RequestInfo{
ClusterRoles: []string{"admin"},
},
Resource: []byte(`{"apiVersion":"v1","kind":"Pod","metadata":{"name":"hello-world","labels":{"name":"hello-world"}},"spec":{"containers":[{"name":"hello-world","image":"hello-world","ports":[{"containerPort":81}],"resources":{"limits":{"memory":"30Mi","cpu":"0.2"},"requests":{"memory":"20Mi","cpu":"0.1"}}}]}}`),
@ -770,7 +771,7 @@ func TestMatchesResourceDescription(t *testing.T) {
},
{
Description: "Should exclude resource since it matches the exclude block",
AdmissionInfo: v1.RequestInfo{
AdmissionInfo: v1beta1.RequestInfo{
ClusterRoles: []string{"system:node"},
},
Resource: []byte(`{"apiVersion":"v1","kind":"Pod","metadata":{"name":"hello-world","labels":{"name":"hello-world"}},"spec":{"containers":[{"name":"hello-world","image":"hello-world","ports":[{"containerPort":81}],"resources":{"limits":{"memory":"30Mi","cpu":"0.2"},"requests":{"memory":"20Mi","cpu":"0.1"}}}]}}`),
@ -790,7 +791,10 @@ func TestMatchesResourceDescription(t *testing.T) {
areErrorsExpected: true,
},
{
Description: "Should pass since resource matches a name in the names field",
Description: "Should pass since resource matches a name in the names field",
AdmissionInfo: v1beta1.RequestInfo{
ClusterRoles: []string{"system:node"},
},
Resource: []byte(`{"apiVersion":"v1","kind":"Pod","metadata":{"name":"hello-world","labels":{"name":"hello-world"}},"spec":{"containers":[{"name":"hello-world","image":"hello-world","ports":[{"containerPort":81}],"resources":{"limits":{"memory":"30Mi","cpu":"0.2"},"requests":{"memory":"20Mi","cpu":"0.1"}}}]}}`),
Policy: []byte(`{"apiVersion":"kyverno.io/v1","kind":"ClusterPolicy","metadata":{"name":"hello-world-policy"},"spec":{"background":false,"rules":[{"name":"hello-world-policy","match":{"resources":{"kinds":["Pod"],"names": ["dev-*","hello-world"]},"clusterRoles":["system:node"]},"mutate":{"overlay":{"spec":{"containers":[{"(image)":"*","imagePullPolicy":"IfNotPresent"}]}}}}]}}`),
areErrorsExpected: false,
@ -809,7 +813,7 @@ func TestMatchesResourceDescription(t *testing.T) {
},
{
Description: "Should fail since resource does not match policy",
AdmissionInfo: v1.RequestInfo{
AdmissionInfo: v1beta1.RequestInfo{
ClusterRoles: []string{"admin"},
},
Resource: []byte(`{"apiVersion":"v1","kind":"Service","metadata":{"name":"hello-world","labels":{"name":"hello-world"}},"spec":{"containers":[{"name":"hello-world","image":"hello-world","ports":[{"containerPort":81}],"resources":{"limits":{"memory":"30Mi","cpu":"0.2"},"requests":{"memory":"20Mi","cpu":"0.1"}}}]}}`),
@ -818,7 +822,7 @@ func TestMatchesResourceDescription(t *testing.T) {
},
{
Description: "Should not fail since resource does not match exclude block",
AdmissionInfo: v1.RequestInfo{
AdmissionInfo: v1beta1.RequestInfo{
ClusterRoles: []string{"system:node"},
},
Resource: []byte(`{"apiVersion":"v1","kind":"Pod","metadata":{"name":"hello-world2","labels":{"name":"hello-world"}},"spec":{"containers":[{"name":"hello-world","image":"hello-world","ports":[{"containerPort":81}],"resources":{"limits":{"memory":"30Mi","cpu":"0.2"},"requests":{"memory":"20Mi","cpu":"0.1"}}}]}}`),
@ -827,7 +831,7 @@ func TestMatchesResourceDescription(t *testing.T) {
},
{
Description: "Should pass since group, version, kind match",
AdmissionInfo: v1.RequestInfo{
AdmissionInfo: v1beta1.RequestInfo{
ClusterRoles: []string{"admin"},
},
Resource: []byte(`{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": { "creationTimestamp": "2020-09-21T12:56:35Z", "name": "qos-demo", "labels": { "test": "qos" } }, "spec": { "replicas": 1, "selector": { "matchLabels": { "app": "nginx" } }, "template": { "metadata": { "creationTimestamp": "2020-09-21T12:56:35Z", "labels": { "app": "nginx" } }, "spec": { "containers": [ { "name": "nginx", "image": "nginx:latest", "resources": { "limits": { "cpu": "50m" } } } ]}}}}`),
@ -836,7 +840,7 @@ func TestMatchesResourceDescription(t *testing.T) {
},
{
Description: "Should pass since version and kind match",
AdmissionInfo: v1.RequestInfo{
AdmissionInfo: v1beta1.RequestInfo{
ClusterRoles: []string{"admin"},
},
Resource: []byte(`{ "apiVersion": "v1", "kind": "Pod", "metadata": { "name": "myapp-pod2", "labels": { "app": "myapp2" } }, "spec": { "containers": [ { "name": "nginx", "image": "nginx" } ] } }`),
@ -845,7 +849,7 @@ func TestMatchesResourceDescription(t *testing.T) {
},
{
Description: "Should fail since resource does not match ",
AdmissionInfo: v1.RequestInfo{
AdmissionInfo: v1beta1.RequestInfo{
ClusterRoles: []string{"admin"},
},
Resource: []byte(`{"apiVersion":"v1","kind":"Service","metadata":{"name":"hello-world","labels":{"name":"hello-world"}},"spec":{"containers":[{"name":"hello-world","image":"hello-world","ports":[{"containerPort":81}],"resources":{"limits":{"memory":"30Mi","cpu":"0.2"},"requests":{"memory":"20Mi","cpu":"0.1"}}}]}}`),
@ -854,7 +858,7 @@ func TestMatchesResourceDescription(t *testing.T) {
},
{
Description: "Should fail since version not match",
AdmissionInfo: v1.RequestInfo{
AdmissionInfo: v1beta1.RequestInfo{
ClusterRoles: []string{"admin"},
},
Resource: []byte(`{ "apiVersion": "apps/v1beta1", "kind": "Deployment", "metadata": { "creationTimestamp": "2020-09-21T12:56:35Z", "name": "qos-demo", "labels": { "test": "qos" } }, "spec": { "replicas": 1, "selector": { "matchLabels": { "app": "nginx" } }, "template": { "metadata": { "creationTimestamp": "2020-09-21T12:56:35Z", "labels": { "app": "nginx" } }, "spec": { "containers": [ { "name": "nginx", "image": "nginx:latest", "resources": { "limits": { "cpu": "50m" } } } ]}}}}`),
@ -863,7 +867,7 @@ func TestMatchesResourceDescription(t *testing.T) {
},
{
Description: "Should fail since cluster role version not match",
AdmissionInfo: v1.RequestInfo{
AdmissionInfo: v1beta1.RequestInfo{
ClusterRoles: []string{"admin"},
},
Resource: []byte(`{ "kind": "ClusterRole", "apiVersion": "rbac.authorization.k8s.io/v1", "metadata": { "name": "secret-reader-demo", "namespace": "default" }, "rules": [ { "apiGroups": [ "" ], "resources": [ "secrets" ], "verbs": [ "get", "watch", "list" ] } ] }`),
@ -872,7 +876,7 @@ func TestMatchesResourceDescription(t *testing.T) {
},
{
Description: "Test for GVK case sensitive",
AdmissionInfo: v1.RequestInfo{
AdmissionInfo: v1beta1.RequestInfo{
ClusterRoles: []string{"admin"},
},
Resource: []byte(`{ "apiVersion": "v1", "kind": "Pod", "metadata": { "name": "myapp-pod2", "labels": { "app": "myapp2" } }, "spec": { "containers": [ { "name": "nginx", "image": "nginx" } ] } }`),
@ -881,7 +885,7 @@ func TestMatchesResourceDescription(t *testing.T) {
},
{
Description: "Test should pass for GVK case sensitive",
AdmissionInfo: v1.RequestInfo{
AdmissionInfo: v1beta1.RequestInfo{
ClusterRoles: []string{"admin"},
},
Resource: []byte(`{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": { "creationTimestamp": "2020-09-21T12:56:35Z", "name": "qos-demo", "labels": { "test": "qos" } }, "spec": { "replicas": 1, "selector": { "matchLabels": { "app": "nginx" } }, "template": { "metadata": { "creationTimestamp": "2020-09-21T12:56:35Z", "labels": { "app": "nginx" } }, "spec": { "containers": [ { "name": "nginx", "image": "nginx:latest", "resources": { "limits": { "cpu": "50m" } } } ]}}}}`),
@ -902,7 +906,7 @@ func TestMatchesResourceDescription(t *testing.T) {
err := MatchesResourceDescription(*resource, rule, tc.AdmissionInfo, []string{}, nil, "")
if err != nil {
if !tc.areErrorsExpected {
t.Errorf("Testcase %d Unexpected error: %v", i+1, err)
t.Errorf("Testcase %d Unexpected error: %v\nmsg: %s", i+1, err, tc.Description)
}
} else {
if tc.areErrorsExpected {
@ -967,7 +971,7 @@ func TestResourceDescriptionMatch_MultipleKind(t *testing.T) {
}
rule := v1.Rule{MatchResources: v1.MatchResources{ResourceDescription: resourceDescription}}
if err := MatchesResourceDescription(*resource, rule, v1.RequestInfo{}, []string{}, nil, ""); err != nil {
if err := MatchesResourceDescription(*resource, rule, v1beta1.RequestInfo{}, []string{}, nil, ""); err != nil {
t.Errorf("Testcase has failed due to the following:%v", err)
}
@ -1028,7 +1032,7 @@ func TestResourceDescriptionMatch_Name(t *testing.T) {
}
rule := v1.Rule{MatchResources: v1.MatchResources{ResourceDescription: resourceDescription}}
if err := MatchesResourceDescription(*resource, rule, v1.RequestInfo{}, []string{}, nil, ""); err != nil {
if err := MatchesResourceDescription(*resource, rule, v1beta1.RequestInfo{}, []string{}, nil, ""); err != nil {
t.Errorf("Testcase has failed due to the following:%v", err)
}
}
@ -1088,7 +1092,7 @@ func TestResourceDescriptionMatch_Name_Regex(t *testing.T) {
}
rule := v1.Rule{MatchResources: v1.MatchResources{ResourceDescription: resourceDescription}}
if err := MatchesResourceDescription(*resource, rule, v1.RequestInfo{}, []string{}, nil, ""); err != nil {
if err := MatchesResourceDescription(*resource, rule, v1beta1.RequestInfo{}, []string{}, nil, ""); err != nil {
t.Errorf("Testcase has failed due to the following:%v", err)
}
}
@ -1156,7 +1160,7 @@ func TestResourceDescriptionMatch_Label_Expression_NotMatch(t *testing.T) {
}
rule := v1.Rule{MatchResources: v1.MatchResources{ResourceDescription: resourceDescription}}
if err := MatchesResourceDescription(*resource, rule, v1.RequestInfo{}, []string{}, nil, ""); err != nil {
if err := MatchesResourceDescription(*resource, rule, v1beta1.RequestInfo{}, []string{}, nil, ""); err != nil {
t.Errorf("Testcase has failed due to the following:%v", err)
}
}
@ -1225,7 +1229,7 @@ func TestResourceDescriptionMatch_Label_Expression_Match(t *testing.T) {
}
rule := v1.Rule{MatchResources: v1.MatchResources{ResourceDescription: resourceDescription}}
if err := MatchesResourceDescription(*resource, rule, v1.RequestInfo{}, []string{}, nil, ""); err != nil {
if err := MatchesResourceDescription(*resource, rule, v1beta1.RequestInfo{}, []string{}, nil, ""); err != nil {
t.Errorf("Testcase has failed due to the following:%v", err)
}
}
@ -1305,7 +1309,7 @@ func TestResourceDescriptionExclude_Label_Expression_Match(t *testing.T) {
rule := v1.Rule{MatchResources: v1.MatchResources{ResourceDescription: resourceDescription},
ExcludeResources: v1.MatchResources{ResourceDescription: resourceDescriptionExclude}}
if err := MatchesResourceDescription(*resource, rule, v1.RequestInfo{}, []string{}, nil, ""); err == nil {
if err := MatchesResourceDescription(*resource, rule, v1beta1.RequestInfo{}, []string{}, nil, ""); err == nil {
t.Errorf("Testcase has failed due to the following:\n Function has returned no error, even though it was supposed to fail")
}
}

View file

@ -208,7 +208,7 @@ func (v *validator) validate() *response.RuleResponse {
}
if !preconditionsPassed && v.ctx.Policy.GetSpec().ValidationFailureAction != kyverno.Audit {
return ruleResponse(v.rule, response.Validation, "preconditions not met", response.RuleStatusSkip)
return ruleResponse(*v.rule, response.Validation, "preconditions not met", response.RuleStatusSkip, nil)
}
if v.deny != nil {
@ -249,7 +249,7 @@ func (v *validator) validateForEach() *response.RuleResponse {
if err != nil {
return ruleError(v.rule, response.Validation, "failed to evaluate preconditions", err)
} else if !preconditionsPassed && v.ctx.Policy.GetSpec().ValidationFailureAction != kyverno.Audit {
return ruleResponse(v.rule, response.Validation, "preconditions not met", response.RuleStatusSkip)
return ruleResponse(*v.rule, response.Validation, "preconditions not met", response.RuleStatusSkip, nil)
}
foreachList := v.rule.Validation.ForEachValidation
@ -279,10 +279,10 @@ func (v *validator) validateForEach() *response.RuleResponse {
}
if applyCount == 0 {
return ruleResponse(v.rule, response.Validation, "rule skipped", response.RuleStatusSkip)
return ruleResponse(*v.rule, response.Validation, "rule skipped", response.RuleStatusSkip, nil)
}
return ruleResponse(v.rule, response.Validation, "rule passed", response.RuleStatusPass)
return ruleResponse(*v.rule, response.Validation, "rule passed", response.RuleStatusPass, nil)
}
func (v *validator) validateElements(foreach *kyverno.ForEachValidation, elements []interface{}, elementScope bool) (*response.RuleResponse, int) {
@ -309,13 +309,13 @@ func (v *validator) validateElements(foreach *kyverno.ForEachValidation, element
continue
} else if r.Status != response.RuleStatusPass {
msg := fmt.Sprintf("validation failure: %v", r.Message)
return ruleResponse(v.rule, response.Validation, msg, r.Status), applyCount
return ruleResponse(*v.rule, response.Validation, msg, r.Status, nil), applyCount
}
applyCount++
}
return ruleResponse(v.rule, response.Validation, "", response.RuleStatusPass), applyCount
return ruleResponse(*v.rule, response.Validation, "", response.RuleStatusPass, nil), applyCount
}
func addElementToContext(ctx *PolicyContext, e interface{}, elementIndex int, elementScope bool) error {
@ -366,10 +366,10 @@ func (v *validator) validateDeny() *response.RuleResponse {
deny := variables.EvaluateConditions(v.log, v.ctx.JSONContext, denyConditions)
if deny {
return ruleResponse(v.rule, response.Validation, v.getDenyMessage(deny), response.RuleStatusFail)
return ruleResponse(*v.rule, response.Validation, v.getDenyMessage(deny), response.RuleStatusFail, nil)
}
return ruleResponse(v.rule, response.Validation, v.getDenyMessage(deny), response.RuleStatusPass)
return ruleResponse(*v.rule, response.Validation, v.getDenyMessage(deny), response.RuleStatusPass, nil)
}
func (v *validator) getDenyMessage(deny bool) string {
@ -473,22 +473,22 @@ func (v *validator) validatePatterns(resource unstructured.Unstructured) *respon
v.log.V(3).Info("validation error", "path", pe.Path, "error", err.Error())
if pe.Skip {
return ruleResponse(v.rule, response.Validation, pe.Error(), response.RuleStatusSkip)
return ruleResponse(*v.rule, response.Validation, pe.Error(), response.RuleStatusSkip, nil)
}
if pe.Path == "" {
return ruleResponse(v.rule, response.Validation, v.buildErrorMessage(err, ""), response.RuleStatusError)
return ruleResponse(*v.rule, response.Validation, v.buildErrorMessage(err, ""), response.RuleStatusError, nil)
}
return ruleResponse(v.rule, response.Validation, v.buildErrorMessage(err, pe.Path), response.RuleStatusFail)
return ruleResponse(*v.rule, response.Validation, v.buildErrorMessage(err, pe.Path), response.RuleStatusFail, nil)
}
return ruleResponse(v.rule, response.Validation, v.buildErrorMessage(err, pe.Path), response.RuleStatusError)
return ruleResponse(*v.rule, response.Validation, v.buildErrorMessage(err, pe.Path), response.RuleStatusError, nil)
}
v.log.V(4).Info("successfully processed rule")
msg := fmt.Sprintf("validation rule '%s' passed.", v.rule.Name)
return ruleResponse(v.rule, response.Validation, msg, response.RuleStatusPass)
return ruleResponse(*v.rule, response.Validation, msg, response.RuleStatusPass, nil)
}
if v.anyPattern != nil {
@ -498,14 +498,14 @@ func (v *validator) validatePatterns(resource unstructured.Unstructured) *respon
anyPatterns, err := deserializeAnyPattern(v.anyPattern)
if err != nil {
msg := fmt.Sprintf("failed to deserialize anyPattern, expected type array: %v", err)
return ruleResponse(v.rule, response.Validation, msg, response.RuleStatusError)
return ruleResponse(*v.rule, response.Validation, msg, response.RuleStatusError, nil)
}
for idx, pattern := range anyPatterns {
err := validate.MatchPattern(v.log, resource.Object, pattern)
if err == nil {
msg := fmt.Sprintf("validation rule '%s' anyPattern[%d] passed.", v.rule.Name, idx)
return ruleResponse(v.rule, response.Validation, msg, response.RuleStatusPass)
return ruleResponse(*v.rule, response.Validation, msg, response.RuleStatusPass, nil)
}
if pe, ok := err.(*validate.PatternError); ok {
@ -529,11 +529,11 @@ func (v *validator) validatePatterns(resource unstructured.Unstructured) *respon
v.log.V(4).Info(fmt.Sprintf("Validation rule '%s' failed. %s", v.rule.Name, errorStr))
msg := buildAnyPatternErrorMessage(v.rule, errorStr)
return ruleResponse(v.rule, response.Validation, msg, response.RuleStatusFail)
return ruleResponse(*v.rule, response.Validation, msg, response.RuleStatusFail, nil)
}
}
return ruleResponse(v.rule, response.Validation, v.rule.Validation.Message, response.RuleStatusPass)
return ruleResponse(*v.rule, response.Validation, v.rule.Validation.Message, response.RuleStatusPass, nil)
}
func deserializeAnyPattern(anyPattern apiextensions.JSON) ([]interface{}, error) {

View file

@ -6,10 +6,10 @@ import (
"testing"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/engine/response"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/store"
"github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/response"
"github.com/kyverno/kyverno/pkg/engine/utils"
utils2 "github.com/kyverno/kyverno/pkg/utils"
"gotest.tools/assert"
@ -2110,7 +2110,7 @@ func executeTest(t *testing.T, err error, test testCase) {
t.Fatal(err)
}
var userInfo kyverno.RequestInfo
var userInfo urkyverno.RequestInfo
err = json.Unmarshal(test.userInfo, &userInfo)
if err != nil {
t.Fatal(err)

View file

@ -5,12 +5,11 @@ import (
"reflect"
"testing"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/engine/context"
"gotest.tools/assert"
authenticationv1 "k8s.io/api/authentication/v1"
"sigs.k8s.io/controller-runtime/pkg/log"
"github.com/kyverno/kyverno/pkg/engine/context"
)
func Test_variablesub1(t *testing.T) {
@ -52,7 +51,7 @@ func Test_variablesub1(t *testing.T) {
}
`)
// userInfo
userReqInfo := kyverno.RequestInfo{
userReqInfo := urkyverno.RequestInfo{
AdmissionUserInfo: authenticationv1.UserInfo{
Username: "user1",
},
@ -140,7 +139,7 @@ func Test_variablesub_multiple(t *testing.T) {
}
`)
// userInfo
userReqInfo := kyverno.RequestInfo{
userReqInfo := urkyverno.RequestInfo{
AdmissionUserInfo: authenticationv1.UserInfo{
Username: "user1",
},
@ -230,7 +229,7 @@ func Test_variablesubstitution(t *testing.T) {
resultMap := []byte(`{"data":{"rules":[{"apiGroups":[""],"resourceNames":["temp"],"resources":["namespaces"],"verbs":["*"]}]},"name":"ns-owner-user1"}`)
// userInfo
userReqInfo := kyverno.RequestInfo{
userReqInfo := urkyverno.RequestInfo{
AdmissionUserInfo: authenticationv1.UserInfo{
Username: "user1",
},

View file

@ -333,7 +333,7 @@ func substituteVariablesIfAny(log logr.Logger, ctx context.EvalInterface, vr Var
return data.Element, nil
}
isDeleteRequest := isDeleteRequest(ctx)
isDeleteRequest := IsDeleteRequest(ctx)
vars := RegexVariables.FindAllString(value, -1)
for len(vars) > 0 {
@ -406,7 +406,7 @@ func substituteVariablesIfAny(log logr.Logger, ctx context.EvalInterface, vr Var
})
}
func isDeleteRequest(ctx context.EvalInterface) bool {
func IsDeleteRequest(ctx context.EvalInterface) bool {
if ctx == nil {
return false
}

View file

@ -39,7 +39,10 @@ type Generator struct {
admissionCtrRecorder record.EventRecorder
// events generated at namespaced policy controller to process 'generate' rule
genPolicyRecorder record.EventRecorder
log logr.Logger
// events generated at mutateExisting controller
mutateExistingRecorder record.EventRecorder
log logr.Logger
}
//Interface to generate event
@ -50,16 +53,17 @@ type Interface interface {
//NewEventGenerator to generate a new event controller
func NewEventGenerator(client *client.Client, cpInformer kyvernoinformer.ClusterPolicyInformer, pInformer kyvernoinformer.PolicyInformer, log logr.Logger) *Generator {
gen := Generator{
client: client,
cpLister: cpInformer.Lister(),
cpSynced: cpInformer.Informer().HasSynced,
pLister: pInformer.Lister(),
pSynced: pInformer.Informer().HasSynced,
queue: workqueue.NewNamedRateLimitingQueue(rateLimiter(), eventWorkQueueName),
policyCtrRecorder: initRecorder(client, PolicyController, log),
admissionCtrRecorder: initRecorder(client, AdmissionController, log),
genPolicyRecorder: initRecorder(client, GeneratePolicyController, log),
log: log,
client: client,
cpLister: cpInformer.Lister(),
cpSynced: cpInformer.Informer().HasSynced,
pLister: pInformer.Lister(),
pSynced: pInformer.Informer().HasSynced,
queue: workqueue.NewNamedRateLimitingQueue(rateLimiter(), eventWorkQueueName),
policyCtrRecorder: initRecorder(client, PolicyController, log),
admissionCtrRecorder: initRecorder(client, AdmissionController, log),
genPolicyRecorder: initRecorder(client, GeneratePolicyController, log),
mutateExistingRecorder: initRecorder(client, MutateExistingController, log),
log: log,
}
return &gen
}
@ -223,6 +227,8 @@ func (gen *Generator) syncHandler(key Info) error {
gen.policyCtrRecorder.Event(robj, eventType, key.Reason, key.Message)
case GeneratePolicyController:
gen.genPolicyRecorder.Event(robj, eventType, key.Reason, key.Message)
case MutateExistingController:
gen.mutateExistingRecorder.Event(robj, eventType, key.Reason, key.Message)
default:
logger.Info("info.source not defined for the request")
}

View file

@ -10,6 +10,8 @@ const (
PolicyController
// GeneratePolicyController : event generated in generate policyController
GeneratePolicyController
// MutateExistingController : event generated for mutateExisting policies
MutateExistingController
)
func (s Source) String() string {
@ -17,5 +19,6 @@ func (s Source) String() string {
"admission-controller",
"policy-controller",
"generate-policy-controller",
"mutate-existing-controller",
}[s]
}

View file

@ -184,7 +184,7 @@ func (o *Controller) useOpenAPIDocument(doc *openapiv2.Document) error {
gvk, preferredGVK, err := o.getGVKByDefinitionName(definitionName)
if err != nil {
log.Log.V(3).Info("unable to cache OpenAPISchema", "definitionName", definitionName, "reason", err.Error())
log.Log.V(5).Info("unable to cache OpenAPISchema", "definitionName", definitionName, "reason", err.Error())
continue
}

View file

@ -15,6 +15,12 @@ import (
//ContainsUserVariables returns error if variable that does not start from request.object
func containsUserVariables(policy kyverno.PolicyInterface, vars [][]string) error {
for _, rule := range policy.GetSpec().Rules {
if rule.IsMutateExisting() {
return nil
}
}
for _, s := range vars {
if strings.Contains(s[0], "userInfo") {
return fmt.Errorf("variable %s is not allowed", s[0])

View file

@ -11,12 +11,15 @@ import (
"github.com/go-logr/logr"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/common"
"github.com/kyverno/kyverno/pkg/autogen"
kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
"github.com/kyverno/kyverno/pkg/client/clientset/versioned/scheme"
kyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1"
urkyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1beta1"
kyvernolister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1"
urkyvernolister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1beta1"
pkgCommon "github.com/kyverno/kyverno/pkg/common"
"github.com/kyverno/kyverno/pkg/config"
client "github.com/kyverno/kyverno/pkg/dclient"
@ -24,6 +27,7 @@ import (
"github.com/kyverno/kyverno/pkg/metrics"
"github.com/kyverno/kyverno/pkg/policyreport"
"github.com/kyverno/kyverno/pkg/utils"
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -71,6 +75,9 @@ type PolicyController struct {
// grLister can list/get generate request from the shared informer's store
grLister kyvernolister.GenerateRequestLister
// urLister can list/get update request from the shared informer's store
urLister urkyvernolister.UpdateRequestLister
// nsLister can list/get namespaces from the shared informer's store
nsLister listerv1.NamespaceLister
@ -86,6 +93,9 @@ type PolicyController struct {
// grListerSynced returns true if the generate request store has been synced at least once
grListerSynced cache.InformerSynced
// urListerSynced returns true if the update request store has been synced at least once
urListerSynced cache.InformerSynced
// Resource manager, manages the mapping for already processed resource
rm resourceManager
@ -112,6 +122,7 @@ func NewPolicyController(
pInformer kyvernoinformer.ClusterPolicyInformer,
npInformer kyvernoinformer.PolicyInformer,
grInformer kyvernoinformer.GenerateRequestInformer,
urInformer urkyvernoinformer.UpdateRequestInformer,
configHandler config.Interface,
eventGen event.Interface,
prGenerator policyreport.GeneratorInterface,
@ -152,12 +163,14 @@ func NewPolicyController(
pc.nsLister = namespaces.Lister()
pc.grLister = grInformer.Lister()
pc.urLister = urInformer.Lister()
pc.pListerSynced = pInformer.Informer().HasSynced
pc.npListerSynced = npInformer.Informer().HasSynced
pc.nsListerSynced = namespaces.Informer().HasSynced
pc.grListerSynced = grInformer.Informer().HasSynced
pc.urListerSynced = urInformer.Informer().HasSynced
// resource manager
// rebuild after 300 seconds/ 5 mins
@ -415,7 +428,7 @@ func (pc *PolicyController) Run(workers int, reconcileCh <-chan bool, stopCh <-c
logger.Info("starting")
defer logger.Info("shutting down")
if !cache.WaitForCacheSync(stopCh, pc.pListerSynced, pc.npListerSynced, pc.nsListerSynced, pc.grListerSynced) {
if !cache.WaitForCacheSync(stopCh, pc.pListerSynced, pc.npListerSynced, pc.nsListerSynced, pc.grListerSynced, pc.urListerSynced) {
logger.Info("failed to sync informer cache")
return
}
@ -486,22 +499,22 @@ func (pc *PolicyController) syncPolicy(key string) error {
logger.V(4).Info("finished syncing policy", "key", key, "processingTime", time.Since(startTime).String())
}()
grList, err := pc.grLister.List(labels.Everything())
urList, err := pc.urLister.List(labels.Everything())
if err != nil {
logger.Error(err, "failed to list generate request")
logger.Error(err, "failed to list update request")
}
policy, err := pc.getPolicy(key)
if err != nil {
if errors.IsNotFound(err) {
deleteGR(pc.kyvernoClient, key, grList, logger)
deleteGR(pc.kyvernoClient, key, urList, logger)
return nil
}
return err
}
updateGR(pc.kyvernoClient, policy.GetName(), grList, logger)
pc.updateUR(policy, urList)
pc.processExistingResources(policy)
return nil
}
@ -520,18 +533,113 @@ func (pc *PolicyController) getPolicy(key string) (policy kyverno.PolicyInterfac
return
}
func deleteGR(kyvernoClient *kyvernoclient.Clientset, policyKey string, grList []*kyverno.GenerateRequest, logger logr.Logger) {
func (pc *PolicyController) updateUR(policy kyverno.PolicyInterface, urList []*urkyverno.UpdateRequest) {
if urList == nil {
for _, rule := range policy.GetSpec().Rules {
if !rule.IsMutateExisting() {
continue
}
triggers := getTriggers(rule)
for _, trigger := range triggers {
ur := newUR(policy, trigger)
new, err := pc.kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).Create(context.TODO(), ur, metav1.CreateOptions{})
if err != nil {
pc.log.Error(err, "failed to create new UR for mutateExisting rule on policy update", "policy", policy.GetName(), "rule", rule.Name,
"target", fmt.Sprintf("%s/%s/%s/%s", trigger.APIVersion, trigger.Kind, trigger.Namespace, trigger.Name))
} else {
pc.log.V(4).Info("successfully created UR for mutateExisting on policy update", "policy", policy.GetName(), "rule", rule.Name,
"target", fmt.Sprintf("%s/%s/%s/%s", trigger.APIVersion, trigger.Kind, trigger.Namespace, trigger.Name))
}
new.Status.State = urkyverno.Pending
if _, err := pc.kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).UpdateStatus(context.TODO(), new, metav1.UpdateOptions{}); err != nil {
pc.log.Error(err, "failed to set UpdateRequest state to Pending")
}
}
}
return
}
updateUR(pc.kyvernoClient, policy.GetName(), urList, pc.log.WithName("updateUR"))
}
func getTriggers(rule kyverno.Rule) []*kyverno.ResourceSpec {
var specs []*kyverno.ResourceSpec
triggers := getTrigger(rule.MatchResources.ResourceDescription)
specs = append(specs, triggers...)
for _, any := range rule.MatchResources.Any {
triggers := getTrigger(any.ResourceDescription)
specs = append(specs, triggers...)
}
triggers = []*kyverno.ResourceSpec{}
for _, all := range rule.MatchResources.All {
triggers = getTrigger(all.ResourceDescription)
}
subset := make(map[*kyverno.ResourceSpec]int, len(triggers))
for _, trigger := range triggers {
c := subset[trigger]
subset[trigger] = c + 1
}
for k, v := range subset {
if v == len(rule.MatchResources.All) {
specs = append(specs, k)
}
}
return specs
}
func getTrigger(rd kyverno.ResourceDescription) []*kyverno.ResourceSpec {
if len(rd.Names) == 0 {
return nil
}
var specs []*kyverno.ResourceSpec
for _, k := range rd.Kinds {
apiVersion, kind := kubeutils.GetKindFromGVK(k)
if kind == "" {
continue
}
for _, ns := range rd.Namespaces {
for _, name := range rd.Names {
if name == "" {
continue
}
spec := &kyverno.ResourceSpec{
APIVersion: apiVersion,
Kind: kind,
Namespace: ns,
Name: name,
}
specs = append(specs, spec)
}
}
}
return specs
}
func deleteGR(kyvernoClient *kyvernoclient.Clientset, policyKey string, grList []*urkyverno.UpdateRequest, logger logr.Logger) {
for _, v := range grList {
if policyKey == v.Spec.Policy {
err := kyvernoClient.KyvernoV1().GenerateRequests(config.KyvernoNamespace).Delete(context.TODO(), v.GetName(), metav1.DeleteOptions{})
err := kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).Delete(context.TODO(), v.GetName(), metav1.DeleteOptions{})
if err != nil && !errors.IsNotFound(err) {
logger.Error(err, "failed to delete gr", "name", v.GetName())
logger.Error(err, "failed to delete ur", "name", v.GetName())
}
}
}
}
func updateGR(kyvernoClient *kyvernoclient.Clientset, policyKey string, grList []*kyverno.GenerateRequest, logger logr.Logger) {
func updateUR(kyvernoClient *kyvernoclient.Clientset, policyKey string, grList []*urkyverno.UpdateRequest, logger logr.Logger) {
for _, gr := range grList {
if policyKey == gr.Spec.Policy {
grLabels := gr.Labels
@ -546,7 +654,7 @@ func updateGR(kyvernoClient *kyvernoclient.Clientset, policyKey string, grList [
grLabels["policy-update"] = fmt.Sprintf("revision-count-%d", nBig.Int64())
gr.SetLabels(grLabels)
_, err = kyvernoClient.KyvernoV1().GenerateRequests(config.KyvernoNamespace).Update(context.TODO(), gr, metav1.UpdateOptions{})
_, err = kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).Update(context.TODO(), gr, metav1.UpdateOptions{})
if err != nil {
logger.Error(err, "failed to update gr", "name", gr.GetName())
}
@ -592,3 +700,42 @@ func missingAutoGenRules(policy kyverno.PolicyInterface, log logr.Logger) bool {
}
return false
}
func newUR(policy kyverno.PolicyInterface, target *kyverno.ResourceSpec) *urkyverno.UpdateRequest {
var policyNameNamespaceKey string
if policy.GetKind() == "Policy" {
policyNameNamespaceKey = policy.GetNamespace() + "/" + policy.GetName()
} else {
policyNameNamespaceKey = policy.GetName()
}
label := map[string]string{
"mutate.updaterequest.kyverno.io/policy-name": policyNameNamespaceKey,
"mutate.updaterequest.kyverno.io/trigger-name": target.Name,
"mutate.updaterequest.kyverno.io/trigger-namespace": target.Namespace,
"mutate.updaterequest.kyverno.io/trigger-kind": target.Kind,
}
if target.APIVersion != "" {
label["mutate.updaterequest.kyverno.io/trigger-apiversion"] = target.APIVersion
}
return &urkyverno.UpdateRequest{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "ur-",
Namespace: config.KyvernoNamespace,
Labels: label,
},
Spec: urkyverno.UpdateRequestSpec{
Type: urkyverno.Mutate,
Policy: policyNameNamespaceKey,
Resource: kyverno.ResourceSpec{
Kind: target.Kind,
Namespace: target.Namespace,
Name: target.Name,
APIVersion: target.APIVersion,
},
},
}
}

View file

@ -13,7 +13,7 @@ import (
type Interface interface {
// GetPolicies returns all policies that apply to a namespace, including cluster-wide policies
// If the namespace is empty, only cluster-wide policies are returned
GetPolicies(PolicyType, string, string) []kyverno.PolicyInterface
GetPolicies(pType PolicyType, kind string, namespace string) []kyverno.PolicyInterface
// add adds a policy to the cache
add(kyverno.PolicyInterface)

View file

@ -191,7 +191,7 @@ func runTestCase(t *testing.T, tc TestCase) bool {
JSONContext: context.NewContext(),
}
er = engine.Generate(policyContext)
er = engine.ApplyBackgroundChecks(policyContext)
t.Log(("---Generation---"))
validateResponse(t, er.PolicyResponse, tc.Expected.Generation.PolicyResponse)
// Expected generate resource will be in same namespaces as resource

142
pkg/utils/annotations.go Normal file
View file

@ -0,0 +1,142 @@
package utils
import (
"encoding/json"
"strings"
"github.com/go-logr/logr"
"github.com/kyverno/kyverno/pkg/engine/response"
jsonutils "github.com/kyverno/kyverno/pkg/utils/json"
yamlv2 "gopkg.in/yaml.v2"
)
const (
PolicyAnnotation = "policies.kyverno.io/last-applied-patches"
policyAnnotation = "policies.kyverno.io~1last-applied-patches"
oldAnnotation = "policies.kyverno.io~1patches"
)
type RulePatch struct {
RuleName string `json:"rulename"`
Op string `json:"op"`
Path string `json:"path"`
}
var OperationToPastTense = map[string]string{
"add": "added",
"remove": "removed",
"replace": "replaced",
"move": "moved",
"copy": "copied",
"test": "tested",
}
func GenerateAnnotationPatches(engineResponses []*response.EngineResponse, log logr.Logger) [][]byte {
var annotations map[string]string
var patchBytes [][]byte
for _, er := range engineResponses {
if ann := er.PatchedResource.GetAnnotations(); ann != nil {
annotations = ann
break
}
}
if annotations == nil {
annotations = make(map[string]string)
}
var patchResponse jsonutils.Patch
value := annotationFromEngineResponses(engineResponses, log)
if value == nil {
// no patches or error while processing patches
return nil
}
if _, ok := annotations[strings.ReplaceAll(policyAnnotation, "~1", "/")]; ok {
// create update patch string
if _, ok := annotations["policies.kyverno.io/patches"]; ok {
patchResponse = jsonutils.NewPatch("/metadata/annotations/"+oldAnnotation, "remove", nil)
delete(annotations, "policies.kyverno.io/patches")
patchByte, _ := json.Marshal(patchResponse)
patchBytes = append(patchBytes, patchByte)
}
patchResponse = jsonutils.NewPatch("/metadata/annotations/"+policyAnnotation, "replace", string(value))
patchByte, _ := json.Marshal(patchResponse)
patchBytes = append(patchBytes, patchByte)
} else {
// mutate rule has annotation patches
if len(annotations) > 0 {
if _, ok := annotations["policies.kyverno.io/patches"]; ok {
patchResponse = jsonutils.NewPatch("/metadata/annotations/"+oldAnnotation, "remove", nil)
delete(annotations, "policies.kyverno.io/patches")
patchByte, _ := json.Marshal(patchResponse)
patchBytes = append(patchBytes, patchByte)
}
patchResponse = jsonutils.NewPatch("/metadata/annotations/"+policyAnnotation, "add", string(value))
patchByte, _ := json.Marshal(patchResponse)
patchBytes = append(patchBytes, patchByte)
} else {
// insert 'policies.kyverno.patches' entry in annotation map
annotations[strings.ReplaceAll(policyAnnotation, "~1", "/")] = string(value)
patchResponse = jsonutils.NewPatch("/metadata/annotations", "add", annotations)
patchByte, _ := json.Marshal(patchResponse)
patchBytes = append(patchBytes, patchByte)
}
}
for _, patchByte := range patchBytes {
err := jsonutils.CheckPatch(patchByte)
if err != nil {
log.Error(err, "failed to build JSON patch for annotation", "patch", string(patchByte))
}
}
return patchBytes
}
func annotationFromEngineResponses(engineResponses []*response.EngineResponse, log logr.Logger) []byte {
var annotationContent = make(map[string]string)
for _, engineResponse := range engineResponses {
if !engineResponse.IsSuccessful() {
log.V(3).Info("skip building annotation; policy failed to apply", "policy", engineResponse.PolicyResponse.Policy.Name)
continue
}
rulePatches := annotationFromPolicyResponse(engineResponse.PolicyResponse, log)
if rulePatches == nil {
continue
}
policyName := engineResponse.PolicyResponse.Policy.Name
for _, rulePatch := range rulePatches {
annotationContent[rulePatch.RuleName+"."+policyName+".kyverno.io"] = OperationToPastTense[rulePatch.Op] + " " + rulePatch.Path
}
}
// return nil if there's no patches
// otherwise result = null, len(result) = 4
if len(annotationContent) == 0 {
return nil
}
result, _ := yamlv2.Marshal(annotationContent)
return result
}
func annotationFromPolicyResponse(policyResponse response.PolicyResponse, log logr.Logger) []RulePatch {
var RulePatches []RulePatch
for _, ruleInfo := range policyResponse.Rules {
for _, patch := range ruleInfo.Patches {
var patchmap map[string]interface{}
if err := json.Unmarshal(patch, &patchmap); err != nil {
log.Error(err, "Failed to parse JSON patch bytes")
continue
}
rp := RulePatch{
RuleName: ruleInfo.Name,
Op: patchmap["op"].(string),
Path: patchmap["path"].(string),
}
RulePatches = append(RulePatches, rp)
log.V(4).Info("annotation value prepared", "patches", RulePatches)
}
}
if len(RulePatches) == 0 {
return nil
}
return RulePatches
}

View file

@ -1,4 +1,4 @@
package webhooks
package utils
import (
"testing"
@ -43,7 +43,7 @@ func newEngineResponse(policy, rule string, patchesStr []string, status response
func Test_empty_annotation(t *testing.T) {
patchStr := `{ "op": "replace", "path": "/spec/containers/0/imagePullPolicy", "value": "IfNotPresent" }`
engineResponse := newEngineResponse("mutate-container", "default-imagepullpolicy", []string{patchStr}, response.RuleStatusPass, nil)
annPatches := generateAnnotationPatches([]*response.EngineResponse{engineResponse}, log.Log)
annPatches := GenerateAnnotationPatches([]*response.EngineResponse{engineResponse}, log.Log)
expectedPatches := `{"path":"/metadata/annotations","op":"add","value":{"policies.kyverno.io/last-applied-patches":"default-imagepullpolicy.mutate-container.kyverno.io: replaced /spec/containers/0/imagePullPolicy\n"}}`
assert.Equal(t, string(annPatches[0]), expectedPatches)
}
@ -54,7 +54,7 @@ func Test_exist_annotation(t *testing.T) {
}
patchStr := `{ "op": "replace", "path": "/spec/containers/0/imagePullPolicy", "value": "IfNotPresent" }`
engineResponse := newEngineResponse("mutate-container", "default-imagepullpolicy", []string{patchStr}, response.RuleStatusPass, annotation)
annPatches := generateAnnotationPatches([]*response.EngineResponse{engineResponse}, log.Log)
annPatches := GenerateAnnotationPatches([]*response.EngineResponse{engineResponse}, log.Log)
expectedPatches := `{"path":"/metadata/annotations/policies.kyverno.io~1last-applied-patches","op":"add","value":"default-imagepullpolicy.mutate-container.kyverno.io: replaced /spec/containers/0/imagePullPolicy\n"}`
assert.Equal(t, string(annPatches[0]), expectedPatches)
}
@ -65,7 +65,7 @@ func Test_exist_kyverno_annotation(t *testing.T) {
}
patchStr := `{ "op": "replace", "path": "/spec/containers/0/imagePullPolicy", "value": "IfNotPresent" }`
engineResponse := newEngineResponse("mutate-container", "default-imagepullpolicy", []string{patchStr}, response.RuleStatusPass, annotation)
annPatches := generateAnnotationPatches([]*response.EngineResponse{engineResponse}, log.Log)
annPatches := GenerateAnnotationPatches([]*response.EngineResponse{engineResponse}, log.Log)
expectedPatches := `{"path":"/metadata/annotations/policies.kyverno.io~1last-applied-patches","op":"add","value":"default-imagepullpolicy.mutate-container.kyverno.io: replaced /spec/containers/0/imagePullPolicy\n"}`
assert.Equal(t, string(annPatches[0]), expectedPatches)
}
@ -75,10 +75,10 @@ func Test_annotation_nil_patch(t *testing.T) {
"policies.kyverno.patches": "old-annotation",
}
engineResponse := newEngineResponse("mutate-container", "default-imagepullpolicy", nil, response.RuleStatusPass, annotation)
annPatches := generateAnnotationPatches([]*response.EngineResponse{engineResponse}, log.Log)
annPatches := GenerateAnnotationPatches([]*response.EngineResponse{engineResponse}, log.Log)
assert.Assert(t, annPatches == nil)
engineResponseNew := newEngineResponse("mutate-container", "default-imagepullpolicy", []string{""}, response.RuleStatusPass, annotation)
annPatchesNew := generateAnnotationPatches([]*response.EngineResponse{engineResponseNew}, log.Log)
annPatchesNew := GenerateAnnotationPatches([]*response.EngineResponse{engineResponseNew}, log.Log)
assert.Assert(t, annPatchesNew == nil)
}
@ -87,7 +87,7 @@ func Test_annotation_failed_Patch(t *testing.T) {
"policies.kyverno.patches": "old-annotation",
}
engineResponse := newEngineResponse("mutate-container", "default-imagepullpolicy", nil, response.RuleStatusFail, annotation)
annPatches := generateAnnotationPatches([]*response.EngineResponse{engineResponse}, log.Log)
annPatches := GenerateAnnotationPatches([]*response.EngineResponse{engineResponse}, log.Log)
assert.Assert(t, annPatches == nil)
}
@ -97,7 +97,7 @@ func Test_exist_patches(t *testing.T) {
}
patchStr := `{ "op": "replace", "path": "/spec/containers/0/imagePullPolicy", "value": "IfNotPresent" }`
engineResponse := newEngineResponse("mutate-container", "default-imagepullpolicy", []string{patchStr}, response.RuleStatusPass, annotation)
annPatches := generateAnnotationPatches([]*response.EngineResponse{engineResponse}, log.Log)
annPatches := GenerateAnnotationPatches([]*response.EngineResponse{engineResponse}, log.Log)
expectedPatches1 := `{"path":"/metadata/annotations/policies.kyverno.io~1patches","op":"remove"}`
expectedPatches2 := `{"path":"/metadata/annotations/policies.kyverno.io~1last-applied-patches","op":"add","value":"default-imagepullpolicy.mutate-container.kyverno.io: replaced /spec/containers/0/imagePullPolicy\n"}`
assert.Equal(t, string(annPatches[0]), expectedPatches1)

View file

@ -108,7 +108,8 @@ func (m *certManager) GetTLSPemPair() (*ktls.PemPair, error) {
return nil
}
f := common.RetryFunc(time.Second, time.Minute, retryReadTLS, m.log.WithName("GetTLSPemPair/Retry"))
msg := "failed to read TLS pair"
f := common.RetryFunc(time.Second, time.Minute, retryReadTLS, msg, m.log.WithName("GetTLSPemPair/Retry"))
err = f()
return tls, err

View file

@ -434,7 +434,7 @@ func (m *webhookConfigManager) buildWebhooks(namespace string) (res []*webhook,
for _, p := range policies {
spec := p.GetSpec()
if spec.HasValidate() || spec.HasGenerate() {
if spec.HasValidate() || spec.HasGenerate() || spec.HasMutate() {
if spec.GetFailurePolicy() == kyverno.Ignore {
m.mergeWebhook(validateIgnore, p, true)
} else {
@ -525,7 +525,8 @@ func (m *webhookConfigManager) getWebhook(webhookKind, webhookName string) (reso
return err
}
retryGetWebhook := common.RetryFunc(time.Second, 10*time.Second, get, m.log)
msg := "getWebhook: unable to get webhook configuration"
retryGetWebhook := common.RetryFunc(time.Second, 10*time.Second, get, msg, m.log)
if err := retryGetWebhook(); err != nil {
return nil, err
}
@ -740,7 +741,8 @@ func (m *webhookConfigManager) mergeWebhook(dst *webhook, policy kyverno.PolicyI
}
if (updateValidate && rule.HasValidate()) ||
(!updateValidate && rule.HasMutate()) ||
(updateValidate && rule.HasMutate() && rule.IsMutateExisting()) ||
(!updateValidate && rule.HasMutate()) && !rule.IsMutateExisting() ||
(!updateValidate && rule.HasVerifyImages()) {
matchedGVK = append(matchedGVK, rule.MatchResources.GetKinds()...)
}
@ -809,9 +811,15 @@ func (m *webhookConfigManager) mergeWebhook(dst *webhook, policy kyverno.PolicyI
rsrcs = append(rsrcs, "pods/ephemeralcontainers")
}
dst.rule[apiGroups] = removeDuplicates(groups)
dst.rule[apiVersions] = removeDuplicates(versions)
dst.rule[resources] = removeDuplicates(rsrcs)
if len(groups) > 0 {
dst.rule[apiGroups] = removeDuplicates(groups)
}
if len(versions) > 0 {
dst.rule[apiVersions] = removeDuplicates(versions)
}
if len(rsrcs) > 0 {
dst.rule[resources] = removeDuplicates(rsrcs)
}
spec := policy.GetSpec()
if spec.WebhookTimeoutSeconds != nil {

View file

@ -6,6 +6,7 @@ import (
"github.com/go-logr/logr"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/autogen"
enginectx "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/response"
@ -157,7 +158,7 @@ func excludeKyvernoResources(kind string) bool {
}
}
func newVariablesContext(request *admissionv1.AdmissionRequest, userRequestInfo *kyverno.RequestInfo) (enginectx.Interface, error) {
func newVariablesContext(request *admissionv1.AdmissionRequest, userRequestInfo *urkyverno.RequestInfo) (enginectx.Interface, error) {
ctx := enginectx.NewContext()
if err := ctx.AddRequest(request); err != nil {
return nil, errors.Wrap(err, "failed to load incoming request in context")

View file

@ -10,7 +10,7 @@ import (
"github.com/gardener/controller-manager-library/pkg/logger"
"github.com/go-logr/logr"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/autogen"
gencommon "github.com/kyverno/kyverno/pkg/background/common"
gen "github.com/kyverno/kyverno/pkg/background/generate"
@ -18,38 +18,24 @@ import (
"github.com/kyverno/kyverno/pkg/config"
client "github.com/kyverno/kyverno/pkg/dclient"
"github.com/kyverno/kyverno/pkg/engine"
"github.com/kyverno/kyverno/pkg/engine/context"
enginectx "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/response"
enginutils "github.com/kyverno/kyverno/pkg/engine/utils"
"github.com/kyverno/kyverno/pkg/engine/variables"
"github.com/kyverno/kyverno/pkg/event"
kyvernoutils "github.com/kyverno/kyverno/pkg/utils"
jsonutils "github.com/kyverno/kyverno/pkg/utils/json"
"github.com/kyverno/kyverno/pkg/webhooks/generate"
"github.com/kyverno/kyverno/pkg/webhooks/updaterequest"
admissionv1 "k8s.io/api/admission/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/labels"
)
func (ws *WebhookServer) applyGeneratePolicies(request *admissionv1.AdmissionRequest, policyContext *engine.PolicyContext, policies []kyverno.PolicyInterface, ts int64, logger logr.Logger) {
admissionReviewCompletionLatencyChannel := make(chan int64, 1)
generateEngineResponsesSenderForAdmissionReviewDurationMetric := make(chan []*response.EngineResponse, 1)
generateEngineResponsesSenderForAdmissionRequestsCountMetric := make(chan []*response.EngineResponse, 1)
go ws.handleGenerate(request, policies, policyContext.JSONContext, policyContext.AdmissionInfo, ws.configHandler, ts, &admissionReviewCompletionLatencyChannel, &generateEngineResponsesSenderForAdmissionReviewDurationMetric, &generateEngineResponsesSenderForAdmissionRequestsCountMetric)
go ws.registerAdmissionReviewDurationMetricGenerate(logger, string(request.Operation), &admissionReviewCompletionLatencyChannel, &generateEngineResponsesSenderForAdmissionReviewDurationMetric)
go ws.registerAdmissionRequestsMetricGenerate(logger, string(request.Operation), &generateEngineResponsesSenderForAdmissionRequestsCountMetric)
}
//handleGenerate handles admission-requests for policies with generate rules
func (ws *WebhookServer) handleGenerate(
request *admissionv1.AdmissionRequest,
policies []kyverno.PolicyInterface,
ctx context.Interface,
userRequestInfo kyverno.RequestInfo,
dynamicConfig config.Interface,
policyContext *engine.PolicyContext,
admissionRequestTimestamp int64,
latencySender *chan int64,
generateEngineResponsesSenderForAdmissionReviewDurationMetric *chan []*response.EngineResponse,
@ -57,33 +43,17 @@ func (ws *WebhookServer) handleGenerate(
) {
logger := ws.log.WithValues("action", "generation", "uid", request.UID, "kind", request.Kind, "namespace", request.Namespace, "name", request.Name, "operation", request.Operation, "gvk", request.Kind.String())
logger.V(6).Info("generate request")
logger.V(6).Info("update request")
var engineResponses []*response.EngineResponse
if (request.Operation == admissionv1.Create || request.Operation == admissionv1.Update) && len(policies) != 0 {
// convert RAW to unstructured
new, old, err := kyvernoutils.ExtractResources(nil, request)
if err != nil {
logger.Error(err, "failed to extract resource")
}
policyContext := &engine.PolicyContext{
NewResource: new,
OldResource: old,
AdmissionInfo: userRequestInfo,
ExcludeGroupRole: dynamicConfig.GetExcludeGroupRole(),
ExcludeResourceFunc: ws.configHandler.ToFilter,
JSONContext: ctx,
Client: ws.client,
}
for _, policy := range policies {
var rules []response.RuleResponse
policyContext.Policy = policy
if request.Kind.Kind != "Namespace" && request.Namespace != "" {
policyContext.NamespaceLabels = common.GetNamespaceSelectorsFromNamespaceLister(request.Kind.Kind, request.Namespace, ws.nsLister, logger)
}
engineResponse := engine.Generate(policyContext)
engineResponse := engine.ApplyBackgroundChecks(policyContext)
for _, rule := range engineResponse.PolicyResponse.Rules {
if rule.Status != response.RuleStatusPass {
ws.deleteGR(logger, engineResponse)
@ -105,11 +75,10 @@ func (ws *WebhookServer) handleGenerate(
go ws.registerPolicyExecutionDurationMetricGenerate(logger, string(request.Operation), policy, *engineResponse)
}
// Adds Generate Request to a channel(queue size 1000) to generators
if failedResponse := applyGenerateRequest(request, ws.grGenerator, userRequestInfo, request.Operation, engineResponses...); err != nil {
if failedResponse := applyGenerateRequest(request, urkyverno.Generate, ws.grGenerator, policyContext.AdmissionInfo, request.Operation, engineResponses...); failedResponse != nil {
// report failure event
for _, failedGR := range failedResponse {
events := failedEvents(fmt.Errorf("failed to create Generate Request: %v", failedGR.err), failedGR.gr, new)
events := failedEvents(fmt.Errorf("failed to create Generate Request: %v", failedGR.err), failedGR.gr, policyContext.NewResource)
ws.eventGen.Add(events...)
}
}
@ -166,7 +135,7 @@ func (ws *WebhookServer) handleUpdateGenerateSourceResource(resLabels map[string
"generate.kyverno.io/policy-name": policyName,
}))
grList, err := ws.grLister.List(selector)
grList, err := ws.urLister.List(selector)
if err != nil {
logger.Error(err, "failed to get generate request for the resource", "label", "generate.kyverno.io/policy-name")
return
@ -182,7 +151,7 @@ func (ws *WebhookServer) handleUpdateGenerateSourceResource(resLabels map[string
// updateAnnotationInGR - function used to update GR annotation
// updating GR will trigger reprocessing of GR and recreation/updation of generated resource
func (ws *WebhookServer) updateAnnotationInGR(gr *kyverno.GenerateRequest, logger logr.Logger) {
func (ws *WebhookServer) updateAnnotationInGR(gr *urkyverno.UpdateRequest, logger logr.Logger) {
grAnnotations := gr.Annotations
if len(grAnnotations) == 0 {
grAnnotations = make(map[string]string)
@ -258,7 +227,7 @@ func (ws *WebhookServer) handleUpdateGenerateTargetResource(request *admissionv1
if enqueueBool {
grName := resLabels["policy.kyverno.io/gr-name"]
gr, err := ws.grLister.Get(grName)
gr, err := ws.urLister.Get(grName)
if err != nil {
logger.Error(err, "failed to get generate request", "name", grName)
return
@ -363,7 +332,7 @@ func stripNonPolicyFields(obj, newRes map[string]interface{}, logger logr.Logger
return obj, newRes
}
//HandleDelete handles admission-requests for delete
//HandleDelete handles DELETE admission-requests for generate policies
func (ws *WebhookServer) handleDelete(request *admissionv1.AdmissionRequest) {
logger := ws.log.WithValues("action", "generation", "uid", request.UID, "kind", request.Kind, "namespace", request.Namespace, "name", request.Name, "operation", request.Operation, "gvk", request.Kind.String())
resource, err := enginutils.ConvertToUnstructured(request.OldObject.Raw)
@ -374,11 +343,15 @@ func (ws *WebhookServer) handleDelete(request *admissionv1.AdmissionRequest) {
resLabels := resource.GetLabels()
if resLabels["app.kubernetes.io/managed-by"] == "kyverno" && request.Operation == admissionv1.Delete {
grName := resLabels["policy.kyverno.io/gr-name"]
gr, err := ws.grLister.Get(grName)
gr, err := ws.urLister.Get(grName)
if err != nil {
logger.Error(err, "failed to get generate request", "name", grName)
return
}
if gr.Spec.Type == urkyverno.Mutate {
return
}
ws.updateAnnotationInGR(gr, logger)
}
}
@ -406,20 +379,20 @@ func (ws *WebhookServer) deleteGR(logger logr.Logger, engineResponse *response.E
}
}
func applyGenerateRequest(request *admissionv1.AdmissionRequest, gnGenerator generate.GenerateRequests, userRequestInfo kyverno.RequestInfo,
func applyGenerateRequest(request *admissionv1.AdmissionRequest, ruleType urkyverno.RequestType, gnGenerator updaterequest.Interface, userRequestInfo urkyverno.RequestInfo,
action admissionv1.Operation, engineResponses ...*response.EngineResponse) (failedGenerateRequest []generateRequestResponse) {
requestBytes, err := json.Marshal(request)
if err != nil {
logger.Error(err, "error loading request into context")
}
admissionRequestInfo := kyverno.AdmissionRequestInfoObject{
admissionRequestInfo := urkyverno.AdmissionRequestInfoObject{
AdmissionRequest: string(requestBytes),
Operation: action,
}
for _, er := range engineResponses {
gr := transform(admissionRequestInfo, userRequestInfo, er)
gr := transform(admissionRequestInfo, userRequestInfo, er, ruleType)
if err := gnGenerator.Apply(gr, action); err != nil {
failedGenerateRequest = append(failedGenerateRequest, generateRequestResponse{gr: gr, err: err})
}
@ -428,15 +401,16 @@ func applyGenerateRequest(request *admissionv1.AdmissionRequest, gnGenerator gen
return
}
func transform(admissionRequestInfo kyverno.AdmissionRequestInfoObject, userRequestInfo kyverno.RequestInfo, er *response.EngineResponse) kyverno.GenerateRequestSpec {
func transform(admissionRequestInfo urkyverno.AdmissionRequestInfoObject, userRequestInfo urkyverno.RequestInfo, er *response.EngineResponse, ruleType urkyverno.RequestType) urkyverno.UpdateRequestSpec {
var PolicyNameNamespaceKey string
if er.PolicyResponse.Policy.Namespace != "" {
PolicyNameNamespaceKey = fmt.Sprintf("%s", er.PolicyResponse.Policy.Namespace+"/"+er.PolicyResponse.Policy.Name)
PolicyNameNamespaceKey = er.PolicyResponse.Policy.Namespace + "/" + er.PolicyResponse.Policy.Name
} else {
PolicyNameNamespaceKey = er.PolicyResponse.Policy.Name
}
gr := kyverno.GenerateRequestSpec{
gr := urkyverno.UpdateRequestSpec{
Type: ruleType,
Policy: PolicyNameNamespaceKey,
Resource: kyverno.ResourceSpec{
Kind: er.PolicyResponse.Resource.Kind,
@ -444,7 +418,7 @@ func transform(admissionRequestInfo kyverno.AdmissionRequestInfoObject, userRequ
Name: er.PolicyResponse.Resource.Name,
APIVersion: er.PolicyResponse.Resource.APIVersion,
},
Context: kyverno.GenerateRequestContext{
Context: urkyverno.UpdateRequestSpecContext{
UserRequestInfo: userRequestInfo,
AdmissionRequestInfo: admissionRequestInfo,
},
@ -454,7 +428,7 @@ func transform(admissionRequestInfo kyverno.AdmissionRequestInfoObject, userRequ
}
type generateRequestResponse struct {
gr kyverno.GenerateRequestSpec
gr urkyverno.UpdateRequestSpec
err error
}
@ -466,7 +440,7 @@ func (resp generateRequestResponse) error() string {
return resp.err.Error()
}
func failedEvents(err error, gr kyverno.GenerateRequestSpec, resource unstructured.Unstructured) []event.Info {
func failedEvents(err error, gr urkyverno.UpdateRequestSpec, resource unstructured.Unstructured) []event.Info {
re := event.Info{}
re.Kind = resource.GetKind()
re.Namespace = resource.GetNamespace()

View file

@ -9,6 +9,7 @@ import (
"github.com/go-logr/logr"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/common"
"github.com/kyverno/kyverno/pkg/engine"
enginectx "github.com/kyverno/kyverno/pkg/engine/context"
@ -56,27 +57,32 @@ func (ws *WebhookServer) admissionHandler(filter bool, inner handlers.AdmissionH
if filter {
inner = handlers.Filter(ws.configHandler, inner)
}
return handlers.Monitor(ws.webhookMonitor, handlers.Admission(ws.log, inner))
return handlers.Monitor(ws.webhookMonitor, handlers.Admission(ws.log.WithName("handlerFunc"), inner))
}
func (ws *WebhookServer) policyMutation(request *admissionv1.AdmissionRequest) *admissionv1.AdmissionResponse {
logger := setupLogger(ws.log, "policy mutation", request)
policy, oldPolicy, err := admissionutils.GetPolicies(request)
if err != nil {
logger.Error(err, "failed to unmarshal policies from admission request")
return admissionutils.ResponseWithMessage(true, fmt.Sprintf("failed to default value, check kyverno controller logs for details: %v", err))
}
if oldPolicy != nil && isStatusUpdate(oldPolicy, policy) {
logger.V(4).Info("skip policy mutation on status update")
return admissionutils.Response(true)
}
startTime := time.Now()
logger.V(3).Info("start policy change mutation")
defer logger.V(3).Info("finished policy change mutation", "time", time.Since(startTime).String())
// Generate JSON Patches for defaults
if patches, updateMsgs := policymutation.GenerateJSONPatchesForDefaults(policy, logger); len(patches) != 0 {
return admissionutils.ResponseWithMessageAndPatch(true, strings.Join(updateMsgs, "'"), patches)
}
return admissionutils.Response(true)
}
@ -88,21 +94,26 @@ func (ws *WebhookServer) policyValidation(request *admissionv1.AdmissionRequest)
logger.Error(err, "failed to unmarshal policies from admission request")
return admissionutils.ResponseWithMessage(true, fmt.Sprintf("failed to validate policy, check kyverno controller logs for details: %v", err))
}
if oldPolicy != nil && isStatusUpdate(oldPolicy, policy) {
logger.V(4).Info("skip policy validation on status update")
return admissionutils.Response(true)
}
startTime := time.Now()
logger.V(3).Info("start policy change validation")
defer logger.V(3).Info("finished policy change validation", "time", time.Since(startTime).String())
response, err := policyvalidate.Validate(policy, ws.client, false, ws.openAPIController)
if err != nil {
logger.Error(err, "policy validation errors")
return admissionutils.ResponseWithMessage(true, err.Error())
}
if response != nil && len(response.Warnings) != 0 {
return response
}
return admissionutils.Response(true)
}
@ -112,6 +123,7 @@ func (ws *WebhookServer) resourceMutation(request *admissionv1.AdmissionRequest)
if excludeKyvernoResources(request.Kind.Kind) {
return admissionutils.ResponseSuccess(true, "")
}
if request.Operation == admissionv1.Delete {
resource, err := utils.ConvertResource(request.OldObject.Raw, request.Kind.Group, request.Kind.Version, request.Kind.Kind, request.Namespace)
if err == nil {
@ -120,25 +132,32 @@ func (ws *WebhookServer) resourceMutation(request *admissionv1.AdmissionRequest)
logger.Info(fmt.Sprintf("Converting oldObject failed: %v", err))
}
return admissionutils.ResponseSuccess(true, "")
}
logger.V(4).Info("received an admission request in mutating webhook")
requestTime := time.Now().Unix()
mutatePolicies := ws.pCache.GetPolicies(policycache.Mutate, request.Kind.Kind, request.Namespace)
verifyImagesPolicies := ws.pCache.GetPolicies(policycache.VerifyImages, request.Kind.Kind, request.Namespace)
if len(mutatePolicies) == 0 && len(verifyImagesPolicies) == 0 {
logger.V(4).Info("no policies matched admission request")
return admissionutils.ResponseSuccess(true, "")
}
addRoles := containsRBACInfo(mutatePolicies)
policyContext, err := ws.buildPolicyContext(request, addRoles)
if err != nil {
logger.Error(err, "failed to build policy context")
return admissionutils.ResponseFailure(false, err.Error())
}
// update container images to a canonical form
if err := enginectx.MutateResourceWithImageInfo(request.Object.Raw, policyContext.JSONContext); err != nil {
ws.log.Error(err, "failed to patch images info to resource, policies that mutate images may be impacted")
}
mutatePatches := ws.applyMutatePolicies(request, policyContext, mutatePolicies, requestTime, logger)
newRequest := patchRequest(mutatePatches, request, logger)
imagePatches, err := ws.applyImageVerifyPolicies(newRequest, policyContext, verifyImagesPolicies, logger)
@ -146,7 +165,9 @@ func (ws *WebhookServer) resourceMutation(request *admissionv1.AdmissionRequest)
logger.Error(err, "image verification failed")
return admissionutils.ResponseFailure(false, err.Error())
}
var patches = append(mutatePatches, imagePatches...)
return admissionutils.ResponseSuccessWithPatch(true, "", patches)
}
@ -155,21 +176,23 @@ func (ws *WebhookServer) resourceValidation(request *admissionv1.AdmissionReques
if request.Operation == admissionv1.Delete {
ws.handleDelete(request)
}
if excludeKyvernoResources(request.Kind.Kind) {
return admissionutils.ResponseSuccess(true, "")
}
logger.V(6).Info("received an admission request in validating webhook")
// timestamp at which this admission request got triggered
requestTime := time.Now().Unix()
policies := ws.pCache.GetPolicies(policycache.ValidateEnforce, request.Kind.Kind, "")
// Get namespace policies from the cache for the requested resource namespace
nsPolicies := ws.pCache.GetPolicies(policycache.ValidateEnforce, request.Kind.Kind, request.Namespace)
policies = append(policies, nsPolicies...)
policies := ws.pCache.GetPolicies(policycache.ValidateEnforce, request.Kind.Kind, request.Namespace)
mutatePolicies := ws.pCache.GetPolicies(policycache.Mutate, request.Kind.Kind, request.Namespace)
generatePolicies := ws.pCache.GetPolicies(policycache.Generate, request.Kind.Kind, request.Namespace)
if len(generatePolicies) == 0 && request.Operation == admissionv1.Update {
// handle generate source resource updates
go ws.handleUpdatesForGenerateRules(request, []kyverno.PolicyInterface{})
}
var roles, clusterRoles []string
if containsRBACInfo(policies, generatePolicies) {
var err error
@ -178,26 +201,32 @@ func (ws *WebhookServer) resourceValidation(request *admissionv1.AdmissionReques
return errorResponse(logger, err, "failed to fetch RBAC data")
}
}
userRequestInfo := kyverno.RequestInfo{
userRequestInfo := urkyverno.RequestInfo{
Roles: roles,
ClusterRoles: clusterRoles,
AdmissionUserInfo: *request.UserInfo.DeepCopy(),
}
ctx, err := newVariablesContext(request, &userRequestInfo)
if err != nil {
return errorResponse(logger, err, "failed create policy rule context")
}
namespaceLabels := make(map[string]string)
if request.Kind.Kind != "Namespace" && request.Namespace != "" {
namespaceLabels = common.GetNamespaceSelectorsFromNamespaceLister(request.Kind.Kind, request.Namespace, ws.nsLister, logger)
}
newResource, oldResource, err := utils.ExtractResources(nil, request)
if err != nil {
return errorResponse(logger, err, "failed create parse resource")
}
if err := ctx.AddImageInfos(&newResource); err != nil {
return errorResponse(logger, err, "failed add image information to policy rule context")
}
policyContext := &engine.PolicyContext{
NewResource: newResource,
OldResource: oldResource,
@ -206,20 +235,25 @@ func (ws *WebhookServer) resourceValidation(request *admissionv1.AdmissionReques
ExcludeResourceFunc: ws.configHandler.ToFilter,
JSONContext: ctx,
Client: ws.client,
AdmissionOperation: true,
}
vh := &validationHandler{
log: ws.log,
eventGen: ws.eventGen,
prGenerator: ws.prGenerator,
}
ok, msg := vh.handleValidation(ws.promConfig, request, policies, policyContext, namespaceLabels, requestTime)
if !ok {
logger.Info("admission request denied")
return admissionutils.ResponseFailure(false, msg)
}
// push admission request to audit handler, this won't block the admission request
ws.auditHandler.Add(request.DeepCopy())
// process generate policies
ws.applyGeneratePolicies(request, policyContext, generatePolicies, requestTime, logger)
go ws.createUpdateRequests(request, policyContext, generatePolicies, mutatePolicies, requestTime, logger)
return admissionutils.ResponseSuccess(true, "")
}

View file

@ -43,7 +43,7 @@ func Admission(logger logr.Logger, inner AdmissionHandler) http.HandlerFunc {
http.Error(writer, "Can't decode body as AdmissionReview", http.StatusExpectationFailed)
return
}
logger = logger.WithName("handlerFunc").WithValues(
logger = logger.WithValues(
"kind", admissionReview.Request.Kind,
"namespace", admissionReview.Request.Namespace,
"name", admissionReview.Request.Name,
@ -67,7 +67,12 @@ func Admission(logger logr.Logger, inner AdmissionHandler) http.HandlerFunc {
if _, err := writer.Write(responseJSON); err != nil {
http.Error(writer, fmt.Sprintf("could not write response: %v", err), http.StatusInternalServerError)
}
logger.V(4).Info("admission review request processed", "time", time.Since(startTime).String())
if admissionReview.Request.Kind.Kind == "Lease" {
logger.V(6).Info("admission review request processed", "time", time.Since(startTime).String())
} else {
logger.V(4).Info("admission review request processed", "time", time.Since(startTime).String())
}
}
}
@ -82,7 +87,7 @@ func Filter(c config.Interface, inner AdmissionHandler) AdmissionHandler {
func Verify(m *webhookconfig.Monitor, logger logr.Logger) AdmissionHandler {
return func(request *admissionv1.AdmissionRequest) *admissionv1.AdmissionResponse {
logger = logger.WithName("verifyHandler").WithValues(
logger = logger.WithValues(
"action", "verify",
"kind", request.Kind,
"namespace", request.Namespace,
@ -90,7 +95,7 @@ func Verify(m *webhookconfig.Monitor, logger logr.Logger) AdmissionHandler {
"operation", request.Operation,
"gvk", request.Kind.String(),
)
logger.V(3).Info("incoming request", "last admission request timestamp", m.Time())
logger.V(6).Info("incoming request", "last admission request timestamp", m.Time())
return admissionutils.Response(true)
}
}

View file

@ -103,7 +103,7 @@ func (ws *WebhookServer) handleMutation(
}
// generate annotations
if annPatches := generateAnnotationPatches(engineResponses, logger); annPatches != nil {
if annPatches := utils.GenerateAnnotationPatches(engineResponses, logger); annPatches != nil {
patches = append(patches, annPatches...)
}

View file

@ -9,11 +9,13 @@ import (
"github.com/go-logr/logr"
"github.com/julienschmidt/httprouter"
v1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/background"
kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
kyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1"
urinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1beta1"
kyvernolister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1"
urlister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/config"
client "github.com/kyverno/kyverno/pkg/dclient"
"github.com/kyverno/kyverno/pkg/engine"
@ -26,8 +28,8 @@ import (
"github.com/kyverno/kyverno/pkg/userinfo"
"github.com/kyverno/kyverno/pkg/utils"
"github.com/kyverno/kyverno/pkg/webhookconfig"
webhookgenerate "github.com/kyverno/kyverno/pkg/webhooks/generate"
"github.com/kyverno/kyverno/pkg/webhooks/handlers"
webhookgenerate "github.com/kyverno/kyverno/pkg/webhooks/updaterequest"
"github.com/pkg/errors"
admissionv1 "k8s.io/api/admission/v1"
informers "k8s.io/client-go/informers/core/v1"
@ -49,6 +51,12 @@ type WebhookServer struct {
// grSynced returns true if the Generate Request store has been synced at least once
grSynced cache.InformerSynced
// urLister can list/get update requests from the shared informer's store
urLister urlister.UpdateRequestNamespaceLister
// urSynced returns true if the Update Request store has been synced at least once
urSynced cache.InformerSynced
// list/get cluster policy resource
pLister kyvernolister.ClusterPolicyLister
@ -101,7 +109,7 @@ type WebhookServer struct {
prGenerator policyreport.GeneratorInterface
// generate request generator
grGenerator *webhookgenerate.Generator
grGenerator webhookgenerate.Interface
nsLister listerv1.NamespaceLister
@ -128,6 +136,7 @@ func NewWebhookServer(
client *client.Client,
tlsPair *tlsutils.PemPair,
grInformer kyvernoinformer.GenerateRequestInformer,
urInformer urinformer.UpdateRequestInformer,
pInformer kyvernoinformer.ClusterPolicyInformer,
rbInformer rbacinformer.RoleBindingInformer,
crbInformer rbacinformer.ClusterRoleBindingInformer,
@ -140,7 +149,7 @@ func NewWebhookServer(
webhookMonitor *webhookconfig.Monitor,
configHandler config.Interface,
prGenerator policyreport.GeneratorInterface,
grGenerator *webhookgenerate.Generator,
grGenerator webhookgenerate.Interface,
auditHandler AuditHandler,
cleanUp chan<- struct{},
log logr.Logger,
@ -160,6 +169,8 @@ func NewWebhookServer(
kyvernoClient: kyvernoClient,
grLister: grInformer.Lister().GenerateRequests(config.KyvernoNamespace),
grSynced: grInformer.Informer().HasSynced,
urLister: urInformer.Lister().UpdateRequests(config.KyvernoNamespace),
urSynced: urInformer.Informer().HasSynced,
pLister: pInformer.Lister(),
pSynced: pInformer.Informer().HasSynced,
rbLister: rbInformer.Lister(),
@ -191,7 +202,7 @@ func NewWebhookServer(
mux.HandlerFunc("POST", config.ValidatingWebhookServicePath, ws.admissionHandler(true, ws.resourceValidation))
mux.HandlerFunc("POST", config.PolicyMutatingWebhookServicePath, ws.admissionHandler(true, ws.policyMutation))
mux.HandlerFunc("POST", config.PolicyValidatingWebhookServicePath, ws.admissionHandler(true, ws.policyValidation))
mux.HandlerFunc("POST", config.VerifyMutatingWebhookServicePath, ws.admissionHandler(false, handlers.Verify(ws.webhookMonitor, ws.log)))
mux.HandlerFunc("POST", config.VerifyMutatingWebhookServicePath, ws.admissionHandler(false, handlers.Verify(ws.webhookMonitor, ws.log.WithName("verifyHandler"))))
mux.HandlerFunc("GET", config.LivenessServicePath, handlers.Probe(ws.webhookRegister.Check))
mux.HandlerFunc("GET", config.ReadinessServicePath, handlers.Probe(nil))
ws.server = &http.Server{
@ -205,7 +216,7 @@ func NewWebhookServer(
}
func (ws *WebhookServer) buildPolicyContext(request *admissionv1.AdmissionRequest, addRoles bool) (*engine.PolicyContext, error) {
userRequestInfo := v1.RequestInfo{
userRequestInfo := v1beta1.RequestInfo{
AdmissionUserInfo: *request.UserInfo.DeepCopy(),
}
@ -246,6 +257,7 @@ func (ws *WebhookServer) buildPolicyContext(request *admissionv1.AdmissionReques
ExcludeResourceFunc: ws.configHandler.ToFilter,
JSONContext: ctx,
Client: ws.client,
AdmissionOperation: true,
}
if request.Operation == admissionv1.Update {
@ -257,7 +269,7 @@ func (ws *WebhookServer) buildPolicyContext(request *admissionv1.AdmissionReques
// RunAsync TLS server in separate thread and returns control immediately
func (ws *WebhookServer) RunAsync(stopCh <-chan struct{}) {
if !cache.WaitForCacheSync(stopCh, ws.grSynced, ws.pSynced, ws.rbSynced, ws.crbSynced, ws.rSynced, ws.crSynced) {
if !cache.WaitForCacheSync(stopCh, ws.grSynced, ws.urSynced, ws.pSynced, ws.rbSynced, ws.crbSynced, ws.rSynced, ws.crSynced) {
ws.log.Info("failed to sync informer cache")
}
go func() {

View file

@ -0,0 +1,71 @@
package webhooks
import (
"fmt"
"time"
"github.com/go-logr/logr"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/engine"
"github.com/kyverno/kyverno/pkg/engine/response"
admissionv1 "k8s.io/api/admission/v1"
)
// createUpdateRequests applies generate and mutateExisting policies, and creates update requests for background reconcile
func (ws *WebhookServer) createUpdateRequests(request *admissionv1.AdmissionRequest, policyContext *engine.PolicyContext, generatePolicies, mutatePolicies []kyverno.PolicyInterface, ts int64, logger logr.Logger) {
admissionReviewCompletionLatencyChannel := make(chan int64, 1)
generateEngineResponsesSenderForAdmissionReviewDurationMetric := make(chan []*response.EngineResponse, 1)
generateEngineResponsesSenderForAdmissionRequestsCountMetric := make(chan []*response.EngineResponse, 1)
go ws.handleMutateExisting(request, mutatePolicies, policyContext, ts)
go ws.handleGenerate(request, generatePolicies, policyContext, ts, &admissionReviewCompletionLatencyChannel, &generateEngineResponsesSenderForAdmissionReviewDurationMetric, &generateEngineResponsesSenderForAdmissionRequestsCountMetric)
go ws.registerAdmissionReviewDurationMetricGenerate(logger, string(request.Operation), &admissionReviewCompletionLatencyChannel, &generateEngineResponsesSenderForAdmissionReviewDurationMetric)
go ws.registerAdmissionRequestsMetricGenerate(logger, string(request.Operation), &generateEngineResponsesSenderForAdmissionRequestsCountMetric)
}
func (ws *WebhookServer) handleMutateExisting(request *admissionv1.AdmissionRequest, policies []kyverno.PolicyInterface, policyContext *engine.PolicyContext, admissionRequestTimestamp int64) {
logger := ws.log.WithValues("action", "mutateExisting", "uid", request.UID, "kind", request.Kind, "namespace", request.Namespace, "name", request.Name, "operation", request.Operation, "gvk", request.Kind.String())
logger.V(4).Info("update request")
if request.Operation == admissionv1.Delete {
policyContext.NewResource = policyContext.OldResource
}
var engineResponses []*response.EngineResponse
for _, policy := range policies {
var rules []response.RuleResponse
policyContext.Policy = policy
engineResponse := engine.ApplyBackgroundChecks(policyContext)
for _, rule := range engineResponse.PolicyResponse.Rules {
if rule.Status == response.RuleStatusPass {
rules = append(rules, rule)
}
}
if len(rules) > 0 {
engineResponse.PolicyResponse.Rules = rules
engineResponses = append(engineResponses, engineResponse)
}
// registering the kyverno_policy_results_total metric concurrently
go ws.registerPolicyResultsMetricMutation(logger, string(request.Operation), policy, *engineResponse)
// registering the kyverno_policy_execution_duration_seconds metric concurrently
go ws.registerPolicyExecutionDurationMetricMutate(logger, string(request.Operation), policy, *engineResponse)
}
if failedResponse := applyGenerateRequest(request, urkyverno.Mutate, ws.grGenerator, policyContext.AdmissionInfo, request.Operation, engineResponses...); failedResponse != nil {
for _, failedGR := range failedResponse {
events := failedEvents(fmt.Errorf("failed to create update request: %v", failedGR.err), failedGR.gr, policyContext.NewResource)
ws.eventGen.Add(events...)
}
}
admissionReviewLatencyDuration := int64(time.Since(time.Unix(admissionRequestTimestamp, 0)))
go ws.registerAdmissionReviewDurationMetricMutate(logger, string(request.Operation), engineResponses, admissionReviewLatencyDuration)
go ws.registerAdmissionRequestsMetricMutate(logger, string(request.Operation), engineResponses)
}

View file

@ -0,0 +1,224 @@
package updaterequest
import (
"context"
"time"
backoff "github.com/cenkalti/backoff"
"github.com/gardener/controller-manager-library/pkg/logger"
"github.com/go-logr/logr"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
kyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1"
urkyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1beta1"
kyvernolister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1"
urkyvernolister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/config"
admissionv1 "k8s.io/api/admission/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/tools/cache"
)
// GenerateRequests provides interface to manage update requests
type Interface interface {
Apply(gr urkyverno.UpdateRequestSpec, action admissionv1.Operation) error
}
// info object stores message data to create update request
type info struct {
spec urkyverno.UpdateRequestSpec
action admissionv1.Operation
}
// Generator defines the implementation to mange update request resource
type Generator struct {
client *kyvernoclient.Clientset
stopCh <-chan struct{}
log logr.Logger
// grLister can list/get generate request from the shared informer's store
grLister kyvernolister.GenerateRequestNamespaceLister
grSynced cache.InformerSynced
urLister urkyvernolister.UpdateRequestNamespaceLister
urSynced cache.InformerSynced
}
// NewGenerator returns a new instance of UpdateRequest resource generator
func NewGenerator(client *kyvernoclient.Clientset, grInformer kyvernoinformer.GenerateRequestInformer, urInformer urkyvernoinformer.UpdateRequestInformer, stopCh <-chan struct{}, log logr.Logger) *Generator {
gen := &Generator{
client: client,
stopCh: stopCh,
log: log,
grLister: grInformer.Lister().GenerateRequests(config.KyvernoNamespace),
grSynced: grInformer.Informer().HasSynced,
urLister: urInformer.Lister().UpdateRequests(config.KyvernoNamespace),
urSynced: urInformer.Informer().HasSynced,
}
return gen
}
// Apply creates update request resource
func (g *Generator) Apply(gr urkyverno.UpdateRequestSpec, action admissionv1.Operation) error {
logger := g.log
logger.V(4).Info("reconcile Update Request", "request", gr)
message := info{
action: action,
spec: gr,
}
go g.processApply(message)
return nil
}
// Run starts the update request spec
func (g *Generator) Run(workers int, stopCh <-chan struct{}) {
logger := g.log
defer utilruntime.HandleCrash()
logger.V(4).Info("starting")
defer func() {
logger.V(4).Info("shutting down")
}()
if !cache.WaitForCacheSync(stopCh, g.grSynced, g.urSynced) {
logger.Info("failed to sync informer cache")
return
}
<-g.stopCh
}
func (g *Generator) processApply(i info) {
if err := g.generate(i); err != nil {
logger.Error(err, "failed to update request CR")
}
}
func (g *Generator) generate(i info) error {
if err := retryApplyResource(g.client, i.spec, g.log, i.action, g.urLister); err != nil {
return err
}
return nil
}
func retryApplyResource(client *kyvernoclient.Clientset, urSpec urkyverno.UpdateRequestSpec,
log logr.Logger, action admissionv1.Operation, urLister urkyvernolister.UpdateRequestNamespaceLister) error {
if action == admissionv1.Delete && urSpec.Type == urkyverno.Generate {
return nil
}
var i int
var err error
_, policyName, err := cache.SplitMetaNamespaceKey(urSpec.Policy)
if err != nil {
return err
}
applyResource := func() error {
ur := urkyverno.UpdateRequest{
Spec: urSpec,
Status: urkyverno.UpdateRequestStatus{
State: urkyverno.Pending,
},
}
queryLabels := make(map[string]string)
if ur.Spec.Type == urkyverno.Mutate {
queryLabels := map[string]string{
"mutate.updaterequest.kyverno.io/policy-name": ur.Spec.Policy,
"mutate.updaterequest.kyverno.io/trigger-name": ur.Spec.Resource.Name,
"mutate.updaterequest.kyverno.io/trigger-namespace": ur.Spec.Resource.Namespace,
"mutate.updaterequest.kyverno.io/trigger-kind": ur.Spec.Resource.Kind,
}
if ur.Spec.Resource.APIVersion != "" {
queryLabels["mutate.updaterequest.kyverno.io/trigger-apiversion"] = ur.Spec.Resource.APIVersion
}
} else if ur.Spec.Type == urkyverno.Generate {
queryLabels = labels.Set(map[string]string{
"generate.kyverno.io/policy-name": policyName,
"generate.kyverno.io/resource-name": urSpec.Resource.Name,
"generate.kyverno.io/resource-kind": urSpec.Resource.Kind,
"generate.kyverno.io/resource-namespace": urSpec.Resource.Namespace,
})
}
ur.SetNamespace(config.KyvernoNamespace)
isExist := false
log.V(4).Info("apply UpdateRequest", "ruleType", ur.Spec.Type)
urList, err := urLister.List(labels.SelectorFromSet(queryLabels))
if err != nil {
logger.Error(err, "failed to get update request for the resource", "kind", urSpec.Resource.Kind, "name", urSpec.Resource.Name, "namespace", urSpec.Resource.Namespace)
return err
}
for _, v := range urList {
log.V(4).Info("updating existing update request", "name", v.GetName())
v.Spec.Context = ur.Spec.Context
v.Spec.Policy = ur.Spec.Policy
v.Spec.Resource = ur.Spec.Resource
v.Status.Message = ""
new, err := client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).Update(context.TODO(), v, metav1.UpdateOptions{})
if err != nil {
log.V(4).Info("failed to update UpdateRequest, retrying", "retryCount", i, "name", ur.GetName(), "namespace", ur.GetNamespace())
i++
} else {
log.V(4).Info("successfully updated UpdateRequest", "retryCount", i, "name", ur.GetName(), "namespace", ur.GetNamespace())
}
new.Status.State = urkyverno.Pending
if _, err := client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).UpdateStatus(context.TODO(), new, metav1.UpdateOptions{}); err != nil {
log.Error(err, "failed to set UpdateRequest state to Pending")
}
isExist = true
}
if !isExist {
log.V(4).Info("creating new UpdateRequest", "type", ur.Spec.Type)
ur.SetGenerateName("ur-")
ur.SetLabels(queryLabels)
new, err := client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).Create(context.TODO(), &ur, metav1.CreateOptions{})
if err != nil {
log.V(4).Info("failed to create UpdateRequest, retrying", "retryCount", i, "name", ur.GetGenerateName(), "namespace", ur.GetNamespace())
i++
} else {
log.V(4).Info("successfully created UpdateRequest", "retryCount", i, "name", new.GetName(), "namespace", ur.GetNamespace())
}
new.Status.State = urkyverno.Pending
if _, err := client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).UpdateStatus(context.TODO(), new, metav1.UpdateOptions{}); err != nil {
log.Error(err, "failed to set UpdateRequest state to Pending")
}
}
return err
}
exbackoff := &backoff.ExponentialBackOff{
InitialInterval: 500 * time.Millisecond,
RandomizationFactor: 0.5,
Multiplier: 1.5,
MaxInterval: time.Second,
MaxElapsedTime: 3 * time.Second,
Clock: backoff.SystemClock,
}
exbackoff.Reset()
err = backoff.Retry(applyResource, exbackoff)
if err != nil {
return err
}
return nil
}

View file

@ -4,22 +4,19 @@ import (
"strings"
"time"
v1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/engine"
"github.com/kyverno/kyverno/pkg/utils"
"github.com/pkg/errors"
"github.com/kyverno/kyverno/pkg/common"
client "github.com/kyverno/kyverno/pkg/dclient"
"github.com/go-logr/logr"
"github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/common"
"github.com/kyverno/kyverno/pkg/config"
client "github.com/kyverno/kyverno/pkg/dclient"
"github.com/kyverno/kyverno/pkg/engine"
"github.com/kyverno/kyverno/pkg/event"
"github.com/kyverno/kyverno/pkg/metrics"
"github.com/kyverno/kyverno/pkg/policycache"
"github.com/kyverno/kyverno/pkg/policyreport"
"github.com/kyverno/kyverno/pkg/userinfo"
"github.com/kyverno/kyverno/pkg/utils"
"github.com/pkg/errors"
admissionv1 "k8s.io/api/admission/v1"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
@ -161,7 +158,7 @@ func (h *auditHandler) process(request *admissionv1.AdmissionRequest) error {
}
}
userRequestInfo := v1.RequestInfo{
userRequestInfo := v1beta1.RequestInfo{
Roles: roles,
ClusterRoles: clusterRoles,
AdmissionUserInfo: request.UserInfo}
@ -193,6 +190,7 @@ func (h *auditHandler) process(request *admissionv1.AdmissionRequest) error {
ExcludeResourceFunc: h.configHandler.ToFilter,
JSONContext: ctx,
Client: h.client,
AdmissionOperation: true,
}
vh := &validationHandler{