kubeeye/pkg/validator/schema.go

165 lines
4.0 KiB
Go
Raw Normal View History

package validator
import (
"bytes"
"context"
"fmt"
"github.com/gobuffalo/packr/v2"
"io"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/yaml"
"kubeye/pkg/config"
"kubeye/pkg/kube"
"sort"
)
var (
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{
2020-11-25 10:20:55 +08:00
// Pod checks
//"hostIPCSet",
//"hostPIDSet",
//"hostNetworkSet",
// Container checks
//"memoryLimitsMissing",
//"memoryRequestsMissing",
"cpuLimitsMissing",
2020-11-25 10:20:55 +08:00
//"cpuRequestsMissing",
//"readinessProbeMissing",
2020-11-25 20:45:05 +08:00
"livenessProbeMissing",
2020-11-25 10:20:55 +08:00
//"pullPolicyNotAlways",
2020-11-25 20:45:05 +08:00
"tagNotSpecified",
2020-11-25 10:20:55 +08:00
//"hostPortSet",
//"runAsRootAllowed",
2020-11-25 20:45:05 +08:00
"runAsPrivileged",
2020-11-25 10:20:55 +08:00
//"notReadOnlyRootFilesystem",
//"privilegeEscalationAllowed",
//"dangerousCapabilities",
//"insecureCapabilities",
//"priorityClassNotSet",
}
)
func init() {
schemaBox = packr.New("Schemas", "../../checks")
for _, checkID := range checkOrder {
contents, err := schemaBox.Find(checkID + ".yaml")
if err != nil {
panic(err)
}
check, err := parseCheck(contents)
if err != nil {
panic(err)
}
check.ID = checkID
builtInChecks[checkID] = check
}
}
func parseCheck(rawBytes []byte) (config.SchemaCheck, error) {
reader := bytes.NewReader(rawBytes)
check := config.SchemaCheck{}
d := yaml.NewYAMLOrJSONDecoder(reader, 4096)
for {
if err := d.Decode(&check); err != nil {
if err == io.EOF {
return check, nil
}
return check, fmt.Errorf("Decoding schema kubeye failed: %v", err)
}
}
}
func resolveCheck(conf *config.Configuration, checkID string, controller kube.GenericWorkload, target config.TargetKind, isInitContainer bool) (*config.SchemaCheck, error) {
check, ok := conf.CustomChecks[checkID]
if !ok {
check, ok = builtInChecks[checkID]
}
if !ok {
return nil, fmt.Errorf("Check %s not found", checkID)
}
if !conf.IsActionable(check.ID, controller.ObjectMeta.GetName()) {
return nil, nil
}
if !check.IsActionable(target, controller.Kind, isInitContainer) {
return nil, nil
}
return &check, nil
}
func applyPodSchemaChecks(conf *config.Configuration, controller kube.GenericWorkload) (ResultSet, error) {
results := ResultSet{}
checkIDs := getSortedKeys(conf.Checks)
for _, checkID := range checkIDs {
check, err := resolveCheck(conf, checkID, controller, config.TargetPod, false)
if err != nil {
return nil, err
} else if check == nil {
continue
}
passes, err := check.CheckPod(&controller.PodSpec)
if err != nil {
return nil, err
}
results[check.ID] = makeResult(conf, check, passes)
}
return results, nil
}
func makeResult(conf *config.Configuration, check *config.SchemaCheck, passes bool) ResultMessage {
result := ResultMessage{
ID: check.ID,
Severity: conf.Checks[check.ID],
Category: check.Category,
Success: passes,
}
if passes {
result.Message = check.SuccessMessage
} else {
result.Message = check.FailureMessage
}
return result
}
func applyContainerSchemaChecks(ctx context.Context, conf *config.Configuration, controller kube.GenericWorkload, container *corev1.Container, isInit bool) (ResultSet, error) {
results := ResultSet{}
checkIDs := getSortedKeys(conf.Checks)
for _, checkID := range checkIDs {
check, err := resolveCheck(conf, checkID, controller, config.TargetContainer, isInit)
if err != nil {
return nil, err
} else if check == nil {
continue
}
var passes bool
if check.SchemaTarget == config.TargetPod {
podCopy := controller.PodSpec
podCopy.InitContainers = []corev1.Container{}
podCopy.Containers = []corev1.Container{*container}
passes, err = check.CheckPod(&podCopy)
} else {
passes, err = check.CheckContainer(container)
}
if err != nil {
return nil, err
}
results[check.ID] = makeResult(conf, check, passes)
}
return results, 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
}