mirror of
https://github.com/FairwindsOps/polaris.git
synced 2026-08-29 22:17:16 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ce71f1632 | ||
|
|
98b47e0aeb | ||
|
|
159c165468 | ||
|
|
4eeabb2c7f | ||
|
|
7e35b03452 | ||
|
|
c8e4f766a2 | ||
|
|
0ee39a4470 | ||
|
|
fc7c913122 | ||
|
|
3e15586597 |
@@ -1,5 +1,13 @@
|
||||
# x.x.x (next release)
|
||||
|
||||
# 0.5.2
|
||||
* Fixed missing success messages for resource requests/limits
|
||||
|
||||
# 0.5.1
|
||||
* Added a few more exemptions
|
||||
* Started checking exemptions based on controller name prefix
|
||||
* `runAsUser != 0` now passes the `runAsNonRoot` check
|
||||
|
||||
# 0.5.0
|
||||
* Added `--load-audit-file` flag to run the dashboard from an existing audit
|
||||
* Added an `ID` field to each check in the output
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
[![Version][version-image]][version-link] [![CircleCI][circleci-image]][circleci-link] [![Go Report Card][goreport-image]][goreport-link]
|
||||
</div>
|
||||
|
||||
[version-image]: https://img.shields.io/static/v1.svg?label=Version&message=0.5.0&color=239922
|
||||
[version-image]: https://img.shields.io/static/v1.svg?label=Version&message=0.5.2&color=239922
|
||||
[version-link]: https://github.com/FairwindsOps/polaris
|
||||
|
||||
[goreport-image]: https://goreportcard.com/badge/github.com/FairwindsOps/polaris
|
||||
|
||||
+67
-57
@@ -50,71 +50,81 @@ controllers_to_scan:
|
||||
- ReplicationControllers
|
||||
exemptions:
|
||||
- controllerNames:
|
||||
- dns-controller
|
||||
- datadog-datadog
|
||||
- kube-flannel-ds
|
||||
- kube2iam
|
||||
- aws-iam-authenticator
|
||||
- datadog
|
||||
- kube2iam
|
||||
- dns-controller
|
||||
- datadog-datadog
|
||||
- kube-flannel-ds
|
||||
- kube2iam
|
||||
- aws-iam-authenticator
|
||||
- datadog
|
||||
- kube2iam
|
||||
rules:
|
||||
- hostNetworkSet
|
||||
- hostNetworkSet
|
||||
- controllerNames:
|
||||
- aws-iam-authenticator
|
||||
- aws-cluster-autoscaler
|
||||
- kube-state-metrics
|
||||
- dns-controller
|
||||
- external-dns
|
||||
- dnsmasq
|
||||
- autoscaler
|
||||
- kubernetes-dashboard
|
||||
- install-cni
|
||||
- kube2iam
|
||||
- aws-iam-authenticator
|
||||
- aws-cluster-autoscaler
|
||||
- kube-state-metrics
|
||||
- dns-controller
|
||||
- external-dns
|
||||
- dnsmasq
|
||||
- autoscaler
|
||||
- kubernetes-dashboard
|
||||
- install-cni
|
||||
- kube2iam
|
||||
rules:
|
||||
- readinessProbeMissing
|
||||
- livenessProbeMissing
|
||||
- readinessProbeMissing
|
||||
- livenessProbeMissing
|
||||
- controllerNames:
|
||||
- aws-iam-authenticator
|
||||
- nginx-ingress-controller
|
||||
- nginx-ingress-default-backend
|
||||
- aws-cluster-autoscaler
|
||||
- kube-state-metrics
|
||||
- dns-controller
|
||||
- external-dns
|
||||
- kubedns
|
||||
- dnsmasq
|
||||
- autoscaler
|
||||
- tiller
|
||||
- kube2iam
|
||||
- aws-iam-authenticator
|
||||
- nginx-ingress-controller
|
||||
- nginx-ingress-default-backend
|
||||
- aws-cluster-autoscaler
|
||||
- kube-state-metrics
|
||||
- dns-controller
|
||||
- external-dns
|
||||
- kubedns
|
||||
- dnsmasq
|
||||
- autoscaler
|
||||
- tiller
|
||||
- kube2iam
|
||||
rules:
|
||||
- runAsRootAllowed
|
||||
- runAsRootAllowed
|
||||
- controllerNames:
|
||||
- aws-iam-authenticator
|
||||
- nginx-ingress-controller
|
||||
- nginx-ingress-default-backend
|
||||
- aws-cluster-autoscaler
|
||||
- kube-state-metrics
|
||||
- dns-controller
|
||||
- external-dns
|
||||
- kubedns
|
||||
- dnsmasq
|
||||
- autoscaler
|
||||
- tiller
|
||||
- kube2iam
|
||||
- aws-iam-authenticator
|
||||
- nginx-ingress-controller
|
||||
- nginx-ingress-default-backend
|
||||
- aws-cluster-autoscaler
|
||||
- kube-state-metrics
|
||||
- dns-controller
|
||||
- external-dns
|
||||
- kubedns
|
||||
- dnsmasq
|
||||
- autoscaler
|
||||
- tiller
|
||||
- kube2iam
|
||||
rules:
|
||||
- notReadOnlyRootFileSystem
|
||||
- notReadOnlyRootFileSystem
|
||||
- controllerNames:
|
||||
- cert-manager
|
||||
- dns-controller
|
||||
- kubedns
|
||||
- dnsmasq
|
||||
- autoscaler
|
||||
- cert-manager
|
||||
- dns-controller
|
||||
- kubedns
|
||||
- dnsmasq
|
||||
- autoscaler
|
||||
rules:
|
||||
- cpuRequestsMissing
|
||||
- cpuLimitsMissing
|
||||
- memoryRequestsMissing
|
||||
- memoryLimitsMissing
|
||||
- cpuRequestsMissing
|
||||
- cpuLimitsMissing
|
||||
- memoryRequestsMissing
|
||||
- memoryLimitsMissing
|
||||
- controllerNames:
|
||||
- kube2iam
|
||||
- kube2iam
|
||||
rules:
|
||||
- runAsPrivileged
|
||||
- runAsPrivileged
|
||||
- controllerNames:
|
||||
- kube-hunter
|
||||
rules:
|
||||
- hostPIDSet
|
||||
- controllerNames:
|
||||
- polaris
|
||||
- kube-hunter
|
||||
- goldilocks
|
||||
rules:
|
||||
- readOnlyRootFilesystem
|
||||
|
||||
@@ -41,7 +41,7 @@ import (
|
||||
|
||||
const (
|
||||
// Version represents the current release version of Polaris
|
||||
Version = "0.5.0"
|
||||
Version = "0.5.2"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
@@ -125,8 +125,8 @@ type SecurityCapabilityLists struct {
|
||||
func ParseFile(path string) (Configuration, error) {
|
||||
var rawBytes []byte
|
||||
var err error
|
||||
configBox := packr.New("Config", "../../examples")
|
||||
if path == "" {
|
||||
configBox := packr.New("Config", "../../examples")
|
||||
rawBytes, err = configBox.Find("config.yaml")
|
||||
} else if strings.HasPrefix(path, "https://") || strings.HasPrefix(path, "http://") {
|
||||
//path is a url
|
||||
|
||||
@@ -2,16 +2,23 @@ package config
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// IsActionable determines whether a check is actionable given the current configuration
|
||||
func (conf *Configuration) IsActionable(subConf interface{}, ruleName, controllerName string) bool {
|
||||
ruleID := GetIDFromField(subConf, ruleName)
|
||||
subConfRef := reflect.ValueOf(subConf)
|
||||
severity, ok := reflect.Indirect(subConfRef).FieldByName(ruleName).Interface().(Severity)
|
||||
if ok && !severity.IsActionable() {
|
||||
fieldVal := reflect.Indirect(subConfRef).FieldByName(ruleName).Interface()
|
||||
if severity, ok := fieldVal.(Severity); ok && !severity.IsActionable() {
|
||||
return false
|
||||
}
|
||||
if ranges, ok := fieldVal.(ResourceRanges); ok {
|
||||
if ranges.Warning.Above == nil && ranges.Warning.Below == nil &&
|
||||
ranges.Error.Above == nil && ranges.Error.Below == nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if conf.DisallowExemptions {
|
||||
return true
|
||||
}
|
||||
@@ -21,7 +28,7 @@ func (conf *Configuration) IsActionable(subConf interface{}, ruleName, controlle
|
||||
continue
|
||||
}
|
||||
for _, controller := range example.ControllerNames {
|
||||
if controller == controllerName {
|
||||
if strings.HasPrefix(controllerName, controller) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
+20
-15
@@ -86,42 +86,50 @@ func (cv *ContainerValidation) validateResources(conf *config.Configuration, con
|
||||
|
||||
missingName := "CPURequestsMissing"
|
||||
rangeName := "CPURequestRanges"
|
||||
id := config.GetIDFromField(conf.Resources, missingName)
|
||||
if conf.IsActionable(conf.Resources, missingName, controllerName) && res.Requests.Cpu().MilliValue() == 0 {
|
||||
id := config.GetIDFromField(conf.Resources, missingName)
|
||||
cv.addFailure(messages.CPURequestsFailure, conf.Resources.CPURequestsMissing, category, id)
|
||||
} else if conf.IsActionable(conf.Resources, rangeName, controllerName) {
|
||||
id := config.GetIDFromField(conf.Resources, rangeName)
|
||||
cv.validateResourceRange(id, messages.CPURequestsLabel, &conf.Resources.CPURequestRanges, res.Requests.Cpu())
|
||||
} else if conf.IsActionable(conf.Resources, missingName, controllerName) {
|
||||
cv.addSuccess(fmt.Sprintf(messages.ResourcePresentSuccess, messages.CPURequestsLabel), category, id)
|
||||
}
|
||||
|
||||
missingName = "CPULimitsMissing"
|
||||
rangeName = "CPULimitRanges"
|
||||
id = config.GetIDFromField(conf.Resources, missingName)
|
||||
if conf.IsActionable(conf.Resources, missingName, controllerName) && res.Limits.Cpu().MilliValue() == 0 {
|
||||
id := config.GetIDFromField(conf.Resources, missingName)
|
||||
cv.addFailure(messages.CPULimitsFailure, conf.Resources.CPULimitsMissing, category, id)
|
||||
} else if conf.IsActionable(conf.Resources, rangeName, controllerName) {
|
||||
id := config.GetIDFromField(conf.Resources, rangeName)
|
||||
cv.validateResourceRange(id, messages.CPULimitsLabel, &conf.Resources.CPULimitRanges, res.Requests.Cpu())
|
||||
} else if conf.IsActionable(conf.Resources, missingName, controllerName) {
|
||||
cv.addSuccess(fmt.Sprintf(messages.ResourcePresentSuccess, messages.CPULimitsLabel), category, id)
|
||||
}
|
||||
|
||||
missingName = "MemoryRequestsMissing"
|
||||
rangeName = "MemoryRequestRanges"
|
||||
id = config.GetIDFromField(conf.Resources, missingName)
|
||||
if conf.IsActionable(conf.Resources, missingName, controllerName) && res.Requests.Memory().MilliValue() == 0 {
|
||||
id := config.GetIDFromField(conf.Resources, missingName)
|
||||
cv.addFailure(messages.MemoryRequestsFailure, conf.Resources.MemoryRequestsMissing, category, id)
|
||||
} else if conf.IsActionable(conf.Resources, rangeName, controllerName) {
|
||||
id := config.GetIDFromField(conf.Resources, rangeName)
|
||||
cv.validateResourceRange(id, messages.MemoryRequestsLabel, &conf.Resources.MemoryRequestRanges, res.Requests.Memory())
|
||||
} else if conf.IsActionable(conf.Resources, missingName, controllerName) {
|
||||
cv.addSuccess(fmt.Sprintf(messages.ResourcePresentSuccess, messages.MemoryRequestsLabel), category, id)
|
||||
}
|
||||
|
||||
missingName = "MemoryLimitsMissing"
|
||||
rangeName = "MemoryLimitRanges"
|
||||
id = config.GetIDFromField(conf.Resources, missingName)
|
||||
if conf.IsActionable(conf.Resources, missingName, controllerName) && res.Limits.Memory().MilliValue() == 0 {
|
||||
id := config.GetIDFromField(conf.Resources, missingName)
|
||||
cv.addFailure(messages.MemoryLimitsFailure, conf.Resources.MemoryLimitsMissing, category, id)
|
||||
} else if conf.IsActionable(conf.Resources, rangeName, controllerName) {
|
||||
id := config.GetIDFromField(conf.Resources, rangeName)
|
||||
cv.validateResourceRange(id, messages.MemoryLimitsLabel, &conf.Resources.MemoryLimitRanges, res.Limits.Memory())
|
||||
} else if conf.IsActionable(conf.Resources, missingName, controllerName) {
|
||||
cv.addSuccess(fmt.Sprintf(messages.ResourcePresentSuccess, messages.MemoryLimitsLabel), category, id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,19 +243,16 @@ func (cv *ContainerValidation) validateSecurity(conf *config.Configuration, cont
|
||||
name := "RunAsRootAllowed"
|
||||
if conf.IsActionable(conf.Security, name, controllerName) {
|
||||
id := config.GetIDFromField(conf.Security, name)
|
||||
if getBoolValue(securityContext.RunAsNonRoot) {
|
||||
runAsRootSuccess := false
|
||||
if getBoolValue(securityContext.RunAsNonRoot) || (securityContext.RunAsUser != nil && *securityContext.RunAsUser > 0) {
|
||||
// Check if the container is explicitly set to True (pass)
|
||||
runAsRootSuccess = true
|
||||
} else if securityContext.RunAsNonRoot == nil && securityContext.RunAsUser == nil {
|
||||
// Or if the container values are unset, check the pod values
|
||||
runAsRootSuccess = getBoolValue(podSecurityContext.RunAsNonRoot) || (podSecurityContext.RunAsUser != nil && *podSecurityContext.RunAsUser > 0)
|
||||
}
|
||||
if runAsRootSuccess {
|
||||
cv.addSuccess(messages.RunAsRootSuccess, category, id)
|
||||
} else if securityContext.RunAsNonRoot == nil {
|
||||
// Check if the value in the container spec if nil (thus defaulting to the podspec)
|
||||
// Check if the container value is not set
|
||||
if getBoolValue(podSecurityContext.RunAsNonRoot) {
|
||||
// if the pod spec default for containers is true, then pass
|
||||
cv.addSuccess(messages.RunAsRootSuccess, category, id)
|
||||
} else {
|
||||
// else fail as RunAsNonRoot defaults to false
|
||||
cv.addFailure(messages.RunAsRootFailure, conf.Security.RunAsRootAllowed, category, id)
|
||||
}
|
||||
} else {
|
||||
cv.addFailure(messages.RunAsRootFailure, conf.Security.RunAsRootAllowed, category, id)
|
||||
}
|
||||
|
||||
+215
-19
@@ -15,6 +15,7 @@
|
||||
package validator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
conf "github.com/fairwindsops/polaris/pkg/config"
|
||||
@@ -119,6 +120,27 @@ exemptions:
|
||||
- foo
|
||||
`
|
||||
|
||||
func testValidateResources(t *testing.T, container *corev1.Container, resourceConf *string, controllerName string, expectedErrors []*ResultMessage, expectedWarnings []*ResultMessage, expectedSuccesses []*ResultMessage) {
|
||||
cv := ContainerValidation{
|
||||
Container: container,
|
||||
ResourceValidation: &ResourceValidation{},
|
||||
}
|
||||
|
||||
parsedConf, err := conf.Parse([]byte(*resourceConf))
|
||||
assert.NoError(t, err, "Expected no error when parsing config")
|
||||
|
||||
cv.validateResources(&parsedConf, controllerName)
|
||||
|
||||
assert.Len(t, cv.Warnings, len(expectedWarnings))
|
||||
assert.ElementsMatch(t, expectedWarnings, cv.Warnings)
|
||||
|
||||
assert.Len(t, cv.Errors, len(expectedErrors))
|
||||
assert.ElementsMatch(t, expectedErrors, cv.Errors)
|
||||
|
||||
assert.Len(t, cv.Successes, len(expectedSuccesses))
|
||||
assert.ElementsMatch(t, expectedSuccesses, cv.Successes)
|
||||
}
|
||||
|
||||
func TestValidateResourcesEmptyConfig(t *testing.T) {
|
||||
container := corev1.Container{
|
||||
Name: "Empty",
|
||||
@@ -168,7 +190,9 @@ func TestValidateResourcesEmptyContainer(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
testValidateResources(t, &container, &resourceConf2, "foo", &expectedErrors, &expectedWarnings)
|
||||
expectedSuccesses := []*ResultMessage{}
|
||||
|
||||
testValidateResources(t, &container, &resourceConf2, "foo", expectedErrors, expectedWarnings, expectedSuccesses)
|
||||
}
|
||||
|
||||
func TestValidateResourcesPartiallyValid(t *testing.T) {
|
||||
@@ -220,7 +244,9 @@ func TestValidateResourcesPartiallyValid(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
testValidateResources(t, &container, &resourceConf1, "foo", &expectedErrors, &expectedWarnings)
|
||||
expectedSuccesses := []*ResultMessage{}
|
||||
|
||||
testValidateResources(t, &container, &resourceConf1, "foo", expectedErrors, expectedWarnings, expectedSuccesses)
|
||||
}
|
||||
|
||||
func TestValidateResourcesInit(t *testing.T) {
|
||||
@@ -271,24 +297,63 @@ func TestValidateResourcesFullyValid(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
testValidateResources(t, &container, &resourceConf1, "foo", &[]*ResultMessage{}, &[]*ResultMessage{})
|
||||
}
|
||||
|
||||
func testValidateResources(t *testing.T, container *corev1.Container, resourceConf *string, controllerName string, expectedErrors *[]*ResultMessage, expectedWarnings *[]*ResultMessage) {
|
||||
cv := ContainerValidation{
|
||||
Container: container,
|
||||
ResourceValidation: &ResourceValidation{},
|
||||
expectedSuccesses := []*ResultMessage{
|
||||
{
|
||||
ID: "cpuRequestRanges",
|
||||
Type: "success",
|
||||
Message: "CPU requests are within the expected range",
|
||||
Category: "Resources",
|
||||
},
|
||||
{
|
||||
ID: "memoryRequestRanges",
|
||||
Type: "success",
|
||||
Message: "Memory requests are within the expected range",
|
||||
Category: "Resources",
|
||||
},
|
||||
{
|
||||
ID: "cpuLimitRanges",
|
||||
Type: "success",
|
||||
Message: "CPU limits are within the expected range",
|
||||
Category: "Resources",
|
||||
},
|
||||
{
|
||||
ID: "memoryLimitRanges",
|
||||
Type: "success",
|
||||
Message: "Memory limits are within the expected range",
|
||||
Category: "Resources",
|
||||
},
|
||||
}
|
||||
|
||||
parsedConf, err := conf.Parse([]byte(*resourceConf))
|
||||
assert.NoError(t, err, "Expected no error when parsing config")
|
||||
testValidateResources(t, &container, &resourceConf1, "foo", []*ResultMessage{}, []*ResultMessage{}, expectedSuccesses)
|
||||
|
||||
cv.validateResources(&parsedConf, controllerName)
|
||||
assert.Len(t, cv.Warnings, len(*expectedWarnings))
|
||||
assert.ElementsMatch(t, *expectedWarnings, cv.Warnings)
|
||||
expectedSuccesses = []*ResultMessage{
|
||||
{
|
||||
ID: "cpuRequestsMissing",
|
||||
Type: "success",
|
||||
Message: "CPU requests are set",
|
||||
Category: "Resources",
|
||||
},
|
||||
{
|
||||
ID: "memoryRequestsMissing",
|
||||
Type: "success",
|
||||
Message: "Memory requests are set",
|
||||
Category: "Resources",
|
||||
},
|
||||
{
|
||||
ID: "cpuLimitsMissing",
|
||||
Type: "success",
|
||||
Message: "CPU limits are set",
|
||||
Category: "Resources",
|
||||
},
|
||||
{
|
||||
ID: "memoryLimitsMissing",
|
||||
Type: "success",
|
||||
Message: "Memory limits are set",
|
||||
Category: "Resources",
|
||||
},
|
||||
}
|
||||
|
||||
assert.Len(t, cv.Errors, len(*expectedErrors))
|
||||
assert.ElementsMatch(t, *expectedErrors, cv.Errors)
|
||||
testValidateResources(t, &container, &resourceConf2, "foo", []*ResultMessage{}, []*ResultMessage{}, expectedSuccesses)
|
||||
}
|
||||
|
||||
func TestValidateHealthChecks(t *testing.T) {
|
||||
@@ -1075,6 +1140,135 @@ func TestValidateSecurity(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateRunAsRoot(t *testing.T) {
|
||||
falseVar := false
|
||||
trueVar := true
|
||||
nonRootUser := int64(1000)
|
||||
rootUser := int64(0)
|
||||
config := conf.Configuration{
|
||||
Security: conf.Security{
|
||||
RunAsRootAllowed: conf.SeverityWarning,
|
||||
},
|
||||
}
|
||||
testCases := []struct {
|
||||
cv ContainerValidation
|
||||
message ResultMessage
|
||||
}{
|
||||
{
|
||||
cv: ContainerValidation{
|
||||
ResourceValidation: &ResourceValidation{},
|
||||
Container: &corev1.Container{Name: "", SecurityContext: &corev1.SecurityContext{
|
||||
RunAsNonRoot: nil,
|
||||
}},
|
||||
parentPodSpec: corev1.PodSpec{
|
||||
SecurityContext: &corev1.PodSecurityContext{
|
||||
RunAsNonRoot: &falseVar,
|
||||
},
|
||||
},
|
||||
},
|
||||
message: ResultMessage{
|
||||
ID: "runAsRootAllowed",
|
||||
Message: "Should not be allowed to run as root",
|
||||
Type: "warning",
|
||||
Category: "Security",
|
||||
},
|
||||
},
|
||||
{
|
||||
cv: ContainerValidation{
|
||||
ResourceValidation: &ResourceValidation{},
|
||||
Container: &corev1.Container{Name: "", SecurityContext: &corev1.SecurityContext{
|
||||
RunAsNonRoot: &trueVar,
|
||||
}},
|
||||
parentPodSpec: corev1.PodSpec{
|
||||
SecurityContext: &corev1.PodSecurityContext{
|
||||
RunAsNonRoot: &falseVar,
|
||||
},
|
||||
},
|
||||
},
|
||||
message: ResultMessage{
|
||||
ID: "runAsRootAllowed",
|
||||
Message: "Is not allowed to run as root",
|
||||
Type: "success",
|
||||
Category: "Security",
|
||||
},
|
||||
},
|
||||
{
|
||||
cv: ContainerValidation{
|
||||
ResourceValidation: &ResourceValidation{},
|
||||
Container: &corev1.Container{Name: "", SecurityContext: &corev1.SecurityContext{
|
||||
RunAsUser: &nonRootUser,
|
||||
}},
|
||||
},
|
||||
message: ResultMessage{
|
||||
ID: "runAsRootAllowed",
|
||||
Message: "Is not allowed to run as root",
|
||||
Type: "success",
|
||||
Category: "Security",
|
||||
},
|
||||
},
|
||||
{
|
||||
cv: ContainerValidation{
|
||||
ResourceValidation: &ResourceValidation{},
|
||||
Container: &corev1.Container{Name: "", SecurityContext: &corev1.SecurityContext{}},
|
||||
parentPodSpec: corev1.PodSpec{
|
||||
SecurityContext: &corev1.PodSecurityContext{
|
||||
RunAsUser: &nonRootUser,
|
||||
},
|
||||
},
|
||||
},
|
||||
message: ResultMessage{
|
||||
ID: "runAsRootAllowed",
|
||||
Message: "Is not allowed to run as root",
|
||||
Type: "success",
|
||||
Category: "Security",
|
||||
},
|
||||
},
|
||||
{
|
||||
cv: ContainerValidation{
|
||||
ResourceValidation: &ResourceValidation{},
|
||||
Container: &corev1.Container{Name: "", SecurityContext: &corev1.SecurityContext{
|
||||
RunAsUser: &rootUser,
|
||||
}},
|
||||
parentPodSpec: corev1.PodSpec{
|
||||
SecurityContext: &corev1.PodSecurityContext{
|
||||
RunAsUser: &nonRootUser,
|
||||
},
|
||||
},
|
||||
},
|
||||
message: ResultMessage{
|
||||
ID: "runAsRootAllowed",
|
||||
Message: "Should not be allowed to run as root",
|
||||
Type: "warning",
|
||||
Category: "Security",
|
||||
},
|
||||
},
|
||||
{
|
||||
cv: ContainerValidation{
|
||||
ResourceValidation: &ResourceValidation{},
|
||||
Container: &corev1.Container{Name: "", SecurityContext: &corev1.SecurityContext{
|
||||
RunAsNonRoot: &falseVar,
|
||||
}},
|
||||
parentPodSpec: corev1.PodSpec{
|
||||
SecurityContext: &corev1.PodSecurityContext{
|
||||
RunAsUser: &nonRootUser,
|
||||
},
|
||||
},
|
||||
},
|
||||
message: ResultMessage{
|
||||
ID: "runAsRootAllowed",
|
||||
Message: "Should not be allowed to run as root",
|
||||
Type: "warning",
|
||||
Category: "Security",
|
||||
},
|
||||
},
|
||||
}
|
||||
for idx, tt := range testCases {
|
||||
tt.cv.validateSecurity(&config, "")
|
||||
assert.Len(t, tt.cv.messages(), 1)
|
||||
assert.Equal(t, &tt.message, tt.cv.messages()[0], fmt.Sprintf("Test case %d failed", idx))
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateResourcesExemption(t *testing.T) {
|
||||
container := corev1.Container{
|
||||
Name: "Empty",
|
||||
@@ -1082,8 +1276,9 @@ func TestValidateResourcesExemption(t *testing.T) {
|
||||
|
||||
expectedWarnings := []*ResultMessage{}
|
||||
expectedErrors := []*ResultMessage{}
|
||||
expectedSuccesses := []*ResultMessage{}
|
||||
|
||||
testValidateResources(t, &container, &resourceConfExemptions, "foo", &expectedErrors, &expectedWarnings)
|
||||
testValidateResources(t, &container, &resourceConfExemptions, "foo", expectedErrors, expectedWarnings, expectedSuccesses)
|
||||
|
||||
expectedWarnings = []*ResultMessage{
|
||||
{
|
||||
@@ -1117,7 +1312,7 @@ func TestValidateResourcesExemption(t *testing.T) {
|
||||
|
||||
disallowExemptionsConf := resourceConfExemptions + "\ndisallowExemptions: true"
|
||||
|
||||
testValidateResources(t, &container, &disallowExemptionsConf, "foo", &expectedErrors, &expectedWarnings)
|
||||
testValidateResources(t, &container, &disallowExemptionsConf, "foo", expectedErrors, expectedWarnings, expectedSuccesses)
|
||||
}
|
||||
|
||||
func TestValidateResourceRangeExemption(t *testing.T) {
|
||||
@@ -1127,8 +1322,9 @@ func TestValidateResourceRangeExemption(t *testing.T) {
|
||||
|
||||
expectedWarnings := []*ResultMessage{}
|
||||
expectedErrors := []*ResultMessage{}
|
||||
expectedSuccesses := []*ResultMessage{}
|
||||
|
||||
testValidateResources(t, &container, &resourceConfRangeExemptions, "foo", &expectedErrors, &expectedWarnings)
|
||||
testValidateResources(t, &container, &resourceConfRangeExemptions, "foo", expectedErrors, expectedWarnings, expectedSuccesses)
|
||||
}
|
||||
|
||||
func resetCV(cv ContainerValidation) ContainerValidation {
|
||||
|
||||
Reference in New Issue
Block a user