From 6fec52436a82d79a5b728b2783fdf9835e57f198 Mon Sep 17 00:00:00 2001 From: Mariam Fahmy Date: Thu, 9 May 2024 14:46:10 +0800 Subject: [PATCH] fix: generate VAPs that match all resources when kinds is set to * (#10208) Signed-off-by: Mariam Fahmy --- pkg/validatingadmissionpolicy/builder.go | 90 +++++++++++-------- .../chainsaw-test.yaml | 19 ++++ .../policy-assert.yaml | 10 +++ .../cpol-match-kind-with-wildcard/policy.yaml | 21 +++++ .../validatingadmissionpolicy.yaml | 32 +++++++ .../validatingadmissionpolicybinding.yaml | 13 +++ .../policy-assert.yaml | 2 - 7 files changed, 147 insertions(+), 40 deletions(-) create mode 100755 test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-match-kind-with-wildcard/chainsaw-test.yaml create mode 100644 test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-match-kind-with-wildcard/policy-assert.yaml create mode 100644 test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-match-kind-with-wildcard/policy.yaml create mode 100644 test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-match-kind-with-wildcard/validatingadmissionpolicy.yaml create mode 100644 test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-match-kind-with-wildcard/validatingadmissionpolicybinding.yaml diff --git a/pkg/validatingadmissionpolicy/builder.go b/pkg/validatingadmissionpolicy/builder.go index 0ab6280c0e..bbc5e92ed0 100644 --- a/pkg/validatingadmissionpolicy/builder.go +++ b/pkg/validatingadmissionpolicy/builder.go @@ -150,55 +150,69 @@ func constructValidatingAdmissionPolicyRules(discoveryClient dclient.IDiscovery, // apiVersions: ["version"] // resources: ["resource"] for _, kind := range res.Kinds { - group, version, kind, subresource := kubeutils.ParseKindSelector(kind) - gvrss, err := discoveryClient.FindResources(group, version, kind, subresource) - if err != nil { - return err - } - if len(gvrss) != 1 { - return fmt.Errorf("no unique match for kind %s", kind) - } + var r admissionregistrationv1alpha1.NamedRuleWithOperations - for topLevelApi, apiResource := range gvrss { - var resources []string - resources = append(resources, apiResource.Name) - // if we have pods, we add pods/ephemeralcontainers by default - if apiResource.Name == "pods" { - resources = append(resources, "pods/ephemeralcontainers") + if kind == "*" { + r = buildNamedRuleWithOperations(resourceNames, "*", "*", ops, "*") + *rules = append(*rules, r) + } else { + group, version, kind, subresource := kubeutils.ParseKindSelector(kind) + gvrss, err := discoveryClient.FindResources(group, version, kind, subresource) + if err != nil { + return err + } + if len(gvrss) != 1 { + return fmt.Errorf("no unique match for kind %s", kind) } - isNewRule := true - // If there's a rule that contains both group and version, then the resource is appended to the existing rule instead of creating a new one. - // Example: apiGroups: ["apps"] - // apiVersions: ["v1"] - // resources: ["deployments", "statefulsets"] - // Otherwise, a new rule is created. - for i := range *rules { - if slices.Contains((*rules)[i].APIGroups, topLevelApi.Group) && slices.Contains((*rules)[i].APIVersions, topLevelApi.Version) { - (*rules)[i].Resources = append((*rules)[i].Resources, resources...) - isNewRule = false - break + for topLevelApi, apiResource := range gvrss { + resources := []string{apiResource.Name} + + // Add pods/ephemeralcontainers if pods resource. + if apiResource.Name == "pods" { + resources = append(resources, "pods/ephemeralcontainers") } - } - if isNewRule { - r := admissionregistrationv1alpha1.NamedRuleWithOperations{ - ResourceNames: resourceNames, - RuleWithOperations: admissionregistrationv1.RuleWithOperations{ - Rule: admissionregistrationv1.Rule{ - Resources: resources, - APIGroups: []string{topLevelApi.Group}, - APIVersions: []string{topLevelApi.Version}, - }, - Operations: ops, - }, + + // Check if there's an existing rule for the same group and version. + var isNewRule bool = true + for i := range *rules { + if slices.Contains((*rules)[i].APIGroups, topLevelApi.Group) && slices.Contains((*rules)[i].APIVersions, topLevelApi.Version) { + (*rules)[i].Resources = append((*rules)[i].Resources, resources...) + isNewRule = false + break + } + } + + // If no existing rule found, create a new one. + if isNewRule { + r = buildNamedRuleWithOperations(resourceNames, topLevelApi.Group, topLevelApi.Version, ops, resources...) + *rules = append(*rules, r) } - *rules = append(*rules, r) } } } return nil } +func buildNamedRuleWithOperations( + resourceNames []string, + group, version string, + operations []admissionregistrationv1.OperationType, + resources ...string, +) admissionregistrationv1alpha1.NamedRuleWithOperations { + return admissionregistrationv1alpha1.NamedRuleWithOperations{ + ResourceNames: resourceNames, + RuleWithOperations: admissionregistrationv1.RuleWithOperations{ + Rule: admissionregistrationv1.Rule{ + Resources: resources, + APIGroups: []string{group}, + APIVersions: []string{version}, + }, + Operations: operations, + }, + } +} + func translateOperations(operations []string) []admissionregistrationv1.OperationType { var vapOperations []admissionregistrationv1.OperationType for _, op := range operations { diff --git a/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-match-kind-with-wildcard/chainsaw-test.yaml b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-match-kind-with-wildcard/chainsaw-test.yaml new file mode 100755 index 0000000000..46411c7d3f --- /dev/null +++ b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-match-kind-with-wildcard/chainsaw-test.yaml @@ -0,0 +1,19 @@ +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + creationTimestamp: null + name: cpol-match-kind-with-wildcard +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-match-kind-with-wildcard/policy-assert.yaml b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-match-kind-with-wildcard/policy-assert.yaml new file mode 100644 index 0000000000..6f9a1a79ab --- /dev/null +++ b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-match-kind-with-wildcard/policy-assert.yaml @@ -0,0 +1,10 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: check-label-app4 +status: + conditions: + - reason: Succeeded + status: "True" + type: Ready + \ No newline at end of file diff --git a/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-match-kind-with-wildcard/policy.yaml b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-match-kind-with-wildcard/policy.yaml new file mode 100644 index 0000000000..7c5dcafcfd --- /dev/null +++ b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-match-kind-with-wildcard/policy.yaml @@ -0,0 +1,21 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: check-label-app4 +spec: + validationFailureAction: Audit + background: false + rules: + - name: check-label-app + match: + all: + - resources: + kinds: + - '*' + namespaces: + - production + - staging + validate: + cel: + expressions: + - expression: "'app' in object.metadata.labels" \ No newline at end of file diff --git a/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-match-kind-with-wildcard/validatingadmissionpolicy.yaml b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-match-kind-with-wildcard/validatingadmissionpolicy.yaml new file mode 100644 index 0000000000..eb3a306bfc --- /dev/null +++ b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-match-kind-with-wildcard/validatingadmissionpolicy.yaml @@ -0,0 +1,32 @@ +apiVersion: admissionregistration.k8s.io/v1alpha1 +kind: ValidatingAdmissionPolicy +metadata: + labels: + app.kubernetes.io/managed-by: kyverno + name: check-label-app4 + ownerReferences: + - apiVersion: kyverno.io/v1 + kind: ClusterPolicy + name: check-label-app4 +spec: + failurePolicy: Fail + matchConstraints: + namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: In + values: + - production + - staging + resourceRules: + - apiGroups: + - '*' + apiVersions: + - '*' + operations: + - CREATE + - UPDATE + resources: + - '*' + validations: + - expression: '''app'' in object.metadata.labels' diff --git a/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-match-kind-with-wildcard/validatingadmissionpolicybinding.yaml b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-match-kind-with-wildcard/validatingadmissionpolicybinding.yaml new file mode 100644 index 0000000000..a0b581284d --- /dev/null +++ b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-match-kind-with-wildcard/validatingadmissionpolicybinding.yaml @@ -0,0 +1,13 @@ +apiVersion: admissionregistration.k8s.io/v1alpha1 +kind: ValidatingAdmissionPolicyBinding +metadata: + labels: + app.kubernetes.io/managed-by: kyverno + name: check-label-app4-binding + ownerReferences: + - apiVersion: kyverno.io/v1 + kind: ClusterPolicy + name: check-label-app4 +spec: + policyName: check-label-app4 + validationActions: [Audit, Warn] diff --git a/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-match-resource-in-specific-namespace/policy-assert.yaml b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-match-resource-in-specific-namespace/policy-assert.yaml index 1a80b3edbb..d53165009e 100644 --- a/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-match-resource-in-specific-namespace/policy-assert.yaml +++ b/test/conformance/chainsaw/generate-validating-admission-policy/clusterpolicy/standard/generate/cpol-match-resource-in-specific-namespace/policy-assert.yaml @@ -7,6 +7,4 @@ status: - reason: Succeeded status: "True" type: Ready - validatingadmissionpolicy: - generated: true \ No newline at end of file