add testcase and checklists
This commit is contained in:
parent
7fdbc7cc92
commit
629351bc54
26
README.md
26
README.md
|
@ -99,19 +99,19 @@ kube-system Warning coredns Deployment 2020-11-27T1
|
||||||
| | NodeTokenExpired | Token certificate expired|
|
| | NodeTokenExpired | Token certificate expired|
|
||||||
| | NodeApiServerExpired | kube-apiserver certificate expired|
|
| | NodeApiServerExpired | kube-apiserver certificate expired|
|
||||||
| | NodeKubeletExpired | Kubelet certificate expired|
|
| | NodeKubeletExpired | Kubelet certificate expired|
|
||||||
| | PodSetCpuRequestsMissing | The CPU Resource Request value was not declared|
|
| :white_check_mark: | PodSetCpuRequestsMissing | The CPU Resource Request value was not declared|
|
||||||
| | PodSetHostIPCSet | Set the hostIP|
|
| :white_check_mark: | PodSetHostIPCSet | Set the hostIP|
|
||||||
| | PodSetHostNetworkSet | Set the hostNetwork|
|
| :white_check_mark: | PodSetHostNetworkSet | Set the hostNetwork|
|
||||||
| | PodHostPIDSet | Set the hostPID|
|
| :white_check_mark: | PodHostPIDSet | Set the hostPID|
|
||||||
| | PodMemoryRequestsMiss | No memory Resource Request value is declared|
|
| :white_check_mark: | PodMemoryRequestsMiss | No memory Resource Request value is declared|
|
||||||
| | PodSetHostPort | Set the hostPort|
|
| :white_check_mark: | PodSetHostPort | Set the hostPort|
|
||||||
| | PodSetMemoryLimitsMissing | No memory Resource limit value is declared|
|
| :white_check_mark: | PodSetMemoryLimitsMissing | No memory Resource limit value is declared|
|
||||||
| | PodNotReadOnlyRootFiles | The file system is not set to read-only|
|
| :white_check_mark: | PodNotReadOnlyRootFiles | The file system is not set to read-only|
|
||||||
| | PodSetPullPolicyNotAlways | The mirror pull strategy is not always|
|
| :white_check_mark: | PodSetPullPolicyNotAlways | The mirror pull strategy is not always|
|
||||||
| | PodSetRunAsRootAllowed | Executed as a root account|
|
| :white_check_mark: | PodSetRunAsRootAllowed | Executed as a root account|
|
||||||
| | PodDangerousCapabilities | You have the dangerous option in capabilities such as ALL/SYS_ADMIN/NET_ADMIN|
|
| :white_check_mark: | PodDangerousCapabilities | You have the dangerous option in capabilities such as ALL/SYS_ADMIN/NET_ADMIN|
|
||||||
| | PodlivenessProbeMissing | ReadinessProbe was not declared|
|
| :white_check_mark: | PodlivenessProbeMissing | ReadinessProbe was not declared|
|
||||||
| | privilegeEscalationAllowed | Privilege escalation is allowed|
|
| :white_check_mark: | privilegeEscalationAllowed | Privilege escalation is allowed|
|
||||||
> unmarked items are under heavy development
|
> unmarked items are under heavy development
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,22 +4,22 @@ category: Resources
|
||||||
target: Container
|
target: Container
|
||||||
containers:
|
containers:
|
||||||
exclude:
|
exclude:
|
||||||
- initContainer
|
- initContainer
|
||||||
schema:
|
schema:
|
||||||
'$schema': http://json-schema.org/draft-07/schema
|
'$schema': http://json-schema.org/draft-07/schema
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- resources
|
- resources
|
||||||
properties:
|
properties:
|
||||||
resources:
|
resources:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- limits
|
- limits
|
||||||
properties:
|
properties:
|
||||||
limits:
|
limits:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- cpu
|
- cpu
|
||||||
properties:
|
properties:
|
||||||
cpu:
|
cpu:
|
||||||
type: string
|
type: string
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
successMessage: Host IPC is not configured
|
||||||
|
failureMessage: Host IPC should not be configured
|
||||||
|
category: Security
|
||||||
|
target: Pod
|
||||||
|
schema:
|
||||||
|
'$schema': http://json-schema.org/draft-07/schema
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
hostIPC:
|
||||||
|
not:
|
||||||
|
const: true
|
|
@ -12,4 +12,4 @@ schema:
|
||||||
items:
|
items:
|
||||||
properties:
|
properties:
|
||||||
hostPort:
|
hostPort:
|
||||||
const: 0
|
const: 0
|
||||||
|
|
|
@ -3,19 +3,19 @@ failureMessage: Liveness probe should be configured
|
||||||
category: Health Checks
|
category: Health Checks
|
||||||
controllers:
|
controllers:
|
||||||
exclude:
|
exclude:
|
||||||
- Job
|
- Job
|
||||||
- CronJob
|
- CronJob
|
||||||
containers:
|
containers:
|
||||||
exclude:
|
exclude:
|
||||||
- initContainer
|
- initContainer
|
||||||
target: Container
|
target: Container
|
||||||
schema:
|
schema:
|
||||||
'$schema': http://json-schema.org/draft-07/schema
|
'$schema': http://json-schema.org/draft-07/schema
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- livenessProbe
|
- livenessProbe
|
||||||
properties:
|
properties:
|
||||||
livenessProbe:
|
livenessProbe:
|
||||||
type: object
|
type: object
|
||||||
not:
|
not:
|
||||||
const: null
|
const: null
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
successMessage: Image pull policy is "Always"
|
||||||
|
failureMessage: Image pull policy should be "Always"
|
||||||
|
category: Images
|
||||||
|
target: Container
|
||||||
|
schema:
|
||||||
|
'$schema': http://json-schema.org/draft-07/schema
|
||||||
|
required:
|
||||||
|
- imagePullPolicy
|
||||||
|
properties:
|
||||||
|
imagePullPolicy:
|
||||||
|
const: Always
|
|
@ -3,17 +3,17 @@ failureMessage: Readiness probe should be configured
|
||||||
category: Health Checks
|
category: Health Checks
|
||||||
controllers:
|
controllers:
|
||||||
exclude:
|
exclude:
|
||||||
- Job
|
- Job
|
||||||
- CronJob
|
- CronJob
|
||||||
containers:
|
containers:
|
||||||
exclude:
|
exclude:
|
||||||
- initContainer
|
- initContainer
|
||||||
target: Container
|
target: Container
|
||||||
schema:
|
schema:
|
||||||
'$schema': http://json-schema.org/draft-07/schema
|
'$schema': http://json-schema.org/draft-07/schema
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- readinessProbe
|
- readinessProbe
|
||||||
properties:
|
properties:
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
type: object
|
type: object
|
||||||
|
|
|
@ -10,4 +10,4 @@ schema:
|
||||||
properties:
|
properties:
|
||||||
privileged:
|
privileged:
|
||||||
not:
|
not:
|
||||||
const: true
|
const: true
|
||||||
|
|
|
@ -5,12 +5,12 @@ target: Container
|
||||||
schema:
|
schema:
|
||||||
'$schema': http://json-schema.org/draft-07/schema
|
'$schema': http://json-schema.org/draft-07/schema
|
||||||
required:
|
required:
|
||||||
- image
|
- image
|
||||||
allOf:
|
allOf:
|
||||||
- properties:
|
- properties:
|
||||||
image:
|
image:
|
||||||
pattern: ^.+:.+$
|
pattern: ^.+:.+$
|
||||||
- properties:
|
- properties:
|
||||||
image:
|
image:
|
||||||
not:
|
not:
|
||||||
pattern: ^.+:latest$
|
pattern: ^.+:latest$
|
||||||
|
|
|
@ -1,16 +1,33 @@
|
||||||
checks:
|
checks:
|
||||||
|
|
||||||
#resource
|
#resource
|
||||||
cpuLimitsMissing: warning
|
cpuLimitsMissing: warning
|
||||||
|
cpuRequestsMissing: warning
|
||||||
|
memoryLimitsMissing: warning
|
||||||
|
memoryRequestsMissing: warning
|
||||||
|
#reliability
|
||||||
|
priorityClassNotSet: warning
|
||||||
#image
|
#image
|
||||||
tagNotSpecified: danger
|
tagNotSpecified: warning
|
||||||
#imageRegistry: warning
|
pullPolicyNotAlways: warning
|
||||||
|
|
||||||
#healthChecks
|
#healthChecks
|
||||||
livenessProbeMissing: warning
|
livenessProbeMissing: warning
|
||||||
readinessProbeMissing: warning
|
readinessProbeMissing: warning
|
||||||
|
|
||||||
#network
|
#network
|
||||||
#hostPortSet: warning
|
hostPortSet: warning
|
||||||
|
hostNetworkSet: warning
|
||||||
|
|
||||||
#security
|
#security
|
||||||
runAsPrivileged: warning
|
runAsPrivileged: warning
|
||||||
|
hostIPCSet: warning
|
||||||
|
hostPIDSet: warning
|
||||||
|
notReadOnlyRootFilesystem: warning
|
||||||
|
privilegeEscalationAllowed: warning
|
||||||
|
runAsRootAllowed: warning
|
||||||
|
dangerousCapabilities: warning
|
||||||
|
insecureCapabilities: warning
|
||||||
|
|
||||||
customChecks:
|
customChecks:
|
||||||
# imageRegistry:
|
# imageRegistry:
|
||||||
|
|
|
@ -164,3 +164,212 @@ func TestValidateHealthChecks(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestValidateImage(t *testing.T) {
|
||||||
|
emptyConf := make(map[string]conf.Severity)
|
||||||
|
standardConf := map[string]conf.Severity{
|
||||||
|
"tagNotSpecified": conf.SeverityWarning,
|
||||||
|
"pullPolicyNotAlways": conf.SeverityIgnore,
|
||||||
|
}
|
||||||
|
strongConf := map[string]conf.Severity{
|
||||||
|
"tagNotSpecified": conf.SeverityWarning,
|
||||||
|
"pullPolicyNotAlways": conf.SeverityWarning,
|
||||||
|
}
|
||||||
|
|
||||||
|
emptyContainer := &corev1.Container{}
|
||||||
|
badContainer := &corev1.Container{Image: "test"}
|
||||||
|
lessBadContainer := &corev1.Container{Image: "test:latest", ImagePullPolicy: ""}
|
||||||
|
goodContainer := &corev1.Container{Image: "test:1.0.0", ImagePullPolicy: "Always"}
|
||||||
|
|
||||||
|
var testCases = []struct {
|
||||||
|
name string
|
||||||
|
image map[string]conf.Severity
|
||||||
|
container *corev1.Container
|
||||||
|
expected []ResultMessage
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "emptyConf + emptyCV",
|
||||||
|
image: emptyConf,
|
||||||
|
container: emptyContainer,
|
||||||
|
expected: []ResultMessage{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "standardConf + emptyCV",
|
||||||
|
image: standardConf,
|
||||||
|
container: emptyContainer,
|
||||||
|
expected: []ResultMessage{{
|
||||||
|
ID: "tagNotSpecified",
|
||||||
|
Message: "Image tag should be specified",
|
||||||
|
Success: false,
|
||||||
|
Severity: "warning",
|
||||||
|
Category: "Images",
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "standardConf + badCV",
|
||||||
|
image: standardConf,
|
||||||
|
container: badContainer,
|
||||||
|
expected: []ResultMessage{{
|
||||||
|
ID: "tagNotSpecified",
|
||||||
|
Message: "Image tag should be specified",
|
||||||
|
Success: false,
|
||||||
|
Severity: "warning",
|
||||||
|
Category: "Images",
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "standardConf + lessBadCV",
|
||||||
|
image: standardConf,
|
||||||
|
container: lessBadContainer,
|
||||||
|
expected: []ResultMessage{{
|
||||||
|
ID: "tagNotSpecified",
|
||||||
|
Message: "Image tag should be specified",
|
||||||
|
Success: false,
|
||||||
|
Severity: "warning",
|
||||||
|
Category: "Images",
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "strongConf + badCV",
|
||||||
|
image: strongConf,
|
||||||
|
container: badContainer,
|
||||||
|
expected: []ResultMessage{{
|
||||||
|
ID: "pullPolicyNotAlways",
|
||||||
|
Message: "Image pull policy should be \"Always\"",
|
||||||
|
Success: false,
|
||||||
|
Severity: "warning",
|
||||||
|
Category: "Images",
|
||||||
|
}, {
|
||||||
|
ID: "tagNotSpecified",
|
||||||
|
Message: "Image tag should be specified",
|
||||||
|
Success: false,
|
||||||
|
Severity: "warning",
|
||||||
|
Category: "Images",
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "strongConf + goodCV",
|
||||||
|
image: strongConf,
|
||||||
|
container: goodContainer,
|
||||||
|
expected: []ResultMessage{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range testCases {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
controller := getEmptyWorkload(t, "")
|
||||||
|
results, err := applyContainerSchemaChecks(context.Background(), &conf.Configuration{Checks: tt.image}, controller, tt.container, false)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
warnings := results.GetWarnings()
|
||||||
|
assert.Len(t, warnings, len(tt.expected))
|
||||||
|
assert.ElementsMatch(t, warnings, tt.expected)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidateNetworking(t *testing.T) {
|
||||||
|
// Test setup.
|
||||||
|
emptyConf := make(map[string]conf.Severity)
|
||||||
|
standardConf := map[string]conf.Severity{
|
||||||
|
"hostPortSet": conf.SeverityWarning,
|
||||||
|
}
|
||||||
|
|
||||||
|
emptyContainer := &corev1.Container{Name: ""}
|
||||||
|
badContainer := &corev1.Container{
|
||||||
|
Ports: []corev1.ContainerPort{{
|
||||||
|
ContainerPort: 3000,
|
||||||
|
HostPort: 443,
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
goodContainer := &corev1.Container{
|
||||||
|
Ports: []corev1.ContainerPort{{
|
||||||
|
ContainerPort: 3000,
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
|
||||||
|
var testCases = []struct {
|
||||||
|
name string
|
||||||
|
networkConf map[string]conf.Severity
|
||||||
|
container *corev1.Container
|
||||||
|
expectedResults []ResultMessage
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty ports + empty validation config",
|
||||||
|
networkConf: emptyConf,
|
||||||
|
container: emptyContainer,
|
||||||
|
expectedResults: []ResultMessage{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty ports + standard validation config",
|
||||||
|
networkConf: standardConf,
|
||||||
|
container: emptyContainer,
|
||||||
|
expectedResults: []ResultMessage{{
|
||||||
|
ID: "hostPortSet",
|
||||||
|
Message: "Host port is not configured",
|
||||||
|
Success: true,
|
||||||
|
Severity: "warning",
|
||||||
|
Category: "Networking",
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty ports + strong validation config",
|
||||||
|
networkConf: standardConf,
|
||||||
|
container: emptyContainer,
|
||||||
|
expectedResults: []ResultMessage{{
|
||||||
|
ID: "hostPortSet",
|
||||||
|
Message: "Host port is not configured",
|
||||||
|
Success: true,
|
||||||
|
Severity: "warning",
|
||||||
|
Category: "Networking",
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "host ports + empty validation config",
|
||||||
|
networkConf: emptyConf,
|
||||||
|
container: badContainer,
|
||||||
|
expectedResults: []ResultMessage{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "host ports + standard validation config",
|
||||||
|
networkConf: standardConf,
|
||||||
|
container: badContainer,
|
||||||
|
expectedResults: []ResultMessage{{
|
||||||
|
ID: "hostPortSet",
|
||||||
|
Message: "Host port should not be configured",
|
||||||
|
Success: false,
|
||||||
|
Severity: "warning",
|
||||||
|
Category: "Networking",
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no host ports + standard validation config",
|
||||||
|
networkConf: standardConf,
|
||||||
|
container: goodContainer,
|
||||||
|
expectedResults: []ResultMessage{{
|
||||||
|
ID: "hostPortSet",
|
||||||
|
Message: "Host port is not configured",
|
||||||
|
Success: true,
|
||||||
|
Severity: "warning",
|
||||||
|
Category: "Networking",
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range testCases {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
controller := getEmptyWorkload(t, "")
|
||||||
|
results, err := applyContainerSchemaChecks(context.Background(), &conf.Configuration{Checks: tt.networkConf}, controller, tt.container, false)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
messages := []ResultMessage{}
|
||||||
|
for _, msg := range results {
|
||||||
|
messages = append(messages, msg)
|
||||||
|
}
|
||||||
|
assert.Len(t, messages, len(tt.expectedResults))
|
||||||
|
assert.ElementsMatch(t, messages, tt.expectedResults)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -34,26 +34,26 @@ var (
|
||||||
// tests as we migrate toward JSON schema
|
// tests as we migrate toward JSON schema
|
||||||
checkOrder = []string{
|
checkOrder = []string{
|
||||||
// Pod checks
|
// Pod checks
|
||||||
//"hostIPCSet",
|
"hostIPCSet",
|
||||||
//"hostPIDSet",
|
"hostPIDSet",
|
||||||
//"hostNetworkSet",
|
"hostNetworkSet",
|
||||||
// Container checks
|
// Container checks
|
||||||
//"memoryLimitsMissing",
|
"memoryLimitsMissing",
|
||||||
//"memoryRequestsMissing",
|
"memoryRequestsMissing",
|
||||||
"cpuLimitsMissing",
|
"cpuLimitsMissing",
|
||||||
//"cpuRequestsMissing",
|
"cpuRequestsMissing",
|
||||||
"readinessProbeMissing",
|
"readinessProbeMissing",
|
||||||
"livenessProbeMissing",
|
"livenessProbeMissing",
|
||||||
//"pullPolicyNotAlways",
|
"pullPolicyNotAlways",
|
||||||
"tagNotSpecified",
|
"tagNotSpecified",
|
||||||
//"hostPortSet",
|
"hostPortSet",
|
||||||
//"runAsRootAllowed",
|
"runAsRootAllowed",
|
||||||
"runAsPrivileged",
|
"runAsPrivileged",
|
||||||
//"notReadOnlyRootFilesystem",
|
"notReadOnlyRootFilesystem",
|
||||||
//"privilegeEscalationAllowed",
|
"privilegeEscalationAllowed",
|
||||||
//"dangerousCapabilities",
|
"dangerousCapabilities",
|
||||||
//"insecureCapabilities",
|
"insecureCapabilities",
|
||||||
//"priorityClassNotSet",
|
"priorityClassNotSet",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue