diff --git a/score/score.go b/score/score.go index 11879fd0..3ab41af1 100644 --- a/score/score.go +++ b/score/score.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/armosec/k8s-interface/workloadinterface" + "go.uber.org/zap" appsv1 "k8s.io/api/apps/v1" // corev1 "k8s.io/api/core/v1" @@ -26,8 +27,10 @@ type ControlScoreWeights struct { type ScoreUtil struct { // ResourceTypeScores map[string]float32 // FrameworksScore map[string]map[string]ControlScoreWeights - K8SApoObj *k8sinterface.KubernetesApi - configPath string + K8SApoObj *k8sinterface.KubernetesApi + resources map[string]workloadinterface.IMetadata + isDebugMode bool + configPath string } var postureScore *ScoreUtil @@ -41,8 +44,15 @@ func (su *ScoreUtil) Calculate(frameworksReports []reporthandling.FrameworkRepor } func (su *ScoreUtil) CalculateFrameworkScore(framework *reporthandling.FrameworkReport) error { + framework.Score = 0 for i := range framework.ControlReports { + framework.ControlReports[i].Score = 0 wcsCtrl, unormalizedScore := su.ControlScore(&framework.ControlReports[i], framework.Name) + + if su.isDebugMode { + zap.L().Debug("control", zap.String("%s", framework.ControlReports[i].Name), zap.String("%s", framework.ControlReports[i].ControlID), zap.Any("failed", unormalizedScore), zap.Any("wcs", wcsCtrl)) + + } framework.WCSScore += wcsCtrl framework.Score += unormalizedScore @@ -53,6 +63,9 @@ func (su *ScoreUtil) CalculateFrameworkScore(framework *reporthandling.Framework return fmt.Errorf("unable to calculate score for framework %s due to bad wcs score", framework.Name) } framework.Score = (framework.Score * 100) / framework.WCSScore + if su.isDebugMode { + zap.L().Debug("framework scan", zap.String("framework", framework.Name), zap.Any("score", framework.Score)) + } framework.ARMOImprovement = (framework.ARMOImprovement * 100) / framework.WCSScore return nil } @@ -66,48 +79,34 @@ workloads: if replicas: */ func (su *ScoreUtil) GetScore(v map[string]interface{}) float32 { - shouldIgnore := os.Getenv("IGNORE_ENABLED") - var score float32 = 1 - ignoredKinds := []string{ - "role", "rolebinding", "clusterrole", "clusterrolebinding", - } - wl := workloadinterface.NewWorkloadObj(v) - kind := "" - shouldIgnore = strings.ToLower(shouldIgnore) + var score float32 = 1.0 + if workloadinterface.IsTypeRegoResponseVector(v) || !workloadinterface.IsTypeWorkload(v) { + return score + } + + wl := workloadinterface.NewWorkloadObj(v) if wl != nil { - kind = strings.ToLower(wl.GetKind()) replicas := wl.GetReplicas() if replicas > 1 { score *= float32(replicas) * replicaFactor } - //temporarily we ignore role,rolebinding,clusterrole,clusterrolebinding - for i := range ignoredKinds { - if shouldIgnore == "true" && ignoredKinds[i] == kind { - return 0 - } - } - - } else { - return 0 - //TODO: external object - } - - if kind == "daemonset" { - b, err := json.Marshal(v) - if err == nil { - dmnset := appsv1.DaemonSet{} - json.Unmarshal(b, &dmnset) + if strings.ToLower(wl.GetKind()) == "daemonset" { + b, err := json.Marshal(v) + if err == nil { + dmnset := appsv1.DaemonSet{} + json.Unmarshal(b, &dmnset) - if dmnset.Status.DesiredNumberScheduled > 0 { - score *= float32(dmnset.Status.DesiredNumberScheduled) + if dmnset.Status.DesiredNumberScheduled > 0 { + score *= float32(dmnset.Status.DesiredNumberScheduled) + } } } - } + } return score } @@ -123,36 +122,45 @@ returns wcsscore,ctrlscore(unnormalized) */ func (su *ScoreUtil) ControlScore(ctrlReport *reporthandling.ControlReport, frameworkName string) (float32, float32) { - return 0, 0 - // all, _, failed := reporthandling.GetResourcesPerControl(ctrlReport) - // for i := range failed { - // ctrlReport.Score += su.GetScore(failed[i]) - // } - // ctrlReport.Score *= ctrlReport.BaseScore - - // var wcsScore float32 = 0 - // for i := range all { - // wcsScore += su.GetScore(all[i]) - // } - - // wcsScore *= ctrlReport.BaseScore - // //x - // unormalizedScore := ctrlReport.Score - // ctrlReport.ARMOImprovement = unormalizedScore * ctrlReport.ARMOImprovement - // if wcsScore > 0 { - // ctrlReport.Score /= wcsScore // used to know severity (ctrl POV) - // } else { - // //ctrlReport.Score = 0 - // zap.L().Error("worst case scenario was 0, meaning no resources input were given - score is not available(will appear as > 1)") - // } - // return wcsScore, unormalizedScore + // return 0, 0 + + failedResourceIDS := ctrlReport.ListResourcesIDs().GetFailedResources() + allResourcesIDS := ctrlReport.ListResourcesIDs().GetAllResources() + for i := range failedResourceIDS { + ctrlReport.Score += su.GetScore(su.resources[failedResourceIDS[i]].GetObject()) + } + ctrlReport.Score *= ctrlReport.BaseScore + + var wcsScore float32 = 0 + for i := range allResourcesIDS { + wcsScore += su.GetScore(su.resources[allResourcesIDS[i]].GetObject()) + } + + wcsScore *= ctrlReport.BaseScore + //x + unormalizedScore := ctrlReport.Score + ctrlReport.ARMOImprovement = unormalizedScore * ctrlReport.ARMOImprovement + if wcsScore > 0 { + ctrlReport.Score /= wcsScore // used to know severity (ctrl POV) + } else { + //ctrlReport.Score = 0 + zap.L().Error("worst case scenario was 0, meaning no resources input were given - score is not available(will appear as > 1)") + } + return wcsScore, unormalizedScore } -func NewScore() *ScoreUtil { +func NewScore(allResources map[string]workloadinterface.IMetadata) *ScoreUtil { if postureScore == nil { - postureScore = &ScoreUtil{} + isDebugBool := false + if strings.ToLower(os.Getenv("ARMO_DEBUG_MODE")) == "true" { + isDebugBool = true + } + postureScore = &ScoreUtil{ + resources: allResources, + isDebugMode: isDebugBool, + } }