Implement namespace support for exceptions (#421)

* Implement namespace support for exceptions

Signed-off-by: Markus Blaschke <mblaschke82@gmail.com>

* remove debug

Signed-off-by: Markus Blaschke <mblaschke82@gmail.com>

* Add documentation

Signed-off-by: Markus Blaschke <mblaschke82@gmail.com>

Co-authored-by: baderbuddy <bader@fairwinds.com>
This commit is contained in:
Markus Blaschke
2020-10-19 14:45:45 +02:00
committed by GitHub
parent b27f619d5e
commit 5bce1db05e
8 changed files with 50 additions and 12 deletions

View File

@@ -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:

View File

@@ -35,6 +35,12 @@ exemptions:
rules:
- hostNetworkSet
- hostPortSet
- namespace: kube-system
controllerNames:
- my-network-controller
rules:
- hostNetworkSet
- hostPortSet
customChecks:
resourceLimits:

View File

@@ -27,7 +27,8 @@ checks:
insecureCapabilities: warning
exemptions:
- controllerNames:
- namespace: kube-system
controllerNames:
- kube-apiserver
- kube-proxy
- kube-scheduler

View File

@@ -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)

View File

@@ -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

View File

@@ -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.")
}

View File

@@ -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
}

View File

@@ -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