From f8361446a45f989553418ffee09da6317f838a57 Mon Sep 17 00:00:00 2001 From: Daniel-GrunbergerCA Date: Tue, 7 Dec 2021 14:49:56 +0200 Subject: [PATCH 01/18] integrate cloud provider description --- go.mod | 6 +++--- go.sum | 4 ++-- resourcehandler/k8sresources.go | 30 +++++++++++++++++++++++++++++- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 605315c0..b1e23ed6 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.17 require ( github.com/armosec/armoapi-go v0.0.23 - github.com/armosec/k8s-interface v0.0.29 + github.com/armosec/k8s-interface v0.0.31 github.com/armosec/opa-utils v0.0.57 github.com/armosec/rbac-utils v0.0.8 github.com/armosec/utils-go v0.0.3 @@ -23,7 +23,7 @@ require ( k8s.io/api v0.22.2 k8s.io/apimachinery v0.22.2 k8s.io/client-go v0.22.2 - sigs.k8s.io/yaml v1.2.0 + sigs.k8s.io/yaml v1.2.0 ) require ( @@ -96,5 +96,5 @@ require ( k8s.io/klog/v2 v2.9.0 // indirect k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a // indirect sigs.k8s.io/controller-runtime v0.10.2 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect ) diff --git a/go.sum b/go.sum index 7657a126..6d24dbde 100644 --- a/go.sum +++ b/go.sum @@ -89,8 +89,8 @@ github.com/armosec/armoapi-go v0.0.23/go.mod h1:iaVVGyc23QGGzAdv4n+szGQg3Rbpixn9 github.com/armosec/k8s-interface v0.0.8/go.mod h1:xxS+V5QT3gVQTwZyAMMDrYLWGrfKOpiJ7Jfhfa0w9sM= github.com/armosec/k8s-interface v0.0.19/go.mod h1:0ztwEWLez2lpMMKHbs0DoZV64S0YIA4s72vCs9iAAiE= github.com/armosec/k8s-interface v0.0.24/go.mod h1:0ztwEWLez2lpMMKHbs0DoZV64S0YIA4s72vCs9iAAiE= -github.com/armosec/k8s-interface v0.0.29 h1:YUwTyIA5Wd9w7AwcWZMJ79w4JhMhTyIccPUASXucNRQ= -github.com/armosec/k8s-interface v0.0.29/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2dsFVc0XtgRh1ZU= +github.com/armosec/k8s-interface v0.0.31 h1:3QSwXD9hZzQ/hKUf6U6znL5QOEUAmY3c/Q2Bmf4fQ2w= +github.com/armosec/k8s-interface v0.0.31/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2dsFVc0XtgRh1ZU= github.com/armosec/opa-utils v0.0.57 h1:7lDEKxblqfsEXLn+6lkj17ctBSnhDuYanfdqG55kW2g= github.com/armosec/opa-utils v0.0.57/go.mod h1:UAT4Xokq91ysLa4Xg0WLqVsjJCnbFgsevkiIJFxTghU= github.com/armosec/rbac-utils v0.0.1/go.mod h1:pQ8CBiij8kSKV7aeZm9FMvtZN28VgA7LZcYyTWimq40= diff --git a/resourcehandler/k8sresources.go b/resourcehandler/k8sresources.go index 7d8ed658..f232e65e 100644 --- a/resourcehandler/k8sresources.go +++ b/resourcehandler/k8sresources.go @@ -3,10 +3,12 @@ package resourcehandler import ( "context" "fmt" + "os" "github.com/armosec/kubescape/cautils" "github.com/armosec/opa-utils/reporthandling" + "github.com/armosec/k8s-interface/cloudsupport" "github.com/armosec/k8s-interface/k8sinterface" "github.com/armosec/k8s-interface/workloadinterface" @@ -49,11 +51,36 @@ func (k8sHandler *K8sResourceHandler) GetResources(frameworks []reporthandling.F if err := k8sHandler.pullResources(k8sResourcesMap, allResources, namespace, labels); err != nil { return k8sResourcesMap, allResources, err } - + if err := getCloudProviderDescription(allResources, k8sResourcesMap); err != nil { + cautils.WarningDisplay(os.Stdout, err.Error()) + } cautils.SuccessTextDisplay("Accessed successfully to Kubernetes objects") return k8sResourcesMap, allResources, nil } +func getCloudProviderDescription(allResources map[string]workloadinterface.IMetadata, k8sResourcesMap *cautils.K8SResources) error { + if cloudsupport.IsRunningInCloudProvider() { + wl, err := cloudsupport.GetDescriptiveInfoFromCloudProvider() + if err != nil { + cluster := k8sinterface.GetCurrentContext().Cluster + provider := cloudsupport.GetCloudProvider(cluster) + // Return error with usefeul info on how to configure credentials for getting cloud provider info + switch provider { + case "gke": + return err + case "eks": + return fmt.Errorf("could not get descriptive information about eks cluster: %s. Check out how to configure credentials in https://docs.aws.amazon.com/sdk-for-go/api/", cluster) + } + return err + } + + allResources[wl.GetID()] = wl + (*k8sResourcesMap)[fmt.Sprintf("%s/%s/%s", wl.GetApiVersion(), wl.GetNamespace(), wl.GetKind())] = []string{wl.GetID()} + } + return nil + +} + func (k8sHandler *K8sResourceHandler) GetClusterAPIServerInfo() *version.Info { clusterAPIServerInfo, err := k8sHandler.k8s.DiscoveryClient.ServerVersion() if err != nil { @@ -62,6 +89,7 @@ func (k8sHandler *K8sResourceHandler) GetClusterAPIServerInfo() *version.Info { } return clusterAPIServerInfo } + func (k8sHandler *K8sResourceHandler) pullResources(k8sResources *cautils.K8SResources, allResources map[string]workloadinterface.IMetadata, namespace string, labels map[string]string) error { var errs error From 1b9ff074af481ca4e81387b7f7bbba7102a9caae Mon Sep 17 00:00:00 2001 From: Daniel-GrunbergerCA Date: Tue, 7 Dec 2021 14:51:34 +0200 Subject: [PATCH 02/18] run workflow --- resourcehandler/k8sresources.go | 1 + 1 file changed, 1 insertion(+) diff --git a/resourcehandler/k8sresources.go b/resourcehandler/k8sresources.go index f232e65e..bb83baa0 100644 --- a/resourcehandler/k8sresources.go +++ b/resourcehandler/k8sresources.go @@ -67,6 +67,7 @@ func getCloudProviderDescription(allResources map[string]workloadinterface.IMeta // Return error with usefeul info on how to configure credentials for getting cloud provider info switch provider { case "gke": + // gke returns link by default return err case "eks": return fmt.Errorf("could not get descriptive information about eks cluster: %s. Check out how to configure credentials in https://docs.aws.amazon.com/sdk-for-go/api/", cluster) From a6d73d6f8b850a5325e7acc746b097321b39c8c6 Mon Sep 17 00:00:00 2001 From: Daniel-GrunbergerCA Date: Tue, 14 Dec 2021 14:05:07 +0200 Subject: [PATCH 03/18] ssend keys for configmaps and env vars --- opaprocessor/processorhandlerutils.go | 21 +++++++++++--- resourcehandler/k8sresources.go | 42 +++++---------------------- 2 files changed, 25 insertions(+), 38 deletions(-) diff --git a/opaprocessor/processorhandlerutils.go b/opaprocessor/processorhandlerutils.go index 0ea14921..0d2159f4 100644 --- a/opaprocessor/processorhandlerutils.go +++ b/opaprocessor/processorhandlerutils.go @@ -116,13 +116,26 @@ func removeData(obj workloadinterface.IMetadata) { func removeConfigMapData(workload workloadinterface.IWorkload) { workload.RemoveAnnotation("kubectl.kubernetes.io/last-applied-configuration") - workloadinterface.RemoveFromMap(workload.GetObject(), "data") workloadinterface.RemoveFromMap(workload.GetObject(), "metadata", "managedFields") - + overrideSensitiveData(workload) } + +func overrideSensitiveData(workload workloadinterface.IWorkload) { + dataInterface, ok := workloadinterface.InspectMap(workload.GetObject(), "data") + if ok { + data, ok := dataInterface.(map[string]interface{}) + if ok { + for key := range data { + workloadinterface.SetInMap(workload.GetObject(), []string{"data"}, key, "XXXXXX") + } + } + } +} + func removeSecretData(workload workloadinterface.IWorkload) { - workloadinterface.NewWorkloadObj(workload.GetObject()).RemoveSecretData() + workload.RemoveAnnotation("kubectl.kubernetes.io/last-applied-configuration") workloadinterface.RemoveFromMap(workload.GetObject(), "metadata", "managedFields") + overrideSensitiveData(workload) } func removePodData(workload workloadinterface.IWorkload) { workload.RemoveAnnotation("kubectl.kubernetes.io/last-applied-configuration") @@ -134,7 +147,7 @@ func removePodData(workload workloadinterface.IWorkload) { } for i := range containers { for j := range containers[i].Env { - containers[i].Env[j].Value = "" + containers[i].Env[j].Value = "XXXXXX" } } workloadinterface.SetInMap(workload.GetObject(), workloadinterface.PodSpec(workload.GetKind()), "containers", containers) diff --git a/resourcehandler/k8sresources.go b/resourcehandler/k8sresources.go index 8503f8c7..654dfa5f 100644 --- a/resourcehandler/k8sresources.go +++ b/resourcehandler/k8sresources.go @@ -3,13 +3,12 @@ package resourcehandler import ( "context" "fmt" - "os" + "strings" "github.com/armosec/kubescape/cautils" "github.com/armosec/kubescape/hostsensorutils" "github.com/armosec/opa-utils/reporthandling" - "github.com/armosec/k8s-interface/cloudsupport" "github.com/armosec/k8s-interface/k8sinterface" "github.com/armosec/k8s-interface/workloadinterface" @@ -56,9 +55,6 @@ func (k8sHandler *K8sResourceHandler) GetResources(frameworks []reporthandling.F if err := k8sHandler.pullResources(k8sResourcesMap, allResources, namespace, labels); err != nil { return k8sResourcesMap, allResources, err } - if err := getCloudProviderDescription(allResources, k8sResourcesMap); err != nil { - cautils.WarningDisplay(os.Stdout, err.Error()) - } if err := k8sHandler.collectHostResources(allResources, k8sResourcesMap); err != nil { return k8sResourcesMap, allResources, err } @@ -71,30 +67,6 @@ func (k8sHandler *K8sResourceHandler) GetResources(frameworks []reporthandling.F return k8sResourcesMap, allResources, nil } -func getCloudProviderDescription(allResources map[string]workloadinterface.IMetadata, k8sResourcesMap *cautils.K8SResources) error { - if cloudsupport.IsRunningInCloudProvider() { - wl, err := cloudsupport.GetDescriptiveInfoFromCloudProvider() - if err != nil { - cluster := k8sinterface.GetCurrentContext().Cluster - provider := cloudsupport.GetCloudProvider(cluster) - // Return error with usefeul info on how to configure credentials for getting cloud provider info - switch provider { - case "gke": - // gke returns link by default - return err - case "eks": - return fmt.Errorf("could not get descriptive information about eks cluster: %s. Check out how to configure credentials in https://docs.aws.amazon.com/sdk-for-go/api/", cluster) - } - return err - } - - allResources[wl.GetID()] = wl - (*k8sResourcesMap)[fmt.Sprintf("%s/%s/%s", wl.GetApiVersion(), wl.GetNamespace(), wl.GetKind())] = []string{wl.GetID()} - } - return nil - -} - func (k8sHandler *K8sResourceHandler) GetClusterAPIServerInfo() *version.Info { clusterAPIServerInfo, err := k8sHandler.k8s.DiscoveryClient.ServerVersion() if err != nil { @@ -112,11 +84,13 @@ func (k8sHandler *K8sResourceHandler) pullResources(k8sResources *cautils.K8SRes gvr := schema.GroupVersionResource{Group: apiGroup, Version: apiVersion, Resource: resource} result, err := k8sHandler.pullSingleResource(&gvr, namespace, labels) if err != nil { - // handle error - if errs == nil { - errs = err - } else { - errs = fmt.Errorf("%s\n%s", errs, err.Error()) + if !strings.Contains(err.Error(), "the server could not find the requested resource") { + // handle error + if errs == nil { + errs = err + } else { + errs = fmt.Errorf("%s\n%s", errs, err.Error()) + } } continue } From 7cdc556292cf5067cae0fa45b8af0d7c33574746 Mon Sep 17 00:00:00 2001 From: Daniel-GrunbergerCA Date: Tue, 14 Dec 2021 14:16:50 +0200 Subject: [PATCH 04/18] go mod --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 53a307d8..fa613907 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.17 require ( github.com/armosec/armoapi-go v0.0.23 - github.com/armosec/k8s-interface v0.0.35 + github.com/armosec/k8s-interface v0.0.36 github.com/armosec/opa-utils v0.0.62 github.com/armosec/rbac-utils v0.0.8 github.com/armosec/utils-go v0.0.3 diff --git a/go.sum b/go.sum index 855bea65..018ba6a5 100644 --- a/go.sum +++ b/go.sum @@ -89,8 +89,8 @@ github.com/armosec/armoapi-go v0.0.23/go.mod h1:iaVVGyc23QGGzAdv4n+szGQg3Rbpixn9 github.com/armosec/k8s-interface v0.0.8/go.mod h1:xxS+V5QT3gVQTwZyAMMDrYLWGrfKOpiJ7Jfhfa0w9sM= github.com/armosec/k8s-interface v0.0.19/go.mod h1:0ztwEWLez2lpMMKHbs0DoZV64S0YIA4s72vCs9iAAiE= github.com/armosec/k8s-interface v0.0.26/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2dsFVc0XtgRh1ZU= -github.com/armosec/k8s-interface v0.0.35 h1:8kfQT7MxNMPb5HL3Sv3PriI4eVQzogECbBzckso/HkA= -github.com/armosec/k8s-interface v0.0.35/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2dsFVc0XtgRh1ZU= +github.com/armosec/k8s-interface v0.0.36 h1:i/fdgpXEsQq08Py8Utg537VzITpWJW4sjR9OXTfi4Oc= +github.com/armosec/k8s-interface v0.0.36/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2dsFVc0XtgRh1ZU= github.com/armosec/opa-utils v0.0.62 h1:C/VN1HUDoa0BX2CTSqgjuKEIlb/rkIwGY2/UlvfS154= github.com/armosec/opa-utils v0.0.62/go.mod h1:P63qZDPG3vjPtSQqwx2N4Nfm8VaboDul7R7kmnUvvWc= github.com/armosec/rbac-utils v0.0.1/go.mod h1:pQ8CBiij8kSKV7aeZm9FMvtZN28VgA7LZcYyTWimq40= From e2f8902222fb1244f0f593d07a0173733df93214 Mon Sep 17 00:00:00 2001 From: dwertent Date: Tue, 14 Dec 2021 20:06:38 +0200 Subject: [PATCH 05/18] use objectsenvelopes pkg --- go.mod | 6 +- go.sum | 14 ++--- hostsensorutils/hostsensordataenvelope.go | 67 ---------------------- hostsensorutils/hostsensorgetfrompod.go | 23 ++++---- hostsensorutils/hostsensorinterface.go | 4 +- hostsensorutils/hostsensormock.go | 6 +- opaprocessor/processorhandler.go | 7 ++- opaprocessor/processorhandler_test.go | 3 +- opaprocessor/processorhandlerutils_test.go | 2 +- resourcehandler/filesloader.go | 5 +- resourcehandler/k8sresources.go | 3 +- resultshandling/printer/prettyprinter.go | 6 +- 12 files changed, 43 insertions(+), 103 deletions(-) delete mode 100644 hostsensorutils/hostsensordataenvelope.go diff --git a/go.mod b/go.mod index fa613907..c215fd76 100644 --- a/go.mod +++ b/go.mod @@ -4,9 +4,9 @@ go 1.17 require ( github.com/armosec/armoapi-go v0.0.23 - github.com/armosec/k8s-interface v0.0.36 - github.com/armosec/opa-utils v0.0.62 - github.com/armosec/rbac-utils v0.0.8 + github.com/armosec/k8s-interface v0.0.37 + github.com/armosec/opa-utils v0.0.64 + github.com/armosec/rbac-utils v0.0.9 github.com/armosec/utils-go v0.0.3 github.com/briandowns/spinner v1.16.0 github.com/enescakir/emoji v1.0.0 diff --git a/go.sum b/go.sum index 018ba6a5..aa051b4d 100644 --- a/go.sum +++ b/go.sum @@ -87,15 +87,13 @@ github.com/armosec/armoapi-go v0.0.2/go.mod h1:vIK17yoKbJRQyZXWWLe3AqfqCRITxW8qm github.com/armosec/armoapi-go v0.0.23 h1:jqoLIWM5CR7DCD9fpFgN0ePqtHvOCoZv/XzCwsUluJU= github.com/armosec/armoapi-go v0.0.23/go.mod h1:iaVVGyc23QGGzAdv4n+szGQg3Rbpixn9yQTU3qWRpaw= github.com/armosec/k8s-interface v0.0.8/go.mod h1:xxS+V5QT3gVQTwZyAMMDrYLWGrfKOpiJ7Jfhfa0w9sM= -github.com/armosec/k8s-interface v0.0.19/go.mod h1:0ztwEWLez2lpMMKHbs0DoZV64S0YIA4s72vCs9iAAiE= -github.com/armosec/k8s-interface v0.0.26/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2dsFVc0XtgRh1ZU= -github.com/armosec/k8s-interface v0.0.36 h1:i/fdgpXEsQq08Py8Utg537VzITpWJW4sjR9OXTfi4Oc= -github.com/armosec/k8s-interface v0.0.36/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2dsFVc0XtgRh1ZU= -github.com/armosec/opa-utils v0.0.62 h1:C/VN1HUDoa0BX2CTSqgjuKEIlb/rkIwGY2/UlvfS154= -github.com/armosec/opa-utils v0.0.62/go.mod h1:P63qZDPG3vjPtSQqwx2N4Nfm8VaboDul7R7kmnUvvWc= +github.com/armosec/k8s-interface v0.0.37 h1:EPjzozpkVw0SmizoALmVg6D8VZIX7gcgTg+WxA02jNc= +github.com/armosec/k8s-interface v0.0.37/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2dsFVc0XtgRh1ZU= +github.com/armosec/opa-utils v0.0.64 h1:RdiFpy6QqoTD2e9k5eIwgDrTWctUL215QI3ust8tnD0= +github.com/armosec/opa-utils v0.0.64/go.mod h1:6tQP8UDq2EvEfSqh8vrUdr/9QVSCG4sJfju1SXQOn4c= github.com/armosec/rbac-utils v0.0.1/go.mod h1:pQ8CBiij8kSKV7aeZm9FMvtZN28VgA7LZcYyTWimq40= -github.com/armosec/rbac-utils v0.0.8 h1:Hpr2p9F3Elp9NxbDAZiMlNUcQOdfyu9rWFE2fM2nNGw= -github.com/armosec/rbac-utils v0.0.8/go.mod h1:fmLZDgT5ILNo5gzR19boIIn7TOpfWh2pIgprxLrYN/g= +github.com/armosec/rbac-utils v0.0.9 h1:rIOWp4K7BELUNX32ktSjVbb8d/0SpH7W76W6Tf+8rzw= +github.com/armosec/rbac-utils v0.0.9/go.mod h1:Ex/IdGWhGv9HZq6Hs8N/ApzCKSIvpNe/ETqDfnuyah0= github.com/armosec/utils-go v0.0.2/go.mod h1:itWmRLzRdsnwjpEOomL0mBWGnVNNIxSjDAdyc+b0iUo= github.com/armosec/utils-go v0.0.3 h1:uyQI676yRciQM0sSN9uPoqHkbspTxHO0kmzXhBeE/xU= github.com/armosec/utils-go v0.0.3/go.mod h1:itWmRLzRdsnwjpEOomL0mBWGnVNNIxSjDAdyc+b0iUo= diff --git a/hostsensorutils/hostsensordataenvelope.go b/hostsensorutils/hostsensordataenvelope.go deleted file mode 100644 index de394157..00000000 --- a/hostsensorutils/hostsensordataenvelope.go +++ /dev/null @@ -1,67 +0,0 @@ -package hostsensorutils - -import ( - "encoding/json" - "fmt" - - "k8s.io/apimachinery/pkg/runtime/schema" -) - -type HostSensorDataEnvelope struct { - schema.GroupVersionResource - NodeName string `json:"nodeName"` - Data json.RawMessage `json:"data"` -} - -func (hsde *HostSensorDataEnvelope) SetNamespace(string) { - -} - -func (hsde *HostSensorDataEnvelope) SetName(val string) { - hsde.NodeName = val -} - -func (hsde *HostSensorDataEnvelope) SetKind(val string) { - hsde.Resource = val - -} - -func (hsde *HostSensorDataEnvelope) SetWorkload(val map[string]interface{}) { //deprecated - hsde.Data, _ = json.Marshal(val) -} - -func (hsde *HostSensorDataEnvelope) SetObject(val map[string]interface{}) { - hsde.Data, _ = json.Marshal(val) -} - -func (hsde *HostSensorDataEnvelope) GetNamespace() string { - return "" -} - -func (hsde *HostSensorDataEnvelope) GetName() string { - return hsde.NodeName -} - -func (hsde *HostSensorDataEnvelope) GetKind() string { - return hsde.Resource -} - -func (hsde *HostSensorDataEnvelope) GetApiVersion() string { - return hsde.Version -} - -func (hsde *HostSensorDataEnvelope) GetWorkload() map[string]interface{} { // DEPRECATED - res := map[string]interface{}{} - json.Unmarshal(hsde.Data, &res) - return res -} - -func (hsde *HostSensorDataEnvelope) GetObject() map[string]interface{} { - res := map[string]interface{}{} - json.Unmarshal(hsde.Data, &res) - return res -} - -func (hsde *HostSensorDataEnvelope) GetID() string { // -> /// - return fmt.Sprintf("%s/%s/%s/%s", hsde.Group, hsde.GetApiVersion(), hsde.GetKind(), hsde.GetName()) -} diff --git a/hostsensorutils/hostsensorgetfrompod.go b/hostsensorutils/hostsensorgetfrompod.go index 865bf276..dbc583dc 100644 --- a/hostsensorutils/hostsensorgetfrompod.go +++ b/hostsensorutils/hostsensorgetfrompod.go @@ -6,6 +6,7 @@ import ( "sync" "github.com/armosec/kubescape/cautils" + "github.com/armosec/opa-utils/objectsenvelopes" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/yaml" ) @@ -56,12 +57,12 @@ func (hsh *HostSensorHandler) ForwardToPod(podName, path string) ([]byte, error) // sendAllPodsHTTPGETRequest fills the raw byte response in the envelope and the node name, but not the GroupVersionKind // so the caller is responsible to convert the raw data to some structured data and add the GroupVersionKind details -func (hsh *HostSensorHandler) sendAllPodsHTTPGETRequest(path string) ([]HostSensorDataEnvelope, error) { +func (hsh *HostSensorHandler) sendAllPodsHTTPGETRequest(path string) ([]objectsenvelopes.HostSensorDataEnvelope, error) { podList, err := hsh.getPodList() if err != nil { return nil, fmt.Errorf("failed to sendAllPodsHTTPGETRequest: %v", err) } - res := make([]HostSensorDataEnvelope, 0, len(podList)) + res := make([]objectsenvelopes.HostSensorDataEnvelope, 0, len(podList)) resLock := sync.Mutex{} wg := sync.WaitGroup{} wg.Add(len(podList)) @@ -74,7 +75,7 @@ func (hsh *HostSensorHandler) sendAllPodsHTTPGETRequest(path string) ([]HostSens } else { resLock.Lock() defer resLock.Unlock() - res = append(res, HostSensorDataEnvelope{NodeName: podList[podName], Data: resBytes}) + res = append(res, objectsenvelopes.HostSensorDataEnvelope{NodeName: podList[podName], Data: resBytes}) } }(podName, path) @@ -84,7 +85,7 @@ func (hsh *HostSensorHandler) sendAllPodsHTTPGETRequest(path string) ([]HostSens } // return list of -func (hsh *HostSensorHandler) GetOpenPortsList() ([]HostSensorDataEnvelope, error) { +func (hsh *HostSensorHandler) GetOpenPortsList() ([]objectsenvelopes.HostSensorDataEnvelope, error) { // loop over pods and port-forward it to each of them res, err := hsh.sendAllPodsHTTPGETRequest("/openedPorts") for resIdx := range res { @@ -96,7 +97,7 @@ func (hsh *HostSensorHandler) GetOpenPortsList() ([]HostSensorDataEnvelope, erro } // return list of -func (hsh *HostSensorHandler) GetLinuxSecurityHardeningStatus() ([]HostSensorDataEnvelope, error) { +func (hsh *HostSensorHandler) GetLinuxSecurityHardeningStatus() ([]objectsenvelopes.HostSensorDataEnvelope, error) { // loop over pods and port-forward it to each of them res, err := hsh.sendAllPodsHTTPGETRequest("/linuxSecurityHardening") for resIdx := range res { @@ -108,7 +109,7 @@ func (hsh *HostSensorHandler) GetLinuxSecurityHardeningStatus() ([]HostSensorDat } // return list of -func (hsh *HostSensorHandler) GetKubeletCommandLine() ([]HostSensorDataEnvelope, error) { +func (hsh *HostSensorHandler) GetKubeletCommandLine() ([]objectsenvelopes.HostSensorDataEnvelope, error) { // loop over pods and port-forward it to each of them res, err := hsh.sendAllPodsHTTPGETRequest("/kubeletCommandLine") for resIdx := range res { @@ -120,7 +121,7 @@ func (hsh *HostSensorHandler) GetKubeletCommandLine() ([]HostSensorDataEnvelope, } // return list of -func (hsh *HostSensorHandler) GetKernelVersion() ([]HostSensorDataEnvelope, error) { +func (hsh *HostSensorHandler) GetKernelVersion() ([]objectsenvelopes.HostSensorDataEnvelope, error) { // loop over pods and port-forward it to each of them res, err := hsh.sendAllPodsHTTPGETRequest("/kernelVersion") for resIdx := range res { @@ -132,7 +133,7 @@ func (hsh *HostSensorHandler) GetKernelVersion() ([]HostSensorDataEnvelope, erro } // return list of -func (hsh *HostSensorHandler) GetOsReleaseFile() ([]HostSensorDataEnvelope, error) { +func (hsh *HostSensorHandler) GetOsReleaseFile() ([]objectsenvelopes.HostSensorDataEnvelope, error) { // loop over pods and port-forward it to each of them res, err := hsh.sendAllPodsHTTPGETRequest("/osRelease") for resIdx := range res { @@ -144,7 +145,7 @@ func (hsh *HostSensorHandler) GetOsReleaseFile() ([]HostSensorDataEnvelope, erro } // return list of -func (hsh *HostSensorHandler) GetKubeletConfigurations() ([]HostSensorDataEnvelope, error) { +func (hsh *HostSensorHandler) GetKubeletConfigurations() ([]objectsenvelopes.HostSensorDataEnvelope, error) { // loop over pods and port-forward it to each of them res, err := hsh.sendAllPodsHTTPGETRequest("/kubeletConfigurations") for resIdx := range res { @@ -166,8 +167,8 @@ func (hsh *HostSensorHandler) GetKubeletConfigurations() ([]HostSensorDataEnvelo return res, err } -func (hsh *HostSensorHandler) CollectResources() ([]HostSensorDataEnvelope, error) { - res := make([]HostSensorDataEnvelope, 0) +func (hsh *HostSensorHandler) CollectResources() ([]objectsenvelopes.HostSensorDataEnvelope, error) { + res := make([]objectsenvelopes.HostSensorDataEnvelope, 0) if hsh.DaemonSet == nil { return res, nil } diff --git a/hostsensorutils/hostsensorinterface.go b/hostsensorutils/hostsensorinterface.go index 6b9e4170..d708b3bd 100644 --- a/hostsensorutils/hostsensorinterface.go +++ b/hostsensorutils/hostsensorinterface.go @@ -1,8 +1,10 @@ package hostsensorutils +import "github.com/armosec/opa-utils/objectsenvelopes" + type IHostSensor interface { Init() error TearDown() error - CollectResources() ([]HostSensorDataEnvelope, error) + CollectResources() ([]objectsenvelopes.HostSensorDataEnvelope, error) GetNamespace() string } diff --git a/hostsensorutils/hostsensormock.go b/hostsensorutils/hostsensormock.go index a8610a33..6fd37071 100644 --- a/hostsensorutils/hostsensormock.go +++ b/hostsensorutils/hostsensormock.go @@ -1,5 +1,7 @@ package hostsensorutils +import "github.com/armosec/opa-utils/objectsenvelopes" + type HostSensorHandlerMock struct { } @@ -11,8 +13,8 @@ func (hshm *HostSensorHandlerMock) TearDown() error { return nil } -func (hshm *HostSensorHandlerMock) CollectResources() ([]HostSensorDataEnvelope, error) { - return []HostSensorDataEnvelope{}, nil +func (hshm *HostSensorHandlerMock) CollectResources() ([]objectsenvelopes.HostSensorDataEnvelope, error) { + return []objectsenvelopes.HostSensorDataEnvelope{}, nil } func (hshm *HostSensorHandlerMock) GetNamespace() string { diff --git a/opaprocessor/processorhandler.go b/opaprocessor/processorhandler.go index bca27171..e2ac76c7 100644 --- a/opaprocessor/processorhandler.go +++ b/opaprocessor/processorhandler.go @@ -6,6 +6,7 @@ import ( "time" "github.com/armosec/kubescape/cautils" + "github.com/armosec/opa-utils/objectsenvelopes" "github.com/armosec/opa-utils/reporthandling" "github.com/golang/glog" @@ -183,20 +184,20 @@ func (opap *OPAProcessor) processRule(rule *reporthandling.PolicyRule) (*reporth if err != nil { return nil, err } - inputResources = workloadinterface.ListMapToMeta(enumeratedData) + inputResources = objectsenvelopes.ListMapToMeta(enumeratedData) ruleReport.ListInputKinds = workloadinterface.ListMetaIDs(inputResources) for i := range inputResources { opap.AllResources[inputResources[i].GetID()] = inputResources[i] } - failedResources := workloadinterface.ListMapToMeta(ruleReport.GetFailedResources()) + failedResources := objectsenvelopes.ListMapToMeta(ruleReport.GetFailedResources()) for i := range failedResources { if r, ok := opap.AllResources[failedResources[i].GetID()]; !ok { opap.AllResources[failedResources[i].GetID()] = r } } - warningResources := workloadinterface.ListMapToMeta(ruleReport.GetWarnignResources()) + warningResources := objectsenvelopes.ListMapToMeta(ruleReport.GetWarnignResources()) for i := range warningResources { if r, ok := opap.AllResources[warningResources[i].GetID()]; !ok { opap.AllResources[warningResources[i].GetID()] = r diff --git a/opaprocessor/processorhandler_test.go b/opaprocessor/processorhandler_test.go index 320f2baf..d3ec4204 100644 --- a/opaprocessor/processorhandler_test.go +++ b/opaprocessor/processorhandler_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/armosec/kubescape/cautils" + "github.com/armosec/opa-utils/objectsenvelopes" "github.com/armosec/opa-utils/reporthandling" "github.com/armosec/opa-utils/resources" @@ -20,7 +21,7 @@ func TestProcess(t *testing.T) { // set k8s k8sResources := make(cautils.K8SResources) allResources := make(map[string]workloadinterface.IMetadata) - imetaObj := workloadinterface.ListMapToMeta(k8sinterface.ConvertUnstructuredSliceToMap(k8sinterface.V1KubeSystemNamespaceMock().Items)) + imetaObj := objectsenvelopes.ListMapToMeta(k8sinterface.ConvertUnstructuredSliceToMap(k8sinterface.V1KubeSystemNamespaceMock().Items)) for i := range imetaObj { allResources[imetaObj[i].GetID()] = imetaObj[i] } diff --git a/opaprocessor/processorhandlerutils_test.go b/opaprocessor/processorhandlerutils_test.go index 7ade114b..ac1c74a1 100644 --- a/opaprocessor/processorhandlerutils_test.go +++ b/opaprocessor/processorhandlerutils_test.go @@ -65,7 +65,7 @@ func TestRemoveData(t *testing.T) { c, _ := workload.GetContainers() for i := range c { for _, e := range c[i].Env { - assert.Equal(t, "", e.Value) + assert.Equal(t, "XXXXXX", e.Value) } } } diff --git a/resourcehandler/filesloader.go b/resourcehandler/filesloader.go index 2b9ebf3a..28cce904 100644 --- a/resourcehandler/filesloader.go +++ b/resourcehandler/filesloader.go @@ -14,6 +14,7 @@ import ( "github.com/armosec/k8s-interface/k8sinterface" "github.com/armosec/kubescape/cautils" + "github.com/armosec/opa-utils/objectsenvelopes" "github.com/armosec/opa-utils/reporthandling" "gopkg.in/yaml.v2" @@ -211,7 +212,7 @@ func readYamlFile(yamlFile []byte) ([]workloadinterface.IMetadata, []error) { continue } if obj, ok := j.(map[string]interface{}); ok { - if o := workloadinterface.NewObject(obj); o != nil { + if o := objectsenvelopes.NewObject(obj); o != nil { yamlObjs = append(yamlObjs, o) } } else { @@ -237,7 +238,7 @@ func convertJsonToWorkload(jsonObj interface{}, workloads *[]workloadinterface.I switch x := jsonObj.(type) { case map[string]interface{}: - if o := workloadinterface.NewObject(x); o != nil { + if o := objectsenvelopes.NewObject(x); o != nil { (*workloads) = append(*workloads, o) } case []interface{}: diff --git a/resourcehandler/k8sresources.go b/resourcehandler/k8sresources.go index 654dfa5f..ff3c42e5 100644 --- a/resourcehandler/k8sresources.go +++ b/resourcehandler/k8sresources.go @@ -7,6 +7,7 @@ import ( "github.com/armosec/kubescape/cautils" "github.com/armosec/kubescape/hostsensorutils" + "github.com/armosec/opa-utils/objectsenvelopes" "github.com/armosec/opa-utils/reporthandling" "github.com/armosec/k8s-interface/k8sinterface" @@ -142,7 +143,7 @@ func (k8sHandler *K8sResourceHandler) pullSingleResource(resource *schema.GroupV func ConvertMapListToMeta(resourceMap []map[string]interface{}) []workloadinterface.IMetadata { workloads := []workloadinterface.IMetadata{} for i := range resourceMap { - if w := workloadinterface.NewObject(resourceMap[i]); w != nil { + if w := objectsenvelopes.NewObject(resourceMap[i]); w != nil { workloads = append(workloads, w) } } diff --git a/resultshandling/printer/prettyprinter.go b/resultshandling/printer/prettyprinter.go index 7fe156b4..42b8a770 100644 --- a/resultshandling/printer/prettyprinter.go +++ b/resultshandling/printer/prettyprinter.go @@ -7,6 +7,7 @@ import ( "github.com/armosec/k8s-interface/workloadinterface" "github.com/armosec/kubescape/cautils" + "github.com/armosec/opa-utils/objectsenvelopes" "github.com/armosec/opa-utils/reporthandling" "github.com/enescakir/emoji" "github.com/olekukonko/tablewriter" @@ -178,9 +179,8 @@ func (printer *PrettyPrinter) printGroupedResource(indent string, ns string, rsc func generateRelatedObjectsStr(workload WorkloadSummary) string { relatedStr := "" - w := workload.resource.GetObject() - if workloadinterface.IsTypeRegoResponseVector(w) { - relatedObjects := workloadinterface.NewRegoResponseVectorObject(w).GetRelatedObjects() + if workload.resource.GetObjectType() == workloadinterface.TypeWorkloadObject { + relatedObjects := objectsenvelopes.NewRegoResponseVectorObject(workload.resource.GetObject()).GetRelatedObjects() for i, related := range relatedObjects { if ns := related.GetNamespace(); i == 0 && ns != "" { relatedStr += fmt.Sprintf("Namespace - %s, ", ns) From 467059cd261f0172683c49aa4304a4ec8f617638 Mon Sep 17 00:00:00 2001 From: Lior Alafi Date: Wed, 15 Dec 2021 18:13:58 +0200 Subject: [PATCH 06/18] adding score --- go.mod | 2 +- go.sum | 3 ++- opaprocessor/processorhandler.go | 5 ++++- opaprocessor/processorhandlerutils.go | 2 +- resultshandling/results.go | 6 +++++- 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index c215fd76..35ab11c2 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.17 require ( github.com/armosec/armoapi-go v0.0.23 github.com/armosec/k8s-interface v0.0.37 - github.com/armosec/opa-utils v0.0.64 + github.com/armosec/opa-utils v0.0.65 github.com/armosec/rbac-utils v0.0.9 github.com/armosec/utils-go v0.0.3 github.com/briandowns/spinner v1.16.0 diff --git a/go.sum b/go.sum index aa051b4d..d58b9c2f 100644 --- a/go.sum +++ b/go.sum @@ -89,8 +89,9 @@ github.com/armosec/armoapi-go v0.0.23/go.mod h1:iaVVGyc23QGGzAdv4n+szGQg3Rbpixn9 github.com/armosec/k8s-interface v0.0.8/go.mod h1:xxS+V5QT3gVQTwZyAMMDrYLWGrfKOpiJ7Jfhfa0w9sM= github.com/armosec/k8s-interface v0.0.37 h1:EPjzozpkVw0SmizoALmVg6D8VZIX7gcgTg+WxA02jNc= github.com/armosec/k8s-interface v0.0.37/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2dsFVc0XtgRh1ZU= -github.com/armosec/opa-utils v0.0.64 h1:RdiFpy6QqoTD2e9k5eIwgDrTWctUL215QI3ust8tnD0= github.com/armosec/opa-utils v0.0.64/go.mod h1:6tQP8UDq2EvEfSqh8vrUdr/9QVSCG4sJfju1SXQOn4c= +github.com/armosec/opa-utils v0.0.65 h1:wz9ruf/EjIqoedFBC0lnByKwD9BTlda4l+ircjniwP8= +github.com/armosec/opa-utils v0.0.65/go.mod h1:6tQP8UDq2EvEfSqh8vrUdr/9QVSCG4sJfju1SXQOn4c= github.com/armosec/rbac-utils v0.0.1/go.mod h1:pQ8CBiij8kSKV7aeZm9FMvtZN28VgA7LZcYyTWimq40= github.com/armosec/rbac-utils v0.0.9 h1:rIOWp4K7BELUNX32ktSjVbb8d/0SpH7W76W6Tf+8rzw= github.com/armosec/rbac-utils v0.0.9/go.mod h1:Ex/IdGWhGv9HZq6Hs8N/ApzCKSIvpNe/ETqDfnuyah0= diff --git a/opaprocessor/processorhandler.go b/opaprocessor/processorhandler.go index e2ac76c7..b3743321 100644 --- a/opaprocessor/processorhandler.go +++ b/opaprocessor/processorhandler.go @@ -8,6 +8,8 @@ import ( "github.com/armosec/kubescape/cautils" "github.com/armosec/opa-utils/objectsenvelopes" "github.com/armosec/opa-utils/reporthandling" + "github.com/armosec/opa-utils/score" + "github.com/golang/glog" "github.com/armosec/k8s-interface/k8sinterface" @@ -66,7 +68,8 @@ func (opaHandler *OPAProcessorHandler) ProcessRulesListenner() { // update score // opap.updateScore() - + scoreutil := score.NewScore(opaSessionObj.AllResources) + scoreutil.Calculate(opaSessionObj.PostureReport.FrameworkReports) // report *opaHandler.reportResults <- opaSessionObj } diff --git a/opaprocessor/processorhandlerutils.go b/opaprocessor/processorhandlerutils.go index 0d2159f4..6ddff1e4 100644 --- a/opaprocessor/processorhandlerutils.go +++ b/opaprocessor/processorhandlerutils.go @@ -28,7 +28,7 @@ func (opap *OPAProcessor) updateResults() { reporthandling.SetUniqueResourcesCounter(&opap.PostureReport.FrameworkReports[f]) // set default score - reporthandling.SetDefaultScore(&opap.PostureReport.FrameworkReports[f]) + // reporthandling.SetDefaultScore(&opap.PostureReport.FrameworkReports[f]) } } diff --git a/resultshandling/results.go b/resultshandling/results.go index 72d281b2..5dea6e4f 100644 --- a/resultshandling/results.go +++ b/resultshandling/results.go @@ -34,7 +34,11 @@ func (resultsHandler *ResultsHandler) HandleResults(scanInfo *cautils.ScanInfo) } // TODO - get score from table - score := CalculatePostureScore(opaSessionObj.PostureReport) + var score float32 = 0 + for i := range opaSessionObj.PostureReport.FrameworkReports { + score += opaSessionObj.PostureReport.FrameworkReports[i].Score + } + score /= float32(len(opaSessionObj.PostureReport.FrameworkReports)) resultsHandler.printerObj.Score(score) return score From 0aea384f419f8d325d5439cacb68f4d7fb23435d Mon Sep 17 00:00:00 2001 From: Lior Alafi Date: Wed, 15 Dec 2021 19:04:40 +0200 Subject: [PATCH 07/18] changed prettyprint to work with risk-score --- resultshandling/printer/prettyprinter.go | 47 ++++++++++++++---------- resultshandling/printer/summary.go | 9 +++-- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/resultshandling/printer/prettyprinter.go b/resultshandling/printer/prettyprinter.go index 42b8a770..02148df7 100644 --- a/resultshandling/printer/prettyprinter.go +++ b/resultshandling/printer/prettyprinter.go @@ -18,7 +18,7 @@ type PrettyPrinter struct { summary Summary verboseMode bool sortedControlNames []string - frameworkSummary ControlSummary + frameworkSummary ResultSummary } func NewPrettyPrinter(verboseMode bool) *PrettyPrinter { @@ -35,15 +35,20 @@ func (printer *PrettyPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) allResources := []string{} frameworkNames := []string{} + var overallRiskScore float32 = 0 for _, frameworkReport := range opaSessionObj.PostureReport.FrameworkReports { frameworkNames = append(frameworkNames, frameworkReport.Name) failedResources = reporthandling.GetUniqueResourcesIDs(append(failedResources, frameworkReport.ListResourcesIDs().GetFailedResources()...)) warningResources = reporthandling.GetUniqueResourcesIDs(append(warningResources, frameworkReport.ListResourcesIDs().GetWarningResources()...)) allResources = reporthandling.GetUniqueResourcesIDs(append(allResources, frameworkReport.ListResourcesIDs().GetAllResources()...)) printer.summarySetup(frameworkReport, opaSessionObj.AllResources) + overallRiskScore += frameworkReport.Score } - printer.frameworkSummary = ControlSummary{ + overallRiskScore /= float32(len(opaSessionObj.PostureReport.FrameworkReports)) + + printer.frameworkSummary = ResultSummary{ + RiskScore: overallRiskScore, TotalResources: len(allResources), TotalFailed: len(failedResources), TotalWarning: len(warningResources), @@ -73,7 +78,10 @@ func (printer *PrettyPrinter) summarySetup(fr reporthandling.FrameworkReport, al if printer.verboseMode { passedWorkloads = groupByNamespaceOrKind(workloadsSummary, workloadSummaryPassed) } - printer.summary[cr.Name] = ControlSummary{ + + //controlSummary + printer.summary[cr.Name] = ResultSummary{ + RiskScore: cr.Score, TotalResources: cr.GetNumberOfResources(), TotalFailed: cr.GetNumberOfFailedResources(), TotalWarning: cr.GetNumberOfWarningResources(), @@ -100,7 +108,7 @@ func (printer *PrettyPrinter) printResults() { } } -func (printer *PrettyPrinter) printSummary(controlName string, controlSummary *ControlSummary) { +func (printer *PrettyPrinter) printSummary(controlName string, controlSummary *ResultSummary) { cautils.SimpleDisplay(printer.writer, "Summary - ") cautils.SuccessDisplay(printer.writer, "Passed:%v ", controlSummary.TotalResources-controlSummary.TotalFailed-controlSummary.TotalWarning) cautils.WarningDisplay(printer.writer, "Excluded:%v ", controlSummary.TotalWarning) @@ -113,7 +121,7 @@ func (printer *PrettyPrinter) printSummary(controlName string, controlSummary *C } -func (printer *PrettyPrinter) printTitle(controlName string, controlSummary *ControlSummary) { +func (printer *PrettyPrinter) printTitle(controlName string, controlSummary *ResultSummary) { cautils.InfoDisplay(printer.writer, "[control: %s] ", controlName) if controlSummary.TotalResources == 0 { cautils.InfoDisplay(printer.writer, "resources not found %v\n", emoji.ConfusedFace) @@ -128,7 +136,7 @@ func (printer *PrettyPrinter) printTitle(controlName string, controlSummary *Con cautils.DescriptionDisplay(printer.writer, "Description: %s\n", controlSummary.Description) } -func (printer *PrettyPrinter) printResources(controlSummary *ControlSummary) { +func (printer *PrettyPrinter) printResources(controlSummary *ResultSummary) { if len(controlSummary.FailedWorkloads) > 0 { cautils.FailureDisplay(printer.writer, "Failed:\n") @@ -194,11 +202,11 @@ func generateRelatedObjectsStr(workload WorkloadSummary) string { return relatedStr } -func generateRow(control string, cs ControlSummary) []string { +func generateRow(control string, cs ResultSummary) []string { row := []string{control} row = append(row, cs.ToSlice()...) if cs.TotalResources != 0 { - row = append(row, fmt.Sprintf("%d%s", percentage(cs.TotalResources, cs.TotalFailed), "%")) + row = append(row, fmt.Sprintf("%.2f%s", cs.RiskScore, "%")) } else { row = append(row, EmptyPercentage) } @@ -206,7 +214,7 @@ func generateRow(control string, cs ControlSummary) []string { } func generateHeader() []string { - return []string{"Control Name", "Failed Resources", "Excluded Resources", "All Resources", "% success"} + return []string{"Control Name", "Failed Resources", "Excluded Resources", "All Resources", "% risk-score"} } func percentage(big, small int) int { @@ -218,18 +226,16 @@ func percentage(big, small int) int { } return int(float64(float64(big-small)/float64(big)) * 100) } -func generateFooter(numControlers, sumFailed, sumWarning, sumTotal int) []string { + +func generateFooter(printer *PrettyPrinter) []string { // Control name | # failed resources | all resources | % success row := []string{} row = append(row, "Resource Summary") //fmt.Sprintf(""%d", numControlers")) - row = append(row, fmt.Sprintf("%d", sumFailed)) - row = append(row, fmt.Sprintf("%d", sumWarning)) - row = append(row, fmt.Sprintf("%d", sumTotal)) - if sumTotal != 0 { - row = append(row, fmt.Sprintf("%d%s", percentage(sumTotal, sumFailed), "%")) - } else { - row = append(row, EmptyPercentage) - } + row = append(row, fmt.Sprintf("%d", printer.frameworkSummary.TotalFailed)) + row = append(row, fmt.Sprintf("%d", printer.frameworkSummary.TotalWarning)) + row = append(row, fmt.Sprintf("%d", printer.frameworkSummary.TotalResources)) + row = append(row, fmt.Sprintf("%.2f%s", printer.frameworkSummary.RiskScore, "%")) + return row } func (printer *PrettyPrinter) printSummaryTable(frameworksNames []string) { @@ -247,7 +253,10 @@ func (printer *PrettyPrinter) printSummaryTable(frameworksNames []string) { controlSummary := printer.summary[printer.sortedControlNames[i]] summaryTable.Append(generateRow(printer.sortedControlNames[i], controlSummary)) } - summaryTable.SetFooter(generateFooter(len(printer.summary), printer.frameworkSummary.TotalFailed, printer.frameworkSummary.TotalWarning, printer.frameworkSummary.TotalResources)) + + summaryTable.SetFooter(generateFooter(printer)) + + // summaryTable.SetFooter(generateFooter()) summaryTable.Render() } diff --git a/resultshandling/printer/summary.go b/resultshandling/printer/summary.go index 9b13b0dd..696ad406 100644 --- a/resultshandling/printer/summary.go +++ b/resultshandling/printer/summary.go @@ -7,13 +7,14 @@ import ( "github.com/armosec/opa-utils/reporthandling" ) -type Summary map[string]ControlSummary +type Summary map[string]ResultSummary func NewSummary() Summary { - return make(map[string]ControlSummary) + return make(map[string]ResultSummary) } -type ControlSummary struct { +type ResultSummary struct { + RiskScore float32 TotalResources int TotalFailed int TotalWarning int @@ -31,7 +32,7 @@ type WorkloadSummary struct { status string } -func (controlSummary *ControlSummary) ToSlice() []string { +func (controlSummary *ResultSummary) ToSlice() []string { s := []string{} s = append(s, fmt.Sprintf("%d", controlSummary.TotalFailed)) s = append(s, fmt.Sprintf("%d", controlSummary.TotalWarning)) From fe9a342b4218340b7961d1acffea13ec5ff9978c Mon Sep 17 00:00:00 2001 From: dwertent Date: Sun, 19 Dec 2021 15:06:30 +0200 Subject: [PATCH 08/18] update submit testing --- clihandler/initcli.go | 56 +++++------------------------ clihandler/initcliutils.go | 73 +++++++++++++++++++++++++++++++++----- go.mod | 2 +- go.sum | 4 ++- 4 files changed, 77 insertions(+), 58 deletions(-) diff --git a/clihandler/initcli.go b/clihandler/initcli.go index f574286f..b870f364 100644 --- a/clihandler/initcli.go +++ b/clihandler/initcli.go @@ -6,9 +6,7 @@ import ( "os" "github.com/armosec/armoapi-go/armotypes" - "github.com/armosec/k8s-interface/k8sinterface" "github.com/armosec/kubescape/cautils" - "github.com/armosec/kubescape/cautils/getter" "github.com/armosec/kubescape/clihandler/cliinterfaces" "github.com/armosec/kubescape/hostsensorutils" "github.com/armosec/kubescape/opaprocessor" @@ -18,8 +16,6 @@ import ( "github.com/armosec/kubescape/resultshandling/printer" "github.com/armosec/kubescape/resultshandling/reporter" "github.com/armosec/opa-utils/reporthandling" - "github.com/armosec/rbac-utils/rbacscanner" - "github.com/golang/glog" "github.com/mattn/go-isatty" ) @@ -31,60 +27,24 @@ type componentInterfaces struct { hostSensorHandler hostsensorutils.IHostSensor } -func initHostSensor(scanInfo *cautils.ScanInfo, k8s *k8sinterface.KubernetesApi) hostsensorutils.IHostSensor { - - hasHostSensorControls := true - // we need to determined which controls needs host sensor - if scanInfo.HostSensor.Get() == nil && hasHostSensorControls { - scanInfo.HostSensor.SetBool(askUserForHostSensor()) - } - if hostSensorVal := scanInfo.HostSensor.Get(); hostSensorVal != nil && *hostSensorVal { - hostSensorHandler, err := hostsensorutils.NewHostSensorHandler(k8s) - if err != nil { - glog.Errorf("failed to create host sensor: %v", err) - return &hostsensorutils.HostSensorHandlerMock{} - } - return hostSensorHandler - } - return &hostsensorutils.HostSensorHandlerMock{} -} - func getInterfaces(scanInfo *cautils.ScanInfo) componentInterfaces { - var resourceHandler resourcehandler.IResourceHandler - var hostSensorHandler hostsensorutils.IHostSensor - var tenantConfig cautils.ITenantConfig - hostSensorHandler = &hostsensorutils.HostSensorHandlerMock{} + k8s := getKubernetesApi(scanInfo) - // scanning environment - scanningTarget := scanInfo.GetScanningEnvironment() - switch scanningTarget { - case cautils.ScanLocalFiles: - k8sinterface.ConnectedToCluster = false // DEPRECATED ? - scanInfo.Local = true // do not submit results when scanning YAML files + tenantConfig := getTenantConfig(scanInfo, k8s) - // not scanning a cluster - use localConfig struct - tenantConfig = cautils.NewLocalConfig(getter.GetArmoAPIConnector(), scanInfo.Account) + // Set submit behavior AFTER loading tenant config + setSubmitBehavior(scanInfo, tenantConfig) - // load resources from file - resourceHandler = resourcehandler.NewFileResourceHandler(scanInfo.InputPatterns) - case cautils.ScanCluster: - k8s := k8sinterface.NewKubernetesApi() // initialize kubernetes api object + hostSensorHandler := getHostSensorHandler(scanInfo, k8s) - // use clusterConfig struct - tenantConfig = cautils.NewClusterConfig(k8s, getter.GetArmoAPIConnector(), scanInfo.Account) + resourceHandler := getResourceHandler(scanInfo, tenantConfig, k8s, hostSensorHandler) - // pull k8s resources - hostSensorHandler = initHostSensor(scanInfo, k8s) - rbacObjects := cautils.NewRBACObjects(rbacscanner.NewRbacScannerFromK8sAPI(k8s, tenantConfig.GetCustomerGUID(), tenantConfig.GetClusterName())) - resourceHandler = resourcehandler.NewK8sResourceHandler(k8s, getFieldSelector(scanInfo), hostSensorHandler, rbacObjects) - - } // reporting behavior - setup reporter - reportHandler := getReporter(scanInfo, tenantConfig) + reportHandler := getReporter(tenantConfig, scanInfo.Submit) v := cautils.NewIVersionCheckHandler() - v.CheckLatestVersion(cautils.NewVersionCheckRequest(cautils.BuildNumber, policyIdentifierNames(scanInfo.PolicyIdentifier), "", scanningTarget)) + v.CheckLatestVersion(cautils.NewVersionCheckRequest(cautils.BuildNumber, policyIdentifierNames(scanInfo.PolicyIdentifier), "", scanInfo.GetScanningEnvironment())) // setup printer printerHandler := printer.GetPrinter(scanInfo.Format, scanInfo.VerboseMode) diff --git a/clihandler/initcliutils.go b/clihandler/initcliutils.go index c62bee2c..55a35b4e 100644 --- a/clihandler/initcliutils.go +++ b/clihandler/initcliutils.go @@ -4,25 +4,70 @@ import ( "fmt" "os" + "github.com/armosec/k8s-interface/k8sinterface" "github.com/armosec/kubescape/cautils" "github.com/armosec/kubescape/cautils/getter" + "github.com/armosec/kubescape/hostsensorutils" "github.com/armosec/kubescape/resourcehandler" "github.com/armosec/kubescape/resultshandling/reporter" "github.com/armosec/opa-utils/reporthandling" + "github.com/armosec/rbac-utils/rbacscanner" "github.com/golang/glog" ) -func getReporter(scanInfo *cautils.ScanInfo, tenantConfig cautils.ITenantConfig) reporter.IReport { - setSubmitBehavior(scanInfo, tenantConfig) - - if !scanInfo.Submit { - return reporter.NewReportMock() +func getKubernetesApi(scanInfo *cautils.ScanInfo) *k8sinterface.KubernetesApi { + if scanInfo.GetScanningEnvironment() == cautils.ScanLocalFiles { + return nil } - if !scanInfo.FrameworkScan { - return reporter.NewReportMock() + return k8sinterface.NewKubernetesApi() +} +func getTenantConfig(scanInfo *cautils.ScanInfo, k8s *k8sinterface.KubernetesApi) cautils.ITenantConfig { + if scanInfo.GetScanningEnvironment() == cautils.ScanLocalFiles { + return cautils.NewLocalConfig(getter.GetArmoAPIConnector(), scanInfo.Account) } + return cautils.NewClusterConfig(k8s, getter.GetArmoAPIConnector(), scanInfo.Account) +} - return reporter.NewReportEventReceiver(tenantConfig.GetConfigObj()) +func getRBACHandler(tenantConfig cautils.ITenantConfig, k8s *k8sinterface.KubernetesApi, submit bool) *cautils.RBACObjects { + if submit { + return cautils.NewRBACObjects(rbacscanner.NewRbacScannerFromK8sAPI(k8s, tenantConfig.GetCustomerGUID(), tenantConfig.GetClusterName())) + } + return nil +} + +func getReporter(tenantConfig cautils.ITenantConfig, submit bool) reporter.IReport { + if submit { + return reporter.NewReportEventReceiver(tenantConfig.GetConfigObj()) + + } + return reporter.NewReportMock() +} +func getResourceHandler(scanInfo *cautils.ScanInfo, tenantConfig cautils.ITenantConfig, k8s *k8sinterface.KubernetesApi, hostSensorHandler hostsensorutils.IHostSensor) resourcehandler.IResourceHandler { + if scanInfo.GetScanningEnvironment() == cautils.ScanLocalFiles { + return resourcehandler.NewFileResourceHandler(scanInfo.InputPatterns) + } + rbacObjects := getRBACHandler(tenantConfig, k8s, scanInfo.Submit) + return resourcehandler.NewK8sResourceHandler(k8s, getFieldSelector(scanInfo), hostSensorHandler, rbacObjects) +} + +func getHostSensorHandler(scanInfo *cautils.ScanInfo, k8s *k8sinterface.KubernetesApi) hostsensorutils.IHostSensor { + if scanInfo.GetScanningEnvironment() == cautils.ScanLocalFiles { + return &hostsensorutils.HostSensorHandlerMock{} + } + hasHostSensorControls := true + // we need to determined which controls needs host sensor + if scanInfo.HostSensor.Get() == nil && hasHostSensorControls { + scanInfo.HostSensor.SetBool(askUserForHostSensor()) + } + if hostSensorVal := scanInfo.HostSensor.Get(); hostSensorVal != nil && *hostSensorVal { + hostSensorHandler, err := hostsensorutils.NewHostSensorHandler(k8s) + if err != nil { + glog.Errorf("failed to create host sensor: %v", err) + return &hostsensorutils.HostSensorHandlerMock{} + } + return hostSensorHandler + } + return &hostsensorutils.HostSensorHandlerMock{} } func getFieldSelector(scanInfo *cautils.ScanInfo) resourcehandler.IFieldSelector { @@ -65,6 +110,18 @@ func setSubmitBehavior(scanInfo *cautils.ScanInfo, tenantConfig cautils.ITenantC */ + // do not submit control scanning + if !scanInfo.FrameworkScan { + scanInfo.Submit = false + return + } + + // do not submit yaml/url scanning + if scanInfo.GetScanningEnvironment() == cautils.ScanLocalFiles { + scanInfo.Submit = false + return + } + if tenantConfig.IsConfigFound() { // config found in cache (submitted) if !scanInfo.Local { // Submit report diff --git a/go.mod b/go.mod index c215fd76..51b433d5 100644 --- a/go.mod +++ b/go.mod @@ -77,7 +77,7 @@ require ( go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.19.1 // indirect - golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect + golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect golang.org/x/net v0.0.0-20210825183410-e898025ed96a // indirect golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1 // indirect golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect diff --git a/go.sum b/go.sum index aa051b4d..f3edc832 100644 --- a/go.sum +++ b/go.sum @@ -693,8 +693,9 @@ golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -890,6 +891,7 @@ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= From 61b5603a3b72ab9ce441328bff74ae166cb6bc3d Mon Sep 17 00:00:00 2001 From: dwertent Date: Sun, 19 Dec 2021 23:21:05 +0200 Subject: [PATCH 09/18] support host sensor and cloud descirption --- go.mod | 4 +- go.sum | 8 +- hostsensorutils/hostsensorgetfrompod.go | 98 ++++++++++--------------- hostsensorutils/hostsensorinterface.go | 4 +- hostsensorutils/hostsensormock.go | 8 +- opaprocessor/processorhandler.go | 2 +- opaprocessor/processorhandlerutils.go | 7 ++ resourcehandler/fieldselector.go | 2 +- resourcehandler/fieldselector_test.go | 4 + resourcehandler/k8sresources.go | 46 +++++++++--- resourcehandler/k8sresourcesutils.go | 14 ++++ 11 files changed, 115 insertions(+), 82 deletions(-) diff --git a/go.mod b/go.mod index aa0ac2c3..4f903f82 100644 --- a/go.mod +++ b/go.mod @@ -4,8 +4,8 @@ go 1.17 require ( github.com/armosec/armoapi-go v0.0.23 - github.com/armosec/k8s-interface v0.0.37 - github.com/armosec/opa-utils v0.0.65 + github.com/armosec/k8s-interface v0.0.44 + github.com/armosec/opa-utils v0.0.68 github.com/armosec/rbac-utils v0.0.9 github.com/armosec/utils-go v0.0.3 github.com/briandowns/spinner v1.16.0 diff --git a/go.sum b/go.sum index 35a408f8..b12f132f 100644 --- a/go.sum +++ b/go.sum @@ -87,11 +87,13 @@ github.com/armosec/armoapi-go v0.0.2/go.mod h1:vIK17yoKbJRQyZXWWLe3AqfqCRITxW8qm github.com/armosec/armoapi-go v0.0.23 h1:jqoLIWM5CR7DCD9fpFgN0ePqtHvOCoZv/XzCwsUluJU= github.com/armosec/armoapi-go v0.0.23/go.mod h1:iaVVGyc23QGGzAdv4n+szGQg3Rbpixn9yQTU3qWRpaw= github.com/armosec/k8s-interface v0.0.8/go.mod h1:xxS+V5QT3gVQTwZyAMMDrYLWGrfKOpiJ7Jfhfa0w9sM= -github.com/armosec/k8s-interface v0.0.37 h1:EPjzozpkVw0SmizoALmVg6D8VZIX7gcgTg+WxA02jNc= github.com/armosec/k8s-interface v0.0.37/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2dsFVc0XtgRh1ZU= +github.com/armosec/k8s-interface v0.0.43/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2dsFVc0XtgRh1ZU= +github.com/armosec/k8s-interface v0.0.44 h1:UsmVPo0GyyBuTVIP+F8rgHpEaZqQE7sUYjj1DT3kHmc= +github.com/armosec/k8s-interface v0.0.44/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2dsFVc0XtgRh1ZU= github.com/armosec/opa-utils v0.0.64/go.mod h1:6tQP8UDq2EvEfSqh8vrUdr/9QVSCG4sJfju1SXQOn4c= -github.com/armosec/opa-utils v0.0.65 h1:wz9ruf/EjIqoedFBC0lnByKwD9BTlda4l+ircjniwP8= -github.com/armosec/opa-utils v0.0.65/go.mod h1:6tQP8UDq2EvEfSqh8vrUdr/9QVSCG4sJfju1SXQOn4c= +github.com/armosec/opa-utils v0.0.68 h1:qsmDjEVPdfJ6+hlSeoBZF5sgeR63HdtPfpVQIg0r1G0= +github.com/armosec/opa-utils v0.0.68/go.mod h1:NVJEQ7695VyylqC7dHw2nD7MHIGJrRIXLgyej1onF64= github.com/armosec/rbac-utils v0.0.1/go.mod h1:pQ8CBiij8kSKV7aeZm9FMvtZN28VgA7LZcYyTWimq40= github.com/armosec/rbac-utils v0.0.9 h1:rIOWp4K7BELUNX32ktSjVbb8d/0SpH7W76W6Tf+8rzw= github.com/armosec/rbac-utils v0.0.9/go.mod h1:Ex/IdGWhGv9HZq6Hs8N/ApzCKSIvpNe/ETqDfnuyah0= diff --git a/hostsensorutils/hostsensorgetfrompod.go b/hostsensorutils/hostsensorgetfrompod.go index dbc583dc..e6e9f480 100644 --- a/hostsensorutils/hostsensorgetfrompod.go +++ b/hostsensorutils/hostsensorgetfrompod.go @@ -5,8 +5,9 @@ import ( "fmt" "sync" + "github.com/armosec/k8s-interface/k8sinterface" "github.com/armosec/kubescape/cautils" - "github.com/armosec/opa-utils/objectsenvelopes" + "github.com/armosec/opa-utils/objectsenvelopes/hostsensor" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/yaml" ) @@ -57,12 +58,12 @@ func (hsh *HostSensorHandler) ForwardToPod(podName, path string) ([]byte, error) // sendAllPodsHTTPGETRequest fills the raw byte response in the envelope and the node name, but not the GroupVersionKind // so the caller is responsible to convert the raw data to some structured data and add the GroupVersionKind details -func (hsh *HostSensorHandler) sendAllPodsHTTPGETRequest(path string) ([]objectsenvelopes.HostSensorDataEnvelope, error) { +func (hsh *HostSensorHandler) sendAllPodsHTTPGETRequest(path, requestKind string) ([]hostsensor.HostSensorDataEnvelope, error) { podList, err := hsh.getPodList() if err != nil { return nil, fmt.Errorf("failed to sendAllPodsHTTPGETRequest: %v", err) } - res := make([]objectsenvelopes.HostSensorDataEnvelope, 0, len(podList)) + res := make([]hostsensor.HostSensorDataEnvelope, 0, len(podList)) resLock := sync.Mutex{} wg := sync.WaitGroup{} wg.Add(len(podList)) @@ -75,7 +76,12 @@ func (hsh *HostSensorHandler) sendAllPodsHTTPGETRequest(path string) ([]objectse } else { resLock.Lock() defer resLock.Unlock() - res = append(res, objectsenvelopes.HostSensorDataEnvelope{NodeName: podList[podName], Data: resBytes}) + hostSensorDataEnvelope := hostsensor.HostSensorDataEnvelope{} + hostSensorDataEnvelope.SetApiVersion(k8sinterface.JoinGroupVersion(hostsensor.GroupHostSensor, hostsensor.Version)) + hostSensorDataEnvelope.SetKind(requestKind) + hostSensorDataEnvelope.SetName(podList[podName]) + hostSensorDataEnvelope.SetData(resBytes) + res = append(res, hostSensorDataEnvelope) } }(podName, path) @@ -84,91 +90,61 @@ func (hsh *HostSensorHandler) sendAllPodsHTTPGETRequest(path string) ([]objectse return res, nil } -// return list of -func (hsh *HostSensorHandler) GetOpenPortsList() ([]objectsenvelopes.HostSensorDataEnvelope, error) { +// return list of OpenPortsList +func (hsh *HostSensorHandler) GetOpenPortsList() ([]hostsensor.HostSensorDataEnvelope, error) { // loop over pods and port-forward it to each of them - res, err := hsh.sendAllPodsHTTPGETRequest("/openedPorts") - for resIdx := range res { - res[resIdx].GroupVersionResource.Resource = "OpenPortsList" - res[resIdx].GroupVersionResource.Group = "hostdata.armo.cloud" - res[resIdx].GroupVersionResource.Version = "v1beta0" - } - return res, err + return hsh.sendAllPodsHTTPGETRequest("/openedPorts", "OpenPortsList") +} + +// return list of LinuxSecurityHardeningStatus +func (hsh *HostSensorHandler) GetLinuxSecurityHardeningStatus() ([]hostsensor.HostSensorDataEnvelope, error) { + // loop over pods and port-forward it to each of them + return hsh.sendAllPodsHTTPGETRequest("/linuxSecurityHardening", "LinuxSecurityHardeningStatus") +} + +// return list of KubeletCommandLine +func (hsh *HostSensorHandler) GetKubeletCommandLine() ([]hostsensor.HostSensorDataEnvelope, error) { + // loop over pods and port-forward it to each of them + return hsh.sendAllPodsHTTPGETRequest("/kubeletCommandLine", "KubeletCommandLine") } // return list of -func (hsh *HostSensorHandler) GetLinuxSecurityHardeningStatus() ([]objectsenvelopes.HostSensorDataEnvelope, error) { +func (hsh *HostSensorHandler) GetKernelVersion() ([]hostsensor.HostSensorDataEnvelope, error) { // loop over pods and port-forward it to each of them - res, err := hsh.sendAllPodsHTTPGETRequest("/linuxSecurityHardening") - for resIdx := range res { - res[resIdx].GroupVersionResource.Resource = "LinuxSecurityHardeningStatus" - res[resIdx].GroupVersionResource.Group = "hostdata.armo.cloud" - res[resIdx].GroupVersionResource.Version = "v1beta0" - } - return res, err + return hsh.sendAllPodsHTTPGETRequest("/kernelVersion", "KernelVersion") } // return list of -func (hsh *HostSensorHandler) GetKubeletCommandLine() ([]objectsenvelopes.HostSensorDataEnvelope, error) { +func (hsh *HostSensorHandler) GetOsReleaseFile() ([]hostsensor.HostSensorDataEnvelope, error) { // loop over pods and port-forward it to each of them - res, err := hsh.sendAllPodsHTTPGETRequest("/kubeletCommandLine") - for resIdx := range res { - res[resIdx].GroupVersionResource.Resource = "KubeletCommandLine" - res[resIdx].GroupVersionResource.Group = "hostdata.armo.cloud" - res[resIdx].GroupVersionResource.Version = "v1beta0" - } - return res, err + return hsh.sendAllPodsHTTPGETRequest("/osRelease", "OsReleaseFile") } // return list of -func (hsh *HostSensorHandler) GetKernelVersion() ([]objectsenvelopes.HostSensorDataEnvelope, error) { +func (hsh *HostSensorHandler) GetKubeletConfigurations() ([]hostsensor.HostSensorDataEnvelope, error) { // loop over pods and port-forward it to each of them - res, err := hsh.sendAllPodsHTTPGETRequest("/kernelVersion") - for resIdx := range res { - res[resIdx].GroupVersionResource.Resource = "KernelVersion" - res[resIdx].GroupVersionResource.Group = "hostdata.armo.cloud" - res[resIdx].GroupVersionResource.Version = "v1beta0" - } - return res, err -} - -// return list of -func (hsh *HostSensorHandler) GetOsReleaseFile() ([]objectsenvelopes.HostSensorDataEnvelope, error) { - // loop over pods and port-forward it to each of them - res, err := hsh.sendAllPodsHTTPGETRequest("/osRelease") - for resIdx := range res { - res[resIdx].GroupVersionResource.Resource = "OsReleaseFile" - res[resIdx].GroupVersionResource.Group = "hostdata.armo.cloud" - res[resIdx].GroupVersionResource.Version = "v1beta0" - } - return res, err -} - -// return list of -func (hsh *HostSensorHandler) GetKubeletConfigurations() ([]objectsenvelopes.HostSensorDataEnvelope, error) { - // loop over pods and port-forward it to each of them - res, err := hsh.sendAllPodsHTTPGETRequest("/kubeletConfigurations") + res, err := hsh.sendAllPodsHTTPGETRequest("/kubeletConfigurations", "") // empty kind, will be overridden for resIdx := range res { jsonBytes, err := yaml.YAMLToJSON(res[resIdx].Data) if err != nil { fmt.Printf("In GetKubeletConfigurations failed to YAMLToJSON: %v;\n%v", err, res[resIdx]) continue } - res[resIdx].Data = jsonBytes + res[resIdx].SetData(jsonBytes) + kindDet := metav1.TypeMeta{} if err = json.Unmarshal(jsonBytes, &kindDet); err != nil { fmt.Printf("In GetKubeletConfigurations failed to Unmarshal GroupVersionKind: %v;\n%v", err, jsonBytes) continue } - res[resIdx].GroupVersionResource.Resource = kindDet.Kind - res[resIdx].GroupVersionResource.Group = kindDet.GroupVersionKind().Group - res[resIdx].GroupVersionResource.Version = kindDet.GroupVersionKind().Version + res[resIdx].SetKind(kindDet.Kind) + res[resIdx].SetApiVersion(k8sinterface.JoinGroupVersion(kindDet.GroupVersionKind().Group, kindDet.GroupVersionKind().Version)) } return res, err } -func (hsh *HostSensorHandler) CollectResources() ([]objectsenvelopes.HostSensorDataEnvelope, error) { - res := make([]objectsenvelopes.HostSensorDataEnvelope, 0) +func (hsh *HostSensorHandler) CollectResources() ([]hostsensor.HostSensorDataEnvelope, error) { + res := make([]hostsensor.HostSensorDataEnvelope, 0) if hsh.DaemonSet == nil { return res, nil } diff --git a/hostsensorutils/hostsensorinterface.go b/hostsensorutils/hostsensorinterface.go index d708b3bd..9b9d9d9b 100644 --- a/hostsensorutils/hostsensorinterface.go +++ b/hostsensorutils/hostsensorinterface.go @@ -1,10 +1,10 @@ package hostsensorutils -import "github.com/armosec/opa-utils/objectsenvelopes" +import "github.com/armosec/opa-utils/objectsenvelopes/hostsensor" type IHostSensor interface { Init() error TearDown() error - CollectResources() ([]objectsenvelopes.HostSensorDataEnvelope, error) + CollectResources() ([]hostsensor.HostSensorDataEnvelope, error) GetNamespace() string } diff --git a/hostsensorutils/hostsensormock.go b/hostsensorutils/hostsensormock.go index 6fd37071..b4518003 100644 --- a/hostsensorutils/hostsensormock.go +++ b/hostsensorutils/hostsensormock.go @@ -1,6 +1,8 @@ package hostsensorutils -import "github.com/armosec/opa-utils/objectsenvelopes" +import ( + "github.com/armosec/opa-utils/objectsenvelopes/hostsensor" +) type HostSensorHandlerMock struct { } @@ -13,8 +15,8 @@ func (hshm *HostSensorHandlerMock) TearDown() error { return nil } -func (hshm *HostSensorHandlerMock) CollectResources() ([]objectsenvelopes.HostSensorDataEnvelope, error) { - return []objectsenvelopes.HostSensorDataEnvelope{}, nil +func (hshm *HostSensorHandlerMock) CollectResources() ([]hostsensor.HostSensorDataEnvelope, error) { + return []hostsensor.HostSensorDataEnvelope{}, nil } func (hshm *HostSensorHandlerMock) GetNamespace() string { diff --git a/opaprocessor/processorhandler.go b/opaprocessor/processorhandler.go index b3743321..7a320b92 100644 --- a/opaprocessor/processorhandler.go +++ b/opaprocessor/processorhandler.go @@ -165,7 +165,7 @@ func (opap *OPAProcessor) processRule(rule *reporthandling.PolicyRule) (*reporth return nil, nil } - inputResources, err := reporthandling.RegoResourcesAggregator(rule, getKubernetesObjects(opap.K8SResources, opap.AllResources, rule.Match)) + inputResources, err := reporthandling.RegoResourcesAggregator(rule, getAllSupportedObjects(opap.K8SResources, opap.AllResources, rule)) if err != nil { return nil, fmt.Errorf("error getting aggregated k8sObjects: %s", err.Error()) } diff --git a/opaprocessor/processorhandlerutils.go b/opaprocessor/processorhandlerutils.go index 6ddff1e4..2bdb65e8 100644 --- a/opaprocessor/processorhandlerutils.go +++ b/opaprocessor/processorhandlerutils.go @@ -32,6 +32,13 @@ func (opap *OPAProcessor) updateResults() { } } +func getAllSupportedObjects(k8sResources *cautils.K8SResources, allResources map[string]workloadinterface.IMetadata, rule *reporthandling.PolicyRule) []workloadinterface.IMetadata { + k8sObjects := []workloadinterface.IMetadata{} + k8sObjects = append(k8sObjects, getKubernetesObjects(k8sResources, allResources, rule.Match)...) + k8sObjects = append(k8sObjects, getKubernetesObjects(k8sResources, allResources, rule.DynamicMatch)...) + return k8sObjects +} + func getKubernetesObjects(k8sResources *cautils.K8SResources, allResources map[string]workloadinterface.IMetadata, match []reporthandling.RuleMatchObjects) []workloadinterface.IMetadata { k8sObjects := []workloadinterface.IMetadata{} for m := range match { diff --git a/resourcehandler/fieldselector.go b/resourcehandler/fieldselector.go index e43edbe5..937d13f7 100644 --- a/resourcehandler/fieldselector.go +++ b/resourcehandler/fieldselector.go @@ -59,7 +59,7 @@ func getNamespacesSelector(resource *schema.GroupVersionResource, ns, operator s fieldSelector := "metadata." if resource.Resource == "namespaces" { fieldSelector += "name" - } else if k8sinterface.IsNamespaceScope(resource) { + } else if k8sinterface.IsResourceInNamespaceScope(resource.Resource) { fieldSelector += "namespace" } else { return "" diff --git a/resourcehandler/fieldselector_test.go b/resourcehandler/fieldselector_test.go index 5d3058af..15e3e1ac 100644 --- a/resourcehandler/fieldselector_test.go +++ b/resourcehandler/fieldselector_test.go @@ -15,6 +15,8 @@ func TestGetNamespacesSelector(t *testing.T) { } func TestExcludedNamespacesSelectors(t *testing.T) { + k8sinterface.InitializeMapResourcesMock() + es := NewExcludeSelector("default,ingress") selectors := es.GetNamespacesSelectors(&schema.GroupVersionResource{Resource: "pods"}) assert.Equal(t, 1, len(selectors)) @@ -26,6 +28,8 @@ func TestExcludedNamespacesSelectors(t *testing.T) { } func TestIncludeNamespacesSelectors(t *testing.T) { + k8sinterface.InitializeMapResourcesMock() + is := NewIncludeSelector("default,ingress") selectors := is.GetNamespacesSelectors(&schema.GroupVersionResource{Resource: "pods"}) assert.Equal(t, 2, len(selectors)) diff --git a/resourcehandler/k8sresources.go b/resourcehandler/k8sresources.go index ff3c42e5..4bcc499f 100644 --- a/resourcehandler/k8sresources.go +++ b/resourcehandler/k8sresources.go @@ -3,6 +3,7 @@ package resourcehandler import ( "context" "fmt" + "os" "strings" "github.com/armosec/kubescape/cautils" @@ -10,6 +11,7 @@ import ( "github.com/armosec/opa-utils/objectsenvelopes" "github.com/armosec/opa-utils/reporthandling" + "github.com/armosec/k8s-interface/cloudsupport" "github.com/armosec/k8s-interface/k8sinterface" "github.com/armosec/k8s-interface/workloadinterface" @@ -61,7 +63,10 @@ func (k8sHandler *K8sResourceHandler) GetResources(frameworks []reporthandling.F } if err := k8sHandler.collectRbacResources(allResources); err != nil { - fmt.Println("failed to collect rbac resources") + cautils.WarningDisplay(os.Stdout, "Warning: failed to collect rbac resources\n") + } + if err := getCloudProviderDescription(allResources, k8sResourcesMap); err != nil { + cautils.WarningDisplay(os.Stdout, fmt.Sprintf("Warning: %v\n", err.Error())) } cautils.SuccessTextDisplay("Accessed successfully to Kubernetes objects") @@ -156,16 +161,15 @@ func (k8sHandler *K8sResourceHandler) collectHostResources(allResources map[stri return err } for rscIdx := range hostResources { - groupResources := k8sinterface.ResourceGroupToString(hostResources[rscIdx].Group, hostResources[rscIdx].GetApiVersion(), hostResources[rscIdx].GetKind()) - for _, groupResource := range groupResources { - allResources[hostResources[rscIdx].GetID()] = &hostResources[rscIdx] + group, version := getGroupNVersion(hostResources[rscIdx].GetApiVersion()) + groupResource := k8sinterface.JoinResourceTriplets(group, version, hostResources[rscIdx].GetKind()) + allResources[hostResources[rscIdx].GetID()] = &hostResources[rscIdx] - grpResourceList, ok := (*resourcesMap)[groupResource] - if !ok { - grpResourceList = make([]string, 0) - } - (*resourcesMap)[groupResource] = append(grpResourceList, hostResources[rscIdx].GetID()) + grpResourceList, ok := (*resourcesMap)[groupResource] + if !ok { + grpResourceList = make([]string, 0) } + (*resourcesMap)[groupResource] = append(grpResourceList, hostResources[rscIdx].GetID()) } return nil } @@ -183,3 +187,27 @@ func (k8sHandler *K8sResourceHandler) collectRbacResources(allResources map[stri } return nil } + +func getCloudProviderDescription(allResources map[string]workloadinterface.IMetadata, k8sResourcesMap *cautils.K8SResources) error { + if cloudsupport.IsRunningInCloudProvider() { + wl, err := cloudsupport.GetDescriptiveInfoFromCloudProvider() + if err != nil { + cluster := k8sinterface.GetCurrentContext().Cluster + provider := cloudsupport.GetCloudProvider(cluster) + // Return error with useful info on how to configure credentials for getting cloud provider info + switch provider { + case "gke": + return fmt.Errorf("could not get descriptive information about gke cluster: %s using sdk client. See https://developers.google.com/accounts/docs/application-default-credentials for more information", cluster) + case "eks": + return fmt.Errorf("could not get descriptive information about eks cluster: %s using sdk client. Check out how to configure credentials in https://docs.aws.amazon.com/sdk-for-go/api/", cluster) + case "aks": + return fmt.Errorf("could not get descriptive information about aks cluster: %s. %v", cluster, err.Error()) + } + return err + } + allResources[wl.GetID()] = wl + (*k8sResourcesMap)[fmt.Sprintf("%s/%s", wl.GetApiVersion(), wl.GetKind())] = []string{wl.GetID()} + } + return nil + +} diff --git a/resourcehandler/k8sresourcesutils.go b/resourcehandler/k8sresourcesutils.go index 2c14b05b..a969354c 100644 --- a/resourcehandler/k8sresourcesutils.go +++ b/resourcehandler/k8sresourcesutils.go @@ -1,6 +1,8 @@ package resourcehandler import ( + "strings" + "github.com/armosec/kubescape/cautils" "github.com/armosec/opa-utils/reporthandling" @@ -66,3 +68,15 @@ func insertK8sResources(k8sResources map[string]map[string]map[string]interface{ } } } + +func getGroupNVersion(apiVersion string) (string, string) { + gv := strings.Split(apiVersion, "/") + group, version := "", "" + if len(gv) >= 1 { + group = gv[0] + } + if len(gv) >= 2 { + version = gv[1] + } + return group, version +} From c085aeaa68646f73a86a9c7827f8b87c7b4be61d Mon Sep 17 00:00:00 2001 From: dwertent Date: Mon, 20 Dec 2021 10:53:40 +0200 Subject: [PATCH 10/18] adding control url to results --- resultshandling/printer/prettyprinter.go | 6 +++++- resultshandling/printer/summary.go | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/resultshandling/printer/prettyprinter.go b/resultshandling/printer/prettyprinter.go index 02148df7..4903116b 100644 --- a/resultshandling/printer/prettyprinter.go +++ b/resultshandling/printer/prettyprinter.go @@ -81,6 +81,7 @@ func (printer *PrettyPrinter) summarySetup(fr reporthandling.FrameworkReport, al //controlSummary printer.summary[cr.Name] = ResultSummary{ + ID: cr.ControlID, RiskScore: cr.Score, TotalResources: cr.GetNumberOfResources(), TotalFailed: cr.GetNumberOfFailedResources(), @@ -121,8 +122,11 @@ func (printer *PrettyPrinter) printSummary(controlName string, controlSummary *R } +func getControlURL(controlID string) string { + return fmt.Sprintf("https://hub.armo.cloud/docs/%s", controlID) +} func (printer *PrettyPrinter) printTitle(controlName string, controlSummary *ResultSummary) { - cautils.InfoDisplay(printer.writer, "[control: %s] ", controlName) + cautils.InfoDisplay(printer.writer, "[control: %s - %s] ", controlName, getControlURL(controlSummary.ID)) if controlSummary.TotalResources == 0 { cautils.InfoDisplay(printer.writer, "resources not found %v\n", emoji.ConfusedFace) } else if controlSummary.TotalFailed != 0 { diff --git a/resultshandling/printer/summary.go b/resultshandling/printer/summary.go index 696ad406..d91b2a11 100644 --- a/resultshandling/printer/summary.go +++ b/resultshandling/printer/summary.go @@ -14,6 +14,7 @@ func NewSummary() Summary { } type ResultSummary struct { + ID string RiskScore float32 TotalResources int TotalFailed int From 14d0df3926604af95fdda6c140736f744a5cd506 Mon Sep 17 00:00:00 2001 From: dwertent Date: Mon, 20 Dec 2021 11:11:31 +0200 Subject: [PATCH 11/18] update generated url --- resultshandling/reporter/mockreporter.go | 2 +- resultshandling/reporter/reporteventreceiver.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/resultshandling/reporter/mockreporter.go b/resultshandling/reporter/mockreporter.go index 6c4dc6a1..22983fef 100644 --- a/resultshandling/reporter/mockreporter.go +++ b/resultshandling/reporter/mockreporter.go @@ -25,6 +25,6 @@ func (reportMock *ReportMock) SetClusterName(clusterName string) { } func (reportMock *ReportMock) DisplayReportURL() { - message := fmt.Sprintf("\nYou can see the results in a user-friendly UI, choose your preferred compliance framework, check risk results history and trends, manage exceptions, get remediation recommendations and much more by registering here: https://%s\n", getter.GetArmoAPIConnector().GetFrontendURL()) + message := fmt.Sprintf("\nYou can see the results in a user-friendly UI, choose your preferred compliance framework, check risk results history and trends, manage exceptions, get remediation recommendations and much more by registering here: https://%s/cli-signup \n", getter.GetArmoAPIConnector().GetFrontendURL()) cautils.InfoTextDisplay(os.Stdout, fmt.Sprintf("\n%s\n", message)) } diff --git a/resultshandling/reporter/reporteventreceiver.go b/resultshandling/reporter/reporteventreceiver.go index 05ef1fe9..a08e5485 100644 --- a/resultshandling/reporter/reporteventreceiver.go +++ b/resultshandling/reporter/reporteventreceiver.go @@ -116,14 +116,14 @@ func (report *ReportEventReceiver) sendReport(host string, postureReport *report } func (report *ReportEventReceiver) DisplayReportURL() { - message := "You can see the results in a user-friendly UI, choose your preferred compliance framework, check risk results history and trends, manage exceptions, get remediation recommendations and much more by registering here: " + message := "You can see the results in a user-friendly UI, choose your preferred compliance framework, check risk results history and trends, manage exceptions, get remediation recommendations and much more by registering here:" u := url.URL{} u.Scheme = "https" u.Host = getter.GetArmoAPIConnector().GetFrontendURL() if report.customerAdminEMail != "" { - cautils.InfoTextDisplay(os.Stdout, "\n\n"+message+u.String()+"\n\n") + cautils.InfoTextDisplay(os.Stdout, fmt.Sprintf("\n\n%s %s/risk/%s\n\n", message, u.String(), report.clusterName)) return } u.Path = "account/sign-up" @@ -132,5 +132,5 @@ func (report *ReportEventReceiver) DisplayReportURL() { q.Add("customerGUID", report.customerGUID) u.RawQuery = q.Encode() - cautils.InfoTextDisplay(os.Stdout, "\n\n"+message+u.String()+"\n\n") + cautils.InfoTextDisplay(os.Stdout, fmt.Sprintf("\n\n%s %s\n\n", message, u.String())) } From a10c67555da2d780aba6946d402d6af149278081 Mon Sep 17 00:00:00 2001 From: dwertent Date: Mon, 20 Dec 2021 11:14:31 +0200 Subject: [PATCH 12/18] adding spinner when sending reporting --- go.mod | 2 +- go.sum | 4 ++-- resultshandling/reporter/reporteventreceiver.go | 3 +++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 4f903f82..2402dc06 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/armosec/opa-utils v0.0.68 github.com/armosec/rbac-utils v0.0.9 github.com/armosec/utils-go v0.0.3 - github.com/briandowns/spinner v1.16.0 + github.com/briandowns/spinner v1.18.0 github.com/enescakir/emoji v1.0.0 github.com/fatih/color v1.13.0 github.com/gofrs/uuid v4.1.0+incompatible diff --git a/go.sum b/go.sum index b12f132f..d42dc8ab 100644 --- a/go.sum +++ b/go.sum @@ -118,8 +118,8 @@ github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqO github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= -github.com/briandowns/spinner v1.16.0 h1:DFmp6hEaIx2QXXuqSJmtfSBSAjRmpGiKG6ip2Wm/yOs= -github.com/briandowns/spinner v1.16.0/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ= +github.com/briandowns/spinner v1.18.0 h1:SJs0maNOs4FqhBwiJ3Gr7Z1D39/rukIVGQvpNZVHVcM= +github.com/briandowns/spinner v1.18.0/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/bytecodealliance/wasmtime-go v0.30.0 h1:WfYpr4WdqInt8m5/HvYinf+HrSEAIhItKIcth+qb1h4= github.com/bytecodealliance/wasmtime-go v0.30.0/go.mod h1:q320gUxqyI8yB+ZqRuaJOEnGkAnHh6WtJjMaT2CW4wI= diff --git a/resultshandling/reporter/reporteventreceiver.go b/resultshandling/reporter/reporteventreceiver.go index a08e5485..979b3b84 100644 --- a/resultshandling/reporter/reporteventreceiver.go +++ b/resultshandling/reporter/reporteventreceiver.go @@ -61,6 +61,9 @@ func (report *ReportEventReceiver) prepareReport(postureReport *reporthandling.P report.initEventReceiverURL() host := hostToString(report.eventReceiverURL, postureReport.ReportID) + cautils.StartSpinner() + defer cautils.StopSpinner() + // send framework results if err := report.sendReport(host, postureReport); err != nil { return err From f57a30898c6ef9f74210bd9889c31a1e5d24f1ba Mon Sep 17 00:00:00 2001 From: dwertent Date: Mon, 20 Dec 2021 13:32:14 +0200 Subject: [PATCH 13/18] print skipped --- resultshandling/printer/prettyprinter.go | 52 ++++++++++++++----- .../reporter/reporteventreceiver.go | 2 +- 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/resultshandling/printer/prettyprinter.go b/resultshandling/printer/prettyprinter.go index 4903116b..9148358c 100644 --- a/resultshandling/printer/prettyprinter.go +++ b/resultshandling/printer/prettyprinter.go @@ -128,7 +128,7 @@ func getControlURL(controlID string) string { func (printer *PrettyPrinter) printTitle(controlName string, controlSummary *ResultSummary) { cautils.InfoDisplay(printer.writer, "[control: %s - %s] ", controlName, getControlURL(controlSummary.ID)) if controlSummary.TotalResources == 0 { - cautils.InfoDisplay(printer.writer, "resources not found %v\n", emoji.ConfusedFace) + cautils.InfoDisplay(printer.writer, "skipped %v\n", emoji.ConfusedFace) } else if controlSummary.TotalFailed != 0 { cautils.FailureDisplay(printer.writer, "failed %v\n", emoji.SadButRelievedFace) } else if controlSummary.TotalWarning != 0 { @@ -172,6 +172,23 @@ func (printer *PrettyPrinter) printGroupedResources(workloads map[string][]Workl } } +// func (printer *PrettyPrinter) printGroupedResources(workloads map[string][]WorkloadSummary) { +// indent := INDENT +// for ns, rsc := range workloads { +// printer.printGroupedResource(indent, ns, rsc) +// } +// // for ns, rsc := range workloads { +// // if !isKindToBeGrouped(ns) { +// // } +// // } +// // if rsc, ok := workloads["User"]; ok { +// // printer.printGroupedResource(indent, "User", rsc) +// // } +// // if rsc, ok := workloads["Group"]; ok { +// // printer.printGroupedResource(indent, "Group", rsc) +// // } +// } + func (printer *PrettyPrinter) printGroupedResource(indent string, ns string, rsc []WorkloadSummary) { preIndent := indent if isKindToBeGrouped(ns) { @@ -189,6 +206,25 @@ func (printer *PrettyPrinter) printGroupedResource(indent string, ns string, rsc indent = preIndent } +// func (printer *PrettyPrinter) printGroupedResource(indent string, ns string, rsc []WorkloadSummary) { +// preIndent := indent + +// cautils.SimpleDisplay(printer.writer, "%s%s %s\n", indent, rsc[0].groupBy, ns) +// // if isKindToBeGrouped(ns) { +// // cautils.SimpleDisplay(printer.writer, "%s%ss\n", indent, ns) +// // } else if ns != "" { +// // cautils.SimpleDisplay(printer.writer, "%sNamespace %s\n", indent, ns) +// // } +// preIndent2 := indent +// for r := range rsc { +// indent += indent +// relatedObjectsStr := generateRelatedObjectsStr(rsc[r]) +// cautils.SimpleDisplay(printer.writer, fmt.Sprintf("%s%s - %s %s\n", indent, rsc[r].resource.GetKind(), rsc[r].resource.GetName(), relatedObjectsStr)) +// indent = preIndent2 +// } +// indent = preIndent +// } + func generateRelatedObjectsStr(workload WorkloadSummary) string { relatedStr := "" if workload.resource.GetObjectType() == workloadinterface.TypeWorkloadObject { @@ -210,9 +246,9 @@ func generateRow(control string, cs ResultSummary) []string { row := []string{control} row = append(row, cs.ToSlice()...) if cs.TotalResources != 0 { - row = append(row, fmt.Sprintf("%.2f%s", cs.RiskScore, "%")) + row = append(row, fmt.Sprintf("%d", int(cs.RiskScore))+"%") } else { - row = append(row, EmptyPercentage) + row = append(row, "skipped") } return row } @@ -221,16 +257,6 @@ func generateHeader() []string { return []string{"Control Name", "Failed Resources", "Excluded Resources", "All Resources", "% risk-score"} } -func percentage(big, small int) int { - if big == 0 { - if small == 0 { - return 100 - } - return 0 - } - return int(float64(float64(big-small)/float64(big)) * 100) -} - func generateFooter(printer *PrettyPrinter) []string { // Control name | # failed resources | all resources | % success row := []string{} diff --git a/resultshandling/reporter/reporteventreceiver.go b/resultshandling/reporter/reporteventreceiver.go index 979b3b84..fc01232d 100644 --- a/resultshandling/reporter/reporteventreceiver.go +++ b/resultshandling/reporter/reporteventreceiver.go @@ -126,7 +126,7 @@ func (report *ReportEventReceiver) DisplayReportURL() { u.Host = getter.GetArmoAPIConnector().GetFrontendURL() if report.customerAdminEMail != "" { - cautils.InfoTextDisplay(os.Stdout, fmt.Sprintf("\n\n%s %s/risk/%s\n\n", message, u.String(), report.clusterName)) + cautils.InfoTextDisplay(os.Stdout, fmt.Sprintf("\n\n%s %s/risk/%s\n(Account: %s)\n\n", message, u.String(), report.clusterName, report.customerGUID)) return } u.Path = "account/sign-up" From 0ef516d147c72f1173597284c1510c5014ac425d Mon Sep 17 00:00:00 2001 From: dwertent Date: Mon, 20 Dec 2021 18:22:08 +0200 Subject: [PATCH 14/18] support printing sensor and cloud resources --- go.mod | 4 +- go.sum | 9 ++- opaprocessor/processorhandlerutils.go | 2 +- opaprocessor/processorhandlerutils_test.go | 3 + policyhandler/handlenotification.go | 1 - resourcehandler/filesloader.go | 2 +- resourcehandler/k8sresources.go | 4 ++ resultshandling/printer/prettyprinter.go | 72 ++++------------------ resultshandling/printer/printresults.go | 2 - resultshandling/printer/summeryhelpers.go | 45 ++++++++++---- 10 files changed, 62 insertions(+), 82 deletions(-) diff --git a/go.mod b/go.mod index 2402dc06..f73c5e18 100644 --- a/go.mod +++ b/go.mod @@ -4,8 +4,8 @@ go 1.17 require ( github.com/armosec/armoapi-go v0.0.23 - github.com/armosec/k8s-interface v0.0.44 - github.com/armosec/opa-utils v0.0.68 + github.com/armosec/k8s-interface v0.0.46 + github.com/armosec/opa-utils v0.0.72 github.com/armosec/rbac-utils v0.0.9 github.com/armosec/utils-go v0.0.3 github.com/briandowns/spinner v1.18.0 diff --git a/go.sum b/go.sum index d42dc8ab..908604b0 100644 --- a/go.sum +++ b/go.sum @@ -88,12 +88,11 @@ github.com/armosec/armoapi-go v0.0.23 h1:jqoLIWM5CR7DCD9fpFgN0ePqtHvOCoZv/XzCwsU github.com/armosec/armoapi-go v0.0.23/go.mod h1:iaVVGyc23QGGzAdv4n+szGQg3Rbpixn9yQTU3qWRpaw= github.com/armosec/k8s-interface v0.0.8/go.mod h1:xxS+V5QT3gVQTwZyAMMDrYLWGrfKOpiJ7Jfhfa0w9sM= github.com/armosec/k8s-interface v0.0.37/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2dsFVc0XtgRh1ZU= -github.com/armosec/k8s-interface v0.0.43/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2dsFVc0XtgRh1ZU= -github.com/armosec/k8s-interface v0.0.44 h1:UsmVPo0GyyBuTVIP+F8rgHpEaZqQE7sUYjj1DT3kHmc= -github.com/armosec/k8s-interface v0.0.44/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2dsFVc0XtgRh1ZU= +github.com/armosec/k8s-interface v0.0.46 h1:qfCGWtbDCRQg8le2K1OveL94Y3dvGuamHmIJZ61+qqs= +github.com/armosec/k8s-interface v0.0.46/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2dsFVc0XtgRh1ZU= github.com/armosec/opa-utils v0.0.64/go.mod h1:6tQP8UDq2EvEfSqh8vrUdr/9QVSCG4sJfju1SXQOn4c= -github.com/armosec/opa-utils v0.0.68 h1:qsmDjEVPdfJ6+hlSeoBZF5sgeR63HdtPfpVQIg0r1G0= -github.com/armosec/opa-utils v0.0.68/go.mod h1:NVJEQ7695VyylqC7dHw2nD7MHIGJrRIXLgyej1onF64= +github.com/armosec/opa-utils v0.0.72 h1:YaaHIafNwsTD28Adr+PblauChX3YDfnP1LJUmpt3kIU= +github.com/armosec/opa-utils v0.0.72/go.mod h1:+5zC2LGTA5ibp1NDi9niwnA6jYSsE/Pb9M5u4M11dV0= github.com/armosec/rbac-utils v0.0.1/go.mod h1:pQ8CBiij8kSKV7aeZm9FMvtZN28VgA7LZcYyTWimq40= github.com/armosec/rbac-utils v0.0.9 h1:rIOWp4K7BELUNX32ktSjVbb8d/0SpH7W76W6Tf+8rzw= github.com/armosec/rbac-utils v0.0.9/go.mod h1:Ex/IdGWhGv9HZq6Hs8N/ApzCKSIvpNe/ETqDfnuyah0= diff --git a/opaprocessor/processorhandlerutils.go b/opaprocessor/processorhandlerutils.go index 2bdb65e8..beb2c208 100644 --- a/opaprocessor/processorhandlerutils.go +++ b/opaprocessor/processorhandlerutils.go @@ -107,7 +107,7 @@ func isRuleKubescapeVersionCompatible(rule *reporthandling.PolicyRule) bool { } func removeData(obj workloadinterface.IMetadata) { - if !workloadinterface.IsTypeWorkload(obj.GetObject()) { + if !k8sinterface.IsTypeWorkload(obj.GetObject()) { return // remove data only from kubernetes objects } workload := workloadinterface.NewWorkloadObj(obj.GetObject()) diff --git a/opaprocessor/processorhandlerutils_test.go b/opaprocessor/processorhandlerutils_test.go index ac1c74a1..3dc82ee2 100644 --- a/opaprocessor/processorhandlerutils_test.go +++ b/opaprocessor/processorhandlerutils_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/armosec/armoapi-go/armotypes" + "github.com/armosec/k8s-interface/k8sinterface" "github.com/armosec/k8s-interface/workloadinterface" "github.com/armosec/kubescape/cautils" "github.com/armosec/opa-utils/reporthandling" @@ -57,6 +58,8 @@ func TestIsRuleKubescapeVersionCompatible(t *testing.T) { } func TestRemoveData(t *testing.T) { + k8sinterface.InitializeMapResourcesMock() + w := `{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"name":"demoservice-server"},"spec":{"replicas":1,"selector":{"matchLabels":{"app":"demoservice-server"}},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"demoservice-server"}},"spec":{"containers":[{"env":[{"name":"SERVER_PORT","value":"8089"},{"name":"SLEEP_DURATION","value":"1"},{"name":"DEMO_FOLDERS","value":"/app"},{"name":"ARMO_TEST_NAME","value":"auto_attach_deployment"},{"name":"CAA_ENABLE_CRASH_REPORTER","value":"1"}],"image":"quay.io/armosec/demoservice:v25","imagePullPolicy":"IfNotPresent","name":"demoservice","ports":[{"containerPort":8089,"protocol":"TCP"}],"resources":{},"terminationMessagePath":"/dev/termination-log","terminationMessagePolicy":"File"}],"dnsPolicy":"ClusterFirst","restartPolicy":"Always","schedulerName":"default-scheduler","securityContext":{},"terminationGracePeriodSeconds":30}}}}` obj, _ := workloadinterface.NewWorkload([]byte(w)) removeData(obj) diff --git a/policyhandler/handlenotification.go b/policyhandler/handlenotification.go index 2c27bdda..be7cf0ab 100644 --- a/policyhandler/handlenotification.go +++ b/policyhandler/handlenotification.go @@ -59,6 +59,5 @@ func (policyHandler *PolicyHandler) getResources(notification *reporthandling.Po opaSessionObj.K8SResources = resourcesMap opaSessionObj.AllResources = allResources - cautils.SuccessTextDisplay("Let’s start!!!") return nil } diff --git a/resourcehandler/filesloader.go b/resourcehandler/filesloader.go index 28cce904..25cc7e74 100644 --- a/resourcehandler/filesloader.go +++ b/resourcehandler/filesloader.go @@ -125,7 +125,7 @@ func mapResources(workloads []workloadinterface.IMetadata) map[string][]workload continue } - if workloadinterface.IsTypeWorkload(workloads[i].GetObject()) { + if k8sinterface.IsTypeWorkload(workloads[i].GetObject()) { w := workloadinterface.NewWorkloadObj(workloads[i].GetObject()) if groupVersionResource.Group != w.GetGroup() || groupVersionResource.Version != w.GetVersion() { // TODO - print warning diff --git a/resourcehandler/k8sresources.go b/resourcehandler/k8sresources.go index 4bcc499f..888e1a60 100644 --- a/resourcehandler/k8sresources.go +++ b/resourcehandler/k8sresources.go @@ -47,6 +47,8 @@ func (k8sHandler *K8sResourceHandler) GetResources(frameworks []reporthandling.F // get k8s resources cautils.ProgressTextDisplay("Accessing Kubernetes objects") + cautils.StartSpinner() + // build resources map // map resources based on framework required resources: map["/group/version/kind"][] k8sResourcesMap := setResourceMap(frameworks) @@ -69,6 +71,8 @@ func (k8sHandler *K8sResourceHandler) GetResources(frameworks []reporthandling.F cautils.WarningDisplay(os.Stdout, fmt.Sprintf("Warning: %v\n", err.Error())) } + cautils.StopSpinner() + cautils.SuccessTextDisplay("Accessed successfully to Kubernetes objects") return k8sResourcesMap, allResources, nil } diff --git a/resultshandling/printer/prettyprinter.go b/resultshandling/printer/prettyprinter.go index 9148358c..b3a2ca36 100644 --- a/resultshandling/printer/prettyprinter.go +++ b/resultshandling/printer/prettyprinter.go @@ -4,6 +4,7 @@ import ( "fmt" "os" "sort" + "strings" "github.com/armosec/k8s-interface/workloadinterface" "github.com/armosec/kubescape/cautils" @@ -121,10 +122,6 @@ func (printer *PrettyPrinter) printSummary(controlName string, controlSummary *R cautils.DescriptionDisplay(printer.writer, "\n") } - -func getControlURL(controlID string) string { - return fmt.Sprintf("https://hub.armo.cloud/docs/%s", controlID) -} func (printer *PrettyPrinter) printTitle(controlName string, controlSummary *ResultSummary) { cautils.InfoDisplay(printer.writer, "[control: %s - %s] ", controlName, getControlURL(controlSummary.ID)) if controlSummary.TotalResources == 0 { @@ -159,72 +156,25 @@ func (printer *PrettyPrinter) printResources(controlSummary *ResultSummary) { func (printer *PrettyPrinter) printGroupedResources(workloads map[string][]WorkloadSummary) { indent := INDENT - for ns, rsc := range workloads { - if !isKindToBeGrouped(ns) { - printer.printGroupedResource(indent, ns, rsc) - } - } - if rsc, ok := workloads["User"]; ok { - printer.printGroupedResource(indent, "User", rsc) - } - if rsc, ok := workloads["Group"]; ok { - printer.printGroupedResource(indent, "Group", rsc) + for title, rsc := range workloads { + printer.printGroupedResource(indent, title, rsc) } } -// func (printer *PrettyPrinter) printGroupedResources(workloads map[string][]WorkloadSummary) { -// indent := INDENT -// for ns, rsc := range workloads { -// printer.printGroupedResource(indent, ns, rsc) -// } -// // for ns, rsc := range workloads { -// // if !isKindToBeGrouped(ns) { -// // } -// // } -// // if rsc, ok := workloads["User"]; ok { -// // printer.printGroupedResource(indent, "User", rsc) -// // } -// // if rsc, ok := workloads["Group"]; ok { -// // printer.printGroupedResource(indent, "Group", rsc) -// // } -// } - -func (printer *PrettyPrinter) printGroupedResource(indent string, ns string, rsc []WorkloadSummary) { +func (printer *PrettyPrinter) printGroupedResource(indent string, title string, rsc []WorkloadSummary) { preIndent := indent - if isKindToBeGrouped(ns) { - cautils.SimpleDisplay(printer.writer, "%s%ss\n", indent, ns) - } else if ns != "" { - cautils.SimpleDisplay(printer.writer, "%sNamespace %s\n", indent, ns) - } - preIndent2 := indent - for r := range rsc { + if title != "" { + cautils.SimpleDisplay(printer.writer, "%s%s\n", indent, title) indent += indent + } + + for r := range rsc { relatedObjectsStr := generateRelatedObjectsStr(rsc[r]) cautils.SimpleDisplay(printer.writer, fmt.Sprintf("%s%s - %s %s\n", indent, rsc[r].resource.GetKind(), rsc[r].resource.GetName(), relatedObjectsStr)) - indent = preIndent2 } indent = preIndent } -// func (printer *PrettyPrinter) printGroupedResource(indent string, ns string, rsc []WorkloadSummary) { -// preIndent := indent - -// cautils.SimpleDisplay(printer.writer, "%s%s %s\n", indent, rsc[0].groupBy, ns) -// // if isKindToBeGrouped(ns) { -// // cautils.SimpleDisplay(printer.writer, "%s%ss\n", indent, ns) -// // } else if ns != "" { -// // cautils.SimpleDisplay(printer.writer, "%sNamespace %s\n", indent, ns) -// // } -// preIndent2 := indent -// for r := range rsc { -// indent += indent -// relatedObjectsStr := generateRelatedObjectsStr(rsc[r]) -// cautils.SimpleDisplay(printer.writer, fmt.Sprintf("%s%s - %s %s\n", indent, rsc[r].resource.GetKind(), rsc[r].resource.GetName(), relatedObjectsStr)) -// indent = preIndent2 -// } -// indent = preIndent -// } - func generateRelatedObjectsStr(workload WorkloadSummary) string { relatedStr := "" if workload.resource.GetObjectType() == workloadinterface.TypeWorkloadObject { @@ -325,3 +275,7 @@ func getWriter(outputFile string) *os.File { return os.Stdout } + +func getControlURL(controlID string) string { + return fmt.Sprintf("https://hub.armo.cloud/docs/%s", strings.ToLower(controlID)) +} diff --git a/resultshandling/printer/printresults.go b/resultshandling/printer/printresults.go index bd82b4ed..5c4a2746 100644 --- a/resultshandling/printer/printresults.go +++ b/resultshandling/printer/printresults.go @@ -6,8 +6,6 @@ import ( var INDENT = " " -const EmptyPercentage = "NaN" - const ( PrettyFormat string = "pretty-printer" JsonFormat string = "json" diff --git a/resultshandling/printer/summeryhelpers.go b/resultshandling/printer/summeryhelpers.go index a2053278..dee39235 100644 --- a/resultshandling/printer/summeryhelpers.go +++ b/resultshandling/printer/summeryhelpers.go @@ -1,7 +1,9 @@ package printer import ( + "github.com/armosec/k8s-interface/k8sinterface" "github.com/armosec/k8s-interface/workloadinterface" + "github.com/armosec/opa-utils/objectsenvelopes" "github.com/armosec/opa-utils/reporthandling" ) @@ -9,19 +11,40 @@ import ( func groupByNamespaceOrKind(resources []WorkloadSummary, status func(workloadSummary *WorkloadSummary) bool) map[string][]WorkloadSummary { mapResources := make(map[string][]WorkloadSummary) for i := range resources { - if status(&resources[i]) { - if isKindToBeGrouped(resources[i].resource.GetKind()) { - if r, ok := mapResources[resources[i].resource.GetKind()]; ok { - r = append(r, resources[i]) - mapResources[resources[i].resource.GetKind()] = r - } else { - mapResources[resources[i].resource.GetKind()] = []WorkloadSummary{resources[i]} - } - } else if r, ok := mapResources[resources[i].resource.GetNamespace()]; ok { + if !status(&resources[i]) { + continue + } + t := resources[i].resource.GetObjectType() + if t == objectsenvelopes.TypeRegoResponseVectorObject && !isKindToBeGrouped(resources[i].resource.GetKind()) { + t = workloadinterface.TypeWorkloadObject + } + switch t { // TODO - find a better way to defind the groups + case workloadinterface.TypeWorkloadObject: + ns := "" + if resources[i].resource.GetNamespace() != "" { + ns = "Namescape " + resources[i].resource.GetNamespace() + } + if r, ok := mapResources[ns]; ok { r = append(r, resources[i]) - mapResources[resources[i].resource.GetNamespace()] = r + mapResources[ns] = r } else { - mapResources[resources[i].resource.GetNamespace()] = []WorkloadSummary{resources[i]} + mapResources[ns] = []WorkloadSummary{resources[i]} + } + case objectsenvelopes.TypeRegoResponseVectorObject: + group := resources[i].resource.GetKind() + "s" + if r, ok := mapResources[group]; ok { + r = append(r, resources[i]) + mapResources[group] = r + } else { + mapResources[group] = []WorkloadSummary{resources[i]} + } + default: + group, _ := k8sinterface.SplitApiVersion(resources[i].resource.GetApiVersion()) + if r, ok := mapResources[group]; ok { + r = append(r, resources[i]) + mapResources[group] = r + } else { + mapResources[group] = []WorkloadSummary{resources[i]} } } } From 37effda7c5f5d8df4fc10152f4d941e3c502cb19 Mon Sep 17 00:00:00 2001 From: dwertent Date: Tue, 21 Dec 2021 11:04:18 +0200 Subject: [PATCH 15/18] update pkg --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index f73c5e18..72545313 100644 --- a/go.mod +++ b/go.mod @@ -4,8 +4,8 @@ go 1.17 require ( github.com/armosec/armoapi-go v0.0.23 - github.com/armosec/k8s-interface v0.0.46 - github.com/armosec/opa-utils v0.0.72 + github.com/armosec/k8s-interface v0.0.50 + github.com/armosec/opa-utils v0.0.75 github.com/armosec/rbac-utils v0.0.9 github.com/armosec/utils-go v0.0.3 github.com/briandowns/spinner v1.18.0 diff --git a/go.sum b/go.sum index 908604b0..eea11167 100644 --- a/go.sum +++ b/go.sum @@ -88,11 +88,11 @@ github.com/armosec/armoapi-go v0.0.23 h1:jqoLIWM5CR7DCD9fpFgN0ePqtHvOCoZv/XzCwsU github.com/armosec/armoapi-go v0.0.23/go.mod h1:iaVVGyc23QGGzAdv4n+szGQg3Rbpixn9yQTU3qWRpaw= github.com/armosec/k8s-interface v0.0.8/go.mod h1:xxS+V5QT3gVQTwZyAMMDrYLWGrfKOpiJ7Jfhfa0w9sM= github.com/armosec/k8s-interface v0.0.37/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2dsFVc0XtgRh1ZU= -github.com/armosec/k8s-interface v0.0.46 h1:qfCGWtbDCRQg8le2K1OveL94Y3dvGuamHmIJZ61+qqs= -github.com/armosec/k8s-interface v0.0.46/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2dsFVc0XtgRh1ZU= +github.com/armosec/k8s-interface v0.0.50 h1:iLPGI0j85vwKANr9QDAnba4Efjg3DyIJg15jRJdvOnc= +github.com/armosec/k8s-interface v0.0.50/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2dsFVc0XtgRh1ZU= github.com/armosec/opa-utils v0.0.64/go.mod h1:6tQP8UDq2EvEfSqh8vrUdr/9QVSCG4sJfju1SXQOn4c= -github.com/armosec/opa-utils v0.0.72 h1:YaaHIafNwsTD28Adr+PblauChX3YDfnP1LJUmpt3kIU= -github.com/armosec/opa-utils v0.0.72/go.mod h1:+5zC2LGTA5ibp1NDi9niwnA6jYSsE/Pb9M5u4M11dV0= +github.com/armosec/opa-utils v0.0.75 h1:GBI3K18xc3WXJHIorIu4bGNAsfMYHUc1x7zueDz2ZbY= +github.com/armosec/opa-utils v0.0.75/go.mod h1:L7d+uiIIXAZ3LEyKtmEIbMcI1hWgWaXGpn5zVCqzwSU= github.com/armosec/rbac-utils v0.0.1/go.mod h1:pQ8CBiij8kSKV7aeZm9FMvtZN28VgA7LZcYyTWimq40= github.com/armosec/rbac-utils v0.0.9 h1:rIOWp4K7BELUNX32ktSjVbb8d/0SpH7W76W6Tf+8rzw= github.com/armosec/rbac-utils v0.0.9/go.mod h1:Ex/IdGWhGv9HZq6Hs8N/ApzCKSIvpNe/ETqDfnuyah0= From ff7881130fdfb8b31300ef2af95d55447d5af83d Mon Sep 17 00:00:00 2001 From: dwertent Date: Tue, 21 Dec 2021 13:09:31 +0200 Subject: [PATCH 16/18] fixed host sensor issue --- clihandler/initcli.go | 41 +++++++++++++------------ clihandler/initcliutils.go | 3 +- hostsensorutils/hostsensordeploy.go | 3 ++ hostsensorutils/hostsensorgetfrompod.go | 11 +------ 4 files changed, 27 insertions(+), 31 deletions(-) diff --git a/clihandler/initcli.go b/clihandler/initcli.go index b870f364..d8ccf8b1 100644 --- a/clihandler/initcli.go +++ b/clihandler/initcli.go @@ -37,6 +37,18 @@ func getInterfaces(scanInfo *cautils.ScanInfo) componentInterfaces { setSubmitBehavior(scanInfo, tenantConfig) hostSensorHandler := getHostSensorHandler(scanInfo, k8s) + if err := hostSensorHandler.Init(); err != nil { + errMsg := "failed to init host sensor" + if scanInfo.VerboseMode { + errMsg = fmt.Sprintf("%s: %v", errMsg, err) + } + cautils.ErrorDisplay(errMsg) + hostSensorHandler = &hostsensorutils.HostSensorHandlerMock{} + } + // excluding hostsensor namespace + if len(scanInfo.IncludeNamespaces) == 0 && hostSensorHandler.GetNamespace() != "" { + scanInfo.ExcludedNamespaces = fmt.Sprintf("%s,%s", scanInfo.ExcludedNamespaces, hostSensorHandler.GetNamespace()) + } resourceHandler := getResourceHandler(scanInfo, tenantConfig, k8s, hostSensorHandler) @@ -73,28 +85,19 @@ func ScanCliSetup(scanInfo *cautils.ScanInfo) error { interfaces.report.SetClusterName(interfaces.tenantConfig.GetClusterName()) interfaces.report.SetCustomerGUID(interfaces.tenantConfig.GetCustomerGUID()) - if err := interfaces.hostSensorHandler.Init(); err != nil { - errMsg := "failed to init host sensor" - if scanInfo.VerboseMode { - errMsg = fmt.Sprintf("%s: %v", errMsg, err) - } - cautils.ErrorDisplay(errMsg) - } else if len(scanInfo.IncludeNamespaces) == 0 && interfaces.hostSensorHandler.GetNamespace() != "" { - scanInfo.ExcludedNamespaces = fmt.Sprintf("%s,%s", scanInfo.ExcludedNamespaces, interfaces.hostSensorHandler) - defer func() { - if err := interfaces.hostSensorHandler.TearDown(); err != nil { - errMsg := "failed to tear down host sensor" - if scanInfo.VerboseMode { - errMsg = fmt.Sprintf("%s: %v", errMsg, err) - } - cautils.ErrorDisplay(errMsg) - } - }() - } - // set policy getter only after setting the customerGUID setPolicyGetter(scanInfo, interfaces.tenantConfig.GetCustomerGUID()) + defer func() { + if err := interfaces.hostSensorHandler.TearDown(); err != nil { + errMsg := "failed to tear down host sensor" + if scanInfo.VerboseMode { + errMsg = fmt.Sprintf("%s: %v", errMsg, err) + } + cautils.ErrorDisplay(errMsg) + } + }() + // cli handler setup go func() { // policy handler setup diff --git a/clihandler/initcliutils.go b/clihandler/initcliutils.go index 55a35b4e..b7ce4c54 100644 --- a/clihandler/initcliutils.go +++ b/clihandler/initcliutils.go @@ -61,7 +61,7 @@ func getHostSensorHandler(scanInfo *cautils.ScanInfo, k8s *k8sinterface.Kubernet } if hostSensorVal := scanInfo.HostSensor.Get(); hostSensorVal != nil && *hostSensorVal { hostSensorHandler, err := hostsensorutils.NewHostSensorHandler(k8s) - if err != nil { + if err != nil || hostSensorHandler == nil { glog.Errorf("failed to create host sensor: %v", err) return &hostsensorutils.HostSensorHandlerMock{} } @@ -69,7 +69,6 @@ func getHostSensorHandler(scanInfo *cautils.ScanInfo, k8s *k8sinterface.Kubernet } return &hostsensorutils.HostSensorHandlerMock{} } - func getFieldSelector(scanInfo *cautils.ScanInfo) resourcehandler.IFieldSelector { if scanInfo.IncludeNamespaces != "" { return resourcehandler.NewIncludeSelector(scanInfo.IncludeNamespaces) diff --git a/hostsensorutils/hostsensordeploy.go b/hostsensorutils/hostsensordeploy.go index 83a6d020..06e1c008 100644 --- a/hostsensorutils/hostsensordeploy.go +++ b/hostsensorutils/hostsensordeploy.go @@ -201,5 +201,8 @@ func (hsh *HostSensorHandler) TearDown() error { } func (hsh *HostSensorHandler) GetNamespace() string { + if hsh.DaemonSet == nil { + return "" + } return hsh.DaemonSet.Namespace } diff --git a/hostsensorutils/hostsensorgetfrompod.go b/hostsensorutils/hostsensorgetfrompod.go index e6e9f480..aa58aae5 100644 --- a/hostsensorutils/hostsensorgetfrompod.go +++ b/hostsensorutils/hostsensorgetfrompod.go @@ -8,7 +8,6 @@ import ( "github.com/armosec/k8s-interface/k8sinterface" "github.com/armosec/kubescape/cautils" "github.com/armosec/opa-utils/objectsenvelopes/hostsensor" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/yaml" ) @@ -123,7 +122,7 @@ func (hsh *HostSensorHandler) GetOsReleaseFile() ([]hostsensor.HostSensorDataEnv // return list of func (hsh *HostSensorHandler) GetKubeletConfigurations() ([]hostsensor.HostSensorDataEnvelope, error) { // loop over pods and port-forward it to each of them - res, err := hsh.sendAllPodsHTTPGETRequest("/kubeletConfigurations", "") // empty kind, will be overridden + res, err := hsh.sendAllPodsHTTPGETRequest("/kubeletConfigurations", "KubeletConfigurations") // empty kind, will be overridden for resIdx := range res { jsonBytes, err := yaml.YAMLToJSON(res[resIdx].Data) if err != nil { @@ -131,14 +130,6 @@ func (hsh *HostSensorHandler) GetKubeletConfigurations() ([]hostsensor.HostSenso continue } res[resIdx].SetData(jsonBytes) - - kindDet := metav1.TypeMeta{} - if err = json.Unmarshal(jsonBytes, &kindDet); err != nil { - fmt.Printf("In GetKubeletConfigurations failed to Unmarshal GroupVersionKind: %v;\n%v", err, jsonBytes) - continue - } - res[resIdx].SetKind(kindDet.Kind) - res[resIdx].SetApiVersion(k8sinterface.JoinGroupVersion(kindDet.GroupVersionKind().Group, kindDet.GroupVersionKind().Version)) } return res, err } From 046a22bd2bfe2ad0ff40131205b218dfb8e17c4f Mon Sep 17 00:00:00 2001 From: dwertent Date: Wed, 22 Dec 2021 12:59:46 +0200 Subject: [PATCH 17/18] print to error stderr --- cautils/display.go | 4 ++-- clihandler/cmd/framework.go | 3 ++- clihandler/initcli.go | 2 +- resultshandling/printer/jsonprinter.go | 2 +- resultshandling/printer/junit.go | 2 +- resultshandling/printer/prometheusprinter.go | 2 +- 6 files changed, 8 insertions(+), 7 deletions(-) diff --git a/cautils/display.go b/cautils/display.go index d82e9114..155124d1 100644 --- a/cautils/display.go +++ b/cautils/display.go @@ -51,8 +51,8 @@ func ErrorDisplay(str string) { if IsSilent() { return } - SuccessDisplay(os.Stdout, "[Error] ") - SimpleDisplay(os.Stdout, fmt.Sprintf("%s\n", str)) + FailureDisplay(os.Stderr, "[Error] ") + SimpleDisplay(os.Stderr, fmt.Sprintf("%s\n", str)) } diff --git a/clihandler/cmd/framework.go b/clihandler/cmd/framework.go index 03d2e1d2..e3533794 100644 --- a/clihandler/cmd/framework.go +++ b/clihandler/cmd/framework.go @@ -90,7 +90,8 @@ var frameworkCmd = &cobra.Command{ cautils.SetSilentMode(scanInfo.Silent) err := clihandler.ScanCliSetup(&scanInfo) if err != nil { - return err + fmt.Fprintf(os.Stderr, "error: %v\n", err) + os.Exit(1) } return nil }, diff --git a/clihandler/initcli.go b/clihandler/initcli.go index d8ccf8b1..0c6900da 100644 --- a/clihandler/initcli.go +++ b/clihandler/initcli.go @@ -122,7 +122,7 @@ func ScanCliSetup(scanInfo *cautils.ScanInfo) error { interfaces.report.DisplayReportURL() adjustedFailThreshold := float32(scanInfo.FailThreshold) / 100 - if score < adjustedFailThreshold { + if score >= adjustedFailThreshold { return fmt.Errorf("Scan score is below threshold") } diff --git a/resultshandling/printer/jsonprinter.go b/resultshandling/printer/jsonprinter.go index 01acad7e..7f2cc8a5 100644 --- a/resultshandling/printer/jsonprinter.go +++ b/resultshandling/printer/jsonprinter.go @@ -21,7 +21,7 @@ func (jsonPrinter *JsonPrinter) SetWriter(outputFile string) { } func (jsonPrinter *JsonPrinter) Score(score float32) { - fmt.Printf("\nFinal score: %d", int(score*100)) + fmt.Printf("\nOverall risk-score (0- Excellent, 100- All failed): %d\n", int(score)) } func (jsonPrinter *JsonPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) { diff --git a/resultshandling/printer/junit.go b/resultshandling/printer/junit.go index 9c480b50..d7648a2d 100644 --- a/resultshandling/printer/junit.go +++ b/resultshandling/printer/junit.go @@ -22,7 +22,7 @@ func (junitPrinter *JunitPrinter) SetWriter(outputFile string) { } func (junitPrinter *JunitPrinter) Score(score float32) { - fmt.Printf("\nFinal score: %d", int(score*100)) + fmt.Printf("\nOverall risk-score (0- Excellent, 100- All failed): %d\n", int(score)) } func (junitPrinter *JunitPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) { diff --git a/resultshandling/printer/prometheusprinter.go b/resultshandling/printer/prometheusprinter.go index a211f55e..97ba7290 100644 --- a/resultshandling/printer/prometheusprinter.go +++ b/resultshandling/printer/prometheusprinter.go @@ -25,7 +25,7 @@ func (prometheusPrinter *PrometheusPrinter) SetWriter(outputFile string) { } func (prometheusPrinter *PrometheusPrinter) Score(score float32) { - fmt.Printf("\n# Overall score out of 100\nkubescape_score %f\n", score*100) + fmt.Printf("\n# Overall risk-score (0- Excellent, 100- All failed)\nkubescape_score %d\n", int(score)) } func (printer *PrometheusPrinter) printResources(allResources map[string]workloadinterface.IMetadata, resourcesIDs *reporthandling.ResourcesIDs, frameworkName, controlName string) { From f5f5552ecdca40ec8af96364adfccd96cd267bb9 Mon Sep 17 00:00:00 2001 From: dwertent Date: Wed, 22 Dec 2021 16:48:18 +0200 Subject: [PATCH 18/18] support threshold --- README.md | 2 +- cautils/customerloader.go | 6 +- cautils/versioncheck.go | 9 +- clihandler/cmd/download.go | 94 ++++++++++++------- clihandler/cmd/framework.go | 2 +- clihandler/cmd/scan.go | 4 +- clihandler/initcli.go | 5 +- clihandler/initcliutils.go | 1 - opaprocessor/processorhandler.go | 2 +- resultshandling/printer/prettyprinter.go | 20 ++-- .../reporter/reporteventreceiver.go | 6 +- 11 files changed, 91 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index 2860d179..ddee4832 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ Set-ExecutionPolicy RemoteSigned -scope CurrentUser | `-e`/`--exclude-namespaces` | Scan all namespaces | Namespaces to exclude from scanning. Recommended to exclude `kube-system` and `kube-public` namespaces | | | `--include-namespaces` | Scan all namespaces | Scan specific namespaces | | | `-s`/`--silent` | Display progress messages | Silent progress messages | | -| `-t`/`--fail-threshold` | `0` (do not fail) | fail command (return exit code 1) if result is below threshold | `0` -> `100` | +| `-t`/`--fail-threshold` | `100` (do not fail) | fail command (return exit code 1) if result is above threshold | `0` -> `100` | | `-f`/`--format` | `pretty-printer` | Output format | `pretty-printer`/`json`/`junit`/`prometheus` | | `-o`/`--output` | print to stdout | Save scan result in file | | | `--use-from` | | Load local framework object from specified path. If not used will download latest | | diff --git a/cautils/customerloader.go b/cautils/customerloader.go index d6000681..fab50611 100644 --- a/cautils/customerloader.go +++ b/cautils/customerloader.go @@ -180,7 +180,9 @@ func NewClusterConfig(k8s *k8sinterface.KubernetesApi, backendAPI getter.IBacken } } if c.configObj.ClusterName == "" { - c.configObj.ClusterName = adoptClusterName(k8sinterface.GetClusterName()) + c.configObj.ClusterName = AdoptClusterName(k8sinterface.GetClusterName()) + } else { // override the cluster name if it has unwanted characters + c.configObj.ClusterName = AdoptClusterName(c.configObj.ClusterName) } return c @@ -425,6 +427,6 @@ func DeleteConfigFile() error { return os.Remove(ConfigFileFullPath()) } -func adoptClusterName(clusterName string) string { +func AdoptClusterName(clusterName string) string { return strings.ReplaceAll(clusterName, "/", "-") } diff --git a/cautils/versioncheck.go b/cautils/versioncheck.go index ab5d4217..aaa72795 100644 --- a/cautils/versioncheck.go +++ b/cautils/versioncheck.go @@ -65,6 +65,9 @@ func NewVersionCheckRequest(buildNumber, frameworkName, frameworkVersion, scanni if buildNumber == "" { buildNumber = UnknownBuildNumber } + if scanningTarget == "" { + scanningTarget = "unknown" + } return &VersionCheckRequest{ Client: "kubescape", ClientVersion: buildNumber, @@ -82,7 +85,7 @@ func (v *VersionCheckHandlerMock) CheckLatestVersion(versionData *VersionCheckRe func (v *VersionCheckHandler) CheckLatestVersion(versionData *VersionCheckRequest) error { defer func() { if err := recover(); err != nil { - fmt.Println("failed to get latest version") + WarningDisplay(os.Stderr, "failed to get latest version\n") } }() @@ -93,7 +96,7 @@ func (v *VersionCheckHandler) CheckLatestVersion(versionData *VersionCheckReques if latestVersion.ClientUpdate != "" { if BuildNumber != "" && BuildNumber < latestVersion.ClientUpdate { - fmt.Println(warningMessage(latestVersion.Client, latestVersion.ClientUpdate)) + WarningDisplay(os.Stderr, warningMessage(latestVersion.Client, latestVersion.ClientUpdate), "\n") } } @@ -103,7 +106,7 @@ func (v *VersionCheckHandler) CheckLatestVersion(versionData *VersionCheckReques // } if latestVersion.Message != "" { - fmt.Println(latestVersion.Message) + InfoDisplay(os.Stderr, latestVersion.Message, "\n") } return nil diff --git a/clihandler/cmd/download.go b/clihandler/cmd/download.go index 74e3cad3..bc4bd3ca 100644 --- a/clihandler/cmd/download.go +++ b/clihandler/cmd/download.go @@ -2,6 +2,7 @@ package cmd import ( "fmt" + "os" "strings" "github.com/armosec/kubescape/cautils" @@ -25,43 +26,10 @@ var downloadCmd = &cobra.Command{ return nil }, RunE: func(cmd *cobra.Command, args []string) error { - if strings.EqualFold(args[0], "framework") { - downloadInfo.FrameworkName = strings.ToLower(args[1]) - g := getter.NewDownloadReleasedPolicy() - if err := g.SetRegoObjects(); err != nil { - return err - } - - if downloadInfo.Path == "" { - downloadInfo.Path = getter.GetDefaultPath(downloadInfo.FrameworkName + ".json") - } - frameworks, err := g.GetFramework(downloadInfo.FrameworkName) - if err != nil { - return err - } - err = getter.SaveFrameworkInFile(frameworks, downloadInfo.Path) - if err != nil { - return err - } - } else if strings.EqualFold(args[0], "control") { - downloadInfo.ControlName = strings.ToLower(args[1]) - g := getter.NewDownloadReleasedPolicy() - if err := g.SetRegoObjects(); err != nil { - return err - } - if downloadInfo.Path == "" { - downloadInfo.Path = getter.GetDefaultPath(downloadInfo.ControlName + ".json") - } - controls, err := g.GetControl(downloadInfo.ControlName) - if err != nil { - return err - } - err = getter.SaveControlInFile(controls, downloadInfo.Path) - if err != nil { - return err - } + if err := download(args); err != nil { + fmt.Fprintf(os.Stderr, "error: %v\n", err) + os.Exit(1) } - return nil }, } @@ -71,3 +39,57 @@ func init() { downloadInfo = cautils.DownloadInfo{} downloadCmd.Flags().StringVarP(&downloadInfo.Path, "output", "o", "", "Output file. If specified, will store save to `~/.kubescape/.json`") } + +func download(args []string) error { + switch strings.ToLower(args[0]) { + case "framework": + return downloadFramework(args[1]) + case "control": + return downloadControl(args[1]) + // case "exceptions": + // case "artifacts": + default: + return fmt.Errorf("unknown command to download") + } +} + +func downloadFramework(frameworkName string) error { + downloadInfo.FrameworkName = strings.ToLower(frameworkName) + g := getter.NewDownloadReleasedPolicy() + if err := g.SetRegoObjects(); err != nil { + return err + } + + if downloadInfo.Path == "" { + downloadInfo.Path = getter.GetDefaultPath(downloadInfo.FrameworkName + ".json") + } + frameworks, err := g.GetFramework(downloadInfo.FrameworkName) + if err != nil { + return err + } + err = getter.SaveFrameworkInFile(frameworks, downloadInfo.Path) + if err != nil { + return err + } + return nil +} + +func downloadControl(controlName string) error { + downloadInfo.ControlName = strings.ToLower(controlName) + g := getter.NewDownloadReleasedPolicy() + if err := g.SetRegoObjects(); err != nil { + return err + } + if downloadInfo.Path == "" { + downloadInfo.Path = getter.GetDefaultPath(downloadInfo.ControlName + ".json") + } + controls, err := g.GetControl(downloadInfo.ControlName) + if err != nil { + return err + } + err = getter.SaveControlInFile(controls, downloadInfo.Path) + if err != nil { + return err + } + return nil +} diff --git a/clihandler/cmd/framework.go b/clihandler/cmd/framework.go index e3533794..ca2aaf04 100644 --- a/clihandler/cmd/framework.go +++ b/clihandler/cmd/framework.go @@ -90,7 +90,7 @@ var frameworkCmd = &cobra.Command{ cautils.SetSilentMode(scanInfo.Silent) err := clihandler.ScanCliSetup(&scanInfo) if err != nil { - fmt.Fprintf(os.Stderr, "error: %v\n", err) + fmt.Fprintf(os.Stderr, "error: %v\n\n", err) os.Exit(1) } return nil diff --git a/clihandler/cmd/scan.go b/clihandler/cmd/scan.go index e45abd3e..9370f4ab 100644 --- a/clihandler/cmd/scan.go +++ b/clihandler/cmd/scan.go @@ -39,7 +39,7 @@ func init() { scanCmd.PersistentFlags().StringVar(&scanInfo.ControlsInputs, "controls-config", "", "Path to an controls-config obj. If not set will download controls-config from ARMO management portal") scanCmd.PersistentFlags().StringVar(&scanInfo.UseExceptions, "exceptions", "", "Path to an exceptions obj. If not set will download exceptions from ARMO management portal") scanCmd.PersistentFlags().StringVarP(&scanInfo.ExcludedNamespaces, "exclude-namespaces", "e", "", "Namespaces to exclude from scanning. Recommended: kube-system,kube-public") - scanCmd.PersistentFlags().Uint16VarP(&scanInfo.FailThreshold, "fail-threshold", "t", 0, "Failure threshold is the percent below which the command fails and returns exit code 1") + scanCmd.PersistentFlags().Uint16VarP(&scanInfo.FailThreshold, "fail-threshold", "t", 100, "Failure threshold is the percent above which the command fails and returns exit code 1") scanCmd.PersistentFlags().StringVarP(&scanInfo.Format, "format", "f", "pretty-printer", `Output format. Supported formats: "pretty-printer"/"json"/"junit"/"prometheus"`) scanCmd.PersistentFlags().StringVar(&scanInfo.IncludeNamespaces, "include-namespaces", "", "scan specific namespaces. e.g: --include-namespaces ns-a,ns-b") scanCmd.PersistentFlags().BoolVarP(&scanInfo.Local, "keep-local", "", false, "If you do not want your Kubescape results reported to Armo backend. Use this flag if you ran with the '--submit' flag in the past and you do not want to submit your current scan results") @@ -50,7 +50,7 @@ func init() { scanCmd.PersistentFlags().BoolVarP(&scanInfo.Silent, "silent", "s", false, "Silent progress messages") scanCmd.PersistentFlags().BoolVarP(&scanInfo.Submit, "submit", "", false, "Send the scan results to Armo management portal where you can see the results in a user-friendly UI, choose your preferred compliance framework, check risk results history and trends, manage exceptions, get remediation recommendations and much more. By default the results are not submitted") - hostF := scanCmd.PersistentFlags().VarPF(&scanInfo.HostSensor, "enable-host-scan", "", "Deploy ARMO K8s host-sensor daemonset in the scanned cluster. Deleting it right after we collecting the data. Required to collect valueable data from cluster nodes for certain controls") + hostF := scanCmd.PersistentFlags().VarPF(&scanInfo.HostSensor, "enable-host-scan", "", "Deploy ARMO K8s host-sensor daemonset in the scanned cluster. Deleting it right after we collecting the data. Required to collect valueable data from cluster nodes for certain controls") hostF.NoOptDefVal = "true" hostF.DefValue = "false, for no TTY in stdin" } diff --git a/clihandler/initcli.go b/clihandler/initcli.go index 0c6900da..eebd806f 100644 --- a/clihandler/initcli.go +++ b/clihandler/initcli.go @@ -121,9 +121,8 @@ func ScanCliSetup(scanInfo *cautils.ScanInfo) error { // print report url interfaces.report.DisplayReportURL() - adjustedFailThreshold := float32(scanInfo.FailThreshold) / 100 - if score >= adjustedFailThreshold { - return fmt.Errorf("Scan score is below threshold") + if score >= float32(scanInfo.FailThreshold) { + return fmt.Errorf("scan risk-score %.2f is above permitted threshold %d", score, scanInfo.FailThreshold) } return nil diff --git a/clihandler/initcliutils.go b/clihandler/initcliutils.go index b7ce4c54..d455a54b 100644 --- a/clihandler/initcliutils.go +++ b/clihandler/initcliutils.go @@ -38,7 +38,6 @@ func getRBACHandler(tenantConfig cautils.ITenantConfig, k8s *k8sinterface.Kubern func getReporter(tenantConfig cautils.ITenantConfig, submit bool) reporter.IReport { if submit { return reporter.NewReportEventReceiver(tenantConfig.GetConfigObj()) - } return reporter.NewReportMock() } diff --git a/opaprocessor/processorhandler.go b/opaprocessor/processorhandler.go index 7a320b92..330d1aa6 100644 --- a/opaprocessor/processorhandler.go +++ b/opaprocessor/processorhandler.go @@ -67,9 +67,9 @@ func (opaHandler *OPAProcessorHandler) ProcessRulesListenner() { opap.updateResults() // update score - // opap.updateScore() scoreutil := score.NewScore(opaSessionObj.AllResources) scoreutil.Calculate(opaSessionObj.PostureReport.FrameworkReports) + // report *opaHandler.reportResults <- opaSessionObj } diff --git a/resultshandling/printer/prettyprinter.go b/resultshandling/printer/prettyprinter.go index b3a2ca36..3a8b416a 100644 --- a/resultshandling/printer/prettyprinter.go +++ b/resultshandling/printer/prettyprinter.go @@ -35,10 +35,12 @@ func (printer *PrettyPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) warningResources := []string{} allResources := []string{} frameworkNames := []string{} + frameworkScores := []float32{} var overallRiskScore float32 = 0 for _, frameworkReport := range opaSessionObj.PostureReport.FrameworkReports { frameworkNames = append(frameworkNames, frameworkReport.Name) + frameworkScores = append(frameworkScores, frameworkReport.Score) failedResources = reporthandling.GetUniqueResourcesIDs(append(failedResources, frameworkReport.ListResourcesIDs().GetFailedResources()...)) warningResources = reporthandling.GetUniqueResourcesIDs(append(warningResources, frameworkReport.ListResourcesIDs().GetWarningResources()...)) allResources = reporthandling.GetUniqueResourcesIDs(append(allResources, frameworkReport.ListResourcesIDs().GetAllResources()...)) @@ -56,7 +58,7 @@ func (printer *PrettyPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) } printer.printResults() - printer.printSummaryTable(frameworkNames) + printer.printSummaryTable(frameworkNames, frameworkScores) } @@ -218,9 +220,9 @@ func generateFooter(printer *PrettyPrinter) []string { return row } -func (printer *PrettyPrinter) printSummaryTable(frameworksNames []string) { +func (printer *PrettyPrinter) printSummaryTable(frameworksNames []string, frameworkScores []float32) { // For control scan framework will be nil - printer.printFramework(frameworksNames) + printer.printFramework(frameworksNames, frameworkScores) summaryTable := tablewriter.NewWriter(printer.writer) summaryTable.SetAutoWrapText(false) @@ -240,16 +242,16 @@ func (printer *PrettyPrinter) printSummaryTable(frameworksNames []string) { summaryTable.Render() } -func (printer *PrettyPrinter) printFramework(frameworksNames []string) { +func (printer *PrettyPrinter) printFramework(frameworksNames []string, frameworkScores []float32) { if len(frameworksNames) == 1 { - cautils.InfoTextDisplay(printer.writer, fmt.Sprintf("%s FRAMEWORK\n", frameworksNames[0])) + cautils.InfoTextDisplay(printer.writer, fmt.Sprintf("FRAMEWORK %s\n", frameworksNames[0])) } else if len(frameworksNames) > 1 { - p := "" + p := "FRAMEWORKS: " for i := 0; i < len(frameworksNames)-1; i++ { - p += frameworksNames[i] + ", " + p += fmt.Sprintf("%s (risk: %.2f), ", frameworksNames[i], frameworkScores[i]) } - p += frameworksNames[len(frameworksNames)-1] - cautils.InfoTextDisplay(printer.writer, fmt.Sprintf("%s FRAMEWORKS\n", p)) + p += fmt.Sprintf("%s (risk: %.2f)\n", frameworksNames[len(frameworksNames)-1], frameworkScores[len(frameworkScores)-1]) + cautils.InfoTextDisplay(printer.writer, p) } } diff --git a/resultshandling/reporter/reporteventreceiver.go b/resultshandling/reporter/reporteventreceiver.go index fc01232d..95b70f9c 100644 --- a/resultshandling/reporter/reporteventreceiver.go +++ b/resultshandling/reporter/reporteventreceiver.go @@ -43,6 +43,10 @@ func NewReportEventReceiver(tenantConfig *cautils.ConfigObj) *ReportEventReceive func (report *ReportEventReceiver) ActionSendReport(opaSessionObj *cautils.OPASessionObj) error { + if report.customerGUID == "" || report.clusterName == "" { + return fmt.Errorf("missing accout ID or cluster name. AccountID: '%s', Cluster name: '%s'", report.customerGUID, report.clusterName) + } + if err := report.prepareReport(opaSessionObj.PostureReport, opaSessionObj.AllResources); err != nil { return err } @@ -54,7 +58,7 @@ func (report *ReportEventReceiver) SetCustomerGUID(customerGUID string) { } func (report *ReportEventReceiver) SetClusterName(clusterName string) { - report.clusterName = clusterName + report.clusterName = cautils.AdoptClusterName(clusterName) // clean cluster name } func (report *ReportEventReceiver) prepareReport(postureReport *reporthandling.PostureReport, allResources map[string]workloadinterface.IMetadata) error {