From 1aeb2b96e25fff4d2567099dc2be1046c3faae62 Mon Sep 17 00:00:00 2001 From: dwertent Date: Tue, 7 Dec 2021 10:30:03 +0200 Subject: [PATCH 1/3] store data only once --- cautils/datastructures.go | 4 +- clihandler/cmd/framework.go | 27 ++++++++- opaprocessor/processorhandler.go | 50 +++++++++-------- opaprocessor/processorhandler_test.go | 8 ++- opaprocessor/processorhandlerutils.go | 55 ++++--------------- policyhandler/handlenotification.go | 44 ++++++++------- resourcehandler/filesloader.go | 31 +++++++---- resourcehandler/k8sresources.go | 23 +++++--- resourcehandler/resourceshandler.go | 3 +- .../reporter/reporteventreceiver.go | 4 -- 10 files changed, 136 insertions(+), 113 deletions(-) diff --git a/cautils/datastructures.go b/cautils/datastructures.go index 2f9c2b71..918edc4a 100644 --- a/cautils/datastructures.go +++ b/cautils/datastructures.go @@ -6,8 +6,8 @@ import ( "github.com/armosec/opa-utils/reporthandling" ) -// K8SResources map[//]<[]resource objects> -type K8SResources map[string][]workloadinterface.IMetadata +// K8SResources map[//][] +type K8SResources map[string][]string type OPASessionObj struct { K8SResources *K8SResources // input k8s objects diff --git a/clihandler/cmd/framework.go b/clihandler/cmd/framework.go index e381ecff..03d2e1d2 100644 --- a/clihandler/cmd/framework.go +++ b/clihandler/cmd/framework.go @@ -13,9 +13,34 @@ import ( "github.com/spf13/cobra" ) +var ( + frameworkExample = ` + # Scan all frameworks and submit the results + kubescape scan --submit + + # Scan the NSA framework + kubescape scan framework nsa + + # Scan the NSA and MITRE framework + kubescape scan framework nsa,mitre + + # Scan kubernetes YAML manifest files + kubescape scan framework nsa *.yaml + + # Scan and save the results in the JSON format + kubescape scan --format json --output results.json + + # Save scan results in JSON format + kubescape scan --format json --output results.json + + # Display all resources + kubescape scan --verbose +` +) var frameworkCmd = &cobra.Command{ - Use: fmt.Sprintf("framework [``/`-`] [flags]\nExamples:\n$ kubescape scan framework nsa [flags]\n$ kubescape scan framework mitre,nsa [flags]\n$ kubescape scan framework 'nsa, mitre' [flags]\nSupported frameworks: %s", getter.NativeFrameworks), + Use: "framework [``/`-`] [flags]", Short: fmt.Sprintf("The framework you wish to use. Supported frameworks: %s", strings.Join(getter.NativeFrameworks, ", ")), + Example: frameworkExample, Long: "Execute a scan on a running Kubernetes cluster or `yaml`/`json` files (use glob) or `-` for stdin", ValidArgs: getter.NativeFrameworks, Args: func(cmd *cobra.Command, args []string) error { diff --git a/opaprocessor/processorhandler.go b/opaprocessor/processorhandler.go index dfde0555..f1573f85 100644 --- a/opaprocessor/processorhandler.go +++ b/opaprocessor/processorhandler.go @@ -8,12 +8,12 @@ import ( "github.com/armosec/kubescape/cautils" "github.com/armosec/opa-utils/exceptions" "github.com/armosec/opa-utils/reporthandling" + "github.com/golang/glog" "github.com/armosec/k8s-interface/k8sinterface" "github.com/armosec/k8s-interface/workloadinterface" "github.com/armosec/opa-utils/resources" - "github.com/golang/glog" "github.com/open-policy-agent/opa/ast" "github.com/open-policy-agent/opa/rego" uuid "github.com/satori/go.uuid" @@ -58,7 +58,7 @@ func (opaHandler *OPAProcessorHandler) ProcessRulesListenner() { // process if err := opap.Process(); err != nil { - fmt.Println(err) + // fmt.Println(err) } // edit results @@ -81,7 +81,7 @@ func (opap *OPAProcessor) Process() error { for i := range opap.Frameworks { frameworkReport, err := opap.processFramework(&opap.Frameworks[i]) if err != nil { - errs = fmt.Errorf("%v\n%s", errs, err.Error()) + appendError(&errs, err) } frameworkReports = append(frameworkReports, *frameworkReport) } @@ -95,6 +95,16 @@ func (opap *OPAProcessor) Process() error { return errs } +func appendError(errs *error, err error) { + if err == nil { + return + } + if errs == nil { + errs = &err + } else { + *errs = fmt.Errorf("%v\n%s", *errs, err.Error()) + } +} func (opap *OPAProcessor) processFramework(framework *reporthandling.Framework) (*reporthandling.FrameworkReport, error) { var errs error @@ -105,7 +115,8 @@ func (opap *OPAProcessor) processFramework(framework *reporthandling.Framework) for i := range framework.Controls { controlReport, err := opap.processControl(&framework.Controls[i]) if err != nil { - errs = fmt.Errorf("%v\n%s", errs, err.Error()) + appendError(&errs, err) + // errs = fmt.Errorf("%v\n%s", errs, err.Error()) } if controlReport != nil { controlReports = append(controlReports, *controlReport) @@ -133,7 +144,7 @@ func (opap *OPAProcessor) processControl(control *reporthandling.Control) (*repo for i := range control.Rules { ruleReport, err := opap.processRule(&control.Rules[i]) if err != nil { - errs = fmt.Errorf("%v\n%s", errs, err.Error()) + appendError(&errs, err) } if ruleReport != nil { ruleReports = append(ruleReports, *ruleReport) @@ -151,7 +162,7 @@ func (opap *OPAProcessor) processRule(rule *reporthandling.PolicyRule) (*reporth return nil, nil } - inputResources, err := reporthandling.RegoResourcesAggregator(rule, getKubernetesObjects(opap.K8SResources, rule.Match)) + inputResources, err := reporthandling.RegoResourcesAggregator(rule, getKubernetesObjects(opap.K8SResources, opap.AllResources, rule.Match)) if err != nil { return nil, fmt.Errorf("error getting aggregated k8sObjects: %s", err.Error()) } @@ -167,8 +178,12 @@ func (opap *OPAProcessor) processRule(rule *reporthandling.PolicyRule) (*reporth } ruleReport.ListInputKinds = workloadinterface.ListMetaIDs(inputResources) + // remove all data from responses, leave only the metadata + keepFields := []string{"kind", "apiVersion", "metadata"} + keepMetadataFields := []string{"name", "namespace", "labels"} + ruleReport.RemoveData(keepFields, keepMetadataFields) + for i := range inputResources { - removeData(inputResources[i]) opap.AllResources[inputResources[i].GetID()] = inputResources[i] } @@ -228,11 +243,9 @@ func (opap *OPAProcessor) regoEval(inputObj []map[string]interface{}, compiledRe // Run evaluation resultSet, err := rego.Eval(context.Background()) if err != nil { - return nil, fmt.Errorf("in 'regoEval', failed to evaluate rule, reason: %s", err.Error()) + return nil, err } results, err := reporthandling.ParseRegoResult(&resultSet) - - // results, err := ParseRegoResult(&resultSet) if err != nil { return results, err } @@ -241,6 +254,11 @@ func (opap *OPAProcessor) regoEval(inputObj []map[string]interface{}, compiledRe } func (opap *OPAProcessor) updateResults() { + // remove data from all objects + for i := range opap.AllResources { + removeData(opap.AllResources[i]) + } + for f := range opap.PostureReport.FrameworkReports { // set exceptions exceptions.SetFrameworkExceptions(&opap.PostureReport.FrameworkReports[f], opap.Exceptions, cautils.ClusterName) @@ -250,17 +268,5 @@ func (opap *OPAProcessor) updateResults() { // set default score reporthandling.SetDefaultScore(&opap.PostureReport.FrameworkReports[f]) - - // edit results - remove data - - // TODO - move function to pkg - use RemoveData - for c := range opap.PostureReport.FrameworkReports[f].ControlReports { - for r, ruleReport := range opap.PostureReport.FrameworkReports[f].ControlReports[c].RuleReports { - // editing the responses -> removing duplications, clearing secret data, etc. - opap.PostureReport.FrameworkReports[f].ControlReports[c].RuleReports[r].RuleResponses = editRuleResponses(ruleReport.RuleResponses) - } - } - } - } diff --git a/opaprocessor/processorhandler_test.go b/opaprocessor/processorhandler_test.go index afa73d14..320f2baf 100644 --- a/opaprocessor/processorhandler_test.go +++ b/opaprocessor/processorhandler_test.go @@ -19,12 +19,18 @@ func TestProcess(t *testing.T) { // set k8s k8sResources := make(cautils.K8SResources) - k8sResources["/v1/pods"] = workloadinterface.ListMapToMeta(k8sinterface.ConvertUnstructuredSliceToMap(k8sinterface.V1KubeSystemNamespaceMock().Items)) + allResources := make(map[string]workloadinterface.IMetadata) + imetaObj := workloadinterface.ListMapToMeta(k8sinterface.ConvertUnstructuredSliceToMap(k8sinterface.V1KubeSystemNamespaceMock().Items)) + for i := range imetaObj { + allResources[imetaObj[i].GetID()] = imetaObj[i] + } + k8sResources["/v1/pods"] = workloadinterface.ListMetaIDs(imetaObj) // set opaSessionObj opaSessionObj := cautils.NewOPASessionObjMock() opaSessionObj.Frameworks = []reporthandling.Framework{*reporthandling.MockFrameworkA()} opaSessionObj.K8SResources = &k8sResources + opaSessionObj.AllResources = allResources opap := NewOPAProcessor(opaSessionObj, resources.NewRegoDependenciesDataMock()) opap.Process() diff --git a/opaprocessor/processorhandlerutils.go b/opaprocessor/processorhandlerutils.go index a6f5ad2a..b5724cc1 100644 --- a/opaprocessor/processorhandlerutils.go +++ b/opaprocessor/processorhandlerutils.go @@ -13,7 +13,7 @@ import ( "github.com/golang/glog" ) -func getKubernetesObjects(k8sResources *cautils.K8SResources, match []reporthandling.RuleMatchObjects) []workloadinterface.IMetadata { +func getKubernetesObjects(k8sResources *cautils.K8SResources, allResources map[string]workloadinterface.IMetadata, match []reporthandling.RuleMatchObjects) []workloadinterface.IMetadata { k8sObjects := []workloadinterface.IMetadata{} for m := range match { for _, groups := range match[m].APIGroups { @@ -26,7 +26,9 @@ func getKubernetesObjects(k8sResources *cautils.K8SResources, match []reporthand continue // glog.Errorf("Resource '%s' is nil, probably failed to pull the resource", groupResource) } - k8sObjects = append(k8sObjects, k8sObj...) + for i := range k8sObj { + k8sObjects = append(k8sObjects, allResources[k8sObj[i]]) + } } } } @@ -45,28 +47,6 @@ func getRuleDependencies() (map[string]string, error) { return modules, nil } -//editRuleResponses editing the responses -> removing duplications, clearing secret data, etc. -func editRuleResponses(ruleResponses []reporthandling.RuleResponse) []reporthandling.RuleResponse { - lenRuleResponses := len(ruleResponses) - for i := 0; i < lenRuleResponses; i++ { - for j := range ruleResponses[i].AlertObject.K8SApiObjects { - w := workloadinterface.NewWorkloadObj(ruleResponses[i].AlertObject.K8SApiObjects[j]) - if w == nil { - continue - } - - cleanRuleResponses(w) - ruleResponses[i].AlertObject.K8SApiObjects[j] = w.GetWorkload() - } - } - return ruleResponses -} -func cleanRuleResponses(workload k8sinterface.IWorkload) { - if workload.GetKind() == "Secret" { - workload.RemoveSecretData() - } -} - func ruleWithArmoOpaDependency(annotations map[string]interface{}) bool { if annotations == nil { return false @@ -107,36 +87,25 @@ func removeData(obj workloadinterface.IMetadata) { workload := workloadinterface.NewWorkloadObj(obj.GetObject()) switch workload.GetKind() { case "Secret": - removeSecretData(obj) + removeSecretData(workload) case "ConfigMap": - removeConfigMapData(obj) + removeConfigMapData(workload) default: - removePodData(obj) + removePodData(workload) } } -func removeConfigMapData(obj workloadinterface.IMetadata) { - if !workloadinterface.IsTypeWorkload(obj.GetObject()) { - return // remove data only from kubernetes objects - } - workload := workloadinterface.NewWorkloadObj(obj.GetObject()) +func removeConfigMapData(workload workloadinterface.IWorkload) { workload.RemoveAnnotation("kubectl.kubernetes.io/last-applied-configuration") workloadinterface.RemoveFromMap(workload.GetObject(), "data") workloadinterface.RemoveFromMap(workload.GetObject(), "metadata", "managedFields") } -func removeSecretData(obj workloadinterface.IMetadata) { - if !workloadinterface.IsTypeWorkload(obj.GetObject()) { - return // remove data only from kubernetes objects - } - workloadinterface.NewWorkloadObj(obj.GetObject()).RemoveSecretData() - workloadinterface.RemoveFromMap(obj.GetObject(), "metadata", "managedFields") +func removeSecretData(workload workloadinterface.IWorkload) { + workloadinterface.NewWorkloadObj(workload.GetObject()).RemoveSecretData() + workloadinterface.RemoveFromMap(workload.GetObject(), "metadata", "managedFields") } -func removePodData(obj workloadinterface.IMetadata) { - if !workloadinterface.IsTypeWorkload(obj.GetObject()) { - return // remove data only from kubernetes objects - } - workload := workloadinterface.NewWorkloadObj(obj.GetObject()) +func removePodData(workload workloadinterface.IWorkload) { workload.RemoveAnnotation("kubectl.kubernetes.io/last-applied-configuration") workloadinterface.RemoveFromMap(workload.GetObject(), "metadata", "managedFields") diff --git a/policyhandler/handlenotification.go b/policyhandler/handlenotification.go index 6346af3d..27bad7a6 100644 --- a/policyhandler/handlenotification.go +++ b/policyhandler/handlenotification.go @@ -40,47 +40,53 @@ func (policyHandler *PolicyHandler) HandleNotificationRequest(notification *repo return err } - k8sResources, err := policyHandler.getResources(notification, opaSessionObj, scanInfo) + err := policyHandler.getResources(notification, opaSessionObj, scanInfo) if err != nil { return err } - if k8sResources == nil || len(*k8sResources) == 0 { + if opaSessionObj.K8SResources == nil || len(*opaSessionObj.K8SResources) == 0 { return fmt.Errorf("empty list of resources") } - opaSessionObj.K8SResources = k8sResources - for i := range *k8sResources { - for resourceIdx := range (*k8sResources)[i] { - // TODO: add remove data function - opaSessionObj.AllResources[(*k8sResources)[i][resourceIdx].GetID()] = (*k8sResources)[i][resourceIdx] - } - } + // update channel *policyHandler.processPolicy <- opaSessionObj return nil } -func (policyHandler *PolicyHandler) getResources(notification *reporthandling.PolicyNotification, opaSessionObj *cautils.OPASessionObj, scanInfo *cautils.ScanInfo) (*cautils.K8SResources, error) { +func (policyHandler *PolicyHandler) getResources(notification *reporthandling.PolicyNotification, opaSessionObj *cautils.OPASessionObj, scanInfo *cautils.ScanInfo) error { opaSessionObj.PostureReport.ClusterAPIServerInfo = policyHandler.resourceHandler.GetClusterAPIServerInfo() - resourcesMap, err := policyHandler.resourceHandler.GetResources(opaSessionObj.Frameworks, ¬ification.Designators) + resourcesMap, allResources, err := policyHandler.resourceHandler.GetResources(opaSessionObj.Frameworks, ¬ification.Designators) if err != nil { - return resourcesMap, err + return err } + + if err := policyHandler.collectHostResources(allResources, resourcesMap); err != nil { + return err + } + opaSessionObj.K8SResources = resourcesMap + opaSessionObj.AllResources = allResources + + cautils.SuccessTextDisplay("Let’s start!!!") + return nil +} + +func (policyHandler *PolicyHandler) collectHostResources(allResources map[string]workloadinterface.IMetadata, resourcesMap *cautils.K8SResources) error { hostResources, err := policyHandler.hostSensorHandler.CollectResources() if err != nil { - return resourcesMap, err + return err } for rscIdx := range hostResources { groupResources := k8sinterface.ResourceGroupToString(hostResources[rscIdx].Group, hostResources[rscIdx].GetApiVersion(), hostResources[rscIdx].GetKind()) for _, groupResource := range groupResources { - grpReasorceList, ok := (*resourcesMap)[groupResource] + allResources[hostResources[rscIdx].GetID()] = &hostResources[rscIdx] + + grpResourceList, ok := (*resourcesMap)[groupResource] if !ok { - grpReasorceList = make([]workloadinterface.IMetadata, 0) + grpResourceList = make([]string, 0) } - grpReasorceList = append(grpReasorceList, &hostResources[rscIdx]) - (*resourcesMap)[groupResource] = grpReasorceList + (*resourcesMap)[groupResource] = append(grpResourceList, hostResources[rscIdx].GetID()) } } - cautils.SuccessTextDisplay("Let’s start!!!") - return resourcesMap, nil + return nil } diff --git a/resourcehandler/filesloader.go b/resourcehandler/filesloader.go index 2a268ea5..0cbe8a41 100644 --- a/resourcehandler/filesloader.go +++ b/resourcehandler/filesloader.go @@ -43,13 +43,19 @@ func NewFileResourceHandler(inputPatterns []string) *FileResourceHandler { } } -func (fileHandler *FileResourceHandler) GetResources(frameworks []reporthandling.Framework, designator *armotypes.PortalDesignator) (*cautils.K8SResources, error) { +func (fileHandler *FileResourceHandler) GetResources(frameworks []reporthandling.Framework, designator *armotypes.PortalDesignator) (*cautils.K8SResources, map[string]workloadinterface.IMetadata, error) { + + // build resources map + // map resources based on framework required resources: map["/group/version/kind"][] + k8sResources := setResourceMap(frameworks) + allResources := map[string]workloadinterface.IMetadata{} + workloads := []workloadinterface.IMetadata{} // load resource from local file system w, err := loadResourcesFromFiles(fileHandler.inputPatterns) if err != nil { - return nil, err + return nil, allResources, err } if w != nil { workloads = append(workloads, w...) @@ -58,31 +64,32 @@ func (fileHandler *FileResourceHandler) GetResources(frameworks []reporthandling // load resources from url w, err = loadResourcesFromUrl(fileHandler.inputPatterns) if err != nil { - return nil, err + return nil, allResources, err } if w != nil { workloads = append(workloads, w...) } if len(workloads) == 0 { - return nil, fmt.Errorf("empty list of workloads - no workloads found") + return nil, allResources, fmt.Errorf("empty list of workloads - no workloads found") } // map all resources: map["/group/version/kind"][] - allResources := mapResources(workloads) - - // build resources map - // map resources based on framework required resources: map["/group/version/kind"][] - k8sResources := setResourceMap(frameworks) // TODO - support designators + mappedResources := mapResources(workloads) // save only relevant resources - for i := range allResources { + for i := range mappedResources { if _, ok := (*k8sResources)[i]; ok { - (*k8sResources)[i] = allResources[i] + ids := []string{} + for j := range mappedResources[i] { + ids = append(ids, mappedResources[i][j].GetID()) + allResources[mappedResources[i][j].GetID()] = mappedResources[i][j] + } + (*k8sResources)[i] = ids } } - return k8sResources, nil + return k8sResources, allResources, nil } diff --git a/resourcehandler/k8sresources.go b/resourcehandler/k8sresources.go index cd0a8c9f..7d8ed658 100644 --- a/resourcehandler/k8sresources.go +++ b/resourcehandler/k8sresources.go @@ -32,23 +32,26 @@ func NewK8sResourceHandler(k8s *k8sinterface.KubernetesApi, fieldSelector IField } } -func (k8sHandler *K8sResourceHandler) GetResources(frameworks []reporthandling.Framework, designator *armotypes.PortalDesignator) (*cautils.K8SResources, error) { +func (k8sHandler *K8sResourceHandler) GetResources(frameworks []reporthandling.Framework, designator *armotypes.PortalDesignator) (*cautils.K8SResources, map[string]workloadinterface.IMetadata, error) { + allResources := map[string]workloadinterface.IMetadata{} + // get k8s resources cautils.ProgressTextDisplay("Accessing Kubernetes objects") // build resources map + // map resources based on framework required resources: map["/group/version/kind"][] k8sResourcesMap := setResourceMap(frameworks) // get namespace and labels from designator (ignore cluster labels) _, namespace, labels := armotypes.DigestPortalDesignator(designator) // pull k8s recourses - if err := k8sHandler.pullResources(k8sResourcesMap, namespace, labels); err != nil { - return k8sResourcesMap, err + if err := k8sHandler.pullResources(k8sResourcesMap, allResources, namespace, labels); err != nil { + return k8sResourcesMap, allResources, err } cautils.SuccessTextDisplay("Accessed successfully to Kubernetes objects") - return k8sResourcesMap, nil + return k8sResourcesMap, allResources, nil } func (k8sHandler *K8sResourceHandler) GetClusterAPIServerInfo() *version.Info { @@ -59,7 +62,7 @@ func (k8sHandler *K8sResourceHandler) GetClusterAPIServerInfo() *version.Info { } return clusterAPIServerInfo } -func (k8sHandler *K8sResourceHandler) pullResources(k8sResources *cautils.K8SResources, namespace string, labels map[string]string) error { +func (k8sHandler *K8sResourceHandler) pullResources(k8sResources *cautils.K8SResources, allResources map[string]workloadinterface.IMetadata, namespace string, labels map[string]string) error { var errs error for groupResource := range *k8sResources { @@ -73,10 +76,14 @@ func (k8sHandler *K8sResourceHandler) pullResources(k8sResources *cautils.K8SRes } else { errs = fmt.Errorf("%s\n%s", errs, err.Error()) } - } else { - // store result as []map[string]interface{} - (*k8sResources)[groupResource] = ConvertMapListToMeta(k8sinterface.ConvertUnstructuredSliceToMap(k8sinterface.FilterOutOwneredResources(result))) + continue } + // store result as []map[string]interface{} + metaObjs := ConvertMapListToMeta(k8sinterface.ConvertUnstructuredSliceToMap(k8sinterface.FilterOutOwneredResources(result))) + for i := range metaObjs { + allResources[metaObjs[i].GetID()] = metaObjs[i] + } + (*k8sResources)[groupResource] = workloadinterface.ListMetaIDs(metaObjs) } return errs } diff --git a/resourcehandler/resourceshandler.go b/resourcehandler/resourceshandler.go index c2ddf15f..723066eb 100644 --- a/resourcehandler/resourceshandler.go +++ b/resourcehandler/resourceshandler.go @@ -2,12 +2,13 @@ package resourcehandler import ( "github.com/armosec/armoapi-go/armotypes" + "github.com/armosec/k8s-interface/workloadinterface" "github.com/armosec/kubescape/cautils" "github.com/armosec/opa-utils/reporthandling" "k8s.io/apimachinery/pkg/version" ) type IResourceHandler interface { - GetResources(frameworks []reporthandling.Framework, designator *armotypes.PortalDesignator) (*cautils.K8SResources, error) + GetResources([]reporthandling.Framework, *armotypes.PortalDesignator) (*cautils.K8SResources, map[string]workloadinterface.IMetadata, error) GetClusterAPIServerInfo() *version.Info } diff --git a/resultshandling/reporter/reporteventreceiver.go b/resultshandling/reporter/reporteventreceiver.go index 8373f8fe..05ef1fe9 100644 --- a/resultshandling/reporter/reporteventreceiver.go +++ b/resultshandling/reporter/reporteventreceiver.go @@ -42,10 +42,6 @@ func NewReportEventReceiver(tenantConfig *cautils.ConfigObj) *ReportEventReceive } func (report *ReportEventReceiver) ActionSendReport(opaSessionObj *cautils.OPASessionObj) error { - // Remove data before reporting - keepFields := []string{"kind", "apiVersion", "metadata"} - keepMetadataFields := []string{"name", "namespace", "labels"} - opaSessionObj.PostureReport.RemoveData(keepFields, keepMetadataFields) if err := report.prepareReport(opaSessionObj.PostureReport, opaSessionObj.AllResources); err != nil { return err From a095634755b27fc509ad90894c56310a1081f26b Mon Sep 17 00:00:00 2001 From: Alex Jones Date: Tue, 7 Dec 2021 13:03:44 +0000 Subject: [PATCH 2/3] spelling mistake on clihandler/cmd/control.go:19 --- clihandler/cmd/control.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clihandler/cmd/control.go b/clihandler/cmd/control.go index a0772767..bc0cb876 100644 --- a/clihandler/cmd/control.go +++ b/clihandler/cmd/control.go @@ -16,7 +16,7 @@ import ( // controlCmd represents the control command var controlCmd = &cobra.Command{ Use: "control /.\nExamples:\n$ kubescape scan control C-0058,C-0057 [flags]\n$ kubescape scan contol C-0058 [flags]\n$ kubescape scan control 'privileged container,allowed hostpath' [flags]", - Short: fmt.Sprintf("The control you wish to use for scan. It must be present in at least one of the folloiwng frameworks: %s", getter.NativeFrameworks), + Short: fmt.Sprintf("The control you wish to use for scan. It must be present in at least one of the following frameworks: %s", getter.NativeFrameworks), Args: func(cmd *cobra.Command, args []string) error { if len(args) > 0 { controls := strings.Split(args[0], ",") From bb1cbe090279d711431c7d179182903d853b2855 Mon Sep 17 00:00:00 2001 From: dwertent Date: Tue, 7 Dec 2021 16:50:43 +0200 Subject: [PATCH 3/3] fixed url scanning, support preRun rego --- README.md | 2 +- clihandler/initcli.go | 8 +++-- go.mod | 16 +++------- go.sum | 18 ++++-------- install.sh | 2 +- opaprocessor/processorhandler.go | 42 ++++++++++++++------------- opaprocessor/processorhandlerutils.go | 30 +++++++++++++++++++ policyhandler/handlenotification.go | 36 +++-------------------- resourcehandler/filesloader.go | 6 ++-- resourcehandler/filesloader_test.go | 2 +- resourcehandler/k8sresources.go | 36 +++++++++++++++++++---- 11 files changed, 107 insertions(+), 91 deletions(-) diff --git a/README.md b/README.md index e4ae2289..2860d179 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ curl -s https://raw.githubusercontent.com/armosec/kubescape/master/install.sh | ## Run: ``` -kubescape scan framework nsa --submit +kubescape scan --submit ``` diff --git a/clihandler/initcli.go b/clihandler/initcli.go index 6b4ede54..c0bc3a15 100644 --- a/clihandler/initcli.go +++ b/clihandler/initcli.go @@ -53,6 +53,7 @@ func getInterfaces(scanInfo *cautils.ScanInfo) componentInterfaces { var tenantConfig cautils.ITenantConfig hostSensorHandler = &hostsensorutils.HostSensorHandlerMock{} + // scanning environment scanningTarget := scanInfo.GetScanningEnvironment() switch scanningTarget { @@ -67,11 +68,12 @@ func getInterfaces(scanInfo *cautils.ScanInfo) componentInterfaces { resourceHandler = resourcehandler.NewFileResourceHandler(scanInfo.InputPatterns) case cautils.ScanCluster: k8s := k8sinterface.NewKubernetesApi() // initialize kubernetes api object + // pull k8s resources - resourceHandler = resourcehandler.NewK8sResourceHandler(k8s, getFieldSelector(scanInfo)) + hostSensorHandler = initHostSensor(scanInfo, k8s) + resourceHandler = resourcehandler.NewK8sResourceHandler(k8s, getFieldSelector(scanInfo), hostSensorHandler) // use clusterConfig struct tenantConfig = cautils.NewClusterConfig(k8s, getter.GetArmoAPIConnector(), scanInfo.Account) - hostSensorHandler = initHostSensor(scanInfo, k8s) } // reporting behavior - setup reporter reportHandler := getReporter(scanInfo, tenantConfig) @@ -131,7 +133,7 @@ func ScanCliSetup(scanInfo *cautils.ScanInfo) error { // cli handler setup go func() { // policy handler setup - policyHandler := policyhandler.NewPolicyHandler(&processNotification, interfaces.resourceHandler, interfaces.hostSensorHandler) + policyHandler := policyhandler.NewPolicyHandler(&processNotification, interfaces.resourceHandler) if err := Scan(policyHandler, scanInfo); err != nil { fmt.Println(err) diff --git a/go.mod b/go.mod index 605315c0..0f278b9c 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.29 - github.com/armosec/opa-utils v0.0.57 + github.com/armosec/k8s-interface v0.0.32 + github.com/armosec/opa-utils v0.0.61 github.com/armosec/rbac-utils v0.0.8 github.com/armosec/utils-go v0.0.3 github.com/briandowns/spinner v1.16.0 @@ -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 ( @@ -36,7 +36,6 @@ require ( github.com/Azure/go-autorest/tracing v0.6.0 // indirect github.com/OneOfOne/xxhash v1.2.8 // indirect github.com/armosec/utils-k8s-go v0.0.1 // indirect - github.com/aws/aws-sdk-go v1.41.11 // indirect github.com/coreos/go-oidc v2.2.1+incompatible // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/docker/docker v20.10.9+incompatible // indirect @@ -49,15 +48,12 @@ require ( github.com/go-logr/logr v0.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/google/go-cmp v0.5.5 // indirect github.com/google/gofuzz v1.1.0 // indirect - github.com/googleapis/gax-go/v2 v2.0.5 // indirect github.com/googleapis/gnostic v0.5.5 // indirect github.com/imdario/mergo v0.3.12 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect - github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/json-iterator/go v1.1.11 // indirect github.com/mattn/go-colorable v0.1.9 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect @@ -73,7 +69,6 @@ require ( github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/yashtewari/glob-intersection v0.0.0-20180916065949-5c77d914dd0b // indirect - go.opencensus.io v0.23.0 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.19.1 // indirect @@ -85,10 +80,7 @@ require ( golang.org/x/text v0.3.6 // indirect golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect gonum.org/v1/gonum v0.9.1 // indirect - google.golang.org/api v0.44.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect - google.golang.org/grpc v1.38.0 // indirect google.golang.org/protobuf v1.27.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect @@ -96,5 +88,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..ac5b4203 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.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/opa-utils v0.0.57 h1:7lDEKxblqfsEXLn+6lkj17ctBSnhDuYanfdqG55kW2g= -github.com/armosec/opa-utils v0.0.57/go.mod h1:UAT4Xokq91ysLa4Xg0WLqVsjJCnbFgsevkiIJFxTghU= +github.com/armosec/k8s-interface v0.0.26/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2dsFVc0XtgRh1ZU= +github.com/armosec/k8s-interface v0.0.32 h1:dvSDRTXVZWrHyWOgu1QDrd4M2De4KYClrnB/k5Dq5fk= +github.com/armosec/k8s-interface v0.0.32/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2dsFVc0XtgRh1ZU= +github.com/armosec/opa-utils v0.0.61 h1:qIjsiv6BdSE7r+8k6FZtn0ZllYiai7Iyd8rl5YI4qPU= +github.com/armosec/opa-utils v0.0.61/go.mod h1:P63qZDPG3vjPtSQqwx2N4Nfm8VaboDul7R7kmnUvvWc= 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= @@ -103,7 +103,6 @@ github.com/armosec/utils-k8s-go v0.0.1 h1:Ay3y7fW+4+FjVc0+obOWm8YsnEvM31vPAVoKTy github.com/armosec/utils-k8s-go v0.0.1/go.mod h1:qrU4pmY2iZsOb39Eltpm0sTTNM3E4pmeyWx4dgDUC2U= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/aws/aws-sdk-go v1.41.1/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= -github.com/aws/aws-sdk-go v1.41.11 h1:QLouWsiYQ8i22kD8k58Dpdhio1A0MpT7bg9ZNXqEjuI= github.com/aws/aws-sdk-go v1.41.11/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= @@ -336,11 +335,9 @@ github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLe github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go v2.0.0+incompatible h1:j0GKcs05QVmm7yesiZq2+9cxHkNK9YM6zKx4D2qucQU= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= @@ -385,9 +382,7 @@ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NH github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= @@ -1018,7 +1013,6 @@ google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34q google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.44.0 h1:URs6qR1lAxDsqWITsQXI4ZkGiYJ5dHtRNiCpfs2OeKA= google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1076,7 +1070,6 @@ google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= @@ -1101,7 +1094,6 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= diff --git a/install.sh b/install.sh index 2d0173bd..ec1d55c0 100755 --- a/install.sh +++ b/install.sh @@ -53,6 +53,6 @@ echo -e "\033[0m" $KUBESCAPE_EXEC version echo -echo -e "\033[35mUsage: $ $KUBESCAPE_EXEC scan framework nsa" +echo -e "\033[35mUsage: $ $KUBESCAPE_EXEC scan --submit" echo -e "\033[0m" diff --git a/opaprocessor/processorhandler.go b/opaprocessor/processorhandler.go index f1573f85..0c32f354 100644 --- a/opaprocessor/processorhandler.go +++ b/opaprocessor/processorhandler.go @@ -6,7 +6,6 @@ import ( "time" "github.com/armosec/kubescape/cautils" - "github.com/armosec/opa-utils/exceptions" "github.com/armosec/opa-utils/reporthandling" "github.com/golang/glog" @@ -167,7 +166,13 @@ func (opap *OPAProcessor) processRule(rule *reporthandling.PolicyRule) (*reporth return nil, fmt.Errorf("error getting aggregated k8sObjects: %s", err.Error()) } - ruleReport, err := opap.runOPAOnSingleRule(rule, workloadinterface.ListMetaToMap(inputResources)) + inputRawResources := workloadinterface.ListMetaToMap(inputResources) + + if inputRawResources, err = opap.executePreRun(rule, inputRawResources); err != nil { + return nil, err + } + + ruleReport, err := opap.runOPAOnSingleRule(rule, inputRawResources, ruleData) if err != nil { // ruleReport.RuleStatus.Status = reporthandling.StatusFailed ruleReport.RuleStatus.Status = "failure" @@ -176,6 +181,8 @@ func (opap *OPAProcessor) processRule(rule *reporthandling.PolicyRule) (*reporth } else { ruleReport.RuleStatus.Status = reporthandling.StatusPassed } + + inputResources = workloadinterface.ListMapToMeta(inputRawResources) ruleReport.ListInputKinds = workloadinterface.ListMetaIDs(inputResources) // remove all data from responses, leave only the metadata @@ -190,15 +197,16 @@ func (opap *OPAProcessor) processRule(rule *reporthandling.PolicyRule) (*reporth return &ruleReport, err } -func (opap *OPAProcessor) runOPAOnSingleRule(rule *reporthandling.PolicyRule, k8sObjects []map[string]interface{}) (reporthandling.RuleReport, error) { +func (opap *OPAProcessor) runOPAOnSingleRule(rule *reporthandling.PolicyRule, k8sObjects []map[string]interface{}, getRuleData func(*reporthandling.PolicyRule) string) (reporthandling.RuleReport, error) { switch rule.RuleLanguage { case reporthandling.RegoLanguage, reporthandling.RegoLanguage2: - return opap.runRegoOnK8s(rule, k8sObjects) + return opap.runRegoOnK8s(rule, k8sObjects, getRuleData) default: return reporthandling.RuleReport{}, fmt.Errorf("rule: '%s', language '%v' not supported", rule.Name, rule.RuleLanguage) } } -func (opap *OPAProcessor) runRegoOnK8s(rule *reporthandling.PolicyRule, k8sObjects []map[string]interface{}) (reporthandling.RuleReport, error) { + +func (opap *OPAProcessor) runRegoOnK8s(rule *reporthandling.PolicyRule, k8sObjects []map[string]interface{}, getRuleData func(*reporthandling.PolicyRule) string) (reporthandling.RuleReport, error) { var errs error ruleReport := reporthandling.RuleReport{ Name: rule.Name, @@ -209,7 +217,7 @@ func (opap *OPAProcessor) runRegoOnK8s(rule *reporthandling.PolicyRule, k8sObjec if err != nil { return ruleReport, fmt.Errorf("rule: '%s', %s", rule.Name, err.Error()) } - modules[rule.Name] = rule.Rule + modules[rule.Name] = getRuleData(rule) compiled, err := ast.CompileModules(modules) if err != nil { return ruleReport, fmt.Errorf("in 'runRegoOnSingleRule', failed to compile rule, name: %s, reason: %s", rule.Name, err.Error()) @@ -253,20 +261,14 @@ func (opap *OPAProcessor) regoEval(inputObj []map[string]interface{}, compiledRe return results, nil } -func (opap *OPAProcessor) updateResults() { - // remove data from all objects - for i := range opap.AllResources { - removeData(opap.AllResources[i]) +func (opap *OPAProcessor) executePreRun(rule *reporthandling.PolicyRule, k8sObjects []map[string]interface{}) ([]map[string]interface{}, error) { + + if preRuleData(rule) == "" { + return k8sObjects, nil } - - for f := range opap.PostureReport.FrameworkReports { - // set exceptions - exceptions.SetFrameworkExceptions(&opap.PostureReport.FrameworkReports[f], opap.Exceptions, cautils.ClusterName) - - // set counters - reporthandling.SetUniqueResourcesCounter(&opap.PostureReport.FrameworkReports[f]) - - // set default score - reporthandling.SetDefaultScore(&opap.PostureReport.FrameworkReports[f]) + ruleReport, err := opap.runOPAOnSingleRule(rule, k8sObjects, preRuleData) + if err != nil { + return nil, err } + return ruleReport.GetFailedResources(), nil } diff --git a/opaprocessor/processorhandlerutils.go b/opaprocessor/processorhandlerutils.go index b5724cc1..ffa8f727 100644 --- a/opaprocessor/processorhandlerutils.go +++ b/opaprocessor/processorhandlerutils.go @@ -7,12 +7,31 @@ import ( "github.com/armosec/k8s-interface/k8sinterface" "github.com/armosec/k8s-interface/workloadinterface" + "github.com/armosec/opa-utils/exceptions" "github.com/armosec/opa-utils/reporthandling" resources "github.com/armosec/opa-utils/resources" "github.com/golang/glog" ) +func (opap *OPAProcessor) updateResults() { + // remove data from all objects + for i := range opap.AllResources { + removeData(opap.AllResources[i]) + } + + for f := range opap.PostureReport.FrameworkReports { + // set exceptions + exceptions.SetFrameworkExceptions(&opap.PostureReport.FrameworkReports[f], opap.Exceptions, cautils.ClusterName) + + // set counters + reporthandling.SetUniqueResourcesCounter(&opap.PostureReport.FrameworkReports[f]) + + // set default score + reporthandling.SetDefaultScore(&opap.PostureReport.FrameworkReports[f]) + } +} + func getKubernetesObjects(k8sResources *cautils.K8SResources, allResources map[string]workloadinterface.IMetadata, match []reporthandling.RuleMatchObjects) []workloadinterface.IMetadata { k8sObjects := []workloadinterface.IMetadata{} for m := range match { @@ -120,3 +139,14 @@ func removePodData(workload workloadinterface.IWorkload) { } workloadinterface.SetInMap(workload.GetObject(), workloadinterface.PodSpec(workload.GetKind()), "containers", containers) } + +func ruleData(rule *reporthandling.PolicyRule) string { + return rule.Rule +} + +func preRuleData(rule *reporthandling.PolicyRule) string { + if len(rule.PreRun) > 0 { + return rule.PreRun[0] + } + return "" +} diff --git a/policyhandler/handlenotification.go b/policyhandler/handlenotification.go index 27bad7a6..2c27bdda 100644 --- a/policyhandler/handlenotification.go +++ b/policyhandler/handlenotification.go @@ -3,29 +3,24 @@ package policyhandler import ( "fmt" - "github.com/armosec/k8s-interface/k8sinterface" - "github.com/armosec/k8s-interface/workloadinterface" "github.com/armosec/kubescape/cautils" - "github.com/armosec/kubescape/hostsensorutils" "github.com/armosec/kubescape/resourcehandler" "github.com/armosec/opa-utils/reporthandling" ) // PolicyHandler - type PolicyHandler struct { - resourceHandler resourcehandler.IResourceHandler - hostSensorHandler hostsensorutils.IHostSensor + resourceHandler resourcehandler.IResourceHandler // we are listening on this chan in opaprocessor/processorhandler.go/ProcessRulesListenner func processPolicy *chan *cautils.OPASessionObj getters *cautils.Getters } // CreatePolicyHandler Create ws-handler obj -func NewPolicyHandler(processPolicy *chan *cautils.OPASessionObj, resourceHandler resourcehandler.IResourceHandler, hostSensorHandler hostsensorutils.IHostSensor) *PolicyHandler { +func NewPolicyHandler(processPolicy *chan *cautils.OPASessionObj, resourceHandler resourcehandler.IResourceHandler) *PolicyHandler { return &PolicyHandler{ - resourceHandler: resourceHandler, - processPolicy: processPolicy, - hostSensorHandler: hostSensorHandler, + resourceHandler: resourceHandler, + processPolicy: processPolicy, } } @@ -61,32 +56,9 @@ func (policyHandler *PolicyHandler) getResources(notification *reporthandling.Po return err } - if err := policyHandler.collectHostResources(allResources, resourcesMap); err != nil { - return err - } opaSessionObj.K8SResources = resourcesMap opaSessionObj.AllResources = allResources cautils.SuccessTextDisplay("Let’s start!!!") return nil } - -func (policyHandler *PolicyHandler) collectHostResources(allResources map[string]workloadinterface.IMetadata, resourcesMap *cautils.K8SResources) error { - hostResources, err := policyHandler.hostSensorHandler.CollectResources() - if err != nil { - 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] - - grpResourceList, ok := (*resourcesMap)[groupResource] - if !ok { - grpResourceList = make([]string, 0) - } - (*resourcesMap)[groupResource] = append(grpResourceList, hostResources[rscIdx].GetID()) - } - } - return nil -} diff --git a/resourcehandler/filesloader.go b/resourcehandler/filesloader.go index 0cbe8a41..2b9ebf3a 100644 --- a/resourcehandler/filesloader.go +++ b/resourcehandler/filesloader.go @@ -115,6 +115,7 @@ func loadResourcesFromFiles(inputPatterns []string) ([]workloadinterface.IMetada // build resources map func mapResources(workloads []workloadinterface.IMetadata) map[string][]workloadinterface.IMetadata { + allResources := map[string][]workloadinterface.IMetadata{} for i := range workloads { groupVersionResource, err := k8sinterface.GetGroupVersionResource(workloads[i].GetKind()) @@ -132,10 +133,9 @@ func mapResources(workloads []workloadinterface.IMetadata) map[string][]workload } resourceTriplets := k8sinterface.JoinResourceTriplets(groupVersionResource.Group, groupVersionResource.Version, groupVersionResource.Resource) if r, ok := allResources[resourceTriplets]; ok { - r = append(r, workloads...) - allResources[resourceTriplets] = r + allResources[resourceTriplets] = append(r, workloads[i]) } else { - allResources[resourceTriplets] = workloads + allResources[resourceTriplets] = []workloadinterface.IMetadata{workloads[i]} } } return allResources diff --git a/resourcehandler/filesloader_test.go b/resourcehandler/filesloader_test.go index 04d64082..6ff81e08 100644 --- a/resourcehandler/filesloader_test.go +++ b/resourcehandler/filesloader_test.go @@ -41,7 +41,7 @@ func TestLoadFile(t *testing.T) { t.Errorf("%v", err) } } -func TestLoadResources(t *testing.T) { +func TestMapResources(t *testing.T) { // policyHandler := &PolicyHandler{} // k8sResources, err := policyHandler.loadResources(opaSessionObj.Frameworks, scanInfo) // files, _ := listFiles([]string{onlineBoutiquePath()}) diff --git a/resourcehandler/k8sresources.go b/resourcehandler/k8sresources.go index 7d8ed658..5eb71242 100644 --- a/resourcehandler/k8sresources.go +++ b/resourcehandler/k8sresources.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/armosec/kubescape/cautils" + "github.com/armosec/kubescape/hostsensorutils" "github.com/armosec/opa-utils/reporthandling" "github.com/armosec/k8s-interface/k8sinterface" @@ -21,14 +22,16 @@ import ( ) type K8sResourceHandler struct { - k8s *k8sinterface.KubernetesApi - fieldSelector IFieldSelector + k8s *k8sinterface.KubernetesApi + hostSensorHandler hostsensorutils.IHostSensor + fieldSelector IFieldSelector } -func NewK8sResourceHandler(k8s *k8sinterface.KubernetesApi, fieldSelector IFieldSelector) *K8sResourceHandler { +func NewK8sResourceHandler(k8s *k8sinterface.KubernetesApi, fieldSelector IFieldSelector, hostSensorHandler hostsensorutils.IHostSensor) *K8sResourceHandler { return &K8sResourceHandler{ - k8s: k8s, - fieldSelector: fieldSelector, + k8s: k8s, + fieldSelector: fieldSelector, + hostSensorHandler: hostSensorHandler, } } @@ -49,6 +52,9 @@ func (k8sHandler *K8sResourceHandler) GetResources(frameworks []reporthandling.F if err := k8sHandler.pullResources(k8sResourcesMap, allResources, namespace, labels); err != nil { return k8sResourcesMap, allResources, err } + if err := k8sHandler.collectHostResources(allResources, k8sResourcesMap); err != nil { + return k8sResourcesMap, allResources, err + } cautils.SuccessTextDisplay("Accessed successfully to Kubernetes objects") return k8sResourcesMap, allResources, nil @@ -132,3 +138,23 @@ func ConvertMapListToMeta(resourceMap []map[string]interface{}) []workloadinterf } return workloads } + +func (k8sHandler *K8sResourceHandler) collectHostResources(allResources map[string]workloadinterface.IMetadata, resourcesMap *cautils.K8SResources) error { + hostResources, err := k8sHandler.hostSensorHandler.CollectResources() + if err != nil { + 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] + + grpResourceList, ok := (*resourcesMap)[groupResource] + if !ok { + grpResourceList = make([]string, 0) + } + (*resourcesMap)[groupResource] = append(grpResourceList, hostResources[rscIdx].GetID()) + } + } + return nil +}