From 381be15a5de177ecb1bb8af189174de58e285de8 Mon Sep 17 00:00:00 2001 From: "gcp-cherry-pick-bot[bot]" <98988430+gcp-cherry-pick-bot[bot]@users.noreply.github.com> Date: Mon, 20 May 2024 11:10:07 +0000 Subject: [PATCH] fix: add resourceNames field in the generated VAPs (#10187) (#10265) Signed-off-by: Mariam Fahmy Co-authored-by: Mariam Fahmy --- pkg/validatingadmissionpolicy/builder.go | 14 +++++-- .../kyvernopolicy_checker.go | 27 +++++++++---- .../chainsaw-test.yaml | 19 +++++++++ .../policy-assert.yaml | 12 ++++++ .../policy.yaml | 20 ++++++++++ .../validatingadmissionpolicy.yaml | 39 +++++++++++++++++++ .../validatingadmissionpolicybinding.yaml | 15 +++++++ .../chainsaw-test.yaml | 19 +++++++++ .../policy-assert.yaml | 12 ++++++ .../policy.yaml | 20 ++++++++++ .../validatingadmissionpolicy.yaml | 7 ++++ .../validatingadmissionpolicybinding.yaml | 7 ++++ .../policy.yaml | 8 ++-- 13 files changed, 202 insertions(+), 17 deletions(-) create mode 100755 test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-any-match-resources-by-names/chainsaw-test.yaml create mode 100644 test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-any-match-resources-by-names/policy-assert.yaml create mode 100644 test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-any-match-resources-by-names/policy.yaml create mode 100644 test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-any-match-resources-by-names/validatingadmissionpolicy.yaml create mode 100644 test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-any-match-resources-by-names/validatingadmissionpolicybinding.yaml create mode 100755 test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/skip-generate/cpol-any-match-resources-by-names-with-wildcard/chainsaw-test.yaml create mode 100644 test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/skip-generate/cpol-any-match-resources-by-names-with-wildcard/policy-assert.yaml create mode 100644 test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/skip-generate/cpol-any-match-resources-by-names-with-wildcard/policy.yaml create mode 100644 test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/skip-generate/cpol-any-match-resources-by-names-with-wildcard/validatingadmissionpolicy.yaml create mode 100644 test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/skip-generate/cpol-any-match-resources-by-names-with-wildcard/validatingadmissionpolicybinding.yaml diff --git a/pkg/validatingadmissionpolicy/builder.go b/pkg/validatingadmissionpolicy/builder.go index 7f5afd1dbede..f499e335d15e 100644 --- a/pkg/validatingadmissionpolicy/builder.go +++ b/pkg/validatingadmissionpolicy/builder.go @@ -109,7 +109,7 @@ func translateResourceFilters(discoveryClient dclient.IDiscovery, matchResources } func translateResource(discoveryClient dclient.IDiscovery, matchResources *admissionregistrationv1alpha1.MatchResources, rules *[]admissionregistrationv1alpha1.NamedRuleWithOperations, res kyvernov1.ResourceDescription) error { - err := constructValidatingAdmissionPolicyRules(discoveryClient, rules, res.Kinds, res.GetOperations()) + err := constructValidatingAdmissionPolicyRules(discoveryClient, rules, res) if err != nil { return err } @@ -120,9 +120,14 @@ func translateResource(discoveryClient dclient.IDiscovery, matchResources *admis return nil } -func constructValidatingAdmissionPolicyRules(discoveryClient dclient.IDiscovery, rules *[]admissionregistrationv1alpha1.NamedRuleWithOperations, kinds []string, operations []string) error { +func constructValidatingAdmissionPolicyRules(discoveryClient dclient.IDiscovery, rules *[]admissionregistrationv1alpha1.NamedRuleWithOperations, res kyvernov1.ResourceDescription) error { // translate operations to their corresponding values in validating admission policy. - ops := translateOperations(operations) + ops := translateOperations(res.GetOperations()) + + resourceNames := res.Names + if res.Name != "" { + resourceNames = append(resourceNames, res.Name) + } // get kinds from kyverno policies and translate them to rules in validating admission policies. // matched resources in kyverno policies are written in the following format: @@ -131,7 +136,7 @@ func constructValidatingAdmissionPolicyRules(discoveryClient dclient.IDiscovery, // apiGroups: ["group"] // apiVersions: ["version"] // resources: ["resource"] - for _, kind := range kinds { + for _, kind := range res.Kinds { group, version, kind, subresource := kubeutils.ParseKindSelector(kind) gvrss, err := discoveryClient.FindResources(group, version, kind, subresource) if err != nil { @@ -164,6 +169,7 @@ func constructValidatingAdmissionPolicyRules(discoveryClient dclient.IDiscovery, } if isNewRule { r := admissionregistrationv1alpha1.NamedRuleWithOperations{ + ResourceNames: resourceNames, RuleWithOperations: admissionregistrationv1.RuleWithOperations{ Rule: admissionregistrationv1.Rule{ Resources: resources, diff --git a/pkg/validatingadmissionpolicy/kyvernopolicy_checker.go b/pkg/validatingadmissionpolicy/kyvernopolicy_checker.go index 5729f42e910e..02593df53869 100644 --- a/pkg/validatingadmissionpolicy/kyvernopolicy_checker.go +++ b/pkg/validatingadmissionpolicy/kyvernopolicy_checker.go @@ -2,13 +2,14 @@ package validatingadmissionpolicy import ( kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1" + "github.com/kyverno/kyverno/ext/wildcard" ) // CanGenerateVAP check if Kyverno policy can be translated to a Kubernetes ValidatingAdmissionPolicy func CanGenerateVAP(spec *kyvernov1.Spec) (bool, string) { var msg string if len(spec.Rules) > 1 { - msg = "skip generating ValidatingAdmissionPolicy: multiple rules aren't applicable." + msg = "skip generating ValidatingAdmissionPolicy: multiple rules are not applicable." return false, msg } @@ -19,19 +20,19 @@ func CanGenerateVAP(spec *kyvernov1.Spec) (bool, string) { } if len(spec.ValidationFailureActionOverrides) > 1 { - msg = "skip generating ValidatingAdmissionPolicy: multiple validationFailureActionOverrides aren't applicable." + msg = "skip generating ValidatingAdmissionPolicy: multiple validationFailureActionOverrides are not applicable." return false, msg } if len(spec.ValidationFailureActionOverrides) != 0 && len(spec.ValidationFailureActionOverrides[0].Namespaces) != 0 { - msg = "skip generating ValidatingAdmissionPolicy: Namespaces in validationFailureActionOverrides isn't applicable." + msg = "skip generating ValidatingAdmissionPolicy: Namespaces in validationFailureActionOverrides is not applicable." return false, msg } // check the matched/excluded resources of the CEL rule. match, exclude := rule.MatchResources, rule.ExcludeResources if !exclude.UserInfo.IsEmpty() || !exclude.ResourceDescription.IsEmpty() || exclude.All != nil || exclude.Any != nil { - msg = "skip generating ValidatingAdmissionPolicy: Exclude isn't applicable." + msg = "skip generating ValidatingAdmissionPolicy: Exclude is not applicable." return false, msg } if ok, msg := checkUserInfo(match.UserInfo); !ok { @@ -65,14 +66,14 @@ func CanGenerateVAP(spec *kyvernov1.Spec) (bool, string) { // since namespace/object selectors are applied to all NamedRuleWithOperations in ValidatingAdmissionPolicy, then // we can't have more than one resource with namespace/object selectors. if len(match.Any) > 1 && (containsNamespaceSelector || containsObjectSelector) { - msg = "skip generating ValidatingAdmissionPolicy: NamespaceSelector / ObjectSelector across multiple resources aren't applicable." + msg = "skip generating ValidatingAdmissionPolicy: NamespaceSelector / ObjectSelector across multiple resources are not applicable." return false, msg } // since 'all' specify resources which will be ANDed, we can't have more than one resource. if match.All != nil { if len(match.All) > 1 { - msg = "skip generating ValidatingAdmissionPolicy: multiple 'all' isn't applicable." + msg = "skip generating ValidatingAdmissionPolicy: multiple 'all' is not applicable." return false, msg } else { if ok, msg := checkUserInfo(match.All[0].UserInfo); !ok { @@ -90,16 +91,26 @@ func CanGenerateVAP(spec *kyvernov1.Spec) (bool, string) { func checkResources(resource kyvernov1.ResourceDescription) (bool, string) { var msg string if len(resource.Namespaces) != 0 || len(resource.Annotations) != 0 { - msg = "skip generating ValidatingAdmissionPolicy: Namespaces / Annotations in resource description isn't applicable." + msg = "skip generating ValidatingAdmissionPolicy: Namespaces / Annotations in resource description is not applicable." return false, msg } + if resource.Name != "" && wildcard.ContainsWildcard(resource.Name) { + msg = "skip generating ValidatingAdmissionPolicy: wildcards in resource name is not applicable." + return false, msg + } + for _, name := range resource.Names { + if wildcard.ContainsWildcard(name) { + msg = "skip generating ValidatingAdmissionPolicy: wildcards in resource name is not applicable." + return false, msg + } + } return true, msg } func checkUserInfo(info kyvernov1.UserInfo) (bool, string) { var msg string if !info.IsEmpty() { - msg = "skip generating ValidatingAdmissionPolicy: Roles / ClusterRoles / Subjects in `any/all` isn't applicable." + msg = "skip generating ValidatingAdmissionPolicy: Roles / ClusterRoles / Subjects in `any/all` is not applicable." return false, msg } return true, msg diff --git a/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-any-match-resources-by-names/chainsaw-test.yaml b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-any-match-resources-by-names/chainsaw-test.yaml new file mode 100755 index 000000000000..ca71f0b3266b --- /dev/null +++ b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-any-match-resources-by-names/chainsaw-test.yaml @@ -0,0 +1,19 @@ +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + creationTimestamp: null + name: cpol-any-match-resources-by-names +spec: + steps: + - name: step-01 + try: + - apply: + file: policy.yaml + - assert: + file: policy-assert.yaml + - name: step-02 + try: + - assert: + file: validatingadmissionpolicy.yaml + - assert: + file: validatingadmissionpolicybinding.yaml diff --git a/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-any-match-resources-by-names/policy-assert.yaml b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-any-match-resources-by-names/policy-assert.yaml new file mode 100644 index 000000000000..612b2ec93d3f --- /dev/null +++ b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-any-match-resources-by-names/policy-assert.yaml @@ -0,0 +1,12 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: check-label-app-4 +status: + conditions: + - reason: Succeeded + status: "True" + type: Ready + validatingadmissionpolicy: + generated: true + \ No newline at end of file diff --git a/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-any-match-resources-by-names/policy.yaml b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-any-match-resources-by-names/policy.yaml new file mode 100644 index 000000000000..cb3ffa2a3209 --- /dev/null +++ b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-any-match-resources-by-names/policy.yaml @@ -0,0 +1,20 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: check-label-app-4 +spec: + validationFailureAction: Audit + rules: + - name: check-label-app + match: + any: + - resources: + kinds: + - Pod + - Deployment + names: + - "staging" + validate: + cel: + expressions: + - expression: "'app' in object.metadata.labels" diff --git a/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-any-match-resources-by-names/validatingadmissionpolicy.yaml b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-any-match-resources-by-names/validatingadmissionpolicy.yaml new file mode 100644 index 000000000000..6338aeb031b2 --- /dev/null +++ b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-any-match-resources-by-names/validatingadmissionpolicy.yaml @@ -0,0 +1,39 @@ +apiVersion: admissionregistration.k8s.io/v1alpha1 +kind: ValidatingAdmissionPolicy +metadata: + labels: + app.kubernetes.io/managed-by: kyverno + name: check-label-app-4 + ownerReferences: + - apiVersion: kyverno.io/v1 + kind: ClusterPolicy + name: check-label-app-4 +spec: + failurePolicy: Fail + matchConstraints: + resourceRules: + - apiGroups: + - "" + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resourceNames: + - staging + resources: + - pods + - pods/ephemeralcontainers + - apiGroups: + - apps + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resourceNames: + - staging + resources: + - deployments + validations: + - expression: "'app' in object.metadata.labels" diff --git a/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-any-match-resources-by-names/validatingadmissionpolicybinding.yaml b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-any-match-resources-by-names/validatingadmissionpolicybinding.yaml new file mode 100644 index 000000000000..96a178857d82 --- /dev/null +++ b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-any-match-resources-by-names/validatingadmissionpolicybinding.yaml @@ -0,0 +1,15 @@ +apiVersion: admissionregistration.k8s.io/v1alpha1 +kind: ValidatingAdmissionPolicyBinding +metadata: + labels: + app.kubernetes.io/managed-by: kyverno + name: check-label-app-4-binding + ownerReferences: + - apiVersion: kyverno.io/v1 + kind: ClusterPolicy + name: check-label-app-4 +spec: + policyName: check-label-app-4 + validationActions: + - Audit + - Warn diff --git a/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/skip-generate/cpol-any-match-resources-by-names-with-wildcard/chainsaw-test.yaml b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/skip-generate/cpol-any-match-resources-by-names-with-wildcard/chainsaw-test.yaml new file mode 100755 index 000000000000..ba37984fe7f1 --- /dev/null +++ b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/skip-generate/cpol-any-match-resources-by-names-with-wildcard/chainsaw-test.yaml @@ -0,0 +1,19 @@ +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + creationTimestamp: null + name: cpol-any-match-resources-by-names-with-wildcard +spec: + steps: + - name: step-01 + try: + - apply: + file: policy.yaml + - assert: + file: policy-assert.yaml + - name: step-02 + try: + - error: + file: validatingadmissionpolicy.yaml + - error: + file: validatingadmissionpolicybinding.yaml diff --git a/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/skip-generate/cpol-any-match-resources-by-names-with-wildcard/policy-assert.yaml b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/skip-generate/cpol-any-match-resources-by-names-with-wildcard/policy-assert.yaml new file mode 100644 index 000000000000..08d8e3b4f1df --- /dev/null +++ b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/skip-generate/cpol-any-match-resources-by-names-with-wildcard/policy-assert.yaml @@ -0,0 +1,12 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: check-label-app-3 +status: + conditions: + - reason: Succeeded + status: "True" + type: Ready + validatingadmissionpolicy: + generated: false + \ No newline at end of file diff --git a/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/skip-generate/cpol-any-match-resources-by-names-with-wildcard/policy.yaml b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/skip-generate/cpol-any-match-resources-by-names-with-wildcard/policy.yaml new file mode 100644 index 000000000000..98771ef5995d --- /dev/null +++ b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/skip-generate/cpol-any-match-resources-by-names-with-wildcard/policy.yaml @@ -0,0 +1,20 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: check-label-app-3 +spec: + validationFailureAction: Audit + rules: + - name: check-label-app + match: + any: + - resources: + kinds: + - Pod + names: + - "prod-*" + - "staging" + validate: + cel: + expressions: + - expression: "'app' in object.metadata.labels" diff --git a/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/skip-generate/cpol-any-match-resources-by-names-with-wildcard/validatingadmissionpolicy.yaml b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/skip-generate/cpol-any-match-resources-by-names-with-wildcard/validatingadmissionpolicy.yaml new file mode 100644 index 000000000000..05aa98b8656b --- /dev/null +++ b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/skip-generate/cpol-any-match-resources-by-names-with-wildcard/validatingadmissionpolicy.yaml @@ -0,0 +1,7 @@ +apiVersion: admissionregistration.k8s.io/v1alpha1 +kind: ValidatingAdmissionPolicy +metadata: + labels: + app.kubernetes.io/managed-by: kyverno + name: check-label-app-3 +spec: {} diff --git a/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/skip-generate/cpol-any-match-resources-by-names-with-wildcard/validatingadmissionpolicybinding.yaml b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/skip-generate/cpol-any-match-resources-by-names-with-wildcard/validatingadmissionpolicybinding.yaml new file mode 100644 index 000000000000..6c4330145ea0 --- /dev/null +++ b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/skip-generate/cpol-any-match-resources-by-names-with-wildcard/validatingadmissionpolicybinding.yaml @@ -0,0 +1,7 @@ +apiVersion: admissionregistration.k8s.io/v1alpha1 +kind: ValidatingAdmissionPolicyBinding +metadata: + labels: + app.kubernetes.io/managed-by: kyverno + name: check-label-app-3-binding +spec: {} diff --git a/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/skip-generate/cpol-multiple-validation-failure-action-overrides/policy.yaml b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/skip-generate/cpol-multiple-validation-failure-action-overrides/policy.yaml index 419a8045a301..200aec435c0a 100644 --- a/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/skip-generate/cpol-multiple-validation-failure-action-overrides/policy.yaml +++ b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/skip-generate/cpol-multiple-validation-failure-action-overrides/policy.yaml @@ -19,8 +19,6 @@ spec: kinds: - Pod validate: - message: "The label `app` is required." - pattern: - metadata: - labels: - app: "?*" + cel: + expressions: + - expression: "'app' in object.metadata.labels"