mirror of
https://github.com/FairwindsOps/polaris.git
synced 2026-08-23 22:26:34 +00:00
change input config to simplify things
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
name: CPULimitsMissing
|
||||
id: cpuLimitsMissing
|
||||
successMessage: CPU limits are set
|
||||
failureMessage: CPU limits should be set
|
||||
category: Resources
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
name: CPURequestsMissing
|
||||
id: cpuRequestsMissing
|
||||
successMessage: CPU requests are set
|
||||
failureMessage: CPU requests should be set
|
||||
category: Resources
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
name: DangerousCapabilities
|
||||
id: dangerousCapabilities
|
||||
successMessage: Container does not have any dangerous capabilities
|
||||
failureMessage: Container should not have dangerous capabilities
|
||||
category: Security
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
name: HostIPCSet
|
||||
id: hostIPCSet
|
||||
successMessage: Host IPC is not configured
|
||||
failureMessage: Host IPC should not be configured
|
||||
category: Security
|
||||
@@ -1,5 +1,3 @@
|
||||
name: HostNetworkSet
|
||||
id: hostNetworkSet
|
||||
successMessage: Host network is not configured
|
||||
failureMessage: Host network should not be configured
|
||||
category: Networking
|
||||
@@ -1,5 +1,3 @@
|
||||
name: HostPIDSet
|
||||
id: hostPIDSet
|
||||
successMessage: Host PID is not configured
|
||||
failureMessage: Host PID should not be configured
|
||||
category: Security
|
||||
@@ -1,5 +1,3 @@
|
||||
name: HostPortSet
|
||||
id: hostPortSet
|
||||
successMessage: Host port is not configured
|
||||
failureMessage: Host port should not be configured
|
||||
category: Networking
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
name: InsecureCapabilities
|
||||
id: insecureCapabilities
|
||||
successMessage: Container does not have any insecure capabilities
|
||||
failureMessage: Container should not have insecure capabilities
|
||||
category: Security
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
name: LivenessProbeMissing
|
||||
id: livenessProbeMissing
|
||||
successMessage: Liveness probe is configured
|
||||
failureMessage: Liveness probe should be configured
|
||||
category: Health Checks
|
||||
@@ -1,5 +1,3 @@
|
||||
name: MemoryLimitsMissing
|
||||
id: memoryLimitsMissing
|
||||
successMessage: Memory limits are set
|
||||
failureMessage: Memory limits should be set
|
||||
category: Resources
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
name: MemoryRequestsMissing
|
||||
id: memoryRequestsMissing
|
||||
successMessage: Memory requests are set
|
||||
failureMessage: Memory requests should be set
|
||||
category: Resources
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
name: NotReadOnlyRootFileSystem
|
||||
id: notReadOnlyRootFileSystem
|
||||
successMessage: Filesystem is read only
|
||||
failureMessage: Filesystem should be read only
|
||||
category: Security
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
name: PrivilegeEscalationAllowed
|
||||
id: privilegeEscalationAllowed
|
||||
successMessage: Privilege escalation not allowed
|
||||
failureMessage: Privilege escalation should not be allowed
|
||||
category: Security
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
name: PullPolicyNotAlways
|
||||
id: pullPolicyNotAlways
|
||||
successMessage: Image pull policy is "Always"
|
||||
failureMessage: Image pull policy should be "Always"
|
||||
category: Images
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
name: ReadinessProbeMissing
|
||||
id: readinessProbeMissing
|
||||
successMessage: Readiness probe is configured
|
||||
failureMessage: Readiness probe should be configured
|
||||
category: Health Checks
|
||||
@@ -1,5 +1,3 @@
|
||||
name: RunAsPrivileged
|
||||
id: runAsPrivileged
|
||||
successMessage: Not running as privileged
|
||||
failureMessage: Should not be running as privileged
|
||||
category: Security
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
name: RunAsRootAllowed
|
||||
id: runAsRootAllowed
|
||||
successMessage: Is not allowed to run as root
|
||||
failureMessage: Should not be allowed to run as root
|
||||
category: Security
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
name: TagNotSpecified
|
||||
id: tagNotSpecified
|
||||
successMessage: Image tag is specified
|
||||
failureMessage: Image tag should be specified
|
||||
category: Images
|
||||
|
||||
@@ -154,6 +154,7 @@ metadata:
|
||||
namespace: polaris
|
||||
labels:
|
||||
app: polaris
|
||||
foo: bar
|
||||
component: dashboard
|
||||
spec:
|
||||
replicas: 1
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
resources:
|
||||
checks:
|
||||
# resources
|
||||
cpuRequestsMissing: warning
|
||||
cpuLimitsMissing: warning
|
||||
memoryRequestsMissing: warning
|
||||
memoryLimitsMissing: warning
|
||||
images:
|
||||
# images
|
||||
tagNotSpecified: error
|
||||
pullPolicyNotAlways: ignore
|
||||
healthChecks:
|
||||
# healthChecks
|
||||
readinessProbeMissing: warning
|
||||
livenessProbeMissing: warning
|
||||
networking:
|
||||
# networking
|
||||
hostNetworkSet: warning
|
||||
hostPortSet: warning
|
||||
security:
|
||||
# security
|
||||
hostIPCSet: error
|
||||
hostPIDSet: error
|
||||
notReadOnlyRootFileSystem: warning
|
||||
@@ -21,7 +22,7 @@ security:
|
||||
runAsPrivileged: error
|
||||
dangerousCapabilities: error
|
||||
insecureCapabilities: warning
|
||||
controllers_to_scan:
|
||||
controllersToScan:
|
||||
- Deployments
|
||||
- StatefulSets
|
||||
- DaemonSets
|
||||
|
||||
@@ -29,13 +29,8 @@ import (
|
||||
// Configuration contains all of the config for the validation checks.
|
||||
type Configuration struct {
|
||||
DisplayName string `json:"displayName"`
|
||||
Resources Resources `json:"resources"`
|
||||
HealthChecks HealthChecks `json:"healthChecks"`
|
||||
Images Images `json:"images"`
|
||||
Networking Networking `json:"networking"`
|
||||
Security Security `json:"security"`
|
||||
Checks map[string]Severity `json:"checks"`
|
||||
ControllersToScan []SupportedController `json:"controllers_to_scan"`
|
||||
ControllersToScan []SupportedController `json:"controllersToScan"`
|
||||
CustomChecks map[string]SchemaCheck `json:"customChecks"`
|
||||
Exemptions []Exemption `json:"exemptions"`
|
||||
DisallowExemptions bool `json:"disallowExemptions"`
|
||||
|
||||
@@ -29,18 +29,18 @@ import (
|
||||
var confInvalid = `test`
|
||||
|
||||
var confValidYAML = `
|
||||
resources:
|
||||
checks:
|
||||
cpuRequestsMissing: warning
|
||||
controllers_to_scan:
|
||||
controllersToScan:
|
||||
- Deployments
|
||||
`
|
||||
|
||||
var confValidJSON = `
|
||||
{
|
||||
"resources": {
|
||||
"checks": {
|
||||
"cpuRequestsMissing": "warning"
|
||||
},
|
||||
"controllers_to_scan": ["Deployments"]
|
||||
"controllersToScan": ["Deployments"]
|
||||
}
|
||||
`
|
||||
|
||||
@@ -96,7 +96,7 @@ func TestConfigNoServerError(t *testing.T) {
|
||||
}
|
||||
|
||||
func testParsedConfig(t *testing.T, config *Configuration) {
|
||||
assert.Equal(t, SeverityWarning, config.Resources.CPURequestsMissing)
|
||||
assert.Equal(t, Severity(""), config.Resources.CPULimitsMissing)
|
||||
assert.Equal(t, SeverityWarning, config.Checks["cpuRequestsMissing"])
|
||||
assert.Equal(t, Severity(""), config.Checks["cpuLimitsMissing"])
|
||||
assert.ElementsMatch(t, []SupportedController{Deployments}, config.ControllersToScan)
|
||||
}
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
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 {
|
||||
if subConfStr, ok := subConf.(string); ok {
|
||||
subConf = conf.GetCategoryConfig(subConfStr)
|
||||
}
|
||||
ruleID := GetIDFromField(subConf, ruleName)
|
||||
subConfRef := reflect.ValueOf(subConf)
|
||||
fieldVal := reflect.Indirect(subConfRef).FieldByName(ruleName).Interface()
|
||||
if severity, ok := fieldVal.(Severity); ok && !severity.IsActionable() {
|
||||
func (conf Configuration) IsActionable(ruleID, controllerName string) bool {
|
||||
if severity, ok := conf.Checks[ruleID]; !ok || !severity.IsActionable() {
|
||||
return false
|
||||
}
|
||||
if conf.DisallowExemptions {
|
||||
@@ -33,31 +26,3 @@ func (conf Configuration) IsActionable(subConf interface{}, ruleName, controller
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// GetCategoryConfig returns the configuration for a particular category name
|
||||
func (conf Configuration) GetCategoryConfig(category string) interface{} {
|
||||
if category == "Networking" {
|
||||
return conf.Networking
|
||||
} else if category == "Security" {
|
||||
return conf.Security
|
||||
} else if category == "Health Checks" {
|
||||
return conf.HealthChecks
|
||||
} else if category == "Resources" {
|
||||
return conf.Resources
|
||||
} else if category == "Images" {
|
||||
return conf.Images
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetSeverity returns the severity configured for a particular check
|
||||
func (conf Configuration) GetSeverity(category string, name string) Severity {
|
||||
subConf := conf.GetCategoryConfig(category)
|
||||
subConfRef := reflect.ValueOf(subConf)
|
||||
fieldVal := reflect.Indirect(subConfRef).FieldByName(name).Interface()
|
||||
if severity, ok := fieldVal.(Severity); ok {
|
||||
return severity
|
||||
}
|
||||
// TODO: don't panic
|
||||
panic("Unknown severity: " + category + "/" + name)
|
||||
}
|
||||
|
||||
@@ -95,7 +95,6 @@ const (
|
||||
|
||||
// SchemaCheck is a Polaris check that runs using JSON Schema
|
||||
type SchemaCheck struct {
|
||||
Name string `yaml:"name"`
|
||||
ID string `yaml:"id"`
|
||||
Category string `yaml:"category"`
|
||||
SuccessMessage string `yaml:"successMessage"`
|
||||
|
||||
@@ -25,7 +25,7 @@ import (
|
||||
)
|
||||
|
||||
var resourceConfMinimal = `---
|
||||
resources:
|
||||
checks:
|
||||
cpuRequestsMissing: warning
|
||||
memoryRequestsMissing: warning
|
||||
cpuLimitsMissing: error
|
||||
@@ -33,7 +33,7 @@ resources:
|
||||
`
|
||||
|
||||
var resourceConfExemptions = `---
|
||||
resources:
|
||||
checks:
|
||||
cpuRequestsMissing: warning
|
||||
memoryRequestsMissing: warning
|
||||
cpuLimitsMissing: error
|
||||
@@ -338,14 +338,14 @@ func TestValidateResourcesFullyValid(t *testing.T) {
|
||||
func TestValidateHealthChecks(t *testing.T) {
|
||||
|
||||
// Test setup.
|
||||
p1 := conf.HealthChecks{}
|
||||
p2 := conf.HealthChecks{
|
||||
ReadinessProbeMissing: conf.SeverityIgnore,
|
||||
LivenessProbeMissing: conf.SeverityIgnore,
|
||||
p1 := make(map[string]conf.Severity)
|
||||
p2 := map[string]conf.Severity{
|
||||
"readinessProbeMissing": conf.SeverityIgnore,
|
||||
"livenessProbeMissing": conf.SeverityIgnore,
|
||||
}
|
||||
p3 := conf.HealthChecks{
|
||||
ReadinessProbeMissing: conf.SeverityError,
|
||||
LivenessProbeMissing: conf.SeverityWarning,
|
||||
p3 := map[string]conf.Severity{
|
||||
"readinessProbeMissing": conf.SeverityError,
|
||||
"livenessProbeMissing": conf.SeverityWarning,
|
||||
}
|
||||
|
||||
probe := corev1.Probe{}
|
||||
@@ -375,7 +375,7 @@ func TestValidateHealthChecks(t *testing.T) {
|
||||
|
||||
var testCases = []struct {
|
||||
name string
|
||||
probes conf.HealthChecks
|
||||
probes map[string]conf.Severity
|
||||
cv ContainerValidation
|
||||
errors *[]*ResultMessage
|
||||
warnings *[]*ResultMessage
|
||||
@@ -390,7 +390,7 @@ func TestValidateHealthChecks(t *testing.T) {
|
||||
|
||||
for idx, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := applyContainerSchemaChecks(&conf.Configuration{HealthChecks: tt.probes}, "", conf.Deployments, &tt.cv)
|
||||
err := applyContainerSchemaChecks(&conf.Configuration{Checks: tt.probes}, "", conf.Deployments, &tt.cv)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -408,14 +408,14 @@ func TestValidateHealthChecks(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestValidateImage(t *testing.T) {
|
||||
emptyConf := conf.Images{}
|
||||
standardConf := conf.Images{
|
||||
TagNotSpecified: conf.SeverityError,
|
||||
PullPolicyNotAlways: conf.SeverityIgnore,
|
||||
emptyConf := make(map[string]conf.Severity)
|
||||
standardConf := map[string]conf.Severity{
|
||||
"tagNotSpecified": conf.SeverityError,
|
||||
"pullPolicyNotAlways": conf.SeverityIgnore,
|
||||
}
|
||||
strongConf := conf.Images{
|
||||
TagNotSpecified: conf.SeverityError,
|
||||
PullPolicyNotAlways: conf.SeverityError,
|
||||
strongConf := map[string]conf.Severity{
|
||||
"tagNotSpecified": conf.SeverityError,
|
||||
"pullPolicyNotAlways": conf.SeverityError,
|
||||
}
|
||||
|
||||
emptyCV := ContainerValidation{
|
||||
@@ -437,7 +437,7 @@ func TestValidateImage(t *testing.T) {
|
||||
|
||||
var testCases = []struct {
|
||||
name string
|
||||
image conf.Images
|
||||
image map[string]conf.Severity
|
||||
cv ContainerValidation
|
||||
expected []*ResultMessage
|
||||
}{
|
||||
@@ -507,7 +507,7 @@ func TestValidateImage(t *testing.T) {
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
tt.cv = resetCV(tt.cv)
|
||||
err := applyContainerSchemaChecks(&conf.Configuration{Images: tt.image}, "", conf.Deployments, &tt.cv)
|
||||
err := applyContainerSchemaChecks(&conf.Configuration{Checks: tt.image}, "", conf.Deployments, &tt.cv)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -519,12 +519,12 @@ func TestValidateImage(t *testing.T) {
|
||||
|
||||
func TestValidateNetworking(t *testing.T) {
|
||||
// Test setup.
|
||||
emptyConf := conf.Networking{}
|
||||
standardConf := conf.Networking{
|
||||
HostPortSet: conf.SeverityWarning,
|
||||
emptyConf := make(map[string]conf.Severity)
|
||||
standardConf := map[string]conf.Severity{
|
||||
"hostPortSet": conf.SeverityWarning,
|
||||
}
|
||||
strongConf := conf.Networking{
|
||||
HostPortSet: conf.SeverityError,
|
||||
strongConf := map[string]conf.Severity{
|
||||
"hostPortSet": conf.SeverityError,
|
||||
}
|
||||
|
||||
emptyCV := ContainerValidation{
|
||||
@@ -553,7 +553,7 @@ func TestValidateNetworking(t *testing.T) {
|
||||
|
||||
var testCases = []struct {
|
||||
name string
|
||||
networkConf conf.Networking
|
||||
networkConf map[string]conf.Severity
|
||||
cv ContainerValidation
|
||||
expectedMessages []*ResultMessage
|
||||
}{
|
||||
@@ -629,7 +629,7 @@ func TestValidateNetworking(t *testing.T) {
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
tt.cv = resetCV(tt.cv)
|
||||
err := applyContainerSchemaChecks(&conf.Configuration{Networking: tt.networkConf}, "", conf.Deployments, &tt.cv)
|
||||
err := applyContainerSchemaChecks(&conf.Configuration{Checks: tt.networkConf}, "", conf.Deployments, &tt.cv)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -644,22 +644,22 @@ func TestValidateSecurity(t *testing.T) {
|
||||
falseVar := false
|
||||
|
||||
// Test setup.
|
||||
emptyConf := conf.Security{}
|
||||
standardConf := conf.Security{
|
||||
RunAsRootAllowed: conf.SeverityWarning,
|
||||
RunAsPrivileged: conf.SeverityError,
|
||||
NotReadOnlyRootFileSystem: conf.SeverityWarning,
|
||||
PrivilegeEscalationAllowed: conf.SeverityError,
|
||||
DangerousCapabilities: conf.SeverityError,
|
||||
InsecureCapabilities: conf.SeverityWarning,
|
||||
emptyConf := map[string]conf.Severity{}
|
||||
standardConf := map[string]conf.Severity{
|
||||
"runAsRootAllowed": conf.SeverityWarning,
|
||||
"runAsPrivileged": conf.SeverityError,
|
||||
"notReadOnlyRootFileSystem": conf.SeverityWarning,
|
||||
"privilegeEscalationAllowed": conf.SeverityError,
|
||||
"dangerousCapabilities": conf.SeverityError,
|
||||
"insecureCapabilities": conf.SeverityWarning,
|
||||
}
|
||||
strongConf := conf.Security{
|
||||
RunAsRootAllowed: conf.SeverityError,
|
||||
RunAsPrivileged: conf.SeverityError,
|
||||
NotReadOnlyRootFileSystem: conf.SeverityError,
|
||||
PrivilegeEscalationAllowed: conf.SeverityError,
|
||||
DangerousCapabilities: conf.SeverityError,
|
||||
InsecureCapabilities: conf.SeverityError,
|
||||
strongConf := map[string]conf.Severity{
|
||||
"runAsRootAllowed": conf.SeverityError,
|
||||
"runAsPrivileged": conf.SeverityError,
|
||||
"notReadOnlyRootFileSystem": conf.SeverityError,
|
||||
"privilegeEscalationAllowed": conf.SeverityError,
|
||||
"dangerousCapabilities": conf.SeverityError,
|
||||
"insecureCapabilities": conf.SeverityError,
|
||||
}
|
||||
|
||||
emptyCV := ContainerValidation{
|
||||
@@ -780,7 +780,7 @@ func TestValidateSecurity(t *testing.T) {
|
||||
|
||||
var testCases = []struct {
|
||||
name string
|
||||
securityConf conf.Security
|
||||
securityConf map[string]conf.Severity
|
||||
cv ContainerValidation
|
||||
expectedMessages []*ResultMessage
|
||||
}{
|
||||
@@ -1119,7 +1119,7 @@ func TestValidateSecurity(t *testing.T) {
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
tt.cv = resetCV(tt.cv)
|
||||
err := applyContainerSchemaChecks(&conf.Configuration{Security: tt.securityConf}, "", conf.Deployments, &tt.cv)
|
||||
err := applyContainerSchemaChecks(&conf.Configuration{Checks: tt.securityConf}, "", conf.Deployments, &tt.cv)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -1135,8 +1135,8 @@ func TestValidateRunAsRoot(t *testing.T) {
|
||||
nonRootUser := int64(1000)
|
||||
rootUser := int64(0)
|
||||
config := conf.Configuration{
|
||||
Security: conf.Security{
|
||||
RunAsRootAllowed: conf.SeverityWarning,
|
||||
Checks: map[string]conf.Severity{
|
||||
"runAsRootAllowed": conf.SeverityWarning,
|
||||
},
|
||||
}
|
||||
testCases := []struct {
|
||||
|
||||
@@ -29,9 +29,9 @@ import (
|
||||
|
||||
func TestValidateController(t *testing.T) {
|
||||
c := conf.Configuration{
|
||||
Security: conf.Security{
|
||||
HostIPCSet: conf.SeverityError,
|
||||
HostPIDSet: conf.SeverityError,
|
||||
Checks: map[string]conf.Severity{
|
||||
"hostIPCSet": conf.SeverityError,
|
||||
"hostPIDSet": conf.SeverityError,
|
||||
},
|
||||
}
|
||||
deployment := controller.NewDeploymentController(test.MockDeploy())
|
||||
@@ -64,9 +64,9 @@ func TestValidateController(t *testing.T) {
|
||||
|
||||
func TestSkipHealthChecks(t *testing.T) {
|
||||
c := conf.Configuration{
|
||||
HealthChecks: conf.HealthChecks{
|
||||
ReadinessProbeMissing: conf.SeverityError,
|
||||
LivenessProbeMissing: conf.SeverityWarning,
|
||||
Checks: map[string]conf.Severity{
|
||||
"readinessProbeMissing": conf.SeverityError,
|
||||
"livenessProbeMissing": conf.SeverityWarning,
|
||||
},
|
||||
ControllersToScan: []conf.SupportedController{
|
||||
conf.Deployments,
|
||||
@@ -139,9 +139,9 @@ func TestSkipHealthChecks(t *testing.T) {
|
||||
|
||||
func TestControllerExemptions(t *testing.T) {
|
||||
c := conf.Configuration{
|
||||
HealthChecks: conf.HealthChecks{
|
||||
ReadinessProbeMissing: conf.SeverityError,
|
||||
LivenessProbeMissing: conf.SeverityWarning,
|
||||
Checks: map[string]conf.Severity{
|
||||
"readinessProbeMissing": conf.SeverityError,
|
||||
"livenessProbeMissing": conf.SeverityWarning,
|
||||
},
|
||||
ControllersToScan: []conf.SupportedController{
|
||||
conf.Deployments,
|
||||
|
||||
@@ -16,9 +16,9 @@ func TestGetTemplateData(t *testing.T) {
|
||||
assert.Equal(t, err, nil, "error should be nil")
|
||||
|
||||
c := conf.Configuration{
|
||||
HealthChecks: conf.HealthChecks{
|
||||
ReadinessProbeMissing: conf.SeverityError,
|
||||
LivenessProbeMissing: conf.SeverityWarning,
|
||||
Checks: map[string]conf.Severity{
|
||||
"readinessProbeMissing": conf.SeverityError,
|
||||
"livenessProbeMissing": conf.SeverityWarning,
|
||||
},
|
||||
ControllersToScan: []conf.SupportedController{
|
||||
conf.Deployments,
|
||||
|
||||
+28
-38
@@ -24,13 +24,11 @@ import (
|
||||
|
||||
func TestValidatePod(t *testing.T) {
|
||||
c := conf.Configuration{
|
||||
Security: conf.Security{
|
||||
HostIPCSet: conf.SeverityError,
|
||||
HostPIDSet: conf.SeverityError,
|
||||
},
|
||||
Networking: conf.Networking{
|
||||
HostNetworkSet: conf.SeverityWarning,
|
||||
HostPortSet: conf.SeverityError,
|
||||
Checks: map[string]conf.Severity{
|
||||
"hostIPCSet": conf.SeverityError,
|
||||
"hostPIDSet": conf.SeverityError,
|
||||
"hostNetworkSet": conf.SeverityWarning,
|
||||
"hostPortSet": conf.SeverityError,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -59,8 +57,8 @@ func TestValidatePod(t *testing.T) {
|
||||
|
||||
expectedMessages := []*ResultMessage{
|
||||
{ID: "hostIPCSet", Message: "Host IPC is not configured", Type: "success", Category: "Security"},
|
||||
{ID: "hostPIDSet", Message: "Host PID is not configured", Type: "success", Category: "Security"},
|
||||
{ID: "hostNetworkSet", Message: "Host network is not configured", Type: "success", Category: "Networking"},
|
||||
{ID: "hostPIDSet", Message: "Host PID is not configured", Type: "success", Category: "Security"},
|
||||
}
|
||||
|
||||
actualPodResult := ValidatePod(c, &pod.Spec, "", conf.Deployments)
|
||||
@@ -72,13 +70,11 @@ func TestValidatePod(t *testing.T) {
|
||||
|
||||
func TestInvalidIPCPod(t *testing.T) {
|
||||
c := conf.Configuration{
|
||||
Security: conf.Security{
|
||||
HostIPCSet: conf.SeverityError,
|
||||
HostPIDSet: conf.SeverityError,
|
||||
},
|
||||
Networking: conf.Networking{
|
||||
HostNetworkSet: conf.SeverityWarning,
|
||||
HostPortSet: conf.SeverityError,
|
||||
Checks: map[string]conf.Severity{
|
||||
"hostIPCSet": conf.SeverityError,
|
||||
"hostPIDSet": conf.SeverityError,
|
||||
"hostNetworkSet": conf.SeverityWarning,
|
||||
"hostPortSet": conf.SeverityError,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -107,8 +103,8 @@ func TestInvalidIPCPod(t *testing.T) {
|
||||
}
|
||||
expectedMessages := []*ResultMessage{
|
||||
{ID: "hostIPCSet", Message: "Host IPC should not be configured", Type: "error", Category: "Security"},
|
||||
{ID: "hostPIDSet", Message: "Host PID is not configured", Type: "success", Category: "Security"},
|
||||
{ID: "hostNetworkSet", Message: "Host network is not configured", Type: "success", Category: "Networking"},
|
||||
{ID: "hostPIDSet", Message: "Host PID is not configured", Type: "success", Category: "Security"},
|
||||
}
|
||||
|
||||
actualPodResult := ValidatePod(c, &pod.Spec, "", conf.Deployments)
|
||||
@@ -120,13 +116,11 @@ func TestInvalidIPCPod(t *testing.T) {
|
||||
|
||||
func TestInvalidNeworkPod(t *testing.T) {
|
||||
c := conf.Configuration{
|
||||
Networking: conf.Networking{
|
||||
HostNetworkSet: conf.SeverityWarning,
|
||||
HostPortSet: conf.SeverityError,
|
||||
},
|
||||
Security: conf.Security{
|
||||
HostIPCSet: conf.SeverityError,
|
||||
HostPIDSet: conf.SeverityError,
|
||||
Checks: map[string]conf.Severity{
|
||||
"hostNetworkSet": conf.SeverityWarning,
|
||||
"hostPortSet": conf.SeverityError,
|
||||
"hostIPCSet": conf.SeverityError,
|
||||
"hostPIDSet": conf.SeverityError,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -170,13 +164,11 @@ func TestInvalidNeworkPod(t *testing.T) {
|
||||
|
||||
func TestInvalidPIDPod(t *testing.T) {
|
||||
c := conf.Configuration{
|
||||
Security: conf.Security{
|
||||
HostIPCSet: conf.SeverityError,
|
||||
HostPIDSet: conf.SeverityError,
|
||||
},
|
||||
Networking: conf.Networking{
|
||||
HostNetworkSet: conf.SeverityWarning,
|
||||
HostPortSet: conf.SeverityError,
|
||||
Checks: map[string]conf.Severity{
|
||||
"hostIPCSet": conf.SeverityError,
|
||||
"hostPIDSet": conf.SeverityError,
|
||||
"hostNetworkSet": conf.SeverityWarning,
|
||||
"hostPortSet": conf.SeverityError,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -219,13 +211,11 @@ func TestInvalidPIDPod(t *testing.T) {
|
||||
|
||||
func TestExemption(t *testing.T) {
|
||||
c := conf.Configuration{
|
||||
Security: conf.Security{
|
||||
HostIPCSet: conf.SeverityError,
|
||||
HostPIDSet: conf.SeverityError,
|
||||
},
|
||||
Networking: conf.Networking{
|
||||
HostNetworkSet: conf.SeverityWarning,
|
||||
HostPortSet: conf.SeverityError,
|
||||
Checks: map[string]conf.Severity{
|
||||
"hostIPCSet": conf.SeverityError,
|
||||
"hostNetworkSet": conf.SeverityWarning,
|
||||
"hostPIDSet": conf.SeverityError,
|
||||
"hostPortSet": conf.SeverityError,
|
||||
},
|
||||
Exemptions: []conf.Exemption{
|
||||
conf.Exemption{
|
||||
@@ -259,8 +249,8 @@ func TestExemption(t *testing.T) {
|
||||
Errors: uint(0),
|
||||
}
|
||||
expectedMessages := []*ResultMessage{
|
||||
{ID: "hostPIDSet", Message: "Host PID is not configured", Type: "success", Category: "Security"},
|
||||
{ID: "hostNetworkSet", Message: "Host network is not configured", Type: "success", Category: "Networking"},
|
||||
{ID: "hostPIDSet", Message: "Host PID is not configured", Type: "success", Category: "Security"},
|
||||
}
|
||||
|
||||
actualPodResult := ValidatePod(c, &pod.Spec, "foo", conf.Deployments)
|
||||
|
||||
+43
-51
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
|
||||
packr "github.com/gobuffalo/packr/v2"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
@@ -13,25 +14,22 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
schemaBox = (*packr.Box)(nil)
|
||||
checks = map[config.TargetKind][]config.SchemaCheck{
|
||||
config.TargetContainer: []config.SchemaCheck{},
|
||||
config.TargetPod: []config.SchemaCheck{},
|
||||
}
|
||||
schemaBox = (*packr.Box)(nil)
|
||||
builtInChecks = map[string]config.SchemaCheck{}
|
||||
// We explicitly set the order to avoid thrash in the
|
||||
// tests as we migrate toward JSON schema
|
||||
checkOrder = []string{
|
||||
// Pod checks
|
||||
"hostIPC",
|
||||
"hostPID",
|
||||
"hostNetwork",
|
||||
"hostIPCSet",
|
||||
"hostPIDSet",
|
||||
"hostNetworkSet",
|
||||
// Container checks
|
||||
"memoryLimitsMissing",
|
||||
"memoryRequestsMissing",
|
||||
"cpuLimitsMissing",
|
||||
"cpuRequestsMissing",
|
||||
"readinessProbe",
|
||||
"livenessProbe",
|
||||
"readinessProbeMissing",
|
||||
"livenessProbeMissing",
|
||||
"pullPolicyNotAlways",
|
||||
"tagNotSpecified",
|
||||
"hostPortSet",
|
||||
@@ -46,8 +44,8 @@ var (
|
||||
|
||||
func init() {
|
||||
schemaBox = packr.New("Schemas", "../../checks")
|
||||
for _, file := range checkOrder {
|
||||
contents, err := schemaBox.Find(file + ".yaml")
|
||||
for _, checkID := range checkOrder {
|
||||
contents, err := schemaBox.Find(checkID + ".yaml")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -55,7 +53,8 @@ func init() {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
checks[check.Target] = append(checks[check.Target], check)
|
||||
check.ID = checkID
|
||||
builtInChecks[checkID] = check
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,14 +73,21 @@ func parseCheck(rawBytes []byte) (config.SchemaCheck, error) {
|
||||
}
|
||||
|
||||
func applyPodSchemaChecks(conf *config.Configuration, pod *corev1.PodSpec, controllerName string, controllerType config.SupportedController, pv *PodValidation) error {
|
||||
for _, check := range checks[config.TargetPod] {
|
||||
if !conf.IsActionable(check.Category, check.Name, controllerName) {
|
||||
checkIDs := getSortedKeys(conf.Checks)
|
||||
for _, checkID := range checkIDs {
|
||||
check, ok := conf.CustomChecks[checkID]
|
||||
if !ok {
|
||||
check, ok = builtInChecks[checkID]
|
||||
}
|
||||
if !ok {
|
||||
return fmt.Errorf("Check %s not found", checkID)
|
||||
}
|
||||
if !conf.IsActionable(check.ID, controllerName) {
|
||||
continue
|
||||
}
|
||||
if !check.IsActionable(config.TargetPod, controllerType, false) {
|
||||
continue
|
||||
}
|
||||
severity := conf.GetSeverity(check.Category, check.Name)
|
||||
passes, err := check.CheckPod(pod)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -89,6 +95,7 @@ func applyPodSchemaChecks(conf *config.Configuration, pod *corev1.PodSpec, contr
|
||||
if passes {
|
||||
pv.addSuccess(check.SuccessMessage, check.Category, check.ID)
|
||||
} else {
|
||||
severity := conf.Checks[checkID]
|
||||
pv.addFailure(check.FailureMessage, severity, check.Category, check.ID)
|
||||
}
|
||||
}
|
||||
@@ -96,43 +103,18 @@ func applyPodSchemaChecks(conf *config.Configuration, pod *corev1.PodSpec, contr
|
||||
}
|
||||
|
||||
func applyContainerSchemaChecks(conf *config.Configuration, controllerName string, controllerType config.SupportedController, cv *ContainerValidation) error {
|
||||
for _, check := range checks[config.TargetContainer] {
|
||||
if !conf.IsActionable(check.Category, check.Name, controllerName) {
|
||||
continue
|
||||
}
|
||||
if !check.IsActionable(config.TargetContainer, controllerType, cv.IsInitContainer) {
|
||||
continue
|
||||
}
|
||||
severity := conf.GetSeverity(check.Category, check.Name)
|
||||
var passes bool
|
||||
var err error
|
||||
if check.SchemaTarget == config.TargetPod {
|
||||
cv.parentPodSpec.Containers = []corev1.Container{*cv.Container}
|
||||
passes, err = check.CheckPod(&cv.parentPodSpec)
|
||||
cv.parentPodSpec.Containers = []corev1.Container{}
|
||||
} else {
|
||||
passes, err = check.CheckContainer(cv.Container)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if passes {
|
||||
cv.addSuccess(check.SuccessMessage, check.Category, check.ID)
|
||||
} else {
|
||||
cv.addFailure(check.FailureMessage, severity, check.Category, check.ID)
|
||||
}
|
||||
}
|
||||
for checkName, severity := range conf.Checks {
|
||||
check, ok := conf.CustomChecks[checkName]
|
||||
checkIDs := getSortedKeys(conf.Checks)
|
||||
for _, checkID := range checkIDs {
|
||||
check, ok := conf.CustomChecks[checkID]
|
||||
if !ok {
|
||||
return fmt.Errorf("Custom check %s not found", checkName)
|
||||
check, ok = builtInChecks[checkID]
|
||||
}
|
||||
if !ok {
|
||||
return fmt.Errorf("Check %s not found", checkID)
|
||||
}
|
||||
if !conf.IsActionable(check.ID, controllerName) {
|
||||
continue
|
||||
}
|
||||
// FIXME: check actionability here
|
||||
/*
|
||||
if !conf.IsActionable(check.Category, check.Name, controllerName) {
|
||||
continue
|
||||
}
|
||||
*/
|
||||
if !check.IsActionable(config.TargetContainer, controllerType, cv.IsInitContainer) {
|
||||
continue
|
||||
}
|
||||
@@ -151,8 +133,18 @@ func applyContainerSchemaChecks(conf *config.Configuration, controllerName strin
|
||||
if passes {
|
||||
cv.addSuccess(check.SuccessMessage, check.Category, check.ID)
|
||||
} else {
|
||||
severity := conf.Checks[checkID]
|
||||
cv.addFailure(check.FailureMessage, severity, check.Category, check.ID)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getSortedKeys(m map[string]config.Severity) []string {
|
||||
keys := make([]string, 0, len(m))
|
||||
for key := range m {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user