mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-28 10:28:36 +00:00
fix: policy validation with subresource and background scan enabled (#6571)
* fix: policy validation with subresource Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * kuttl Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * workflow Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> --------- Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
parent
4138fc3678
commit
49f0baa277
24 changed files with 305 additions and 76 deletions
1
.github/workflows/conformance.yaml
vendored
1
.github/workflows/conformance.yaml
vendored
|
@ -45,6 +45,7 @@ jobs:
|
|||
- exceptions
|
||||
- generate
|
||||
- mutate
|
||||
- policy-validation
|
||||
- rangeoperators
|
||||
- rbac
|
||||
- reports
|
||||
|
|
|
@ -190,6 +190,80 @@ func Validate(policy, oldPolicy kyvernov1.PolicyInterface, client dclient.Interf
|
|||
|
||||
rules := autogen.ComputeRules(policy)
|
||||
rulesPath := specPath.Child("rules")
|
||||
|
||||
for _, rule := range rules {
|
||||
// Validate Kind with match resource kinds
|
||||
match := rule.MatchResources
|
||||
exclude := rule.ExcludeResources
|
||||
for _, value := range match.Any {
|
||||
wildcardErr := validateWildcard(value.ResourceDescription.Kinds, spec, rule)
|
||||
if wildcardErr != nil {
|
||||
return warnings, wildcardErr
|
||||
}
|
||||
if !slices.Contains(value.ResourceDescription.Kinds, "*") {
|
||||
err := validateKinds(value.ResourceDescription.Kinds, mock, background, rule.HasValidate(), client)
|
||||
if err != nil {
|
||||
return warnings, fmt.Errorf("the kind defined in the any match resource is invalid: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, value := range match.All {
|
||||
wildcardErr := validateWildcard(value.ResourceDescription.Kinds, spec, rule)
|
||||
if wildcardErr != nil {
|
||||
return warnings, wildcardErr
|
||||
}
|
||||
if !slices.Contains(value.ResourceDescription.Kinds, "*") {
|
||||
err := validateKinds(value.ResourceDescription.Kinds, mock, background, rule.HasValidate(), client)
|
||||
if err != nil {
|
||||
return warnings, fmt.Errorf("the kind defined in the all match resource is invalid: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, value := range exclude.Any {
|
||||
wildcardErr := validateWildcard(value.ResourceDescription.Kinds, spec, rule)
|
||||
if wildcardErr != nil {
|
||||
return warnings, wildcardErr
|
||||
}
|
||||
if !slices.Contains(value.ResourceDescription.Kinds, "*") {
|
||||
err := validateKinds(value.ResourceDescription.Kinds, mock, background, rule.HasValidate(), client)
|
||||
if err != nil {
|
||||
return warnings, fmt.Errorf("the kind defined in the any exclude resource is invalid: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, value := range exclude.All {
|
||||
wildcardErr := validateWildcard(value.ResourceDescription.Kinds, spec, rule)
|
||||
if wildcardErr != nil {
|
||||
return warnings, wildcardErr
|
||||
}
|
||||
if !slices.Contains(value.ResourceDescription.Kinds, "*") {
|
||||
err := validateKinds(value.ResourceDescription.Kinds, mock, background, rule.HasValidate(), client)
|
||||
if err != nil {
|
||||
return warnings, fmt.Errorf("the kind defined in the all exclude resource is invalid: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if !slices.Contains(rule.MatchResources.Kinds, "*") {
|
||||
err := validateKinds(rule.MatchResources.Kinds, mock, background, rule.HasValidate(), client)
|
||||
if err != nil {
|
||||
return warnings, fmt.Errorf("match resource kind is invalid: %w", err)
|
||||
}
|
||||
err = validateKinds(rule.ExcludeResources.Kinds, mock, background, rule.HasValidate(), client)
|
||||
if err != nil {
|
||||
return warnings, fmt.Errorf("exclude resource kind is invalid: %w", err)
|
||||
}
|
||||
} else {
|
||||
wildcardErr := validateWildcard(rule.MatchResources.Kinds, spec, rule)
|
||||
if wildcardErr != nil {
|
||||
return warnings, wildcardErr
|
||||
}
|
||||
wildcardErr = validateWildcard(rule.ExcludeResources.Kinds, spec, rule)
|
||||
if wildcardErr != nil {
|
||||
return warnings, wildcardErr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for i, rule := range rules {
|
||||
rulePath := rulesPath.Index(i)
|
||||
// check for forward slash
|
||||
|
@ -290,83 +364,13 @@ func Validate(policy, oldPolicy kyvernov1.PolicyInterface, client dclient.Interf
|
|||
}
|
||||
}
|
||||
|
||||
// Validate Kind with match resource kinds
|
||||
match := rule.MatchResources
|
||||
exclude := rule.ExcludeResources
|
||||
for _, value := range match.Any {
|
||||
wildcardErr := validateWildcard(value.ResourceDescription.Kinds, spec, rule)
|
||||
if wildcardErr != nil {
|
||||
return warnings, wildcardErr
|
||||
}
|
||||
if !slices.Contains(value.ResourceDescription.Kinds, "*") {
|
||||
err := validateKinds(value.ResourceDescription.Kinds, mock, background, rule.HasValidate(), client)
|
||||
if err != nil {
|
||||
return warnings, fmt.Errorf("the kind defined in the any match resource is invalid: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, value := range match.All {
|
||||
wildcardErr := validateWildcard(value.ResourceDescription.Kinds, spec, rule)
|
||||
if wildcardErr != nil {
|
||||
return warnings, wildcardErr
|
||||
}
|
||||
if !slices.Contains(value.ResourceDescription.Kinds, "*") {
|
||||
err := validateKinds(value.ResourceDescription.Kinds, mock, background, rule.HasValidate(), client)
|
||||
if err != nil {
|
||||
return warnings, fmt.Errorf("the kind defined in the all match resource is invalid: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, value := range exclude.Any {
|
||||
wildcardErr := validateWildcard(value.ResourceDescription.Kinds, spec, rule)
|
||||
if wildcardErr != nil {
|
||||
return warnings, wildcardErr
|
||||
}
|
||||
if !slices.Contains(value.ResourceDescription.Kinds, "*") {
|
||||
err := validateKinds(value.ResourceDescription.Kinds, mock, background, rule.HasValidate(), client)
|
||||
if err != nil {
|
||||
return warnings, fmt.Errorf("the kind defined in the any exclude resource is invalid: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, value := range exclude.All {
|
||||
wildcardErr := validateWildcard(value.ResourceDescription.Kinds, spec, rule)
|
||||
if wildcardErr != nil {
|
||||
return warnings, wildcardErr
|
||||
}
|
||||
if !slices.Contains(value.ResourceDescription.Kinds, "*") {
|
||||
err := validateKinds(value.ResourceDescription.Kinds, mock, background, rule.HasValidate(), client)
|
||||
if err != nil {
|
||||
return warnings, fmt.Errorf("the kind defined in the all exclude resource is invalid: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !slices.Contains(rule.MatchResources.Kinds, "*") {
|
||||
err := validateKinds(rule.MatchResources.Kinds, mock, background, rule.HasValidate(), client)
|
||||
if err != nil {
|
||||
return warnings, fmt.Errorf("match resource kind is invalid: %w", err)
|
||||
}
|
||||
err = validateKinds(rule.ExcludeResources.Kinds, mock, background, rule.HasValidate(), client)
|
||||
if err != nil {
|
||||
return warnings, fmt.Errorf("exclude resource kind is invalid: %w", err)
|
||||
}
|
||||
} else {
|
||||
wildcardErr := validateWildcard(rule.MatchResources.Kinds, spec, rule)
|
||||
if wildcardErr != nil {
|
||||
return warnings, wildcardErr
|
||||
}
|
||||
wildcardErr = validateWildcard(rule.ExcludeResources.Kinds, spec, rule)
|
||||
if wildcardErr != nil {
|
||||
return warnings, wildcardErr
|
||||
}
|
||||
}
|
||||
|
||||
// Validate string values in labels
|
||||
if !isLabelAndAnnotationsString(rule) {
|
||||
return warnings, fmt.Errorf("labels and annotations supports only string values, \"use double quotes around the non string values\"")
|
||||
}
|
||||
|
||||
match := rule.MatchResources
|
||||
exclude := rule.ExcludeResources
|
||||
matchKinds := match.GetKinds()
|
||||
excludeKinds := exclude.GetKinds()
|
||||
allKinds := make([]string, 0, len(matchKinds)+len(excludeKinds))
|
||||
|
@ -1212,8 +1216,8 @@ func validateWildcard(kinds []string, spec *kyvernov1.Spec, rule kyvernov1.Rule)
|
|||
// and found in the cache, returns error if not found. It also returns an error if background scanning
|
||||
// is enabled for a subresource.
|
||||
func validateKinds(kinds []string, mock, backgroundScanningEnabled, isValidationPolicy bool, client dclient.Interface) error {
|
||||
for _, k := range kinds {
|
||||
if !mock {
|
||||
if !mock {
|
||||
for _, k := range kinds {
|
||||
group, version, kind, subresource := kubeutils.ParseKindSelector(k)
|
||||
gvrss, err := client.Discovery().FindResources(group, version, kind, subresource)
|
||||
if err != nil {
|
||||
|
@ -1224,8 +1228,8 @@ func validateKinds(kinds []string, mock, backgroundScanningEnabled, isValidation
|
|||
}
|
||||
if backgroundScanningEnabled {
|
||||
for gvrs := range gvrss {
|
||||
if strings.Contains(gvrs.Resource, "/") {
|
||||
return fmt.Errorf("background scan enabled with subresource %s", subresource)
|
||||
if gvrs.SubResource != "" {
|
||||
return fmt.Errorf("background scan enabled with subresource %s", k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
apiVersion: kuttl.dev/v1beta1
|
||||
kind: TestStep
|
||||
apply:
|
||||
- file: policy-1.yaml
|
||||
shouldFail: true
|
|
@ -0,0 +1,5 @@
|
|||
apiVersion: kuttl.dev/v1beta1
|
||||
kind: TestStep
|
||||
apply:
|
||||
- file: policy-2.yaml
|
||||
shouldFail: true
|
|
@ -0,0 +1,5 @@
|
|||
apiVersion: kuttl.dev/v1beta1
|
||||
kind: TestStep
|
||||
apply:
|
||||
- file: policy-3.yaml
|
||||
shouldFail: true
|
|
@ -0,0 +1,5 @@
|
|||
apiVersion: kuttl.dev/v1beta1
|
||||
kind: TestStep
|
||||
apply:
|
||||
- file: policy-4.yaml
|
||||
shouldFail: true
|
|
@ -0,0 +1,5 @@
|
|||
apiVersion: kuttl.dev/v1beta1
|
||||
kind: TestStep
|
||||
apply:
|
||||
- file: policy-5.yaml
|
||||
shouldFail: true
|
|
@ -0,0 +1,7 @@
|
|||
## Description
|
||||
|
||||
This test tries to create various policies targeting subresources and `background` set to `true`.
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
Every policies creation is expected to fail.
|
|
@ -0,0 +1,16 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: deny
|
||||
spec:
|
||||
validationFailureAction: Audit
|
||||
background: true
|
||||
rules:
|
||||
- name: deny
|
||||
match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- Scale
|
||||
validate:
|
||||
deny: {}
|
|
@ -0,0 +1,16 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: deny
|
||||
spec:
|
||||
validationFailureAction: Audit
|
||||
background: true
|
||||
rules:
|
||||
- name: deny
|
||||
match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- Pod/scale
|
||||
validate:
|
||||
deny: {}
|
|
@ -0,0 +1,16 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: deny
|
||||
spec:
|
||||
validationFailureAction: Audit
|
||||
background: true
|
||||
rules:
|
||||
- name: deny
|
||||
match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- Pod/*
|
||||
validate:
|
||||
deny: {}
|
|
@ -0,0 +1,16 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: deny
|
||||
spec:
|
||||
validationFailureAction: Audit
|
||||
background: true
|
||||
rules:
|
||||
- name: deny
|
||||
match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- '*/*'
|
||||
validate:
|
||||
deny: {}
|
|
@ -0,0 +1,16 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: deny
|
||||
spec:
|
||||
validationFailureAction: Audit
|
||||
background: true
|
||||
rules:
|
||||
- name: deny
|
||||
match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- '*/status'
|
||||
validate:
|
||||
deny: {}
|
|
@ -0,0 +1,5 @@
|
|||
apiVersion: kuttl.dev/v1beta1
|
||||
kind: TestStep
|
||||
apply:
|
||||
- file: policy-1.yaml
|
||||
shouldFail: true
|
|
@ -0,0 +1,5 @@
|
|||
apiVersion: kuttl.dev/v1beta1
|
||||
kind: TestStep
|
||||
apply:
|
||||
- file: policy-2.yaml
|
||||
shouldFail: true
|
|
@ -0,0 +1,5 @@
|
|||
apiVersion: kuttl.dev/v1beta1
|
||||
kind: TestStep
|
||||
apply:
|
||||
- file: policy-3.yaml
|
||||
shouldFail: true
|
|
@ -0,0 +1,5 @@
|
|||
apiVersion: kuttl.dev/v1beta1
|
||||
kind: TestStep
|
||||
apply:
|
||||
- file: policy-4.yaml
|
||||
shouldFail: true
|
|
@ -0,0 +1,5 @@
|
|||
apiVersion: kuttl.dev/v1beta1
|
||||
kind: TestStep
|
||||
apply:
|
||||
- file: policy-5.yaml
|
||||
shouldFail: true
|
|
@ -0,0 +1,7 @@
|
|||
## Description
|
||||
|
||||
This test tries to create various policies targeting subresources and `background` set to `true`.
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
Every policies creation is expected to fail.
|
|
@ -0,0 +1,16 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: Policy
|
||||
metadata:
|
||||
name: deny
|
||||
spec:
|
||||
validationFailureAction: Audit
|
||||
background: true
|
||||
rules:
|
||||
- name: deny
|
||||
match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- Scale
|
||||
validate:
|
||||
deny: {}
|
|
@ -0,0 +1,16 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: Policy
|
||||
metadata:
|
||||
name: deny
|
||||
spec:
|
||||
validationFailureAction: Audit
|
||||
background: true
|
||||
rules:
|
||||
- name: deny
|
||||
match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- Pod/scale
|
||||
validate:
|
||||
deny: {}
|
|
@ -0,0 +1,16 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: Policy
|
||||
metadata:
|
||||
name: deny
|
||||
spec:
|
||||
validationFailureAction: Audit
|
||||
background: true
|
||||
rules:
|
||||
- name: deny
|
||||
match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- Pod/*
|
||||
validate:
|
||||
deny: {}
|
|
@ -0,0 +1,16 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: Policy
|
||||
metadata:
|
||||
name: deny
|
||||
spec:
|
||||
validationFailureAction: Audit
|
||||
background: true
|
||||
rules:
|
||||
- name: deny
|
||||
match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- '*/*'
|
||||
validate:
|
||||
deny: {}
|
|
@ -0,0 +1,16 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: Policy
|
||||
metadata:
|
||||
name: deny
|
||||
spec:
|
||||
validationFailureAction: Audit
|
||||
background: true
|
||||
rules:
|
||||
- name: deny
|
||||
match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- '*/status'
|
||||
validate:
|
||||
deny: {}
|
Loading…
Add table
Reference in a new issue