From 69f52b987922aea59f6b30a2f07a8857a4951b0c Mon Sep 17 00:00:00 2001 From: "gcp-cherry-pick-bot[bot]" <98988430+gcp-cherry-pick-bot[bot]@users.noreply.github.com> Date: Tue, 19 Dec 2023 10:51:47 +0000 Subject: [PATCH] fix: add `skipBackgoundRequests` to configure loop protection option (#9157) (#9207) * fix typo * add new attribute skipBackgroundRequests * move to per rule config * check flag * clean up * update docs * fix logger * add retryCount to ur.status * add chainsaw tests --------- Signed-off-by: ShutingZhao Co-authored-by: shuting --- api/kyverno/v1/rule_types.go | 7 + api/kyverno/v1beta1/updaterequest_types.go | 2 + api/kyverno/v2beta1/rule_types.go | 7 + .../kyverno/charts/crds/templates/crds.yaml | 58 +++++ .../data/crds/kyverno.io_clusterpolicies.yaml | 28 +++ .../data/crds/kyverno.io_policies.yaml | 28 +++ config/crds/kyverno.io_clusterpolicies.yaml | 28 +++ config/crds/kyverno.io_policies.yaml | 28 +++ config/crds/kyverno.io_updaterequests.yaml | 2 + config/install-latest-testing.yaml | 58 +++++ docs/user/crd/index.html | 36 ++++ pkg/background/common/util.go | 52 +---- pkg/background/generate/generate.go | 30 ++- pkg/background/mutate/mutate.go | 10 +- .../applyconfigurations/kyverno/v1/rule.go | 31 ++- .../kyverno/v1beta1/updaterequeststatus.go | 9 + .../kyverno/v2beta1/rule.go | 31 ++- pkg/webhooks/policy/handlers.go | 6 +- pkg/webhooks/resource/handlers.go | 6 +- pkg/webhooks/resource/updaterequest.go | 14 +- pkg/webhooks/resource/utils.go | 13 ++ .../README.md | 11 + .../chainsaw-step-01-apply-1-1.yaml | 198 ++++++++++++++++++ .../chainsaw-step-01-assert-1-1.yaml | 9 + .../chainsaw-step-02-apply-1-1.yaml | 13 ++ .../chainsaw-step-02-assert-1-1.yaml | 28 +++ .../chainsaw-test.yaml | 19 ++ .../README.md | 11 + .../chainsaw-step-01-apply-1-1.yaml | 198 ++++++++++++++++++ .../chainsaw-step-01-assert-1-1.yaml | 9 + .../chainsaw-step-02-apply-1-1.yaml | 13 ++ .../chainsaw-step-02-assert-1-1.yaml | 14 ++ .../chainsaw-step-02-error-1-1.yaml | 5 + .../chainsaw-test.yaml | 21 ++ .../new.yaml | 13 ++ 35 files changed, 958 insertions(+), 88 deletions(-) create mode 100644 test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-create-upon-generated-resource/README.md create mode 100755 test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-create-upon-generated-resource/chainsaw-step-01-apply-1-1.yaml create mode 100755 test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-create-upon-generated-resource/chainsaw-step-01-assert-1-1.yaml create mode 100755 test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-create-upon-generated-resource/chainsaw-step-02-apply-1-1.yaml create mode 100755 test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-create-upon-generated-resource/chainsaw-step-02-assert-1-1.yaml create mode 100755 test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-create-upon-generated-resource/chainsaw-test.yaml create mode 100644 test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/README.md create mode 100755 test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/chainsaw-step-01-apply-1-1.yaml create mode 100755 test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/chainsaw-step-01-assert-1-1.yaml create mode 100755 test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/chainsaw-step-02-apply-1-1.yaml create mode 100755 test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/chainsaw-step-02-assert-1-1.yaml create mode 100755 test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/chainsaw-step-02-error-1-1.yaml create mode 100755 test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/chainsaw-test.yaml create mode 100644 test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/new.yaml diff --git a/api/kyverno/v1/rule_types.go b/api/kyverno/v1/rule_types.go index c0d26db287..82cc0e8850 100644 --- a/api/kyverno/v1/rule_types.go +++ b/api/kyverno/v1/rule_types.go @@ -98,6 +98,13 @@ type Rule struct { // VerifyImages is used to verify image signatures and mutate them to add a digest // +optional VerifyImages []ImageVerification `json:"verifyImages,omitempty" yaml:"verifyImages,omitempty"` + + // SkipBackgroundRequests bypasses admission requests that are sent by the background controller. + // The default value is set to "true", it must be set to "false" to apply + // generate and mutateExisting rules to those requests. + // +kubebuilder:default=true + // +kubebuilder:validation:Optional + SkipBackgroundRequests bool `json:"skipBackgroundRequests,omitempty" yaml:"skipBackgroundRequests,omitempty"` } // HasMutate checks for mutate rule diff --git a/api/kyverno/v1beta1/updaterequest_types.go b/api/kyverno/v1beta1/updaterequest_types.go index fa0987f3d2..a5a07e8cd7 100644 --- a/api/kyverno/v1beta1/updaterequest_types.go +++ b/api/kyverno/v1beta1/updaterequest_types.go @@ -38,6 +38,8 @@ type UpdateRequestStatus struct { // This will track the resources that are updated by the generate Policy. // Will be used during clean up resources. GeneratedResources []kyvernov1.ResourceSpec `json:"generatedResources,omitempty" yaml:"generatedResources,omitempty"` + + RetryCount int `json:"retryCount,omitempty" yaml:"retryCount,omitempty"` } // +genclient diff --git a/api/kyverno/v2beta1/rule_types.go b/api/kyverno/v2beta1/rule_types.go index 5b76ef96e1..e956288acb 100644 --- a/api/kyverno/v2beta1/rule_types.go +++ b/api/kyverno/v2beta1/rule_types.go @@ -65,6 +65,13 @@ type Rule struct { // VerifyImages is used to verify image signatures and mutate them to add a digest // +optional VerifyImages []ImageVerification `json:"verifyImages,omitempty" yaml:"verifyImages,omitempty"` + + // SkipBackgroundRequests bypasses admission requests that are sent by the background controller. + // The default value is set to "true", it must be set to "false" to apply + // generate and mutateExisting rules to those requests. + // +kubebuilder:default=true + // +kubebuilder:validation:Optional + SkipBackgroundRequests bool `json:"skipBackgroundRequests,omitempty" yaml:"skipBackgroundRequests,omitempty"` } // HasMutate checks for mutate rule diff --git a/charts/kyverno/charts/crds/templates/crds.yaml b/charts/kyverno/charts/crds/templates/crds.yaml index b55666c232..4defa2ad27 100644 --- a/charts/kyverno/charts/crds/templates/crds.yaml +++ b/charts/kyverno/charts/crds/templates/crds.yaml @@ -8706,6 +8706,13 @@ spec: is supported for backwards compatibility but will be deprecated in the next major release. See: https://kyverno.io/docs/writing-policies/preconditions/' x-kubernetes-preserve-unknown-fields: true + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default value + is set to "true", it must be set to "false" to apply generate + and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: @@ -13140,6 +13147,13 @@ spec: is supported for backwards compatibility but will be deprecated in the next major release. See: https://kyverno.io/docs/writing-policies/preconditions/' x-kubernetes-preserve-unknown-fields: true + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default + value is set to "true", it must be set to "false" to apply + generate and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: @@ -17356,6 +17370,13 @@ spec: type: object type: array type: object + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default value + is set to "true", it must be set to "false" to apply generate + and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: @@ -21856,6 +21877,13 @@ spec: is supported for backwards compatibility but will be deprecated in the next major release. See: https://kyverno.io/docs/writing-policies/preconditions/' x-kubernetes-preserve-unknown-fields: true + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default + value is set to "true", it must be set to "false" to apply + generate and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: @@ -26438,6 +26466,13 @@ spec: is supported for backwards compatibility but will be deprecated in the next major release. See: https://kyverno.io/docs/writing-policies/preconditions/' x-kubernetes-preserve-unknown-fields: true + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default value + is set to "true", it must be set to "false" to apply generate + and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: @@ -30873,6 +30908,13 @@ spec: is supported for backwards compatibility but will be deprecated in the next major release. See: https://kyverno.io/docs/writing-policies/preconditions/' x-kubernetes-preserve-unknown-fields: true + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default + value is set to "true", it must be set to "false" to apply + generate and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: @@ -35090,6 +35132,13 @@ spec: type: object type: array type: object + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default value + is set to "true", it must be set to "false" to apply generate + and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: @@ -39590,6 +39639,13 @@ spec: is supported for backwards compatibility but will be deprecated in the next major release. See: https://kyverno.io/docs/writing-policies/preconditions/' x-kubernetes-preserve-unknown-fields: true + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default + value is set to "true", it must be set to "false" to apply + generate and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: @@ -43177,6 +43233,8 @@ spec: message: description: Specifies request status message. type: string + retryCount: + type: integer state: description: State represents state of the update request. type: string diff --git a/cmd/cli/kubectl-kyverno/data/crds/kyverno.io_clusterpolicies.yaml b/cmd/cli/kubectl-kyverno/data/crds/kyverno.io_clusterpolicies.yaml index 13ed761c4d..8f0fea113c 100644 --- a/cmd/cli/kubectl-kyverno/data/crds/kyverno.io_clusterpolicies.yaml +++ b/cmd/cli/kubectl-kyverno/data/crds/kyverno.io_clusterpolicies.yaml @@ -2410,6 +2410,13 @@ spec: is supported for backwards compatibility but will be deprecated in the next major release. See: https://kyverno.io/docs/writing-policies/preconditions/' x-kubernetes-preserve-unknown-fields: true + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default value + is set to "true", it must be set to "false" to apply generate + and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: @@ -6844,6 +6851,13 @@ spec: is supported for backwards compatibility but will be deprecated in the next major release. See: https://kyverno.io/docs/writing-policies/preconditions/' x-kubernetes-preserve-unknown-fields: true + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default + value is set to "true", it must be set to "false" to apply + generate and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: @@ -11060,6 +11074,13 @@ spec: type: object type: array type: object + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default value + is set to "true", it must be set to "false" to apply generate + and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: @@ -15560,6 +15581,13 @@ spec: is supported for backwards compatibility but will be deprecated in the next major release. See: https://kyverno.io/docs/writing-policies/preconditions/' x-kubernetes-preserve-unknown-fields: true + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default + value is set to "true", it must be set to "false" to apply + generate and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: diff --git a/cmd/cli/kubectl-kyverno/data/crds/kyverno.io_policies.yaml b/cmd/cli/kubectl-kyverno/data/crds/kyverno.io_policies.yaml index 656e9e423f..cf03f69018 100644 --- a/cmd/cli/kubectl-kyverno/data/crds/kyverno.io_policies.yaml +++ b/cmd/cli/kubectl-kyverno/data/crds/kyverno.io_policies.yaml @@ -2411,6 +2411,13 @@ spec: is supported for backwards compatibility but will be deprecated in the next major release. See: https://kyverno.io/docs/writing-policies/preconditions/' x-kubernetes-preserve-unknown-fields: true + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default value + is set to "true", it must be set to "false" to apply generate + and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: @@ -6846,6 +6853,13 @@ spec: is supported for backwards compatibility but will be deprecated in the next major release. See: https://kyverno.io/docs/writing-policies/preconditions/' x-kubernetes-preserve-unknown-fields: true + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default + value is set to "true", it must be set to "false" to apply + generate and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: @@ -11063,6 +11077,13 @@ spec: type: object type: array type: object + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default value + is set to "true", it must be set to "false" to apply generate + and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: @@ -15563,6 +15584,13 @@ spec: is supported for backwards compatibility but will be deprecated in the next major release. See: https://kyverno.io/docs/writing-policies/preconditions/' x-kubernetes-preserve-unknown-fields: true + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default + value is set to "true", it must be set to "false" to apply + generate and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: diff --git a/config/crds/kyverno.io_clusterpolicies.yaml b/config/crds/kyverno.io_clusterpolicies.yaml index 13ed761c4d..8f0fea113c 100644 --- a/config/crds/kyverno.io_clusterpolicies.yaml +++ b/config/crds/kyverno.io_clusterpolicies.yaml @@ -2410,6 +2410,13 @@ spec: is supported for backwards compatibility but will be deprecated in the next major release. See: https://kyverno.io/docs/writing-policies/preconditions/' x-kubernetes-preserve-unknown-fields: true + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default value + is set to "true", it must be set to "false" to apply generate + and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: @@ -6844,6 +6851,13 @@ spec: is supported for backwards compatibility but will be deprecated in the next major release. See: https://kyverno.io/docs/writing-policies/preconditions/' x-kubernetes-preserve-unknown-fields: true + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default + value is set to "true", it must be set to "false" to apply + generate and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: @@ -11060,6 +11074,13 @@ spec: type: object type: array type: object + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default value + is set to "true", it must be set to "false" to apply generate + and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: @@ -15560,6 +15581,13 @@ spec: is supported for backwards compatibility but will be deprecated in the next major release. See: https://kyverno.io/docs/writing-policies/preconditions/' x-kubernetes-preserve-unknown-fields: true + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default + value is set to "true", it must be set to "false" to apply + generate and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: diff --git a/config/crds/kyverno.io_policies.yaml b/config/crds/kyverno.io_policies.yaml index 656e9e423f..cf03f69018 100644 --- a/config/crds/kyverno.io_policies.yaml +++ b/config/crds/kyverno.io_policies.yaml @@ -2411,6 +2411,13 @@ spec: is supported for backwards compatibility but will be deprecated in the next major release. See: https://kyverno.io/docs/writing-policies/preconditions/' x-kubernetes-preserve-unknown-fields: true + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default value + is set to "true", it must be set to "false" to apply generate + and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: @@ -6846,6 +6853,13 @@ spec: is supported for backwards compatibility but will be deprecated in the next major release. See: https://kyverno.io/docs/writing-policies/preconditions/' x-kubernetes-preserve-unknown-fields: true + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default + value is set to "true", it must be set to "false" to apply + generate and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: @@ -11063,6 +11077,13 @@ spec: type: object type: array type: object + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default value + is set to "true", it must be set to "false" to apply generate + and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: @@ -15563,6 +15584,13 @@ spec: is supported for backwards compatibility but will be deprecated in the next major release. See: https://kyverno.io/docs/writing-policies/preconditions/' x-kubernetes-preserve-unknown-fields: true + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default + value is set to "true", it must be set to "false" to apply + generate and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: diff --git a/config/crds/kyverno.io_updaterequests.yaml b/config/crds/kyverno.io_updaterequests.yaml index f1ed657058..c1ff4500e2 100644 --- a/config/crds/kyverno.io_updaterequests.yaml +++ b/config/crds/kyverno.io_updaterequests.yaml @@ -392,6 +392,8 @@ spec: message: description: Specifies request status message. type: string + retryCount: + type: integer state: description: State represents state of the update request. type: string diff --git a/config/install-latest-testing.yaml b/config/install-latest-testing.yaml index dc1a914b2d..86c3624108 100644 --- a/config/install-latest-testing.yaml +++ b/config/install-latest-testing.yaml @@ -8925,6 +8925,13 @@ spec: is supported for backwards compatibility but will be deprecated in the next major release. See: https://kyverno.io/docs/writing-policies/preconditions/' x-kubernetes-preserve-unknown-fields: true + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default value + is set to "true", it must be set to "false" to apply generate + and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: @@ -13359,6 +13366,13 @@ spec: is supported for backwards compatibility but will be deprecated in the next major release. See: https://kyverno.io/docs/writing-policies/preconditions/' x-kubernetes-preserve-unknown-fields: true + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default + value is set to "true", it must be set to "false" to apply + generate and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: @@ -17575,6 +17589,13 @@ spec: type: object type: array type: object + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default value + is set to "true", it must be set to "false" to apply generate + and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: @@ -22075,6 +22096,13 @@ spec: is supported for backwards compatibility but will be deprecated in the next major release. See: https://kyverno.io/docs/writing-policies/preconditions/' x-kubernetes-preserve-unknown-fields: true + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default + value is set to "true", it must be set to "false" to apply + generate and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: @@ -26659,6 +26687,13 @@ spec: is supported for backwards compatibility but will be deprecated in the next major release. See: https://kyverno.io/docs/writing-policies/preconditions/' x-kubernetes-preserve-unknown-fields: true + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default value + is set to "true", it must be set to "false" to apply generate + and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: @@ -31094,6 +31129,13 @@ spec: is supported for backwards compatibility but will be deprecated in the next major release. See: https://kyverno.io/docs/writing-policies/preconditions/' x-kubernetes-preserve-unknown-fields: true + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default + value is set to "true", it must be set to "false" to apply + generate and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: @@ -35311,6 +35353,13 @@ spec: type: object type: array type: object + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default value + is set to "true", it must be set to "false" to apply generate + and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: @@ -39811,6 +39860,13 @@ spec: is supported for backwards compatibility but will be deprecated in the next major release. See: https://kyverno.io/docs/writing-policies/preconditions/' x-kubernetes-preserve-unknown-fields: true + skipBackgroundRequests: + default: true + description: SkipBackgroundRequests bypasses admission requests + that are sent by the background controller. The default + value is set to "true", it must be set to "false" to apply + generate and mutateExisting rules to those requests. + type: boolean validate: description: Validation is used to validate matching resources. properties: @@ -43402,6 +43458,8 @@ spec: message: description: Specifies request status message. type: string + retryCount: + type: integer state: description: State represents state of the update request. type: string diff --git a/docs/user/crd/index.html b/docs/user/crd/index.html index 44496d6a4a..52bf1f66f2 100644 --- a/docs/user/crd/index.html +++ b/docs/user/crd/index.html @@ -3496,6 +3496,19 @@ Generation

VerifyImages is used to verify image signatures and mutate them to add a digest

+ + +skipBackgroundRequests
+ +bool + + + +

SkipBackgroundRequests bypasses admission requests that are sent by the background controller. +The default value is set to “true”, it must be set to “false” to apply +generate and mutateExisting rules to those requests.

+ +
@@ -5411,6 +5424,16 @@ string Will be used during clean up resources.

+ + +retryCount
+ +int + + + + +
@@ -7739,6 +7762,19 @@ Generation

VerifyImages is used to verify image signatures and mutate them to add a digest

+ + +skipBackgroundRequests
+ +bool + + + +

SkipBackgroundRequests bypasses admission requests that are sent by the background controller. +The default value is set to “true”, it must be set to “false” to apply +generate and mutateExisting rules to those requests.

+ +
diff --git a/pkg/background/common/util.go b/pkg/background/common/util.go index 2b5663791d..3a9db924d0 100644 --- a/pkg/background/common/util.go +++ b/pkg/background/common/util.go @@ -2,8 +2,6 @@ package common import ( "context" - "fmt" - "strconv" kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1" kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1" @@ -30,6 +28,11 @@ func UpdateStatus(client versioned.Interface, urLister kyvernov1beta1listers.Upd latest.Status.GeneratedResources = genResources } + if state == kyvernov1beta1.Failed { + if latest, err = retryOrDeleteOnFailure(client, latest, 3); err != nil { + return nil, err + } + } new, err := client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).UpdateStatus(context.TODO(), latest, metav1.UpdateOptions{}) if err != nil { return ur, errors.Wrapf(err, "failed to update ur status to %s", string(state)) @@ -56,50 +59,17 @@ func ResourceSpecFromUnstructured(obj unstructured.Unstructured) kyvernov1.Resou } } -func increaseRetryAnnotation(ur *kyvernov1beta1.UpdateRequest) (int, map[string]string, error) { - urAnnotations := ur.Annotations - if len(urAnnotations) == 0 { - urAnnotations = map[string]string{ - kyvernov1beta1.URGenerateRetryCountAnnotation: "1", - } - } - - retry := 1 - val, ok := urAnnotations[kyvernov1beta1.URGenerateRetryCountAnnotation] - if !ok { - urAnnotations[kyvernov1beta1.URGenerateRetryCountAnnotation] = "1" - } else { - retryUint, err := strconv.ParseUint(val, 10, 64) - if err != nil { - return retry, urAnnotations, fmt.Errorf("unable to convert retry-count %v: %w", val, err) - } - retry = int(retryUint) - retry += 1 - incrementedRetryString := strconv.Itoa(retry) - urAnnotations[kyvernov1beta1.URGenerateRetryCountAnnotation] = incrementedRetryString - } - - return retry, urAnnotations, nil -} - -func UpdateRetryAnnotation(kyvernoClient versioned.Interface, ur *kyvernov1beta1.UpdateRequest) error { - retry, urAnnotations, err := increaseRetryAnnotation(ur) - if err != nil { - return err - } - if retry > 3 { +func retryOrDeleteOnFailure(kyvernoClient versioned.Interface, ur *kyvernov1beta1.UpdateRequest, limit int) (latest *kyvernov1beta1.UpdateRequest, err error) { + if ur.Status.RetryCount > limit { err = kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).Delete(context.TODO(), ur.GetName(), metav1.DeleteOptions{}) if err != nil { - return errors.Wrapf(err, "exceeds retry limit, failed to delete the UR: %s, retry: %v, resourceVersion: %s", ur.Name, retry, ur.GetResourceVersion()) + return nil, errors.Wrapf(err, "exceeds retry limit, failed to delete the UR: %s, retry: %v, resourceVersion: %s", ur.Name, ur.Status.RetryCount, ur.GetResourceVersion()) } } else { - ur.SetAnnotations(urAnnotations) - _, err = kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).Update(context.TODO(), ur, metav1.UpdateOptions{}) - if err != nil { - return errors.Wrapf(err, "failed to update annotation in update request: %s for the resource, retry: %v, resourceVersion %s, annotations: %v", ur.Name, retry, ur.GetResourceVersion(), urAnnotations) - } + ur.Status.RetryCount++ } - return nil + + return ur, nil } func FindDownstream(client dclient.Interface, apiVersion, kind string, labels map[string]string) (*unstructured.UnstructuredList, error) { diff --git a/pkg/background/generate/generate.go b/pkg/background/generate/generate.go index 21b96f1ab0..5f56f06cbe 100644 --- a/pkg/background/generate/generate.go +++ b/pkg/background/generate/generate.go @@ -22,6 +22,7 @@ import ( engineapi "github.com/kyverno/kyverno/pkg/engine/api" enginecontext "github.com/kyverno/kyverno/pkg/engine/context" "github.com/kyverno/kyverno/pkg/engine/jmespath" + "github.com/kyverno/kyverno/pkg/engine/validate" "github.com/kyverno/kyverno/pkg/engine/variables" "github.com/kyverno/kyverno/pkg/event" admissionutils "github.com/kyverno/kyverno/pkg/utils/admission" @@ -100,9 +101,10 @@ func (c *GenerateController) ProcessUR(ur *kyvernov1beta1.UpdateRequest) error { trigger, err := c.getTrigger(ur.Spec) if err != nil { logger.V(3).Info("the trigger resource does not exist or is pending creation, re-queueing", "details", err.Error()) - if err := common.UpdateRetryAnnotation(c.kyvernoClient, ur); err != nil { + if err := updateStatus(c.statusControl, *ur, err, nil); err != nil { return err } + return nil } if trigger == nil { @@ -112,19 +114,27 @@ func (c *GenerateController) ProcessUR(ur *kyvernov1beta1.UpdateRequest) error { namespaceLabels := engineutils.GetNamespaceSelectorsFromNamespaceLister(trigger.GetKind(), trigger.GetNamespace(), c.nsLister, logger) genResources, err = c.applyGenerate(*trigger, *ur, namespaceLabels) if err != nil { - // Need not update the status when policy doesn't apply on resource, because all the update requests are removed by the cleanup controller if strings.Contains(err.Error(), doesNotApply) { - logger.V(4).Info("skipping updating status of update request") - return nil + ur.Status.State = kyvernov1beta1.Completed + logger.V(4).Info(fmt.Sprintf("%s, updating UR status to Completed", err.Error())) + _, err := c.kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).UpdateStatus(context.TODO(), ur, metav1.UpdateOptions{}) + return err + } + + policy, err := c.getPolicySpec(*ur) + if err != nil { + return err } - policy, _ := c.getPolicySpec(*ur) events := event.NewBackgroundFailedEvent(err, policy, ur.Spec.Rule, event.GeneratePolicyController, kyvernov1.ResourceSpec{Kind: trigger.GetKind(), Namespace: trigger.GetNamespace(), Name: trigger.GetName()}) c.eventGen.Add(events...) } - return updateStatus(c.statusControl, *ur, err, genResources) + if err = updateStatus(c.statusControl, *ur, err, genResources); err != nil { + return err + } + return err } const doesNotApply = "policy does not apply to resource" @@ -365,8 +375,7 @@ func (c *GenerateController) ApplyGeneratePolicy(log logr.Logger, policyContext genResource, err = applyRule(log, c.client, rule, resource, jsonContext, policy, ur) if err != nil { - log.Error(err, "failed to apply generate rule", "policy", policy.GetName(), - "rule", rule.Name, "resource", resource.GetName(), "suggestion", "users need to grant Kyverno's service account additional privileges") + log.Error(err, "failed to apply generate rule", "policy", policy.GetName(), "rule", rule.Name, "resource", resource.GetName()) return nil, err } ruleNameToProcessingTime[rule.Name] = time.Since(startTime) @@ -452,6 +461,11 @@ func applyRule(log logr.Logger, client dclient.Interface, rule kyvernov1.Rule, t } else { if !rule.Generation.Synchronize { logger.V(4).Info("synchronize disabled, skip syncing changes") + continue + } + if err := validate.MatchPattern(logger, generatedObj.Object, newResource.Object); err == nil { + logger.V(4).Info("patterns match, skipping updates") + continue } logger.V(4).Info("updating existing resource") if targetMeta.GetAPIVersion() == "" { diff --git a/pkg/background/mutate/mutate.go b/pkg/background/mutate/mutate.go index 90dfdf36f9..281b5d659b 100644 --- a/pkg/background/mutate/mutate.go +++ b/pkg/background/mutate/mutate.go @@ -97,9 +97,8 @@ func (c *mutateExistingController) ProcessUR(ur *kyvernov1beta1.UpdateRequest) e trigger, err = common.GetResource(c.client, ur.Spec, c.log) if err != nil || trigger == nil { logger.WithName(rule.Name).Error(err, "failed to get trigger resource") - errs = append(errs, err) - if err := common.UpdateRetryAnnotation(c.kyvernoClient, ur); err != nil { - errs = append(errs, err) + if err := updateURStatus(c.statusControl, *ur, err); err != nil { + return err } continue } @@ -109,9 +108,8 @@ func (c *mutateExistingController) ProcessUR(ur *kyvernov1beta1.UpdateRequest) e if err != nil || trigger == nil { if admissionRequest.SubResource == "" { logger.WithName(rule.Name).Error(err, "failed to get trigger resource") - errs = append(errs, err) - if err := common.UpdateRetryAnnotation(c.kyvernoClient, ur); err != nil { - errs = append(errs, err) + if err := updateURStatus(c.statusControl, *ur, err); err != nil { + return err } continue } else { diff --git a/pkg/client/applyconfigurations/kyverno/v1/rule.go b/pkg/client/applyconfigurations/kyverno/v1/rule.go index cd21d724e9..dbf9f622bf 100644 --- a/pkg/client/applyconfigurations/kyverno/v1/rule.go +++ b/pkg/client/applyconfigurations/kyverno/v1/rule.go @@ -27,17 +27,18 @@ import ( // RuleApplyConfiguration represents an declarative configuration of the Rule type for use // with apply. type RuleApplyConfiguration struct { - Name *string `json:"name,omitempty"` - Context []ContextEntryApplyConfiguration `json:"context,omitempty"` - MatchResources *MatchResourcesApplyConfiguration `json:"match,omitempty"` - ExcludeResources *MatchResourcesApplyConfiguration `json:"exclude,omitempty"` - ImageExtractors *kyvernov1.ImageExtractorConfigs `json:"imageExtractors,omitempty"` - RawAnyAllConditions *apiextensionsv1.JSON `json:"preconditions,omitempty"` - CELPreconditions []v1alpha1.MatchCondition `json:"celPreconditions,omitempty"` - Mutation *MutationApplyConfiguration `json:"mutate,omitempty"` - Validation *ValidationApplyConfiguration `json:"validate,omitempty"` - Generation *GenerationApplyConfiguration `json:"generate,omitempty"` - VerifyImages []ImageVerificationApplyConfiguration `json:"verifyImages,omitempty"` + Name *string `json:"name,omitempty"` + Context []ContextEntryApplyConfiguration `json:"context,omitempty"` + MatchResources *MatchResourcesApplyConfiguration `json:"match,omitempty"` + ExcludeResources *MatchResourcesApplyConfiguration `json:"exclude,omitempty"` + ImageExtractors *kyvernov1.ImageExtractorConfigs `json:"imageExtractors,omitempty"` + RawAnyAllConditions *apiextensionsv1.JSON `json:"preconditions,omitempty"` + CELPreconditions []v1alpha1.MatchCondition `json:"celPreconditions,omitempty"` + Mutation *MutationApplyConfiguration `json:"mutate,omitempty"` + Validation *ValidationApplyConfiguration `json:"validate,omitempty"` + Generation *GenerationApplyConfiguration `json:"generate,omitempty"` + VerifyImages []ImageVerificationApplyConfiguration `json:"verifyImages,omitempty"` + SkipBackgroundRequests *bool `json:"skipBackgroundRequests,omitempty"` } // RuleApplyConfiguration constructs an declarative configuration of the Rule type for use with @@ -145,3 +146,11 @@ func (b *RuleApplyConfiguration) WithVerifyImages(values ...*ImageVerificationAp } return b } + +// WithSkipBackgroundRequests sets the SkipBackgroundRequests field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the SkipBackgroundRequests field is set to the value of the last call. +func (b *RuleApplyConfiguration) WithSkipBackgroundRequests(value bool) *RuleApplyConfiguration { + b.SkipBackgroundRequests = &value + return b +} diff --git a/pkg/client/applyconfigurations/kyverno/v1beta1/updaterequeststatus.go b/pkg/client/applyconfigurations/kyverno/v1beta1/updaterequeststatus.go index 9d9fa62ced..f618029624 100644 --- a/pkg/client/applyconfigurations/kyverno/v1beta1/updaterequeststatus.go +++ b/pkg/client/applyconfigurations/kyverno/v1beta1/updaterequeststatus.go @@ -30,6 +30,7 @@ type UpdateRequestStatusApplyConfiguration struct { State *v1beta1.UpdateRequestState `json:"state,omitempty"` Message *string `json:"message,omitempty"` GeneratedResources []v1.ResourceSpecApplyConfiguration `json:"generatedResources,omitempty"` + RetryCount *int `json:"retryCount,omitempty"` } // UpdateRequestStatusApplyConfiguration constructs an declarative configuration of the UpdateRequestStatus type for use with @@ -74,3 +75,11 @@ func (b *UpdateRequestStatusApplyConfiguration) WithGeneratedResources(values .. } return b } + +// WithRetryCount sets the RetryCount field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the RetryCount field is set to the value of the last call. +func (b *UpdateRequestStatusApplyConfiguration) WithRetryCount(value int) *UpdateRequestStatusApplyConfiguration { + b.RetryCount = &value + return b +} diff --git a/pkg/client/applyconfigurations/kyverno/v2beta1/rule.go b/pkg/client/applyconfigurations/kyverno/v2beta1/rule.go index a0de73193c..2fe65b89d0 100644 --- a/pkg/client/applyconfigurations/kyverno/v2beta1/rule.go +++ b/pkg/client/applyconfigurations/kyverno/v2beta1/rule.go @@ -27,17 +27,18 @@ import ( // RuleApplyConfiguration represents an declarative configuration of the Rule type for use // with apply. type RuleApplyConfiguration struct { - Name *string `json:"name,omitempty"` - Context []v1.ContextEntryApplyConfiguration `json:"context,omitempty"` - MatchResources *MatchResourcesApplyConfiguration `json:"match,omitempty"` - ExcludeResources *MatchResourcesApplyConfiguration `json:"exclude,omitempty"` - ImageExtractors *kyvernov1.ImageExtractorConfigs `json:"imageExtractors,omitempty"` - RawAnyAllConditions *AnyAllConditionsApplyConfiguration `json:"preconditions,omitempty"` - CELPreconditions []admissionregistrationv1.MatchCondition `json:"celPreconditions,omitempty"` - Mutation *v1.MutationApplyConfiguration `json:"mutate,omitempty"` - Validation *ValidationApplyConfiguration `json:"validate,omitempty"` - Generation *v1.GenerationApplyConfiguration `json:"generate,omitempty"` - VerifyImages []ImageVerificationApplyConfiguration `json:"verifyImages,omitempty"` + Name *string `json:"name,omitempty"` + Context []v1.ContextEntryApplyConfiguration `json:"context,omitempty"` + MatchResources *MatchResourcesApplyConfiguration `json:"match,omitempty"` + ExcludeResources *MatchResourcesApplyConfiguration `json:"exclude,omitempty"` + ImageExtractors *kyvernov1.ImageExtractorConfigs `json:"imageExtractors,omitempty"` + RawAnyAllConditions *AnyAllConditionsApplyConfiguration `json:"preconditions,omitempty"` + CELPreconditions []admissionregistrationv1.MatchCondition `json:"celPreconditions,omitempty"` + Mutation *v1.MutationApplyConfiguration `json:"mutate,omitempty"` + Validation *ValidationApplyConfiguration `json:"validate,omitempty"` + Generation *v1.GenerationApplyConfiguration `json:"generate,omitempty"` + VerifyImages []ImageVerificationApplyConfiguration `json:"verifyImages,omitempty"` + SkipBackgroundRequests *bool `json:"skipBackgroundRequests,omitempty"` } // RuleApplyConfiguration constructs an declarative configuration of the Rule type for use with @@ -145,3 +146,11 @@ func (b *RuleApplyConfiguration) WithVerifyImages(values ...*ImageVerificationAp } return b } + +// WithSkipBackgroundRequests sets the SkipBackgroundRequests field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the SkipBackgroundRequests field is set to the value of the last call. +func (b *RuleApplyConfiguration) WithSkipBackgroundRequests(value bool) *RuleApplyConfiguration { + b.SkipBackgroundRequests = &value + return b +} diff --git a/pkg/webhooks/policy/handlers.go b/pkg/webhooks/policy/handlers.go index e05199eff5..e2d0b1dece 100644 --- a/pkg/webhooks/policy/handlers.go +++ b/pkg/webhooks/policy/handlers.go @@ -14,13 +14,13 @@ import ( type policyHandlers struct { client dclient.Interface - backgroungServiceAccountName string + backgroundServiceAccountName string } func NewHandlers(client dclient.Interface, serviceaccount string) webhooks.PolicyHandlers { return &policyHandlers{ client: client, - backgroungServiceAccountName: serviceaccount, + backgroundServiceAccountName: serviceaccount, } } @@ -30,7 +30,7 @@ func (h *policyHandlers) Validate(ctx context.Context, logger logr.Logger, reque logger.Error(err, "failed to unmarshal policies from admission request") return admissionutils.Response(request.UID, err) } - warnings, err := policyvalidate.Validate(policy, oldPolicy, h.client, false, h.backgroungServiceAccountName) + warnings, err := policyvalidate.Validate(policy, oldPolicy, h.client, false, h.backgroundServiceAccountName) if err != nil { logger.Error(err, "policy validation errors") } diff --git a/pkg/webhooks/resource/handlers.go b/pkg/webhooks/resource/handlers.go index 499cb11dd2..cac3653da3 100644 --- a/pkg/webhooks/resource/handlers.go +++ b/pkg/webhooks/resource/handlers.go @@ -56,7 +56,7 @@ type resourceHandlers struct { pcBuilder webhookutils.PolicyContextBuilder admissionReports bool - backgroungServiceAccountName string + backgroundServiceAccountName string } func NewHandlers( @@ -73,7 +73,7 @@ func NewHandlers( urGenerator webhookgenerate.Generator, eventGen event.Interface, admissionReports bool, - backgroungServiceAccountName string, + backgroundServiceAccountName string, jp jmespath.Interface, ) webhooks.ResourceHandlers { return &resourceHandlers{ @@ -91,7 +91,7 @@ func NewHandlers( eventGen: eventGen, pcBuilder: webhookutils.NewPolicyContextBuilder(configuration, jp), admissionReports: admissionReports, - backgroungServiceAccountName: backgroungServiceAccountName, + backgroundServiceAccountName: backgroundServiceAccountName, } } diff --git a/pkg/webhooks/resource/updaterequest.go b/pkg/webhooks/resource/updaterequest.go index 3b037f76c7..e3a34175eb 100644 --- a/pkg/webhooks/resource/updaterequest.go +++ b/pkg/webhooks/resource/updaterequest.go @@ -17,9 +17,6 @@ import ( // handleBackgroundApplies applies generate and mutateExisting policies, and creates update requests for background reconcile func (h *resourceHandlers) handleBackgroundApplies(ctx context.Context, logger logr.Logger, request admissionv1.AdmissionRequest, policyContext *engine.PolicyContext, generatePolicies, mutatePolicies []kyvernov1.PolicyInterface, ts time.Time) { - if h.backgroungServiceAccountName == policyContext.AdmissionInfo().AdmissionUserInfo.Username { - return - } go h.handleMutateExisting(ctx, logger, request, mutatePolicies, policyContext, ts) h.handleGenerate(ctx, logger, request, generatePolicies, policyContext, ts) } @@ -34,10 +31,12 @@ func (h *resourceHandlers) handleMutateExisting(ctx context.Context, logger logr if !policy.GetSpec().IsMutateExisting() { continue } + + policyNew := skipBackgroundRequests(policy, logger, h.backgroundServiceAccountName, policyContext.AdmissionInfo().AdmissionUserInfo.Username) logger.V(4).Info("update request for mutateExisting policy") var rules []engineapi.RuleResponse - policyContext := policyContext.WithPolicy(policy) + policyContext := policyContext.WithPolicy(policyNew) engineResponse := h.engine.ApplyBackgroundChecks(ctx, policyContext) for _, rule := range engineResponse.PolicyResponse.Rules { @@ -73,5 +72,10 @@ func (h *resourceHandlers) handleMutateExisting(ctx context.Context, logger logr func (h *resourceHandlers) handleGenerate(ctx context.Context, logger logr.Logger, request admissionv1.AdmissionRequest, generatePolicies []kyvernov1.PolicyInterface, policyContext *engine.PolicyContext, ts time.Time) { gh := generation.NewGenerationHandler(logger, h.engine, h.client, h.kyvernoClient, h.nsLister, h.urLister, h.cpolLister, h.polLister, h.urGenerator, h.eventGen, h.metricsConfig) - go gh.Handle(ctx, request, generatePolicies, policyContext) + var policies []kyvernov1.PolicyInterface + for _, p := range generatePolicies { + new := skipBackgroundRequests(p, logger, h.backgroundServiceAccountName, policyContext.AdmissionInfo().AdmissionUserInfo.Username) + policies = append(policies, new) + } + go gh.Handle(ctx, request, policies, policyContext) } diff --git a/pkg/webhooks/resource/utils.go b/pkg/webhooks/resource/utils.go index cdcedd0e63..c7008f2f0b 100644 --- a/pkg/webhooks/resource/utils.go +++ b/pkg/webhooks/resource/utils.go @@ -100,3 +100,16 @@ func transform(admissionRequestInfo kyvernov1beta1.AdmissionRequestInfoObject, u return urs } + +func skipBackgroundRequests(policy kyvernov1.PolicyInterface, logger logr.Logger, bgsaDesired, bgsaActual string) kyvernov1.PolicyInterface { + policyNew := policy.CreateDeepCopy() + policyNew.GetSpec().Rules = nil + for _, rule := range policy.GetSpec().Rules { + if rule.SkipBackgroundRequests && (bgsaDesired == bgsaActual) { + continue + } + logger.V(4).Info("applying background rule", "rule", rule.Name, "skipBackgroundRequests", rule.SkipBackgroundRequests, "backgroundSaDesired", bgsaDesired, "backgroundSaActual", bgsaActual) + policyNew.GetSpec().Rules = append(policyNew.GetSpec().Rules, *rule.DeepCopy()) + } + return policyNew +} diff --git a/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-create-upon-generated-resource/README.md b/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-create-upon-generated-resource/README.md new file mode 100644 index 0000000000..49b9a456d2 --- /dev/null +++ b/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-create-upon-generated-resource/README.md @@ -0,0 +1,11 @@ +## Description + +This test checks the generate rule to be applied on Kyverno generated resources when `skipBackgroundRequests` is disabled. + +## Expected Behavior + +The serviceaccount is created when Kyverno creates a new secret. + +## Reference Issue(s) + +https://github.com/kyverno/kyverno/issues/9131 diff --git a/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-create-upon-generated-resource/chainsaw-step-01-apply-1-1.yaml b/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-create-upon-generated-resource/chainsaw-step-01-apply-1-1.yaml new file mode 100755 index 0000000000..5dea128479 --- /dev/null +++ b/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-create-upon-generated-resource/chainsaw-step-01-apply-1-1.yaml @@ -0,0 +1,198 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/component: background-controller + app.kubernetes.io/instance: kyverno + app.kubernetes.io/part-of: kyverno + name: kyverno:background-controller:additional +rules: +- apiGroups: + - "" + resources: + - "" + verbs: + - create + - update + - patch + - delete + - get + - list +- apiGroups: + - "" + resources: + - serviceaccounts + verbs: + - create + - update + - patch + - delete +--- +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: cpol-data-sync-create-upon-generated-resource +spec: + rules: + - generate: + apiVersion: v1 + data: + kind: Secret + metadata: + name: otel-collector-signalfx-config + stringData: + otel-collector-signalfx-config: | + service: + extensions: + - health_check + - http_forwarder + pipelines: + metrics: + receivers: + # but actually, it's a scraper + - prometheus + processors: + - batch + - metricstransform + - k8sattributes + - resourcedetection + exporters: + - signalfx + - logging + telemetry: + metrics: + address: 0.0.0.0:8888 + receivers: + prometheus: + config: + scrape_configs: + - job_name: k8s + kubernetes_sd_configs: + - role: pod + namespaces: + own_namespace: true + # todo: needs to be replaced by Kyverno + relabel_configs: + # Only keep the discovered targets that has the label otel.collector.signalfx/scrape + # Only keep the discovered targets that has the label otel.collector.signalfx/scrape + - action: keep + regex: "true" + source_labels: + - __meta_kubernetes_pod_label_otel_collector_signalfx_scrape + # Add + - action: replace + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $$1:$$2 + source_labels: + - __address__ + - __meta_kubernetes_pod_label_otel_collector_signalfx_port + target_label: __address__ + - action: replace + regex: (.+) + source_labels: + - __meta_kubernetes_pod_annotation_otel_collector_signalfx_metric_path + target_label: __metrics_path__ + - action: replace + regex: (.*)-.*-.*$ + source_labels: + - __meta_kubernetes_pod_name + target_label: deployment + - action: replace + source_labels: + - __meta_kubernetes_namespace + target_label: kubernetes_namespace + - action: replace + source_labels: + - __meta_kubernetes_pod_name + target_label: kubernetes_pod_name + - action: replace + source_labels: + - __meta_kubernetes_pod_container_name + target_label: kubernetes_container_name + scrape_interval: 10s + # Process the datapoints, enrich with more labels + processors: + attributes/newenvironment: + actions: + - action: insert + key: environment + value: managed-gke-dev + batch: {} + k8sattributes: + extract: + metadata: + - podName + - podUID + - namespace + - cluster + - node + passthrough: false + filter: + namespace: "{{request.object.metadata.namespace}}" + memory_limiter: + check_interval: 5s + limit_mib: 1638 + spike_limit_mib: 512 + metricstransform: + transforms: + - action: update + include: .* + match_type: regexp + operations: + - action: add_label + new_label: metric_source + new_value: managed_gke + - action: add_label + new_label: managed_gke + new_value: "true" + - action: add_label + new_label: kubernetes_cluster + new_value: ccoe-europe-west4-dev-1 + resourcedetection: + detectors: + - system + override: true + exporters: + signalfx: + access_token: "{{request.object.data.auth_token | base64_decode(@) || 'BACKGROUND'}}" + access_token_passthrough: true + realm: eu0 + logging: + loglevel: info + extensions: + health_check: + endpoint: 0.0.0.0:13133 + http_forwarder: + egress: + endpoint: https://api.eu0.signalfx.com + memory_ballast: {} + zpages: null + type: Opaque + kind: Secret + name: otel-collector-signalfx-secret + namespace: '{{request.object.metadata.namespace}}' + synchronize: true + match: + any: + - resources: + kinds: + - Secret + names: + - otel-collector-signalfx-token + name: generate-otel-secret-config + skipBackgroundRequests: true + - generate: + apiVersion: v1 + kind: ServiceAccount + name: otel-collector-signalfx-sa + namespace: '{{request.object.metadata.namespace}}' + synchronize: true + match: + any: + - resources: + kinds: + - Secret + names: + - otel-collector-signalfx-secret + name: generate-otel-sa + skipBackgroundRequests: false \ No newline at end of file diff --git a/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-create-upon-generated-resource/chainsaw-step-01-assert-1-1.yaml b/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-create-upon-generated-resource/chainsaw-step-01-assert-1-1.yaml new file mode 100755 index 0000000000..12939cb668 --- /dev/null +++ b/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-create-upon-generated-resource/chainsaw-step-01-assert-1-1.yaml @@ -0,0 +1,9 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: cpol-data-sync-create-upon-generated-resource +status: + conditions: + - reason: Succeeded + status: "True" + type: Ready diff --git a/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-create-upon-generated-resource/chainsaw-step-02-apply-1-1.yaml b/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-create-upon-generated-resource/chainsaw-step-02-apply-1-1.yaml new file mode 100755 index 0000000000..5287b994f8 --- /dev/null +++ b/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-create-upon-generated-resource/chainsaw-step-02-apply-1-1.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: cpol-data-sync-create-upon-generated-resource-ns +--- +apiVersion: v1 +kind: Secret +metadata: + name: otel-collector-signalfx-token + namespace: cpol-data-sync-create-upon-generated-resource-ns +data: + auth_token: YmFy +type: Opaque diff --git a/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-create-upon-generated-resource/chainsaw-step-02-assert-1-1.yaml b/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-create-upon-generated-resource/chainsaw-step-02-assert-1-1.yaml new file mode 100755 index 0000000000..35cad808ce --- /dev/null +++ b/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-create-upon-generated-resource/chainsaw-step-02-assert-1-1.yaml @@ -0,0 +1,28 @@ +apiVersion: v1 +kind: Secret +metadata: + labels: + app.kubernetes.io/managed-by: kyverno + generate.kyverno.io/policy-name: cpol-data-sync-create-upon-generated-resource + generate.kyverno.io/rule-name: generate-otel-secret-config + generate.kyverno.io/trigger-group: "" + generate.kyverno.io/trigger-kind: Secret + generate.kyverno.io/trigger-namespace: cpol-data-sync-create-upon-generated-resource-ns + generate.kyverno.io/trigger-version: v1 + name: otel-collector-signalfx-secret + namespace: cpol-data-sync-create-upon-generated-resource-ns +type: Opaque +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app.kubernetes.io/managed-by: kyverno + generate.kyverno.io/policy-name: cpol-data-sync-create-upon-generated-resource + generate.kyverno.io/rule-name: generate-otel-sa + generate.kyverno.io/trigger-group: "" + generate.kyverno.io/trigger-kind: Secret + generate.kyverno.io/trigger-namespace: cpol-data-sync-create-upon-generated-resource-ns + generate.kyverno.io/trigger-version: v1 + name: otel-collector-signalfx-sa + namespace: cpol-data-sync-create-upon-generated-resource-ns \ No newline at end of file diff --git a/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-create-upon-generated-resource/chainsaw-test.yaml b/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-create-upon-generated-resource/chainsaw-test.yaml new file mode 100755 index 0000000000..5ffd23bd25 --- /dev/null +++ b/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-create-upon-generated-resource/chainsaw-test.yaml @@ -0,0 +1,19 @@ +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + creationTimestamp: null + name: cpol-data-sync-create +spec: + steps: + - name: step-01 + try: + - apply: + file: chainsaw-step-01-apply-1-1.yaml + - assert: + file: chainsaw-step-01-assert-1-1.yaml + - name: step-02 + try: + - apply: + file: chainsaw-step-02-apply-1-1.yaml + - assert: + file: chainsaw-step-02-assert-1-1.yaml diff --git a/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/README.md b/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/README.md new file mode 100644 index 0000000000..14eb96d15a --- /dev/null +++ b/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/README.md @@ -0,0 +1,11 @@ +## Description + +This test checks the generate rule doesn't apply on Kyverno generated resources when `skipBackgroundRequests` is enabled. + +## Expected Behavior + +The serviceaccount is not created when Kyverno creates a new secret. + +## Reference Issue(s) + +https://github.com/kyverno/kyverno/issues/9131 diff --git a/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/chainsaw-step-01-apply-1-1.yaml b/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/chainsaw-step-01-apply-1-1.yaml new file mode 100755 index 0000000000..576514409d --- /dev/null +++ b/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/chainsaw-step-01-apply-1-1.yaml @@ -0,0 +1,198 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/component: background-controller + app.kubernetes.io/instance: kyverno + app.kubernetes.io/part-of: kyverno + name: kyverno:background-controller:additional +rules: +- apiGroups: + - "" + resources: + - "" + verbs: + - create + - update + - patch + - delete + - get + - list +- apiGroups: + - "" + resources: + - serviceaccounts + verbs: + - create + - update + - patch + - delete +--- +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: cpol-data-sync-no-creation-upon-generated-resource +spec: + rules: + - generate: + apiVersion: v1 + data: + kind: Secret + metadata: + name: otel-collector-signalfx-config + stringData: + otel-collector-signalfx-config: | + service: + extensions: + - health_check + - http_forwarder + pipelines: + metrics: + receivers: + # but actually, it's a scraper + - prometheus + processors: + - batch + - metricstransform + - k8sattributes + - resourcedetection + exporters: + - signalfx + - logging + telemetry: + metrics: + address: 0.0.0.0:8888 + receivers: + prometheus: + config: + scrape_configs: + - job_name: k8s + kubernetes_sd_configs: + - role: pod + namespaces: + own_namespace: true + # todo: needs to be replaced by Kyverno + relabel_configs: + # Only keep the discovered targets that has the label otel.collector.signalfx/scrape + # Only keep the discovered targets that has the label otel.collector.signalfx/scrape + - action: keep + regex: "true" + source_labels: + - __meta_kubernetes_pod_label_otel_collector_signalfx_scrape + # Add + - action: replace + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $$1:$$2 + source_labels: + - __address__ + - __meta_kubernetes_pod_label_otel_collector_signalfx_port + target_label: __address__ + - action: replace + regex: (.+) + source_labels: + - __meta_kubernetes_pod_annotation_otel_collector_signalfx_metric_path + target_label: __metrics_path__ + - action: replace + regex: (.*)-.*-.*$ + source_labels: + - __meta_kubernetes_pod_name + target_label: deployment + - action: replace + source_labels: + - __meta_kubernetes_namespace + target_label: kubernetes_namespace + - action: replace + source_labels: + - __meta_kubernetes_pod_name + target_label: kubernetes_pod_name + - action: replace + source_labels: + - __meta_kubernetes_pod_container_name + target_label: kubernetes_container_name + scrape_interval: 10s + # Process the datapoints, enrich with more labels + processors: + attributes/newenvironment: + actions: + - action: insert + key: environment + value: managed-gke-dev + batch: {} + k8sattributes: + extract: + metadata: + - podName + - podUID + - namespace + - cluster + - node + passthrough: false + filter: + namespace: "{{request.object.metadata.namespace}}" + memory_limiter: + check_interval: 5s + limit_mib: 1638 + spike_limit_mib: 512 + metricstransform: + transforms: + - action: update + include: .* + match_type: regexp + operations: + - action: add_label + new_label: metric_source + new_value: managed_gke + - action: add_label + new_label: managed_gke + new_value: "true" + - action: add_label + new_label: kubernetes_cluster + new_value: ccoe-europe-west4-dev-1 + resourcedetection: + detectors: + - system + override: true + exporters: + signalfx: + access_token: "{{request.object.data.auth_token | base64_decode(@) || 'BACKGROUND'}}" + access_token_passthrough: true + realm: eu0 + logging: + loglevel: info + extensions: + health_check: + endpoint: 0.0.0.0:13133 + http_forwarder: + egress: + endpoint: https://api.eu0.signalfx.com + memory_ballast: {} + zpages: null + type: Opaque + kind: Secret + name: otel-collector-signalfx-secret + namespace: '{{request.object.metadata.namespace}}' + synchronize: true + match: + any: + - resources: + kinds: + - Secret + names: + - otel-collector-signalfx-token + name: generate-otel-secret-config + skipBackgroundRequests: true + - generate: + apiVersion: v1 + kind: ServiceAccount + name: otel-collector-signalfx-sa + namespace: '{{request.object.metadata.namespace}}' + synchronize: true + match: + any: + - resources: + kinds: + - Secret + names: + - otel-collector-signalfx-secret + name: generate-otel-sa + skipBackgroundRequests: true \ No newline at end of file diff --git a/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/chainsaw-step-01-assert-1-1.yaml b/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/chainsaw-step-01-assert-1-1.yaml new file mode 100755 index 0000000000..29c18ddebe --- /dev/null +++ b/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/chainsaw-step-01-assert-1-1.yaml @@ -0,0 +1,9 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: cpol-data-sync-no-creation-upon-generated-resource +status: + conditions: + - reason: Succeeded + status: "True" + type: Ready diff --git a/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/chainsaw-step-02-apply-1-1.yaml b/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/chainsaw-step-02-apply-1-1.yaml new file mode 100755 index 0000000000..dbe4a09012 --- /dev/null +++ b/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/chainsaw-step-02-apply-1-1.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: cpol-data-sync-no-creation-upon-generated-resource-ns +--- +apiVersion: v1 +kind: Secret +metadata: + name: otel-collector-signalfx-token + namespace: cpol-data-sync-no-creation-upon-generated-resource-ns +data: + auth_token: YmFy +type: Opaque diff --git a/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/chainsaw-step-02-assert-1-1.yaml b/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/chainsaw-step-02-assert-1-1.yaml new file mode 100755 index 0000000000..5ad96d7b11 --- /dev/null +++ b/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/chainsaw-step-02-assert-1-1.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Secret +metadata: + labels: + app.kubernetes.io/managed-by: kyverno + generate.kyverno.io/policy-name: cpol-data-sync-no-creation-upon-generated-resource + generate.kyverno.io/rule-name: generate-otel-secret-config + generate.kyverno.io/trigger-group: "" + generate.kyverno.io/trigger-kind: Secret + generate.kyverno.io/trigger-namespace: cpol-data-sync-no-creation-upon-generated-resource-ns + generate.kyverno.io/trigger-version: v1 + name: otel-collector-signalfx-secret + namespace: cpol-data-sync-no-creation-upon-generated-resource-ns +type: Opaque \ No newline at end of file diff --git a/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/chainsaw-step-02-error-1-1.yaml b/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/chainsaw-step-02-error-1-1.yaml new file mode 100755 index 0000000000..554d566d5d --- /dev/null +++ b/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/chainsaw-step-02-error-1-1.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: otel-collector-signalfx-sa + namespace: cpol-data-sync-no-creation-upon-generated-resource-ns \ No newline at end of file diff --git a/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/chainsaw-test.yaml b/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/chainsaw-test.yaml new file mode 100755 index 0000000000..2f38831512 --- /dev/null +++ b/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/chainsaw-test.yaml @@ -0,0 +1,21 @@ +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + creationTimestamp: null + name: cpol-data-sync-create +spec: + steps: + - name: step-01 + try: + - apply: + file: chainsaw-step-01-apply-1-1.yaml + - assert: + file: chainsaw-step-01-assert-1-1.yaml + - name: step-02 + try: + - apply: + file: chainsaw-step-02-apply-1-1.yaml + - assert: + file: chainsaw-step-02-assert-1-1.yaml + - error: + file: chainsaw-step-02-error-1-1.yaml diff --git a/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/new.yaml b/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/new.yaml new file mode 100644 index 0000000000..6033c78503 --- /dev/null +++ b/test/conformance/chainsaw/generate/clusterpolicy/cornercases/cpol-data-sync-no-creation-upon-generated-resource/new.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app.kubernetes.io/managed-by: kyverno + generate.kyverno.io/policy-name: cpol-data-sync-create-upon-generated-resource + generate.kyverno.io/rule-name: generate-otel-sa + generate.kyverno.io/trigger-group: "" + generate.kyverno.io/trigger-kind: Secret + generate.kyverno.io/trigger-namespace: cpol-data-sync-create-upon-generated-resource-ns + generate.kyverno.io/trigger-version: v1 + name: otel-collector-signalfx-sa + namespace: cpol-data-sync-create-upon-generated-resource-ns \ No newline at end of file