From 20069c13c343104469fcbfd922ade6d80c489ef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Charles-Edouard=20Br=C3=A9t=C3=A9ch=C3=A9?= Date: Mon, 28 Mar 2022 16:01:27 +0200 Subject: [PATCH] feat: stop mutating rules (#3410) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: stop adding autogen annotation Signed-off-by: Charles-Edouard Brétéché * feat: stop mutating rules Signed-off-by: Charles-Edouard Brétéché * feat: stop mutating rules Signed-off-by: Charles-Edouard Brétéché * fix: use toggle Signed-off-by: Charles-Edouard Brétéché * fix: review comments Signed-off-by: Charles-Edouard Brétéché Co-authored-by: shuting --- .github/workflows/e2e.yaml | 4 +- .github/workflows/tests.yaml | 5 + Makefile | 14 +-- api/kyverno/v1/clusterpolicy_types.go | 15 +-- api/kyverno/v1/policy_types.go | 15 +-- api/kyverno/v1/rule_test.go | 4 +- api/kyverno/v1/spec_types.go | 5 - charts/kyverno/README.md | 2 +- charts/kyverno/values.yaml | 4 +- cmd/kyverno/main.go | 2 +- config/install.yaml | 1 + config/manifest/deployment.yaml | 1 + pkg/autogen/autogen.go | 105 ++++++++++++++++++ pkg/autogen/autogen_test.go | 14 +-- pkg/autogen/rule.go | 6 +- pkg/compatibility/add_labels.go | 3 +- pkg/engine/forceMutate.go | 3 +- pkg/engine/generation.go | 3 +- pkg/engine/imageVerify.go | 3 +- .../mutate/patch/strategicMergePatch_test.go | 3 +- pkg/engine/mutation.go | 3 +- pkg/engine/utils_test.go | 3 +- pkg/engine/validation.go | 3 +- pkg/generate/cleanup/controller.go | 3 +- pkg/generate/generate.go | 3 +- pkg/generate/generate_controller.go | 3 +- pkg/kyverno/apply/apply_command.go | 3 - pkg/kyverno/apply/apply_command_test.go | 11 +- pkg/kyverno/common/common.go | 26 ++--- pkg/kyverno/common/common_test.go | 20 ++-- pkg/kyverno/common/fetch.go | 5 +- pkg/kyverno/test/test_command.go | 3 +- pkg/kyverno/validate/command.go | 4 +- pkg/metrics/policyruleinfo/policyRuleInfo.go | 9 +- pkg/openapi/validation.go | 3 +- pkg/policy/background.go | 3 +- pkg/policy/existing.go | 3 +- pkg/policy/policy_controller.go | 19 ++-- pkg/policy/validate.go | 6 +- pkg/policycache/cache.go | 5 +- pkg/policycache/cache_test.go | 21 ++-- pkg/policymutation/policymutation.go | 38 ++++--- pkg/toggle/toggle.go | 44 +++++++- pkg/utils/json.go | 47 -------- pkg/webhookconfig/configmanager.go | 15 +-- pkg/webhooks/common.go | 3 +- pkg/webhooks/generation.go | 3 +- pkg/webhooks/policymutation.go | 3 +- pkg/webhooks/policymutation_test.go | 14 +-- 49 files changed, 324 insertions(+), 214 deletions(-) diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index d395e525dc..2002fcbd6c 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -62,7 +62,9 @@ jobs: - name: e2e testing run: | echo ">>> Install Kyverno" - sed 's/imagePullPolicy:.*$/imagePullPolicy: IfNotPresent/g' ${GITHUB_WORKSPACE}/config/install.yaml | kubectl apply -f - + cat ${GITHUB_WORKSPACE}/config/install.yaml | \ + sed -e 's/imagePullPolicy:.*$/imagePullPolicy: IfNotPresent/g' | \ + kubectl apply -f - kubectl apply -f ${GITHUB_WORKSPACE}/config/github/rbac.yaml chmod a+x ${GITHUB_WORKSPACE}/scripts/verify-deployment.sh sleep 50 diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 9f7c10c729..0cd3775b31 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -68,6 +68,10 @@ jobs: run: make verify-codegen tests: + strategy: + fail-fast: false + matrix: + autogen-internals: [true, false] runs-on: ubuntu-latest needs: pre-checks steps: @@ -93,4 +97,5 @@ jobs: - name: Kyverno unit test run: | export PROJECT_PATH=$(pwd) + export FLAG_AUTOGEN_INTERNALS=${{ matrix.autogen-internals }} make test-unit diff --git a/Makefile b/Makefile index c768ad7f4c..aa63af2460 100644 --- a/Makefile +++ b/Makefile @@ -294,10 +294,8 @@ test-unit: $(GO_ACC) @echo " running unit tests" go-acc ./... -o $(CODE_COVERAGE_FILE_TXT) -code-cov-report: -# generate code coverage report +code-cov-report: ## Generate code coverage report @echo " generating code coverage report" - GO111MODULE=on go test -v -coverprofile=coverage.out ./... go tool cover -func=coverage.out -o $(CODE_COVERAGE_FILE_TXT) go tool cover -html=coverage.out -o $(CODE_COVERAGE_FILE_HTML) @@ -359,16 +357,15 @@ release-notes: ################################## .PHONY: kyverno-crd -kyverno-crd: controller-gen +kyverno-crd: controller-gen ## Generate Kyverno CRDs $(CONTROLLER_GEN) crd paths=./api/kyverno/... crd:crdVersions=v1 output:dir=./config/crds .PHONY: report-crd -report-crd: controller-gen +report-crd: controller-gen ## Generate policy reports CRDs $(CONTROLLER_GEN) crd paths=./api/policyreport/... crd:crdVersions=v1 output:dir=./config/crds -# install the right version of controller-gen .PHONY: install-controller-gen -install-controller-gen: +install-controller-gen: ## Install controller-gen @{ \ set -e ;\ CONTROLLER_GEN_TMP_DIR=$$(mktemp -d) ;\ @@ -379,9 +376,8 @@ install-controller-gen: } CONTROLLER_GEN=$(GOPATH)/bin/controller-gen -# setup controller-gen with the right version, if necessary .PHONY: controller-gen -controller-gen: +controller-gen: ## Setup controller-gen ifeq (, $(shell which controller-gen)) @{ \ echo "controller-gen not found!";\ diff --git a/api/kyverno/v1/clusterpolicy_types.go b/api/kyverno/v1/clusterpolicy_types.go index f42cb0a8e7..2bed6ed1f4 100644 --- a/api/kyverno/v1/clusterpolicy_types.go +++ b/api/kyverno/v1/clusterpolicy_types.go @@ -31,16 +31,6 @@ type ClusterPolicy struct { Status PolicyStatus `json:"status,omitempty" yaml:"status,omitempty"` } -// GetSpec returns the policy spec -func (p *ClusterPolicy) GetSpec() Spec { - return p.Spec -} - -// GetRules returns the policy rules -func (p *ClusterPolicy) GetRules() []Rule { - return p.Spec.GetRules() -} - // HasAutoGenAnnotation checks if a policy has auto-gen annotation func (p *ClusterPolicy) HasAutoGenAnnotation() bool { annotations := p.GetAnnotations() @@ -86,6 +76,11 @@ func (p *ClusterPolicy) BackgroundProcessingEnabled() bool { return p.Spec.BackgroundProcessingEnabled() } +// GetSpec returns the policy spec +func (p *ClusterPolicy) GetSpec() Spec { + return p.Spec +} + // IsNamespaced indicates if the policy is namespace scoped func (p *ClusterPolicy) IsNamespaced() bool { return p.GetNamespace() != "" diff --git a/api/kyverno/v1/policy_types.go b/api/kyverno/v1/policy_types.go index 2439241a51..eda4cbb91d 100755 --- a/api/kyverno/v1/policy_types.go +++ b/api/kyverno/v1/policy_types.go @@ -32,16 +32,6 @@ type Policy struct { Status PolicyStatus `json:"status,omitempty" yaml:"status,omitempty"` } -// GetSpec returns the policy spec -func (p *Policy) GetSpec() Spec { - return p.Spec -} - -// GetRules returns the policy rules -func (p *Policy) GetRules() []Rule { - return p.Spec.GetRules() -} - // HasAutoGenAnnotation checks if a policy has auto-gen annotation func (p *Policy) HasAutoGenAnnotation() bool { annotations := p.GetAnnotations() @@ -87,6 +77,11 @@ func (p *Policy) BackgroundProcessingEnabled() bool { return p.Spec.BackgroundProcessingEnabled() } +// GetSpec returns the policy spec +func (p *Policy) GetSpec() Spec { + return p.Spec +} + // IsNamespaced indicates if the policy is namespace scoped func (p *Policy) IsNamespaced() bool { return false diff --git a/api/kyverno/v1/rule_test.go b/api/kyverno/v1/rule_test.go index a52fc2b4a3..541e0191c7 100644 --- a/api/kyverno/v1/rule_test.go +++ b/api/kyverno/v1/rule_test.go @@ -88,7 +88,7 @@ func Test_Validate_RuleType_MultipleRule(t *testing.T) { var policy *ClusterPolicy err := json.Unmarshal(rawPolicy, &policy) assert.NilError(t, err) - for _, rule := range policy.GetRules() { + for _, rule := range policy.Spec.Rules { path := field.NewPath("dummy") errs := rule.Validate(path, false, nil) assert.Assert(t, len(errs) != 0) @@ -143,7 +143,7 @@ func Test_Validate_RuleType_SingleRule(t *testing.T) { var policy *ClusterPolicy err := json.Unmarshal(rawPolicy, &policy) assert.NilError(t, err) - for _, rule := range policy.GetRules() { + for _, rule := range policy.Spec.Rules { path := field.NewPath("dummy") errs := rule.Validate(path, false, nil) assert.Assert(t, len(errs) == 0) diff --git a/api/kyverno/v1/spec_types.go b/api/kyverno/v1/spec_types.go index 6ba5528116..a7d73ee9a6 100644 --- a/api/kyverno/v1/spec_types.go +++ b/api/kyverno/v1/spec_types.go @@ -65,11 +65,6 @@ type Spec struct { WebhookTimeoutSeconds *int32 `json:"webhookTimeoutSeconds,omitempty" yaml:"webhookTimeoutSeconds,omitempty"` } -// GetRules returns the spec rules -func (s *Spec) GetRules() []Rule { - return s.Rules -} - func (s *Spec) SetRules(rules []Rule) { s.Rules = rules } diff --git a/charts/kyverno/README.md b/charts/kyverno/README.md index 705d6f63d8..87379d2eb7 100644 --- a/charts/kyverno/README.md +++ b/charts/kyverno/README.md @@ -97,7 +97,7 @@ The command removes all the Kubernetes components associated with the chart and | dnsPolicy | string | `"ClusterFirst"` | `dnsPolicy` determines the manner in which DNS resolution happens in the cluster. In case of `hostNetwork: true`, usually, the `dnsPolicy` is suitable to be `ClusterFirstWithHostNet`. For further reference: https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-s-dns-policy. | | envVarsInit | object | `{}` | Env variables for initContainers. | | envVars | object | `{}` | Env variables for containers. | -| extraArgs | list | `[]` | Extra arguments to give to the binary. | +| extraArgs | list | `["--autogenInternals=false"]` | Extra arguments to give to the binary. | | resources.limits | object | `{"memory":"384Mi"}` | Pod resource limits | | resources.requests | object | `{"cpu":"100m","memory":"128Mi"}` | Pod resource requests | | initResources.limits | object | `{"cpu":"100m","memory":"256Mi"}` | Pod resource limits | diff --git a/charts/kyverno/values.yaml b/charts/kyverno/values.yaml index b587f7eb84..aa99a2c9a5 100644 --- a/charts/kyverno/values.yaml +++ b/charts/kyverno/values.yaml @@ -143,8 +143,8 @@ envVarsInit: {} envVars: {} # -- Extra arguments to give to the binary. -extraArgs: [] -# - --webhookTimeout=4 +extraArgs: + - --autogenInternals=false resources: # -- Pod resource limits diff --git a/cmd/kyverno/main.go b/cmd/kyverno/main.go index 2990f9c033..bb494e8c10 100755 --- a/cmd/kyverno/main.go +++ b/cmd/kyverno/main.go @@ -103,7 +103,7 @@ func main() { flag.BoolVar(&autoUpdateWebhooks, "autoUpdateWebhooks", true, "Set this flag to 'false' to disable auto-configuration of the webhook.") flag.Float64Var(&clientRateLimitQPS, "clientRateLimitQPS", 0, "Configure the maximum QPS to the master from Kyverno. Uses the client default if zero.") flag.IntVar(&clientRateLimitBurst, "clientRateLimitBurst", 0, "Configure the maximum burst for throttle. Uses the client default if zero.") - flag.BoolVar(&toggle.AutogenInternals, "autogenInternals", toggle.DefaultAutogenInternals, "Enables autogen internal policies. When this is 'true' policy rules should not be mutated.") + flag.Func(toggle.AutogenInternalsFlagName, toggle.AutogenInternalsDescription, toggle.AutogenInternalsFlag) flag.DurationVar(&webhookRegistrationTimeout, "webhookRegistrationTimeout", 120*time.Second, "Timeout for webhook registration, e.g., 30s, 1m, 5m.") if err := flag.Set("v", "2"); err != nil { diff --git a/config/install.yaml b/config/install.yaml index f8b76dcad5..84a4259674 100644 --- a/config/install.yaml +++ b/config/install.yaml @@ -10971,6 +10971,7 @@ spec: - args: - --filterK8sResources=[Event,*,*][*,kube-system,*][*,kube-public,*][*,kube-node-lease,*][Node,*,*][APIService,*,*][TokenReview,*,*][SubjectAccessReview,*,*][*,kyverno,kyverno*][Binding,*,*][ReplicaSet,*,*][ReportChangeRequest,*,*][ClusterReportChangeRequest,*,*][PolicyReport,*,*][ClusterPolicyReport,*,*] - -v=2 + - --autogenInternals=false env: - name: INIT_CONFIG value: kyverno diff --git a/config/manifest/deployment.yaml b/config/manifest/deployment.yaml index dc213f2090..03a74d2b99 100755 --- a/config/manifest/deployment.yaml +++ b/config/manifest/deployment.yaml @@ -78,6 +78,7 @@ spec: # configure the workers for generate controller # - --genWorkers=20 - "-v=2" + - --autogenInternals=false ports: - containerPort: 9443 name: https diff --git a/pkg/autogen/autogen.go b/pkg/autogen/autogen.go index ae0d1d1b5c..a577765edc 100644 --- a/pkg/autogen/autogen.go +++ b/pkg/autogen/autogen.go @@ -9,8 +9,10 @@ import ( jsonpatch "github.com/evanphx/json-patch" "github.com/go-logr/logr" kyverno "github.com/kyverno/kyverno/api/kyverno/v1" + "github.com/kyverno/kyverno/pkg/toggle" "github.com/kyverno/kyverno/pkg/utils" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + log "sigs.k8s.io/controller-runtime/pkg/log" ) const ( @@ -240,3 +242,106 @@ func GenerateRulePatches(spec *kyverno.Spec, controllers string, log logr.Logger } return } + +type Policy interface { + GetAnnotations() map[string]string + GetSpec() kyverno.Spec +} + +// podControllersKey annotation could be: +// scenario A: not exist, set default to "all", which generates on all pod controllers +// - if name / selector exist in resource description -> skip +// as these fields may not be applicable to pod controllers +// scenario B: "none", user explicitly disable this feature -> skip +// scenario C: some certain controllers that user set -> generate on defined controllers +// copy entire match / exclude block, it's users' responsibility to +// make sure all fields are applicable to pod controllers + +// GenerateRules generates rule for podControllers based on scenario A and C +func GenerateRules(spec *kyverno.Spec, controllers string, log logr.Logger) []kyverno.Rule { + var rules []kyverno.Rule + for _, rule := range spec.Rules { + // handle all other controllers other than CronJob + if genRule := generateRuleForControllers(*rule.DeepCopy(), stripCronJob(controllers), log); genRule != nil { + if convRule, err := convertRule(*genRule, "Pod"); err == nil { + rules = append(rules, *convRule) + } + } + // handle CronJob, it appends an additional rule + if genRule := generateCronJobRule(*rule.DeepCopy(), controllers, log); genRule != nil { + if convRule, err := convertRule(*genRule, "Cronjob"); err == nil { + rules = append(rules, *convRule) + } + } + } + return rules +} + +func convertRule(rule kyvernoRule, kind string) (*kyverno.Rule, error) { + if bytes, err := json.Marshal(rule); err != nil { + return nil, err + } else { + bytes = updateGenRuleByte(bytes, kind, rule) + if err := json.Unmarshal(bytes, &rule); err != nil { + return nil, err + } + } + out := kyverno.Rule{ + Name: rule.Name, + VerifyImages: rule.VerifyImages, + } + if rule.MatchResources != nil { + out.MatchResources = *rule.MatchResources + } + if rule.ExcludeResources != nil { + out.ExcludeResources = *rule.ExcludeResources + } + if rule.Context != nil { + out.Context = *rule.Context + } + if rule.AnyAllConditions != nil { + out.SetAnyAllConditions(*rule.AnyAllConditions) + } + if rule.Mutation != nil { + out.Mutation = *rule.Mutation + } + if rule.Validation != nil { + out.Validation = *rule.Validation + } + return &out, nil +} + +func ComputeRules(p Policy) []kyverno.Rule { + spec := p.GetSpec() + if !toggle.AutogenInternals() { + return spec.Rules + } + applyAutoGen, desiredControllers := CanAutoGen(&spec, log.Log) + + if !applyAutoGen { + desiredControllers = "none" + } + + ann := p.GetAnnotations() + actualControllers, ok := ann[kyverno.PodControllersAnnotation] + + if !ok || !applyAutoGen { + actualControllers = desiredControllers + } else { + if !applyAutoGen { + actualControllers = desiredControllers + } + } + + if actualControllers == "none" { + return spec.Rules + } + genRules := GenerateRules(spec.DeepCopy(), actualControllers, log.Log) + if len(genRules) == 0 { + return spec.Rules + } + var out []kyverno.Rule + out = append(out, spec.Rules...) + out = append(out, genRules...) + return out +} diff --git a/pkg/autogen/autogen_test.go b/pkg/autogen/autogen_test.go index 08c6816bc0..af3b797d29 100644 --- a/pkg/autogen/autogen_test.go +++ b/pkg/autogen/autogen_test.go @@ -260,7 +260,7 @@ func Test_Any(t *testing.T) { } policy := policies[0] - policy.GetRules()[0].MatchResources.Any = kyverno.ResourceFilters{ + policy.Spec.Rules[0].MatchResources.Any = kyverno.ResourceFilters{ { ResourceDescription: kyverno.ResourceDescription{ Kinds: []string{"Pod"}, @@ -298,7 +298,7 @@ func Test_All(t *testing.T) { } policy := policies[0] - policy.GetRules()[0].MatchResources.All = kyverno.ResourceFilters{ + policy.Spec.Rules[0].MatchResources.All = kyverno.ResourceFilters{ { ResourceDescription: kyverno.ResourceDescription{ Kinds: []string{"Pod"}, @@ -336,7 +336,7 @@ func Test_Exclude(t *testing.T) { } policy := policies[0] - policy.GetRules()[0].ExcludeResources.Namespaces = []string{"fake-namespce"} + policy.Spec.Rules[0].ExcludeResources.Namespaces = []string{"fake-namespce"} rulePatches, errs := GenerateRulePatches(&policy.Spec, PodControllers, log.Log) if len(errs) != 0 { @@ -400,7 +400,7 @@ func Test_ForEachPod(t *testing.T) { } policy := policies[0] - policy.GetRules()[0].ExcludeResources.Namespaces = []string{"fake-namespce"} + policy.Spec.Rules[0].ExcludeResources.Namespaces = []string{"fake-namespce"} rulePatches, errs := GenerateRulePatches(&policy.Spec, PodControllers, log.Log) if len(errs) != 0 { @@ -439,10 +439,10 @@ func Test_CronJob_hasExclude(t *testing.T) { kyverno.PodControllersAnnotation: controllers, }) - rule := policy.GetRules()[0].DeepCopy() + rule := policy.Spec.Rules[0].DeepCopy() rule.ExcludeResources.Kinds = []string{"Pod"} rule.ExcludeResources.Namespaces = []string{"test"} - policy.GetRules()[0] = *rule + policy.Spec.Rules[0] = *rule rulePatches, errs := GenerateRulePatches(&policy.Spec, controllers, log.Log) if len(errs) != 0 { @@ -529,7 +529,7 @@ func Test_Deny(t *testing.T) { } policy := policies[0] - policy.GetRules()[0].MatchResources.Any = kyverno.ResourceFilters{ + policy.Spec.Rules[0].MatchResources.Any = kyverno.ResourceFilters{ { ResourceDescription: kyverno.ResourceDescription{ Kinds: []string{"Pod"}, diff --git a/pkg/autogen/rule.go b/pkg/autogen/rule.go index 9edfaabd55..45db01b377 100644 --- a/pkg/autogen/rule.go +++ b/pkg/autogen/rule.go @@ -418,11 +418,11 @@ func updateGenRuleByte(pbyte []byte, kind string, genRule kyvernoRule) (obj []by return obj } if kind == "Pod" { - obj = []byte(strings.Replace(string(pbyte), "request.object.spec", "request.object.spec.template.spec", -1)) + obj = []byte(strings.ReplaceAll(string(pbyte), "request.object.spec", "request.object.spec.template.spec")) } if kind == "Cronjob" { - obj = []byte(strings.Replace(string(pbyte), "request.object.spec", "request.object.spec.jobTemplate.spec.template.spec", -1)) + obj = []byte(strings.ReplaceAll(string(pbyte), "request.object.spec", "request.object.spec.jobTemplate.spec.template.spec")) } - obj = []byte(strings.Replace(string(obj), "request.object.metadata", "request.object.spec.template.metadata", -1)) + obj = []byte(strings.ReplaceAll(string(obj), "request.object.metadata", "request.object.spec.template.metadata")) return obj } diff --git a/pkg/compatibility/add_labels.go b/pkg/compatibility/add_labels.go index ea913d86cf..bf642a049a 100644 --- a/pkg/compatibility/add_labels.go +++ b/pkg/compatibility/add_labels.go @@ -6,6 +6,7 @@ import ( "strings" "time" + "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" "github.com/kyverno/kyverno/pkg/config" @@ -94,7 +95,7 @@ func AddCloneLabel(client *dclient.Client, pInformer kyvernoinformer.ClusterPoli } for _, policy := range policies { - for _, rule := range policy.GetRules() { + for _, rule := range autogen.ComputeRules(policy) { if rule.HasGenerate() { clone := rule.Generation.Clone if clone.Name != "" { diff --git a/pkg/engine/forceMutate.go b/pkg/engine/forceMutate.go index 36eefda6db..683880c509 100644 --- a/pkg/engine/forceMutate.go +++ b/pkg/engine/forceMutate.go @@ -19,7 +19,8 @@ func ForceMutate(ctx *context.Context, policy kyverno.ClusterPolicy, resource un "namespace", resource.GetNamespace(), "name", resource.GetName()) patchedResource := resource - for _, rule := range policy.GetRules() { + // TODO: if we apply autogen, tests will fail + for _, rule := range policy.Spec.Rules { if !rule.HasMutate() { continue } diff --git a/pkg/engine/generation.go b/pkg/engine/generation.go index b4a9f1d3bf..feab929b80 100644 --- a/pkg/engine/generation.go +++ b/pkg/engine/generation.go @@ -3,6 +3,7 @@ package engine import ( "time" + "github.com/kyverno/kyverno/pkg/autogen" "github.com/kyverno/kyverno/pkg/engine/common" kyverno "github.com/kyverno/kyverno/api/kyverno/v1" @@ -48,7 +49,7 @@ func filterRules(policyContext *PolicyContext, startTime time.Time) *response.En return resp } - for _, rule := range policyContext.Policy.GetRules() { + for _, rule := range autogen.ComputeRules(&policyContext.Policy) { if ruleResp := filterRule(rule, policyContext); ruleResp != nil { resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, *ruleResp) } diff --git a/pkg/engine/imageVerify.go b/pkg/engine/imageVerify.go index 204b693c01..28de645a7a 100644 --- a/pkg/engine/imageVerify.go +++ b/pkg/engine/imageVerify.go @@ -6,6 +6,7 @@ import ( "time" v1 "github.com/kyverno/kyverno/api/kyverno/v1" + "github.com/kyverno/kyverno/pkg/autogen" "github.com/kyverno/kyverno/pkg/engine/variables" "github.com/kyverno/kyverno/pkg/registryclient" "github.com/pkg/errors" @@ -48,7 +49,7 @@ func VerifyAndPatchImages(policyContext *PolicyContext) (resp *response.EngineRe } } - rules := policyContext.Policy.GetRules() + rules := autogen.ComputeRules(&policyContext.Policy) for i := range rules { rule := &rules[i] if len(rule.VerifyImages) == 0 { diff --git a/pkg/engine/mutate/patch/strategicMergePatch_test.go b/pkg/engine/mutate/patch/strategicMergePatch_test.go index 75ab141a92..55d0cd7328 100644 --- a/pkg/engine/mutate/patch/strategicMergePatch_test.go +++ b/pkg/engine/mutate/patch/strategicMergePatch_test.go @@ -5,6 +5,7 @@ import ( "testing" kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1" + "github.com/kyverno/kyverno/pkg/autogen" assertnew "github.com/stretchr/testify/assert" "gotest.tools/assert" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -242,7 +243,7 @@ func Test_PolicyDeserilize(t *testing.T) { err := json.Unmarshal(rawPolicy, &policy) assert.NilError(t, err) - overlayPatches := policy.GetRules()[0].Mutation.GetPatchStrategicMerge() + overlayPatches := autogen.ComputeRules(&policy)[0].Mutation.GetPatchStrategicMerge() patchString, err := json.Marshal(overlayPatches) assert.NilError(t, err) diff --git a/pkg/engine/mutation.go b/pkg/engine/mutation.go index 8a266328db..e21d0abe2e 100644 --- a/pkg/engine/mutation.go +++ b/pkg/engine/mutation.go @@ -8,6 +8,7 @@ import ( "github.com/go-logr/logr" gojmespath "github.com/jmespath/go-jmespath" kyverno "github.com/kyverno/kyverno/api/kyverno/v1" + "github.com/kyverno/kyverno/pkg/autogen" "github.com/kyverno/kyverno/pkg/engine/mutate" "github.com/kyverno/kyverno/pkg/engine/response" "github.com/kyverno/kyverno/pkg/engine/utils" @@ -37,7 +38,7 @@ func Mutate(policyContext *PolicyContext) (resp *response.EngineResponse) { var err error - for _, rule := range policy.GetRules() { + for _, rule := range autogen.ComputeRules(&policy) { if !rule.HasMutate() { continue } diff --git a/pkg/engine/utils_test.go b/pkg/engine/utils_test.go index 61c53aa59f..da5a4094f2 100644 --- a/pkg/engine/utils_test.go +++ b/pkg/engine/utils_test.go @@ -5,6 +5,7 @@ import ( "testing" v1 "github.com/kyverno/kyverno/api/kyverno/v1" + "github.com/kyverno/kyverno/pkg/autogen" "github.com/kyverno/kyverno/pkg/engine/utils" "gotest.tools/assert" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -897,7 +898,7 @@ func TestMatchesResourceDescription(t *testing.T) { } resource, _ := utils.ConvertToUnstructured(tc.Resource) - for _, rule := range policy.GetRules() { + for _, rule := range autogen.ComputeRules(&policy) { err := MatchesResourceDescription(*resource, rule, tc.AdmissionInfo, []string{}, nil, "") if err != nil { if !tc.areErrorsExpected { diff --git a/pkg/engine/validation.go b/pkg/engine/validation.go index fbea84969b..ff95e0ccdb 100644 --- a/pkg/engine/validation.go +++ b/pkg/engine/validation.go @@ -8,6 +8,7 @@ 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/pkg/errors" "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" @@ -87,7 +88,7 @@ func validateResource(log logr.Logger, ctx *PolicyContext) *response.EngineRespo ctx.JSONContext.Checkpoint() defer ctx.JSONContext.Restore() - rules := ctx.Policy.GetRules() + rules := autogen.ComputeRules(&ctx.Policy) for i := range rules { rule := &rules[i] if !rule.HasValidate() { diff --git a/pkg/generate/cleanup/controller.go b/pkg/generate/cleanup/controller.go index 28d01e243e..d4e7395851 100644 --- a/pkg/generate/cleanup/controller.go +++ b/pkg/generate/cleanup/controller.go @@ -7,6 +7,7 @@ import ( "k8s.io/client-go/kubernetes" "github.com/go-logr/logr" + "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" kyvernolister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1" @@ -141,7 +142,7 @@ func (c *Controller) deletePolicy(obj interface{}) { // clean up the GR // Get the corresponding GR // get the list of GR for the current Policy version - rules := p.GetRules() + rules := autogen.ComputeRules(p) generatePolicyWithClone := pkgCommon.ProcessDeletePolicyForCloneGenerateRule(rules, c.client, p.GetName(), logger) diff --git a/pkg/generate/generate.go b/pkg/generate/generate.go index 79cadad5f7..8359da5d07 100644 --- a/pkg/generate/generate.go +++ b/pkg/generate/generate.go @@ -11,6 +11,7 @@ import ( "time" kyverno "github.com/kyverno/kyverno/api/kyverno/v1" + "github.com/kyverno/kyverno/pkg/autogen" "github.com/kyverno/kyverno/pkg/engine/response" "github.com/go-logr/logr" @@ -259,7 +260,7 @@ func (c *Controller) applyGeneratePolicy(log logr.Logger, policyContext *engine. // To manage existing resources, we compare the creation time for the default resource to be generated and policy creation time ruleNameToProcessingTime := make(map[string]time.Duration) - for _, rule := range policy.GetRules() { + for _, rule := range autogen.ComputeRules(&policy) { var err error if !rule.HasGenerate() { continue diff --git a/pkg/generate/generate_controller.go b/pkg/generate/generate_controller.go index cda96cf584..b4953a1f64 100644 --- a/pkg/generate/generate_controller.go +++ b/pkg/generate/generate_controller.go @@ -9,6 +9,7 @@ import ( "k8s.io/client-go/kubernetes" "github.com/go-logr/logr" + "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" kyvernolister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1" @@ -258,7 +259,7 @@ func (c *Controller) updatePolicy(old, cur interface{}) { } var policyHasGenerate bool - for _, rule := range curP.GetRules() { + for _, rule := range autogen.ComputeRules(curP) { if rule.HasGenerate() { policyHasGenerate = true } diff --git a/pkg/kyverno/apply/apply_command.go b/pkg/kyverno/apply/apply_command.go index 70492310e3..1e5b7be255 100644 --- a/pkg/kyverno/apply/apply_command.go +++ b/pkg/kyverno/apply/apply_command.go @@ -15,7 +15,6 @@ import ( "github.com/kyverno/kyverno/pkg/openapi" policy2 "github.com/kyverno/kyverno/pkg/policy" "github.com/kyverno/kyverno/pkg/policyreport" - "github.com/kyverno/kyverno/pkg/toggle" "github.com/spf13/cobra" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/cli-runtime/pkg/genericclioptions" @@ -131,7 +130,6 @@ func Command() *cobra.Command { return nil }, } - cmd.Flags().StringArrayVarP(&resourcePaths, "resource", "r", []string{}, "Path to resource files") cmd.Flags().BoolVarP(&cluster, "cluster", "c", false, "Checks if policies should be applied to cluster in the current context") cmd.Flags().StringVarP(&mutateLogPath, "output", "o", "", "Prints the mutated resources in provided file/directory") @@ -141,7 +139,6 @@ func Command() *cobra.Command { cmd.Flags().BoolVarP(&policyReport, "policy-report", "", false, "Generates policy report when passed (default policyviolation r") cmd.Flags().StringVarP(&namespace, "namespace", "n", "", "Optional Policy parameter passed with cluster flag") cmd.Flags().BoolVarP(&stdin, "stdin", "i", false, "Optional mutate policy parameter to pipe directly through to kubectl") - cmd.Flags().BoolVarP(&toggle.AutogenInternals, "autogenInternals", "", toggle.DefaultAutogenInternals, "Use autogen internals") cmd.Flags().BoolVarP(®istryAccess, "registry", "", false, "If set to true, access the image registry using local docker credentials to populate external data") return cmd } diff --git a/pkg/kyverno/apply/apply_command_test.go b/pkg/kyverno/apply/apply_command_test.go index 043c265a78..1c8b97fcd2 100644 --- a/pkg/kyverno/apply/apply_command_test.go +++ b/pkg/kyverno/apply/apply_command_test.go @@ -63,12 +63,11 @@ func Test_Apply(t *testing.T) { } compareSummary := func(expected preport.PolicyReportSummary, actual map[string]interface{}) { - - assert.Assert(t, actual[preport.StatusPass].(int64) == int64(expected.Pass)) - assert.Assert(t, actual[preport.StatusFail].(int64) == int64(expected.Fail)) - assert.Assert(t, actual[preport.StatusSkip].(int64) == int64(expected.Skip)) - assert.Assert(t, actual[preport.StatusWarn].(int64) == int64(expected.Warn)) - assert.Assert(t, actual[preport.StatusError].(int64) == int64(expected.Error)) + assert.Equal(t, actual[preport.StatusPass].(int64), int64(expected.Pass)) + assert.Equal(t, actual[preport.StatusFail].(int64), int64(expected.Fail)) + assert.Equal(t, actual[preport.StatusSkip].(int64), int64(expected.Skip)) + assert.Equal(t, actual[preport.StatusWarn].(int64), int64(expected.Warn)) + assert.Equal(t, actual[preport.StatusError].(int64), int64(expected.Error)) } for _, tc := range testcases { diff --git a/pkg/kyverno/common/common.go b/pkg/kyverno/common/common.go index 1ec51bc0b2..fa613bce21 100644 --- a/pkg/kyverno/common/common.go +++ b/pkg/kyverno/common/common.go @@ -13,8 +13,8 @@ import ( "reflect" "strings" + "github.com/kyverno/kyverno/pkg/autogen" "github.com/kyverno/kyverno/pkg/engine/variables" - "github.com/kyverno/kyverno/pkg/toggle" jsonpatch "github.com/evanphx/json-patch/v5" "github.com/go-git/go-billy/v5" @@ -175,8 +175,8 @@ func GetPolicies(paths []string) (policies []*v1.ClusterPolicy, errors []error) } // MutatePolicy - applies mutation to a policy -func MutatePolicy(policy *v1.ClusterPolicy, autogenInternals bool, logger logr.Logger) (*v1.ClusterPolicy, error) { - patches, _ := policymutation.GenerateJSONPatchesForDefaults(policy, autogenInternals, logger) +func MutatePolicy(policy *v1.ClusterPolicy, logger logr.Logger) (*v1.ClusterPolicy, error) { + patches, _ := policymutation.GenerateJSONPatchesForDefaults(policy, logger) if len(patches) == 0 { return policy, nil } @@ -444,7 +444,7 @@ func MutatePolicies(policies []*v1.ClusterPolicy) ([]*v1.ClusterPolicy, error) { logger := log.Log.WithName("apply") for _, policy := range policies { - p, err := MutatePolicy(policy, toggle.AutogenInternals, logger) + p, err := MutatePolicy(policy, logger) if err != nil { if !sanitizederror.IsErrorSanitized(err) { return nil, sanitizederror.NewWithError("failed to mutate policy.", err) @@ -472,7 +472,7 @@ func ApplyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unst policyWithNamespaceSelector := false OuterLoop: - for _, p := range policy.GetRules() { + for _, p := range autogen.ComputeRules(policy) { if p.MatchResources.ResourceDescription.NamespaceSelector != nil || p.ExcludeResources.ResourceDescription.NamespaceSelector != nil { policyWithNamespaceSelector = true @@ -574,7 +574,7 @@ OuterLoop: } var policyHasValidate bool - for _, rule := range policy.GetRules() { + for _, rule := range autogen.ComputeRules(policy) { if rule.HasValidate() { policyHasValidate = true } @@ -592,7 +592,7 @@ OuterLoop: } var policyHasGenerate bool - for _, rule := range policy.GetRules() { + for _, rule := range autogen.ComputeRules(policy) { if rule.HasGenerate() { policyHasGenerate = true } @@ -770,7 +770,7 @@ func GetResourceAccordingToResourcePath(fs billy.Filesystem, resourcePaths []str func ProcessValidateEngineResponse(policy *v1.ClusterPolicy, validateResponse *response.EngineResponse, resPath string, rc *ResultCounts, policyReport bool) policyreport.Info { var violatedRules []v1.ViolatedRule printCount := 0 - for _, policyRule := range policy.GetRules() { + for _, policyRule := range autogen.ComputeRules(policy) { ruleFoundInEngineResponse := false if !policyRule.HasValidate() { continue @@ -851,7 +851,7 @@ func buildPVInfo(er *response.EngineResponse, violatedRules []v1.ViolatedRule) p func processGenerateEngineResponse(policy *v1.ClusterPolicy, generateResponse *response.EngineResponse, resPath string, rc *ResultCounts) { printCount := 0 - for _, policyRule := range policy.GetRules() { + for _, policyRule := range autogen.ComputeRules(policy) { ruleFoundInEngineResponse := false for i, genResponseRule := range generateResponse.PolicyResponse.Rules { if policyRule.Name == genResponseRule.Name { @@ -879,7 +879,7 @@ func SetInStoreContext(mutatedPolicies []*v1.ClusterPolicy, variables map[string storePolicies := make([]store.Policy, 0) for _, policy := range mutatedPolicies { storeRules := make([]store.Rule, 0) - for _, rule := range policy.GetRules() { + for _, rule := range autogen.ComputeRules(policy) { contextVal := make(map[string]string) if len(rule.Context) != 0 { for _, contextVar := range rule.Context { @@ -911,7 +911,7 @@ func SetInStoreContext(mutatedPolicies []*v1.ClusterPolicy, variables map[string func processMutateEngineResponse(policy *v1.ClusterPolicy, mutateResponse *response.EngineResponse, resPath string, rc *ResultCounts, mutateLogPath string, stdin bool, mutateLogPathIsDir bool, resourceName string, printPatchResource bool) error { var policyHasMutate bool - for _, rule := range policy.GetRules() { + for _, rule := range autogen.ComputeRules(policy) { if rule.HasMutate() { policyHasMutate = true } @@ -922,7 +922,7 @@ func processMutateEngineResponse(policy *v1.ClusterPolicy, mutateResponse *respo printCount := 0 printMutatedRes := false - for _, policyRule := range policy.GetRules() { + for _, policyRule := range autogen.ComputeRules(policy) { ruleFoundInEngineResponse := false for i, mutateResponseRule := range mutateResponse.PolicyResponse.Rules { if policyRule.Name == mutateResponseRule.Name { @@ -1021,7 +1021,7 @@ func CheckVariableForPolicy(valuesMap map[string]map[string]Resource, globalValM func GetKindsFromPolicy(policy *v1.ClusterPolicy) map[string]struct{} { var kindOnwhichPolicyIsApplied = make(map[string]struct{}) - for _, rule := range policy.GetRules() { + for _, rule := range autogen.ComputeRules(policy) { for _, kind := range rule.MatchResources.ResourceDescription.Kinds { kindOnwhichPolicyIsApplied[kind] = struct{}{} } diff --git a/pkg/kyverno/common/common_test.go b/pkg/kyverno/common/common_test.go index d34b65839f..ca17b8f5ef 100644 --- a/pkg/kyverno/common/common_test.go +++ b/pkg/kyverno/common/common_test.go @@ -3,6 +3,7 @@ package common import ( "testing" + "github.com/kyverno/kyverno/pkg/toggle" ut "github.com/kyverno/kyverno/pkg/utils" "gotest.tools/assert" ) @@ -73,7 +74,7 @@ func Test_NamespaceSelector(t *testing.T) { Fail: 1, Warn: 0, Error: 0, - Skip: 0, + Skip: 2, }, }, { @@ -89,7 +90,7 @@ func Test_NamespaceSelector(t *testing.T) { Fail: 1, Warn: 0, Error: 0, - Skip: 0, + Skip: 4, }, }, } @@ -99,10 +100,15 @@ func Test_NamespaceSelector(t *testing.T) { policyArray, _ := ut.GetPolicy(tc.policy) resourceArray, _ := GetResource(tc.resource) ApplyPolicyOnResource(policyArray[0], resourceArray[0], "", false, nil, false, tc.namespaceSelectorMap, false, rc, false) - assert.Assert(t, int64(rc.Pass) == int64(tc.result.Pass)) - assert.Assert(t, int64(rc.Fail) == int64(tc.result.Fail)) - assert.Assert(t, int64(rc.Skip) == int64(tc.result.Skip)) - assert.Assert(t, int64(rc.Warn) == int64(tc.result.Warn)) - assert.Assert(t, int64(rc.Error) == int64(tc.result.Error)) + 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 + if toggle.AutogenInternals() { + assert.Equal(t, int64(rc.Skip), int64(tc.result.Skip)) + } else { + assert.Equal(t, int64(rc.Skip), int64(0)) + } + assert.Equal(t, int64(rc.Warn), int64(tc.result.Warn)) + assert.Equal(t, int64(rc.Error), int64(tc.result.Error)) } } diff --git a/pkg/kyverno/common/fetch.go b/pkg/kyverno/common/fetch.go index e50b4df55f..9375fe2443 100644 --- a/pkg/kyverno/common/fetch.go +++ b/pkg/kyverno/common/fetch.go @@ -10,6 +10,7 @@ import ( "github.com/go-git/go-billy/v5" v1 "github.com/kyverno/kyverno/api/kyverno/v1" + "github.com/kyverno/kyverno/pkg/autogen" client "github.com/kyverno/kyverno/pkg/dclient" engineutils "github.com/kyverno/kyverno/pkg/engine/utils" "github.com/kyverno/kyverno/pkg/utils" @@ -31,7 +32,7 @@ func GetResources(policies []*v1.ClusterPolicy, resourcePaths []string, dClient var resourceTypes []string for _, policy := range policies { - for _, rule := range policy.GetRules() { + for _, rule := range autogen.ComputeRules(policy) { resourceTypesInRule := GetKindsFromRule(rule) for resourceKind := range resourceTypesInRule { resourceTypesMap[resourceKind] = true @@ -120,7 +121,7 @@ func GetResourcesWithTest(fs billy.Filesystem, policies []*v1.ClusterPolicy, res var resourceTypesMap = make(map[string]bool) var resourceTypes []string for _, policy := range policies { - for _, rule := range policy.GetRules() { + for _, rule := range autogen.ComputeRules(policy) { for _, kind := range rule.MatchResources.Kinds { resourceTypesMap[kind] = true } diff --git a/pkg/kyverno/test/test_command.go b/pkg/kyverno/test/test_command.go index a35f062e13..b8cc27ca9b 100644 --- a/pkg/kyverno/test/test_command.go +++ b/pkg/kyverno/test/test_command.go @@ -18,6 +18,7 @@ import ( "github.com/kataras/tablewriter" v1 "github.com/kyverno/kyverno/api/kyverno/v1" report "github.com/kyverno/kyverno/api/policyreport/v1alpha2" + "github.com/kyverno/kyverno/pkg/autogen" client "github.com/kyverno/kyverno/pkg/dclient" "github.com/kyverno/kyverno/pkg/engine/response" "github.com/kyverno/kyverno/pkg/engine/utils" @@ -775,7 +776,7 @@ func applyPoliciesFromPath(fs billy.Filesystem, policyBytes []byte, isGit bool, for _, p := range filteredPolicies { var filteredRules = []v1.Rule{} - for _, rule := range p.GetRules() { + for _, rule := range autogen.ComputeRules(p) { for _, res := range values.Results { if rule.Name == res.Rule { filteredRules = append(filteredRules, rule) diff --git a/pkg/kyverno/validate/command.go b/pkg/kyverno/validate/command.go index 26c77a4225..9bbf15360b 100644 --- a/pkg/kyverno/validate/command.go +++ b/pkg/kyverno/validate/command.go @@ -13,7 +13,6 @@ import ( sanitizederror "github.com/kyverno/kyverno/pkg/kyverno/sanitizedError" "github.com/kyverno/kyverno/pkg/openapi" policy2 "github.com/kyverno/kyverno/pkg/policy" - "github.com/kyverno/kyverno/pkg/toggle" "github.com/kyverno/kyverno/pkg/utils" "github.com/spf13/cobra" "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" @@ -88,7 +87,6 @@ func Command() *cobra.Command { } cmd.Flags().StringVarP(&outputType, "output", "o", "", "Prints the mutated policy in yaml or json format") cmd.Flags().StringArrayVarP(&crdPaths, "crd", "c", []string{}, "Path to CRD files") - cmd.Flags().BoolVarP(&toggle.AutogenInternals, "autogenInternals", "", toggle.DefaultAutogenInternals, "Use autogen internals") return cmd } @@ -180,7 +178,7 @@ func validatePolicies(policies []*v1.ClusterPolicy, v1crd apiextensions.CustomRe fmt.Printf("Policy %s is valid.\n\n", policy.Name) if outputType != "" { logger := log.Log.WithName("validate") - p, err := common.MutatePolicy(policy, toggle.AutogenInternals, logger) + p, err := common.MutatePolicy(policy, logger) if err != nil { if !sanitizederror.IsErrorSanitized(err) { return sanitizederror.NewWithError("failed to mutate policy.", err) diff --git a/pkg/metrics/policyruleinfo/policyRuleInfo.go b/pkg/metrics/policyruleinfo/policyRuleInfo.go index 7116f314ff..e6c5bf583d 100644 --- a/pkg/metrics/policyruleinfo/policyRuleInfo.go +++ b/pkg/metrics/policyruleinfo/policyRuleInfo.go @@ -4,6 +4,7 @@ import ( "fmt" kyverno "github.com/kyverno/kyverno/api/kyverno/v1" + "github.com/kyverno/kyverno/pkg/autogen" "github.com/kyverno/kyverno/pkg/metrics" prom "github.com/prometheus/client_golang/prometheus" ) @@ -73,7 +74,7 @@ func (pc PromConfig) AddPolicy(policy interface{}) error { policyName := inputPolicy.GetName() ready := inputPolicy.IsReady() // registering the metrics on a per-rule basis - for _, rule := range inputPolicy.GetRules() { + for _, rule := range autogen.ComputeRules(inputPolicy) { ruleName := rule.Name ruleType := metrics.ParseRuleType(rule) @@ -93,7 +94,7 @@ func (pc PromConfig) AddPolicy(policy interface{}) error { policyName := inputPolicy.GetName() ready := inputPolicy.IsReady() // registering the metrics on a per-rule basis - for _, rule := range inputPolicy.GetRules() { + for _, rule := range autogen.ComputeRules(inputPolicy) { ruleName := rule.Name ruleType := metrics.ParseRuleType(rule) @@ -110,7 +111,7 @@ func (pc PromConfig) AddPolicy(policy interface{}) error { func (pc PromConfig) RemovePolicy(policy interface{}) error { switch inputPolicy := policy.(type) { case *kyverno.ClusterPolicy: - for _, rule := range inputPolicy.GetRules() { + for _, rule := range autogen.ComputeRules(inputPolicy) { policyValidationMode, err := metrics.ParsePolicyValidationMode(inputPolicy.Spec.ValidationFailureAction) if err != nil { return err @@ -129,7 +130,7 @@ func (pc PromConfig) RemovePolicy(policy interface{}) error { } return nil case *kyverno.Policy: - for _, rule := range inputPolicy.GetRules() { + for _, rule := range autogen.ComputeRules(inputPolicy) { policyValidationMode, err := metrics.ParsePolicyValidationMode(inputPolicy.Spec.ValidationFailureAction) if err != nil { return err diff --git a/pkg/openapi/validation.go b/pkg/openapi/validation.go index e0e5d5b3f8..07fa9869db 100644 --- a/pkg/openapi/validation.go +++ b/pkg/openapi/validation.go @@ -13,6 +13,7 @@ import ( openapiv2 "github.com/googleapis/gnostic/openapiv2" v1 "github.com/kyverno/kyverno/api/kyverno/v1" "github.com/kyverno/kyverno/data" + "github.com/kyverno/kyverno/pkg/autogen" "github.com/kyverno/kyverno/pkg/common" "github.com/kyverno/kyverno/pkg/engine" "github.com/kyverno/kyverno/pkg/utils" @@ -138,7 +139,7 @@ func (o *Controller) ValidateResource(patchedResource unstructured.Unstructured, // ValidatePolicyMutation ... func (o *Controller) ValidatePolicyMutation(policy v1.ClusterPolicy) error { var kindToRules = make(map[string][]v1.Rule) - for _, rule := range policy.GetRules() { + for _, rule := range autogen.ComputeRules(&policy) { if rule.HasMutate() { for _, kind := range rule.MatchResources.Kinds { kindToRules[kind] = append(kindToRules[common.GetFormatedKind(kind)], rule) diff --git a/pkg/policy/background.go b/pkg/policy/background.go index f3373d1573..bfbea12c59 100644 --- a/pkg/policy/background.go +++ b/pkg/policy/background.go @@ -6,6 +6,7 @@ import ( "strings" kyverno "github.com/kyverno/kyverno/api/kyverno/v1" + "github.com/kyverno/kyverno/pkg/autogen" "github.com/kyverno/kyverno/pkg/engine/context" "github.com/kyverno/kyverno/pkg/engine/variables" "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" @@ -19,7 +20,7 @@ func containsUserVariables(policy *kyverno.ClusterPolicy, vars [][]string) error return fmt.Errorf("variable %s is not allowed", s[0]) } } - rules := policy.GetRules() + rules := autogen.ComputeRules(policy) for idx := range rules { if err := hasUserMatchExclude(idx, &rules[idx]); err != nil { return err diff --git a/pkg/policy/existing.go b/pkg/policy/existing.go index 504cd0b9e1..bc62b0f8c7 100644 --- a/pkg/policy/existing.go +++ b/pkg/policy/existing.go @@ -8,6 +8,7 @@ import ( "github.com/go-logr/logr" kyverno "github.com/kyverno/kyverno/api/kyverno/v1" + "github.com/kyverno/kyverno/pkg/autogen" "github.com/kyverno/kyverno/pkg/common" "github.com/kyverno/kyverno/pkg/engine" "github.com/kyverno/kyverno/pkg/engine/response" @@ -24,7 +25,7 @@ func (pc *PolicyController) processExistingResources(policy *kyverno.ClusterPoli // Parse through all the resources drops the cache after configured rebuild time pc.rm.Drop() - for _, rule := range policy.GetRules() { + for _, rule := range autogen.ComputeRules(policy) { if !rule.HasValidate() && !rule.HasVerifyImages() { continue } diff --git a/pkg/policy/policy_controller.go b/pkg/policy/policy_controller.go index 892618aa47..44bc42fb15 100644 --- a/pkg/policy/policy_controller.go +++ b/pkg/policy/policy_controller.go @@ -23,7 +23,6 @@ import ( "github.com/kyverno/kyverno/pkg/kyverno/common" "github.com/kyverno/kyverno/pkg/metrics" "github.com/kyverno/kyverno/pkg/policyreport" - "github.com/kyverno/kyverno/pkg/toggle" "github.com/kyverno/kyverno/pkg/utils" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" @@ -195,7 +194,7 @@ func (pc *PolicyController) addPolicy(obj interface{}) { go pc.registerPolicyChangesMetricAddPolicy(logger, p) if p.Spec.Background == nil || p.Spec.ValidationFailureAction == "" || missingAutoGenRules(p, logger) { - pol, _ := common.MutatePolicy(p, toggle.AutogenInternals, logger) + pol, _ := common.MutatePolicy(p, logger) pol.SetGroupVersionKind(schema.GroupVersionKind{Group: "kyverno.io", Version: "v1", Kind: "ClusterPolicy"}) _, err := pc.client.UpdateResource("kyverno.io/v1", "ClusterPolicy", "", pol, false) if err != nil { @@ -222,7 +221,7 @@ func (pc *PolicyController) updatePolicy(old, cur interface{}) { go pc.registerPolicyChangesMetricUpdatePolicy(logger, oldP, curP) if curP.Spec.Background == nil || curP.Spec.ValidationFailureAction == "" || missingAutoGenRules(curP, logger) { - pol, _ := common.MutatePolicy(curP, toggle.AutogenInternals, logger) + pol, _ := common.MutatePolicy(curP, logger) pol.SetGroupVersionKind(schema.GroupVersionKind{Group: "kyverno.io", Version: "v1", Kind: "ClusterPolicy"}) _, err := pc.client.UpdateResource("kyverno.io/v1", "ClusterPolicy", "", pol, false) if err != nil { @@ -271,7 +270,7 @@ func (pc *PolicyController) deletePolicy(obj interface{}) { // we process policies that are not set of background processing // as we need to clean up GRs when a policy is deleted // skip generate policies with clone - rules := p.GetRules() + rules := autogen.ComputeRules(p) generatePolicyWithClone := pkgCommon.ProcessDeletePolicyForCloneGenerateRule(rules, pc.client, p.GetName(), logger) @@ -294,7 +293,7 @@ func (pc *PolicyController) addNsPolicy(obj interface{}) { pol := ConvertPolicyToClusterPolicy(p) if pol.Spec.Background == nil || pol.Spec.ValidationFailureAction == "" || missingAutoGenRules(pol, logger) { - nsPol, _ := common.MutatePolicy(pol, toggle.AutogenInternals, logger) + nsPol, _ := common.MutatePolicy(pol, logger) nsPol.SetGroupVersionKind(schema.GroupVersionKind{Group: "kyverno.io", Version: "v1", Kind: "Policy"}) _, err := pc.client.UpdateResource("kyverno.io/v1", "Policy", p.Namespace, nsPol, false) if err != nil { @@ -321,7 +320,7 @@ func (pc *PolicyController) updateNsPolicy(old, cur interface{}) { ncurP := ConvertPolicyToClusterPolicy(curP) if ncurP.Spec.Background == nil || ncurP.Spec.ValidationFailureAction == "" || missingAutoGenRules(ncurP, logger) { - nsPol, _ := common.MutatePolicy(ncurP, toggle.AutogenInternals, logger) + nsPol, _ := common.MutatePolicy(ncurP, logger) nsPol.SetGroupVersionKind(schema.GroupVersionKind{Group: "kyverno.io", Version: "v1", Kind: "Policy"}) _, err := pc.client.UpdateResource("kyverno.io/v1", "Policy", ncurP.GetNamespace(), nsPol, false) if err != nil { @@ -377,11 +376,11 @@ func (pc *PolicyController) deleteNsPolicy(obj interface{}) { func (pc *PolicyController) enqueueRCRDeletedRule(old, cur *kyverno.ClusterPolicy) { curRule := make(map[string]bool) - for _, rule := range cur.GetRules() { + for _, rule := range autogen.ComputeRules(cur) { curRule[rule.Name] = true } - for _, rule := range old.GetRules() { + for _, rule := range autogen.ComputeRules(old) { if !curRule[rule.Name] { pc.prGenerator.Add(policyreport.Info{ PolicyName: cur.GetName(), @@ -566,7 +565,7 @@ func missingAutoGenRules(policy *kyverno.ClusterPolicy, log logr.Logger) bool { var podRuleName []string ruleCount := 1 if canApplyAutoGen, _ := autogen.CanAutoGen(&policy.Spec, log); canApplyAutoGen { - for _, rule := range policy.GetRules() { + for _, rule := range autogen.ComputeRules(policy) { podRuleName = append(podRuleName, rule.Name) } } @@ -593,7 +592,7 @@ func missingAutoGenRules(policy *kyverno.ClusterPolicy, log logr.Logger) bool { } } - if len(policy.GetRules()) != (ruleCount * len(podRuleName)) { + if len(autogen.ComputeRules(policy)) != (ruleCount * len(podRuleName)) { return true } } diff --git a/pkg/policy/validate.go b/pkg/policy/validate.go index f23025044d..2ff7b6fe48 100644 --- a/pkg/policy/validate.go +++ b/pkg/policy/validate.go @@ -9,6 +9,7 @@ import ( "strings" "github.com/distribution/distribution/reference" + "github.com/kyverno/kyverno/pkg/autogen" "github.com/kyverno/kyverno/pkg/engine/context" jsonpatch "github.com/evanphx/json-patch/v5" @@ -110,8 +111,7 @@ func Validate(policy *kyverno.ClusterPolicy, client *dclient.Client, mock bool, if errs := policy.Validate(clusterResources); len(errs) != 0 { return nil, errs.ToAggregate() } - - rules := policy.GetRules() + rules := autogen.ComputeRules(policy) rulesPath := specPath.Child("rules") for i, rule := range rules { rulePath := rulesPath.Index(i) @@ -365,7 +365,7 @@ func ValidateVariables(p *kyverno.ClusterPolicy, backgroundMode bool) error { // hasInvalidVariables - checks for unexpected variables in the policy func hasInvalidVariables(policy *kyverno.ClusterPolicy, background bool) error { - for _, r := range policy.GetRules() { + for _, r := range autogen.ComputeRules(policy) { ruleCopy := r.DeepCopy() if err := ruleForbiddenSectionsHaveVariables(ruleCopy); err != nil { diff --git a/pkg/policycache/cache.go b/pkg/policycache/cache.go index c6ccde8242..8093eea0b8 100644 --- a/pkg/policycache/cache.go +++ b/pkg/policycache/cache.go @@ -6,6 +6,7 @@ import ( "github.com/go-logr/logr" kyverno "github.com/kyverno/kyverno/api/kyverno/v1" + "github.com/kyverno/kyverno/pkg/autogen" kyvernolister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1" "github.com/kyverno/kyverno/pkg/common" policy2 "github.com/kyverno/kyverno/pkg/policy" @@ -124,7 +125,7 @@ func (m *pMap) add(policy *kyverno.ClusterPolicy) { pName = pSpace + "/" + pName } - for _, rule := range policy.GetRules() { + for _, rule := range autogen.ComputeRules(policy) { if len(rule.MatchResources.Any) > 0 { for _, rmr := range rule.MatchResources.Any { @@ -230,7 +231,7 @@ func (m *pMap) remove(policy *kyverno.ClusterPolicy) { pName = pSpace + "/" + pName } - for _, rule := range policy.GetRules() { + for _, rule := range autogen.ComputeRules(policy) { if len(rule.MatchResources.Any) > 0 { for _, rmr := range rule.MatchResources.Any { removeCacheHelper(rmr, m, pName) diff --git a/pkg/policycache/cache_test.go b/pkg/policycache/cache_test.go index 36e6d03922..122e00855c 100644 --- a/pkg/policycache/cache_test.go +++ b/pkg/policycache/cache_test.go @@ -6,6 +6,7 @@ import ( "testing" kyverno "github.com/kyverno/kyverno/api/kyverno/v1" + "github.com/kyverno/kyverno/pkg/autogen" lv1 "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1" "gotest.tools/assert" "k8s.io/apimachinery/pkg/labels" @@ -49,7 +50,7 @@ func Test_All(t *testing.T) { policy := newPolicy(t) //add pCache.Add(policy) - for _, rule := range policy.GetRules() { + for _, rule := range autogen.ComputeRules(policy) { for _, kind := range rule.MatchResources.Kinds { // get @@ -82,7 +83,7 @@ func Test_Add_Duplicate_Policy(t *testing.T) { pCache.Add(policy) pCache.Add(policy) pCache.Add(policy) - for _, rule := range policy.GetRules() { + for _, rule := range autogen.ComputeRules(policy) { for _, kind := range rule.MatchResources.Kinds { mutate := pCache.get(Mutate, kind, "") @@ -111,7 +112,7 @@ func Test_Add_Validate_Audit(t *testing.T) { policy.Spec.ValidationFailureAction = "audit" pCache.Add(policy) pCache.Add(policy) - for _, rule := range policy.GetRules() { + for _, rule := range autogen.ComputeRules(policy) { for _, kind := range rule.MatchResources.Kinds { validateEnforce := pCache.get(ValidateEnforce, kind, "") @@ -930,7 +931,7 @@ func Test_Ns_All(t *testing.T) { //add pCache.Add(policy) nspace := policy.GetNamespace() - for _, rule := range policy.GetRules() { + for _, rule := range autogen.ComputeRules(policy) { for _, kind := range rule.MatchResources.Kinds { // get @@ -963,7 +964,7 @@ func Test_Ns_Add_Duplicate_Policy(t *testing.T) { pCache.Add(policy) pCache.Add(policy) nspace := policy.GetNamespace() - for _, rule := range policy.GetRules() { + for _, rule := range autogen.ComputeRules(policy) { for _, kind := range rule.MatchResources.Kinds { mutate := pCache.get(Mutate, kind, nspace) @@ -992,7 +993,7 @@ func Test_Ns_Add_Validate_Audit(t *testing.T) { policy.Spec.ValidationFailureAction = "audit" pCache.Add(policy) pCache.Add(policy) - for _, rule := range policy.GetRules() { + for _, rule := range autogen.ComputeRules(policy) { for _, kind := range rule.MatchResources.Kinds { validateEnforce := pCache.get(ValidateEnforce, kind, nspace) @@ -1031,7 +1032,7 @@ func Test_GVk_Cache(t *testing.T) { policy := newGVKPolicy(t) //add pCache.Add(policy) - for _, rule := range policy.GetRules() { + for _, rule := range autogen.ComputeRules(policy) { for _, kind := range rule.MatchResources.Kinds { generate := pCache.get(Generate, kind, "") @@ -1065,7 +1066,7 @@ func Test_Add_Validate_Enforce(t *testing.T) { nspace := policy.GetNamespace() //add pCache.Add(policy) - for _, rule := range policy.GetRules() { + for _, rule := range autogen.ComputeRules(policy) { for _, kind := range rule.MatchResources.Kinds { validateEnforce := pCache.get(ValidateEnforce, kind, nspace) if len(validateEnforce) != 1 { @@ -1100,7 +1101,7 @@ func Test_Mutate_Policy(t *testing.T) { pCache.Add(policy) pCache.Add(policy) pCache.Add(policy) - for _, rule := range policy.GetRules() { + for _, rule := range autogen.ComputeRules(policy) { for _, kind := range rule.MatchResources.Kinds { // get @@ -1117,7 +1118,7 @@ func Test_Generate_Policy(t *testing.T) { policy := newgenratePolicy(t) //add pCache.Add(policy) - for _, rule := range policy.GetRules() { + for _, rule := range autogen.ComputeRules(policy) { for _, kind := range rule.MatchResources.Kinds { // get diff --git a/pkg/policymutation/policymutation.go b/pkg/policymutation/policymutation.go index 1b9d47988d..5e4b14ede5 100644 --- a/pkg/policymutation/policymutation.go +++ b/pkg/policymutation/policymutation.go @@ -10,6 +10,7 @@ import ( kyverno "github.com/kyverno/kyverno/api/kyverno/v1" "github.com/kyverno/kyverno/pkg/autogen" "github.com/kyverno/kyverno/pkg/common" + "github.com/kyverno/kyverno/pkg/toggle" "github.com/kyverno/kyverno/pkg/utils" ) @@ -17,7 +18,7 @@ import ( // - ValidationFailureAction // - Background // - auto-gen annotation and rules -func GenerateJSONPatchesForDefaults(policy *kyverno.ClusterPolicy, autogenInternals bool, log logr.Logger) ([]byte, []string) { +func GenerateJSONPatchesForDefaults(policy *kyverno.ClusterPolicy, log logr.Logger) ([]byte, []string) { var patches [][]byte var updateMsgs []string @@ -38,16 +39,19 @@ func GenerateJSONPatchesForDefaults(policy *kyverno.ClusterPolicy, autogenIntern updateMsgs = append(updateMsgs, updateMsg) } - patch, errs := GeneratePodControllerRule(*policy, autogenInternals, log) - if len(errs) > 0 { - var errMsgs []string - for _, err := range errs { - errMsgs = append(errMsgs, err.Error()) - log.Error(err, "failed to generate pod controller rule") + // if autogenInternals is enabled, we don't mutate rules in the webhook + if !toggle.AutogenInternals() { + patch, errs := GeneratePodControllerRule(*policy, log) + if len(errs) > 0 { + var errMsgs []string + for _, err := range errs { + errMsgs = append(errMsgs, err.Error()) + log.Error(err, "failed to generate pod controller rule") + } + updateMsgs = append(updateMsgs, strings.Join(errMsgs, ";")) } - updateMsgs = append(updateMsgs, strings.Join(errMsgs, ";")) + patches = append(patches, patch...) } - patches = append(patches, patch...) formatedGVK, errs := checkForGVKFormatPatch(policy, log) if len(errs) > 0 { @@ -65,7 +69,7 @@ func GenerateJSONPatchesForDefaults(policy *kyverno.ClusterPolicy, autogenIntern func checkForGVKFormatPatch(policy *kyverno.ClusterPolicy, log logr.Logger) (patches [][]byte, errs []error) { patches = make([][]byte, 0) - for i, rule := range policy.GetRules() { + for i, rule := range autogen.ComputeRules(policy) { patchByte, err := convertGVKForKinds(fmt.Sprintf("/spec/rules/%s/match/resources/kinds", strconv.Itoa(i)), rule.MatchResources.Kinds, log) if err == nil && patchByte != nil { patches = append(patches, patchByte) @@ -248,7 +252,7 @@ func defaultFailurePolicy(spec *kyverno.Spec, log logr.Logger) ([]byte, string) // make sure all fields are applicable to pod controllers // GeneratePodControllerRule returns two patches: rulePatches and annotation patch(if necessary) -func GeneratePodControllerRule(policy kyverno.ClusterPolicy, autogenInternals bool, log logr.Logger) (patches [][]byte, errs []error) { +func GeneratePodControllerRule(policy kyverno.ClusterPolicy, log logr.Logger) (patches [][]byte, errs []error) { applyAutoGen, desiredControllers := autogen.CanAutoGen(&policy.Spec, log) if !applyAutoGen { @@ -262,13 +266,11 @@ func GeneratePodControllerRule(policy kyverno.ClusterPolicy, autogenInternals bo // - predefined controllers are invalid, overwrite the value if !ok || !applyAutoGen { actualControllers = desiredControllers - if !autogenInternals { - annPatch, err := defaultPodControllerAnnotation(ann, actualControllers) - if err != nil { - errs = append(errs, fmt.Errorf("failed to generate pod controller annotation for policy '%s': %v", policy.Name, err)) - } else { - patches = append(patches, annPatch) - } + annPatch, err := defaultPodControllerAnnotation(ann, actualControllers) + if err != nil { + errs = append(errs, fmt.Errorf("failed to generate pod controller annotation for policy '%s': %v", policy.Name, err)) + } else { + patches = append(patches, annPatch) } } else { if !applyAutoGen { diff --git a/pkg/toggle/toggle.go b/pkg/toggle/toggle.go index c8e4cbe57f..7e76bccb37 100644 --- a/pkg/toggle/toggle.go +++ b/pkg/toggle/toggle.go @@ -1,5 +1,45 @@ package toggle -const DefaultAutogenInternals = false +import ( + "os" + "strconv" +) -var AutogenInternals = DefaultAutogenInternals +const ( + AutogenInternalsFlagName = "autogenInternals" + AutogenInternalsDescription = "Enables autogen internal policies. When this is 'true' policy rules should not be mutated." + AutogenInternalsEnvVar = "FLAG_AUTOGEN_INTERNALS" + DefaultAutogenInternals = false +) + +var autogenInternals *bool + +func getBool(in string) (*bool, error) { + if in == "" { + return nil, nil + } + value, err := strconv.ParseBool(in) + if err != nil { + return nil, err + } + return &value, nil +} + +func AutogenInternalsFlag(in string) error { + if value, err := getBool(in); err != nil { + return err + } else { + autogenInternals = value + return nil + } +} + +func AutogenInternals() bool { + if autogenInternals != nil { + return *autogenInternals + } + if value, err := getBool(os.Getenv(AutogenInternalsEnvVar)); err == nil && value != nil { + return *value + } + return DefaultAutogenInternals +} diff --git a/pkg/utils/json.go b/pkg/utils/json.go index d7eeaba328..471714958f 100644 --- a/pkg/utils/json.go +++ b/pkg/utils/json.go @@ -1,12 +1,5 @@ package utils -import ( - "encoding/json" - "reflect" - - v1 "github.com/kyverno/kyverno/api/kyverno/v1" -) - // JoinPatches joins array of serialized JSON patches to the single JSONPatch array func JoinPatches(patches [][]byte) []byte { var result []byte @@ -24,43 +17,3 @@ func JoinPatches(patches [][]byte) []byte { result = append(result, []byte("\n]")...) return result } - -// MarshalPolicy accurately marshals a policy to JSON, -// normal marshal would cause empty sub structs in -// policy to be non nil. -// TODO This needs to be removed. A simpler way to encode and decode Policy is needed. -func MarshalPolicy(policy v1.ClusterPolicy) []byte { - var rules []interface{} - policyRules := policy.GetRules() - rulesRaw, _ := json.Marshal(policyRules) - _ = json.Unmarshal(rulesRaw, &rules) - for i, r := range rules { - rule, _ := r.(map[string]interface{}) - - if reflect.DeepEqual(policyRules[i].Mutation, v1.Mutation{}) { - delete(rule, "mutate") - } - if reflect.DeepEqual(policyRules[i].Validation, v1.Validation{}) { - delete(rule, "validate") - } - if reflect.DeepEqual(policyRules[i].Generation, v1.Generation{}) { - delete(rule, "generate") - } - - rules[i] = rule - } - - var policyRepresentation = make(map[string]interface{}) - policyRaw, _ := json.Marshal(policy) - _ = json.Unmarshal(policyRaw, &policyRepresentation) - - specRepresentation, _ := policyRepresentation["spec"].(map[string]interface{}) - - specRepresentation["rules"] = rules - - policyRepresentation["spec"] = specRepresentation - - policyRaw, _ = json.Marshal(policyRepresentation) - - return policyRaw -} diff --git a/pkg/webhookconfig/configmanager.go b/pkg/webhookconfig/configmanager.go index cdaefe1944..5af9484cc1 100644 --- a/pkg/webhookconfig/configmanager.go +++ b/pkg/webhookconfig/configmanager.go @@ -441,17 +441,17 @@ func (m *webhookConfigManager) buildWebhooks(namespace string) (res []*webhook, spec := p.GetSpec() if spec.HasValidate() || spec.HasGenerate() { if spec.FailurePolicy != nil && *spec.FailurePolicy == kyverno.Ignore { - m.mergeWebhook(validateIgnore, &spec, true) + m.mergeWebhook(validateIgnore, p, true) } else { - m.mergeWebhook(validateFail, &spec, true) + m.mergeWebhook(validateFail, p, true) } } if spec.HasMutate() || spec.HasVerifyImages() { if spec.FailurePolicy != nil && *spec.FailurePolicy == kyverno.Ignore { - m.mergeWebhook(mutateIgnore, &spec, false) + m.mergeWebhook(mutateIgnore, p, false) } else { - m.mergeWebhook(mutateFail, &spec, false) + m.mergeWebhook(mutateFail, p, false) } } } @@ -734,9 +734,9 @@ func (m *webhookConfigManager) updateStatus(namespace, name string, ready bool) } // mergeWebhook merges the matching kinds of the policy to webhook.rule -func (m *webhookConfigManager) mergeWebhook(dst *webhook, spec *kyverno.Spec, updateValidate bool) { +func (m *webhookConfigManager) mergeWebhook(dst *webhook, policy policy, updateValidate bool) { matchedGVK := make([]string, 0) - for _, rule := range spec.GetRules() { + for _, rule := range autogen.ComputeRules(policy) { // matching kinds in generate policies need to be added to both webhook if rule.HasGenerate() { matchedGVK = append(matchedGVK, rule.MatchKinds()...) @@ -818,6 +818,7 @@ func (m *webhookConfigManager) mergeWebhook(dst *webhook, spec *kyverno.Spec, up dst.rule[apiVersions] = removeDuplicates(versions) dst.rule[resources] = removeDuplicates(rsrcs) + spec := policy.GetSpec() if spec.WebhookTimeoutSeconds != nil { if dst.maxWebhookTimeout < int64(*spec.WebhookTimeoutSeconds) { dst.maxWebhookTimeout = int64(*spec.WebhookTimeoutSeconds) @@ -850,7 +851,7 @@ func webhookKey(webhookKind, failurePolicy string) string { } func hasWildcard(spec *kyverno.Spec) bool { - for _, rule := range spec.GetRules() { + for _, rule := range spec.Rules { if kinds := rule.MatchKinds(); utils.ContainsString(kinds, "*") { return true } diff --git a/pkg/webhooks/common.go b/pkg/webhooks/common.go index 447d0f83cb..e1a9095648 100644 --- a/pkg/webhooks/common.go +++ b/pkg/webhooks/common.go @@ -7,6 +7,7 @@ import ( "github.com/go-logr/logr" wildcard "github.com/kyverno/go-wildcard" kyverno "github.com/kyverno/kyverno/api/kyverno/v1" + "github.com/kyverno/kyverno/pkg/autogen" "github.com/kyverno/kyverno/pkg/engine/response" engineutils "github.com/kyverno/kyverno/pkg/engine/utils" yamlv2 "gopkg.in/yaml.v2" @@ -142,7 +143,7 @@ func processResourceWithPatches(patch []byte, resource []byte, log logr.Logger) func containsRBACInfo(policies ...[]*kyverno.ClusterPolicy) bool { for _, policySlice := range policies { for _, policy := range policySlice { - for _, rule := range policy.GetRules() { + for _, rule := range autogen.ComputeRules(policy) { if checkForRBACInfo(rule) { return true } diff --git a/pkg/webhooks/generation.go b/pkg/webhooks/generation.go index a4ad2dd5cf..8a94e29bd8 100644 --- a/pkg/webhooks/generation.go +++ b/pkg/webhooks/generation.go @@ -11,6 +11,7 @@ import ( "github.com/go-logr/logr" kyverno "github.com/kyverno/kyverno/api/kyverno/v1" + "github.com/kyverno/kyverno/pkg/autogen" "github.com/kyverno/kyverno/pkg/common" "github.com/kyverno/kyverno/pkg/config" client "github.com/kyverno/kyverno/pkg/dclient" @@ -236,7 +237,7 @@ func (ws *WebhookServer) handleUpdateGenerateTargetResource(request *v1beta1.Adm return } - for _, rule := range policy.GetRules() { + for _, rule := range autogen.ComputeRules(policy) { if rule.Generation.Kind == targetSourceKind && rule.Generation.Name == targetSourceName { updatedRule, err := getGeneratedByResource(newRes, resLabels, ws.client, rule, logger) if err != nil { diff --git a/pkg/webhooks/policymutation.go b/pkg/webhooks/policymutation.go index 3b272e08b4..98c657dd4f 100644 --- a/pkg/webhooks/policymutation.go +++ b/pkg/webhooks/policymutation.go @@ -10,7 +10,6 @@ import ( logr "github.com/go-logr/logr" kyverno "github.com/kyverno/kyverno/api/kyverno/v1" "github.com/kyverno/kyverno/pkg/policymutation" - "github.com/kyverno/kyverno/pkg/toggle" v1beta1 "k8s.io/api/admission/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -43,7 +42,7 @@ func (ws *WebhookServer) policyMutation(request *v1beta1.AdmissionRequest) *v1be defer logger.V(3).Info("finished policy change mutation", "time", time.Since(startTime).String()) // Generate JSON Patches for defaults - patches, updateMsgs := policymutation.GenerateJSONPatchesForDefaults(policy, toggle.AutogenInternals, logger) + patches, updateMsgs := policymutation.GenerateJSONPatchesForDefaults(policy, logger) if len(patches) != 0 { patchType := v1beta1.PatchTypeJSONPatch return &v1beta1.AdmissionResponse{ diff --git a/pkg/webhooks/policymutation_test.go b/pkg/webhooks/policymutation_test.go index b20902bb85..43fb6f2adb 100644 --- a/pkg/webhooks/policymutation_test.go +++ b/pkg/webhooks/policymutation_test.go @@ -34,7 +34,7 @@ func TestGeneratePodControllerRule_NilAnnotation(t *testing.T) { var policy kyverno.ClusterPolicy assert.Assert(t, json.Unmarshal(policyRaw, &policy)) - patches, errs := policymutation.GeneratePodControllerRule(policy, false, log.Log) + patches, errs := policymutation.GeneratePodControllerRule(policy, log.Log) assert.Assert(t, len(errs) == 0) p, err := utils.ApplyPatches(policyRaw, patches) @@ -67,7 +67,7 @@ func TestGeneratePodControllerRule_PredefinedAnnotation(t *testing.T) { var policy kyverno.ClusterPolicy assert.Assert(t, json.Unmarshal(policyRaw, &policy)) - patches, errs := policymutation.GeneratePodControllerRule(policy, false, log.Log) + patches, errs := policymutation.GeneratePodControllerRule(policy, log.Log) assert.Assert(t, len(errs) == 0) assert.Assert(t, len(patches) == 1) } @@ -118,7 +118,7 @@ func TestGeneratePodControllerRule_DisableFeature(t *testing.T) { var policy kyverno.ClusterPolicy assert.Assert(t, json.Unmarshal(policyRaw, &policy)) - patches, errs := policymutation.GeneratePodControllerRule(policy, false, log.Log) + patches, errs := policymutation.GeneratePodControllerRule(policy, log.Log) assert.Assert(t, len(errs) == 0) assert.Assert(t, len(patches) == 0) } @@ -169,7 +169,7 @@ func TestGeneratePodControllerRule_Mutate(t *testing.T) { var policy kyverno.ClusterPolicy assert.Assert(t, json.Unmarshal(policyRaw, &policy)) - patches, errs := policymutation.GeneratePodControllerRule(policy, false, log.Log) + patches, errs := policymutation.GeneratePodControllerRule(policy, log.Log) assert.Assert(t, len(errs) == 0) p, err := utils.ApplyPatches(policyRaw, patches) @@ -303,7 +303,7 @@ func TestGeneratePodControllerRule_ExistOtherAnnotation(t *testing.T) { var policy kyverno.ClusterPolicy assert.Assert(t, json.Unmarshal(policyRaw, &policy)) - patches, errs := policymutation.GeneratePodControllerRule(policy, false, log.Log) + patches, errs := policymutation.GeneratePodControllerRule(policy, log.Log) assert.Assert(t, len(errs) == 0) p, err := utils.ApplyPatches(policyRaw, patches) @@ -375,7 +375,7 @@ func TestGeneratePodControllerRule_ValidateAnyPattern(t *testing.T) { var policy kyverno.ClusterPolicy assert.Assert(t, json.Unmarshal(policyRaw, &policy)) - patches, errs := policymutation.GeneratePodControllerRule(policy, false, log.Log) + patches, errs := policymutation.GeneratePodControllerRule(policy, log.Log) assert.Assert(t, len(errs) == 0) p, err := utils.ApplyPatches(policyRaw, patches) @@ -514,7 +514,7 @@ func TestGeneratePodControllerRule_ValidatePattern(t *testing.T) { var policy kyverno.ClusterPolicy // var policy, generatePolicy unstructured.Unstructured assert.Assert(t, json.Unmarshal(policyRaw, &policy)) - patches, errs := policymutation.GeneratePodControllerRule(policy, false, log.Log) + patches, errs := policymutation.GeneratePodControllerRule(policy, log.Log) assert.Assert(t, len(errs) == 0) p, err := utils.ApplyPatches(policyRaw, patches)