diff --git a/docs/usage.md b/docs/usage.md index d1d293e0..61ff76e8 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -71,9 +71,16 @@ To exempt a controller from all checks via annotations, use the annotation `pola kubectl annotate deployment my-deployment polaris.fairwinds.com/exempt=true ``` -To exempt a controller via the config, you have to specify a list of controller names and a list of rules, e.g. +To exempt a controller via the config, you have to specify a namespace (optional), a list of controller names and a list of rules, e.g. ```yaml exemptions: + # exception valid for kube-system namespace + - namespace: kube-system + controllerNames: + - dns-controller + rules: + - hostNetworkSet + # exception valid in all namespaces - controllerNames: - dns-controller rules: diff --git a/examples/config-full.yaml b/examples/config-full.yaml index 19d01d07..c4553d0d 100644 --- a/examples/config-full.yaml +++ b/examples/config-full.yaml @@ -35,6 +35,12 @@ exemptions: rules: - hostNetworkSet - hostPortSet + - namespace: kube-system + controllerNames: + - my-network-controller + rules: + - hostNetworkSet + - hostPortSet customChecks: resourceLimits: diff --git a/examples/config.yaml b/examples/config.yaml index cd3b1dba..403fa355 100644 --- a/examples/config.yaml +++ b/examples/config.yaml @@ -27,7 +27,8 @@ checks: insecureCapabilities: warning exemptions: - - controllerNames: + - namespace: kube-system + controllerNames: - kube-apiserver - kube-proxy - kube-scheduler diff --git a/pkg/config/config.go b/pkg/config/config.go index e697926c..0137f849 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -40,6 +40,7 @@ type Configuration struct { type Exemption struct { Rules []string `json:"rules"` ControllerNames []string `json:"controllerNames"` + Namespace string `json:"namespace"` } var configBox = (*packr.Box)(nil) diff --git a/pkg/config/exemptions.go b/pkg/config/exemptions.go index 31711797..2f413525 100644 --- a/pkg/config/exemptions.go +++ b/pkg/config/exemptions.go @@ -5,7 +5,7 @@ import ( ) // IsActionable determines whether a check is actionable given the current configuration -func (conf Configuration) IsActionable(ruleID, controllerName string) bool { +func (conf Configuration) IsActionable(ruleID, namespace, controllerName string) bool { if severity, ok := conf.Checks[ruleID]; !ok || !severity.IsActionable() { return false } @@ -14,10 +14,15 @@ func (conf Configuration) IsActionable(ruleID, controllerName string) bool { } for _, example := range conf.Exemptions { + if example.Namespace != "" && example.Namespace != namespace { + continue + } + for _, rule := range example.Rules { if rule != ruleID { continue } + for _, controller := range example.ControllerNames { if strings.HasPrefix(controllerName, controller) { return false diff --git a/pkg/config/exemptions_test.go b/pkg/config/exemptions_test.go index ebffc12c..cead8aab 100644 --- a/pkg/config/exemptions_test.go +++ b/pkg/config/exemptions_test.go @@ -39,10 +39,19 @@ exemptions: - test ` +var confNamespaceTest = ` +checks: + ANY: warning +exemptions: + - namespace: kube-system + controllerNames: + - test +` + func TestInclusiveExemption(t *testing.T) { parsedConf, _ := Parse([]byte(confExemptTest)) - applicable := parsedConf.IsActionable("ANY", "test") - applicableOtherController := parsedConf.IsActionable("ANY", "other") + applicable := parsedConf.IsActionable("ANY", "test", "test") + applicableOtherController := parsedConf.IsActionable("ANY","test", "other") assert.False(t, applicable, "Expected all checks to be exempted when their controller is specified.") assert.True(t, applicableOtherController, "Expected checks to only be exempted when their controller is specified.") @@ -50,13 +59,22 @@ func TestInclusiveExemption(t *testing.T) { func TestIndividualRuleException(t *testing.T) { parsedConf, _ := Parse([]byte(confExemptRuleTest)) - applicable := parsedConf.IsActionable("ANY", "test") - applicableOtherRule := parsedConf.IsActionable("OTHER", "test") - applicableOtherRuleOtherController := parsedConf.IsActionable("OTHER", "other") - applicableRuleOtherController := parsedConf.IsActionable("ANY", "other") + applicable := parsedConf.IsActionable("ANY", "test", "test") + applicableOtherRule := parsedConf.IsActionable("OTHER","test", "test") + applicableOtherRuleOtherController := parsedConf.IsActionable("OTHER","test", "other") + applicableRuleOtherController := parsedConf.IsActionable("ANY","test", "other") assert.False(t, applicable, "Expected all checks to be exempted when their controller and rule are specified.") assert.True(t, applicableOtherRule, "Expected checks to only be exempted when their controller and rule are specified.") assert.True(t, applicableOtherRuleOtherController, "Expected checks to only be exempted when their controller and rule are specified.") assert.True(t, applicableRuleOtherController, "Expected checks to only be exempted when their controller and rule are specified.") } + +func TestNamespaceExemption(t *testing.T) { + parsedConf, _ := Parse([]byte(confNamespaceTest)) + applicable := parsedConf.IsActionable("ANY", "kube-system", "test") + applicableOtherController := parsedConf.IsActionable("ANY","default", "test") + + assert.False(t, applicable, "Expected all checks to be exempted when their namespace and controller is specified.") + assert.True(t, applicableOtherController, "Expected checks to only be exempted when their namespace and controller is specified.") +} \ No newline at end of file diff --git a/pkg/config/schema.go b/pkg/config/schema.go index 255741b1..0ef8b055 100644 --- a/pkg/config/schema.go +++ b/pkg/config/schema.go @@ -152,7 +152,7 @@ func (check SchemaCheck) CheckObject(obj interface{}) (bool, error) { } // IsActionable decides if this check applies to a particular target -func (check SchemaCheck) IsActionable(target TargetKind, controllerType string, isInit bool) bool { +func (check SchemaCheck) IsActionable(target TargetKind, namespace, controllerType string, isInit bool) bool { if check.Target != target { return false } diff --git a/pkg/validator/schema.go b/pkg/validator/schema.go index bc18d67b..17c38e46 100644 --- a/pkg/validator/schema.go +++ b/pkg/validator/schema.go @@ -86,10 +86,10 @@ func resolveCheck(conf *config.Configuration, checkID string, controller kube.Ge if !ok { return nil, fmt.Errorf("Check %s not found", checkID) } - if !conf.IsActionable(check.ID, controller.ObjectMeta.GetName()) { + if !conf.IsActionable(check.ID, controller.ObjectMeta.GetNamespace(), controller.ObjectMeta.GetName()) { return nil, nil } - if !check.IsActionable(target, controller.Kind, isInitContainer) { + if !check.IsActionable(target, controller.ObjectMeta.GetNamespace(), controller.Kind, isInitContainer) { return nil, nil } return &check, nil