diff --git a/pkg/policymutation/policymutation.go b/pkg/policymutation/policymutation.go index 2ed877009b..b97255fc98 100644 --- a/pkg/policymutation/policymutation.go +++ b/pkg/policymutation/policymutation.go @@ -316,10 +316,13 @@ func generateRuleForControllers(rule kyverno.Rule, controllers string, log logr. MatchResources: match.DeepCopy(), } + if !reflect.DeepEqual(exclude, kyverno.ExcludeResources{}) { + controllerRule.ExcludeResources = exclude.DeepCopy() + } + // overwrite Kinds by pod controllers defined in the annotation controllerRule.MatchResources.Kinds = strings.Split(controllers, ",") if len(exclude.Kinds) != 0 { - controllerRule.ExcludeResources = exclude.DeepCopy() controllerRule.ExcludeResources.Kinds = strings.Split(controllers, ",") } diff --git a/pkg/policymutation/policymutation_test.go b/pkg/policymutation/policymutation_test.go index b9a5f70c7a..19e057fd4e 100644 --- a/pkg/policymutation/policymutation_test.go +++ b/pkg/policymutation/policymutation_test.go @@ -21,6 +21,32 @@ func currentDir() (string, error) { return filepath.Join(homedir, "github.com/nirmata/kyverno"), nil } +func Test_Exclude(t *testing.T) { + dir, err := os.Getwd() + baseDir := filepath.Dir(filepath.Dir(dir)) + assert.NilError(t, err) + + policies, errs := utils.GetPolicy(baseDir + "/samples/best_practices/disallow_bind_mounts.yaml") + if len(errs) != 0 { + t.Log(errs) + } + + policy := policies[0] + policy.Spec.Rules[0].ExcludeResources.Namespaces = []string{"fake-namespce"} + + rulePatches, errs := generateRulePatches(*policy, engine.PodControllers, log.Log) + if len(errs) != 0 { + t.Log(errs) + } + + expectedPatches := [][]byte{ + []byte(`{"path":"/spec/rules/1","op":"add","value":{"name":"autogen-validate-hostPath","match":{"resources":{"kinds":["DaemonSet","Deployment","Job","StatefulSet"]}},"exclude":{"resources":{"namespaces":["fake-namespce"]}},"validate":{"message":"Host path volumes are not allowed","pattern":{"spec":{"template":{"spec":{"=(volumes)":[{"X(hostPath)":"null"}]}}}}}}}`), + []byte(`{"path":"/spec/rules/2","op":"add","value":{"name":"autogen-cronjob-validate-hostPath","match":{"resources":{"kinds":["CronJob"]}},"exclude":{"resources":{"namespaces":["fake-namespce"]}},"validate":{"message":"Host path volumes are not allowed","pattern":{"spec":{"jobTemplate":{"spec":{"template":{"spec":{"=(volumes)":[{"X(hostPath)":"null"}]}}}}}}}}}`), + } + + assert.DeepEqual(t, rulePatches, expectedPatches) +} + func Test_CronJobOnly(t *testing.T) { controllers := engine.PodControllerCronJob @@ -44,7 +70,7 @@ func Test_CronJobOnly(t *testing.T) { } expectedPatches := [][]byte{ - []byte(`{"path":"/spec/rules/1","op":"add","value":{"name":"autogen-cronjob-validate-hostPath","match":{"resources":{"kinds":["CronJob"]}},"validate":{"message":"Host path volumes are not allowed","pattern":{"spec":{"jobTemplate":{"spec":{"template":{"spec":{"=(volumes)":[{"X(hostPath)":null}]}}}}}}}}}`), + []byte(`{"path":"/spec/rules/1","op":"add","value":{"name":"autogen-cronjob-validate-hostPath","match":{"resources":{"kinds":["CronJob"]}},"validate":{"message":"Host path volumes are not allowed","pattern":{"spec":{"jobTemplate":{"spec":{"template":{"spec":{"=(volumes)":[{"X(hostPath)":"null"}]}}}}}}}}}`), } assert.DeepEqual(t, rulePatches, expectedPatches) @@ -78,7 +104,7 @@ func Test_CronJob_hasExclude(t *testing.T) { } expectedPatches := [][]byte{ - []byte(`{"path":"/spec/rules/1","op":"add","value":{"name":"autogen-cronjob-validate-hostPath","match":{"resources":{"kinds":["CronJob"]}},"exclude":{"resources":{"kinds":["CronJob"],"namespaces":["test"]}},"validate":{"message":"Host path volumes are not allowed","pattern":{"spec":{"jobTemplate":{"spec":{"template":{"spec":{"=(volumes)":[{"X(hostPath)":null}]}}}}}}}}}`), + []byte(`{"path":"/spec/rules/1","op":"add","value":{"name":"autogen-cronjob-validate-hostPath","match":{"resources":{"kinds":["CronJob"]}},"exclude":{"resources":{"kinds":["CronJob"],"namespaces":["test"]}},"validate":{"message":"Host path volumes are not allowed","pattern":{"spec":{"jobTemplate":{"spec":{"template":{"spec":{"=(volumes)":[{"X(hostPath)":"null"}]}}}}}}}}}`), } assert.DeepEqual(t, rulePatches, expectedPatches) @@ -106,8 +132,8 @@ func Test_CronJobAndDeployment(t *testing.T) { } expectedPatches := [][]byte{ - []byte(`{"path":"/spec/rules/1","op":"add","value":{"name":"autogen-validate-hostPath","match":{"resources":{"kinds":["Deployment"]}},"validate":{"message":"Host path volumes are not allowed","pattern":{"spec":{"template":{"spec":{"=(volumes)":[{"X(hostPath)":null}]}}}}}}}`), - []byte(`{"path":"/spec/rules/2","op":"add","value":{"name":"autogen-cronjob-validate-hostPath","match":{"resources":{"kinds":["CronJob"]}},"validate":{"message":"Host path volumes are not allowed","pattern":{"spec":{"jobTemplate":{"spec":{"template":{"spec":{"=(volumes)":[{"X(hostPath)":null}]}}}}}}}}}`), + []byte(`{"path":"/spec/rules/1","op":"add","value":{"name":"autogen-validate-hostPath","match":{"resources":{"kinds":["Deployment"]}},"validate":{"message":"Host path volumes are not allowed","pattern":{"spec":{"template":{"spec":{"=(volumes)":[{"X(hostPath)":"null"}]}}}}}}}`), + []byte(`{"path":"/spec/rules/2","op":"add","value":{"name":"autogen-cronjob-validate-hostPath","match":{"resources":{"kinds":["CronJob"]}},"validate":{"message":"Host path volumes are not allowed","pattern":{"spec":{"jobTemplate":{"spec":{"template":{"spec":{"=(volumes)":[{"X(hostPath)":"null"}]}}}}}}}}}`), } assert.DeepEqual(t, rulePatches, expectedPatches) diff --git a/samples/DisallowBindMounts.md b/samples/DisallowBindMounts.md index a46f9224fd..8b0d329e86 100644 --- a/samples/DisallowBindMounts.md +++ b/samples/DisallowBindMounts.md @@ -24,5 +24,5 @@ spec: pattern: spec: =(volumes): - - X(hostPath): null + - X(hostPath): "null" ```` diff --git a/samples/best_practices/disallow_bind_mounts.yaml b/samples/best_practices/disallow_bind_mounts.yaml index 43bcbc4185..8c26e27d47 100644 --- a/samples/best_practices/disallow_bind_mounts.yaml +++ b/samples/best_practices/disallow_bind_mounts.yaml @@ -23,4 +23,4 @@ spec: pattern: spec: =(volumes): - - X(hostPath): null + - X(hostPath): "null"