From da27a27ad5b48140ddd723f2128198146ea96cbc Mon Sep 17 00:00:00 2001 From: David Wertenteil Date: Wed, 18 May 2022 00:34:15 +0300 Subject: [PATCH 1/4] adding status rest api --- core/cautils/scaninfo.go | 63 ++++---- core/core/initutils.go | 3 +- core/core/scan.go | 26 +--- core/pkg/policyhandler/handlenotification.go | 19 ++- core/pkg/policyhandler/handlepullpolicies.go | 22 +-- .../policyhandler/handlepullpoliciesutils.go | 10 +- .../resultshandling/printer/v2/jsonprinter.go | 2 +- core/pkg/resultshandling/printer/v2/utils.go | 2 +- core/pkg/resultshandling/results.go | 8 +- go.mod | 2 +- go.sum | 5 +- httphandler/README.md | 62 ++++++-- httphandler/go.mod | 3 +- httphandler/go.sum | 5 +- .../handlerequests/v1/datastructuremethods.go | 5 +- .../v1/datastructuremethods_test.go | 7 +- .../handlerequests/v1/requestshandler.go | 145 +++++++++++++----- .../handlerequests/v1/requestshandlerutils.go | 22 +-- httphandler/listener/setup.go | 2 + 19 files changed, 260 insertions(+), 153 deletions(-) diff --git a/core/cautils/scaninfo.go b/core/cautils/scaninfo.go index 474e5627..3b3cc45a 100644 --- a/core/cautils/scaninfo.go +++ b/core/cautils/scaninfo.go @@ -8,6 +8,7 @@ import ( "path/filepath" "strings" + "github.com/armosec/armoapi-go/armotypes" apisv1 "github.com/armosec/opa-utils/httpserver/apis/v1" giturl "github.com/armosec/go-git-url" @@ -77,33 +78,39 @@ const ( ControlViewType ViewTypes = "control" ) +type PolicyIdentifier struct { + Name string // policy name e.g. nsa,mitre,c-0012 + Kind apisv1.NotificationPolicyKind // policy kind e.g. Framework,Control,Rule + Designators armotypes.PortalDesignator +} + type ScanInfo struct { - Getters // TODO - remove from object - PolicyIdentifier []reporthandling.PolicyIdentifier // TODO - remove from object - UseExceptions string // Load file with exceptions configuration - ControlsInputs string // Load file with inputs for controls - UseFrom []string // Load framework from local file (instead of download). Use when running offline - UseDefault bool // Load framework from cached file (instead of download). Use when running offline - UseArtifactsFrom string // Load artifacts from local path. Use when running offline - VerboseMode bool // Display all of the input resources and not only failed resources - View string // Display all of the input resources and not only failed resources - Format string // Format results (table, json, junit ...) - Output string // Store results in an output file, Output file name - FormatVersion string // Output object can be differnet between versions, this is for testing and backward compatibility - ExcludedNamespaces string // used for host scanner namespace - IncludeNamespaces string // DEPRECATED? - InputPatterns []string // Yaml files input patterns - Silent bool // Silent mode - Do not print progress logs - FailThreshold float32 // Failure score threshold - Submit bool // Submit results to Armo BE - ScanID string // Report id of the current scan - HostSensorEnabled BoolPtrFlag // Deploy ARMO K8s host scanner to collect data from certain controls - HostSensorYamlPath string // Path to hostsensor file - Local bool // Do not submit results - Account string // account ID - KubeContext string // context name - FrameworkScan bool // false if scanning control - ScanAll bool // true if scan all frameworks + Getters // TODO - remove from object + PolicyIdentifier []PolicyIdentifier // TODO - remove from object + UseExceptions string // Load file with exceptions configuration + ControlsInputs string // Load file with inputs for controls + UseFrom []string // Load framework from local file (instead of download). Use when running offline + UseDefault bool // Load framework from cached file (instead of download). Use when running offline + UseArtifactsFrom string // Load artifacts from local path. Use when running offline + VerboseMode bool // Display all of the input resources and not only failed resources + View string // Display all of the input resources and not only failed resources + Format string // Format results (table, json, junit ...) + Output string // Store results in an output file, Output file name + FormatVersion string // Output object can be differnet between versions, this is for testing and backward compatibility + ExcludedNamespaces string // used for host scanner namespace + IncludeNamespaces string // + InputPatterns []string // Yaml files input patterns + Silent bool // Silent mode - Do not print progress logs + FailThreshold float32 // Failure score threshold + Submit bool // Submit results to Armo BE + ScanID string // Report id of the current scan + HostSensorEnabled BoolPtrFlag // Deploy ARMO K8s host scanner to collect data from certain controls + HostSensorYamlPath string // Path to hostsensor file + Local bool // Do not submit results + Account string // account ID + KubeContext string // context name + FrameworkScan bool // false if scanning control + ScanAll bool // true if scan all frameworks } type Getters struct { @@ -193,8 +200,8 @@ func (scanInfo *ScanInfo) GetScanningEnvironment() string { func (scanInfo *ScanInfo) SetPolicyIdentifiers(policies []string, kind apisv1.NotificationPolicyKind) { for _, policy := range policies { if !scanInfo.contains(policy) { - newPolicy := reporthandling.PolicyIdentifier{} - newPolicy.Kind = reporthandling.NotificationPolicyKind(kind) // reporthandling.KindFramework + newPolicy := PolicyIdentifier{} + newPolicy.Kind = kind newPolicy.Name = policy scanInfo.PolicyIdentifier = append(scanInfo.PolicyIdentifier, newPolicy) } diff --git a/core/core/initutils.go b/core/core/initutils.go index 7d8ffcec..41b6f0e1 100644 --- a/core/core/initutils.go +++ b/core/core/initutils.go @@ -13,7 +13,6 @@ import ( "github.com/armosec/kubescape/v2/core/pkg/resultshandling/reporter" reporterv2 "github.com/armosec/kubescape/v2/core/pkg/resultshandling/reporter/v2" - "github.com/armosec/opa-utils/reporthandling" "github.com/armosec/rbac-utils/rbacscanner" ) @@ -105,7 +104,7 @@ func getFieldSelector(scanInfo *cautils.ScanInfo) resourcehandler.IFieldSelector return &resourcehandler.EmptySelector{} } -func policyIdentifierNames(pi []reporthandling.PolicyIdentifier) string { +func policyIdentifierNames(pi []cautils.PolicyIdentifier) string { policiesNames := "" for i := range pi { policiesNames += pi[i].Name diff --git a/core/core/scan.go b/core/core/scan.go index 1f0208dc..5a0dcd57 100644 --- a/core/core/scan.go +++ b/core/core/scan.go @@ -5,7 +5,6 @@ import ( apisv1 "github.com/armosec/opa-utils/httpserver/apis/v1" - "github.com/armosec/armoapi-go/armotypes" "github.com/armosec/k8s-interface/k8sinterface" "github.com/armosec/kubescape/v2/core/cautils" @@ -20,7 +19,6 @@ import ( "github.com/armosec/kubescape/v2/core/pkg/resultshandling/printer" "github.com/armosec/kubescape/v2/core/pkg/resultshandling/reporter" - "github.com/armosec/opa-utils/reporthandling" "github.com/armosec/opa-utils/resources" ) @@ -146,7 +144,7 @@ func (ks *Kubescape) Scan(scanInfo *cautils.ScanInfo) (*resultshandling.ResultsH // ===================== policies & resources ===================== policyHandler := policyhandler.NewPolicyHandler(interfaces.resourceHandler) - scanData, err := collectResources(policyHandler, scanInfo) + scanData, err := policyHandler.CollectResources(scanInfo.PolicyIdentifier, scanInfo) if err != nil { return resultsHandling, err } @@ -169,28 +167,6 @@ func (ks *Kubescape) Scan(scanInfo *cautils.ScanInfo) (*resultshandling.ResultsH return resultsHandling, nil } -// TODO - remove function -func collectResources(policyHandler *policyhandler.PolicyHandler, scanInfo *cautils.ScanInfo) (*cautils.OPASessionObj, error) { - policyNotification := &reporthandling.PolicyNotification{ - Rules: scanInfo.PolicyIdentifier, - KubescapeNotification: reporthandling.KubescapeNotification{ - Designators: armotypes.PortalDesignator{}, - NotificationType: reporthandling.TypeExecPostureScan, - }, - } - switch policyNotification.KubescapeNotification.NotificationType { - case reporthandling.TypeExecPostureScan: - collectedResources, err := policyHandler.CollectResources(policyNotification, scanInfo) - if err != nil { - return nil, err - } - return collectedResources, nil - - default: - return nil, fmt.Errorf("notification type '%s' Unknown", policyNotification.KubescapeNotification.NotificationType) - } -} - // func askUserForHostSensor() bool { // return false diff --git a/core/pkg/policyhandler/handlenotification.go b/core/pkg/policyhandler/handlenotification.go index 371d0a42..2955d838 100644 --- a/core/pkg/policyhandler/handlenotification.go +++ b/core/pkg/policyhandler/handlenotification.go @@ -3,9 +3,9 @@ package policyhandler import ( "fmt" + "github.com/armosec/armoapi-go/armotypes" "github.com/armosec/kubescape/v2/core/cautils" "github.com/armosec/kubescape/v2/core/pkg/resourcehandler" - "github.com/armosec/opa-utils/reporthandling" ) // PolicyHandler - @@ -22,7 +22,7 @@ func NewPolicyHandler(resourceHandler resourcehandler.IResourceHandler) *PolicyH } } -func (policyHandler *PolicyHandler) CollectResources(notification *reporthandling.PolicyNotification, scanInfo *cautils.ScanInfo) (*cautils.OPASessionObj, error) { +func (policyHandler *PolicyHandler) CollectResources(policyIdentifier []cautils.PolicyIdentifier, scanInfo *cautils.ScanInfo) (*cautils.OPASessionObj, error) { opaSessionObj := cautils.NewOPASessionObj(nil, nil, scanInfo) // validate notification @@ -30,11 +30,11 @@ func (policyHandler *PolicyHandler) CollectResources(notification *reporthandlin policyHandler.getters = &scanInfo.Getters // get policies - if err := policyHandler.getPolicies(notification, opaSessionObj); err != nil { + if err := policyHandler.getPolicies(policyIdentifier, opaSessionObj); err != nil { return opaSessionObj, err } - err := policyHandler.getResources(notification, opaSessionObj, scanInfo) + err := policyHandler.getResources(policyIdentifier, opaSessionObj, scanInfo) if err != nil { return opaSessionObj, err } @@ -46,10 +46,10 @@ func (policyHandler *PolicyHandler) CollectResources(notification *reporthandlin return opaSessionObj, nil } -func (policyHandler *PolicyHandler) getResources(notification *reporthandling.PolicyNotification, opaSessionObj *cautils.OPASessionObj, scanInfo *cautils.ScanInfo) error { +func (policyHandler *PolicyHandler) getResources(policyIdentifier []cautils.PolicyIdentifier, opaSessionObj *cautils.OPASessionObj, scanInfo *cautils.ScanInfo) error { opaSessionObj.Report.ClusterAPIServerInfo = policyHandler.resourceHandler.GetClusterAPIServerInfo() - resourcesMap, allResources, armoResources, err := policyHandler.resourceHandler.GetResources(opaSessionObj, ¬ification.Designators) + resourcesMap, allResources, armoResources, err := policyHandler.resourceHandler.GetResources(opaSessionObj, &policyIdentifier[0].Designators) if err != nil { return err } @@ -60,3 +60,10 @@ func (policyHandler *PolicyHandler) getResources(notification *reporthandling.Po return nil } + +func getDesignator(policyIdentifier []cautils.PolicyIdentifier) *armotypes.PortalDesignator { + if len(policyIdentifier) > 0 { + return &policyIdentifier[0].Designators + } + return &armotypes.PortalDesignator{} +} diff --git a/core/pkg/policyhandler/handlepullpolicies.go b/core/pkg/policyhandler/handlepullpolicies.go index 0be54834..458b6074 100644 --- a/core/pkg/policyhandler/handlepullpolicies.go +++ b/core/pkg/policyhandler/handlepullpolicies.go @@ -4,6 +4,8 @@ import ( "fmt" "strings" + apisv1 "github.com/armosec/opa-utils/httpserver/apis/v1" + "github.com/armosec/kubescape/v2/core/cautils" "github.com/armosec/kubescape/v2/core/cautils/getter" "github.com/armosec/kubescape/v2/core/cautils/logger" @@ -11,18 +13,18 @@ import ( "github.com/armosec/opa-utils/reporthandling" ) -func (policyHandler *PolicyHandler) getPolicies(notification *reporthandling.PolicyNotification, policiesAndResources *cautils.OPASessionObj) error { +func (policyHandler *PolicyHandler) getPolicies(policyIdentifier []cautils.PolicyIdentifier, policiesAndResources *cautils.OPASessionObj) error { logger.L().Info("Downloading/Loading policy definitions") cautils.StartSpinner() defer cautils.StopSpinner() - policies, err := policyHandler.getScanPolicies(notification) + policies, err := policyHandler.getScanPolicies(policyIdentifier) if err != nil { return err } if len(policies) == 0 { - return fmt.Errorf("failed to download policies: '%s'. Make sure the policy exist and you spelled it correctly. For more information, please feel free to contact ARMO team", strings.Join(policyIdentifierToSlice(notification.Rules), ", ")) + return fmt.Errorf("failed to download policies: '%s'. Make sure the policy exist and you spelled it correctly. For more information, please feel free to contact ARMO team", strings.Join(policyIdentifierToSlice(policyIdentifier), ", ")) } policiesAndResources.Policies = policies @@ -44,12 +46,12 @@ func (policyHandler *PolicyHandler) getPolicies(notification *reporthandling.Pol return nil } -func (policyHandler *PolicyHandler) getScanPolicies(notification *reporthandling.PolicyNotification) ([]reporthandling.Framework, error) { +func (policyHandler *PolicyHandler) getScanPolicies(policyIdentifier []cautils.PolicyIdentifier) ([]reporthandling.Framework, error) { frameworks := []reporthandling.Framework{} - switch getScanKind(notification) { - case reporthandling.KindFramework: // Download frameworks - for _, rule := range notification.Rules { + switch getScanKind(policyIdentifier) { + case apisv1.KindFramework: // Download frameworks + for _, rule := range policyIdentifier { receivedFramework, err := policyHandler.getters.PolicyGetter.GetFramework(rule.Name) if err != nil { return frameworks, policyDownloadError(err) @@ -63,11 +65,11 @@ func (policyHandler *PolicyHandler) getScanPolicies(notification *reporthandling } } } - case reporthandling.KindControl: // Download controls + case apisv1.KindControl: // Download controls f := reporthandling.Framework{} var receivedControl *reporthandling.Control var err error - for _, rule := range notification.Rules { + for _, rule := range policyIdentifier { receivedControl, err = policyHandler.getters.PolicyGetter.GetControl(rule.Name) if err != nil { return frameworks, policyDownloadError(err) @@ -89,7 +91,7 @@ func (policyHandler *PolicyHandler) getScanPolicies(notification *reporthandling return frameworks, nil } -func policyIdentifierToSlice(rules []reporthandling.PolicyIdentifier) []string { +func policyIdentifierToSlice(rules []cautils.PolicyIdentifier) []string { s := []string{} for i := range rules { s = append(s, fmt.Sprintf("%s: %s", rules[i].Kind, rules[i].Name)) diff --git a/core/pkg/policyhandler/handlepullpoliciesutils.go b/core/pkg/policyhandler/handlepullpoliciesutils.go index c4a4b321..ba15be3f 100644 --- a/core/pkg/policyhandler/handlepullpoliciesutils.go +++ b/core/pkg/policyhandler/handlepullpoliciesutils.go @@ -4,12 +4,14 @@ import ( "fmt" "strings" - "github.com/armosec/opa-utils/reporthandling" + apisv1 "github.com/armosec/opa-utils/httpserver/apis/v1" + + "github.com/armosec/kubescape/v2/core/cautils" ) -func getScanKind(notification *reporthandling.PolicyNotification) reporthandling.NotificationPolicyKind { - if len(notification.Rules) > 0 { - return notification.Rules[0].Kind +func getScanKind(policyIdentifier []cautils.PolicyIdentifier) apisv1.NotificationPolicyKind { + if len(policyIdentifier) > 0 { + return policyIdentifier[0].Kind } return "unknown" } diff --git a/core/pkg/resultshandling/printer/v2/jsonprinter.go b/core/pkg/resultshandling/printer/v2/jsonprinter.go index 6bbaa0d8..77b9836b 100644 --- a/core/pkg/resultshandling/printer/v2/jsonprinter.go +++ b/core/pkg/resultshandling/printer/v2/jsonprinter.go @@ -28,7 +28,7 @@ func (jsonPrinter *JsonPrinter) Score(score float32) { } func (jsonPrinter *JsonPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) { - r, err := json.Marshal(DataToJson(opaSessionObj)) + r, err := json.Marshal(FinalizeResults(opaSessionObj)) if err != nil { logger.L().Fatal("failed to Marshal posture report object") } diff --git a/core/pkg/resultshandling/printer/v2/utils.go b/core/pkg/resultshandling/printer/v2/utils.go index bf42c5c8..d3a20af8 100644 --- a/core/pkg/resultshandling/printer/v2/utils.go +++ b/core/pkg/resultshandling/printer/v2/utils.go @@ -12,7 +12,7 @@ import ( ) // finalizeV2Report finalize the results objects by copying data from map to lists -func DataToJson(data *cautils.OPASessionObj) *reporthandlingv2.PostureReport { +func FinalizeResults(data *cautils.OPASessionObj) *reporthandlingv2.PostureReport { report := reporthandlingv2.PostureReport{ SummaryDetails: data.Report.SummaryDetails, ClusterAPIServerInfo: data.Report.ClusterAPIServerInfo, diff --git a/core/pkg/resultshandling/results.go b/core/pkg/resultshandling/results.go index 8ea0fac0..9e4d42e5 100644 --- a/core/pkg/resultshandling/results.go +++ b/core/pkg/resultshandling/results.go @@ -10,6 +10,7 @@ import ( printerv1 "github.com/armosec/kubescape/v2/core/pkg/resultshandling/printer/v1" printerv2 "github.com/armosec/kubescape/v2/core/pkg/resultshandling/printer/v2" "github.com/armosec/kubescape/v2/core/pkg/resultshandling/reporter" + reporthandlingv2 "github.com/armosec/opa-utils/reporthandling/v2" ) type ResultsHandler struct { @@ -52,7 +53,12 @@ func (resultsHandler *ResultsHandler) GetReporter() reporter.IReport { // ToJson return results in json format func (resultsHandler *ResultsHandler) ToJson() ([]byte, error) { - return json.Marshal(printerv2.DataToJson(resultsHandler.scanData)) + return json.Marshal(printerv2.FinalizeResults(resultsHandler.scanData)) +} + +// GetResults return results +func (resultsHandler *ResultsHandler) GetResults() *reporthandlingv2.PostureReport { + return printerv2.FinalizeResults(resultsHandler.scanData) } // HandleResults handle the scan results according to the pre defind interfaces diff --git a/go.mod b/go.mod index 28982d40..e1790c5c 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/armosec/armoapi-go v0.0.73 github.com/armosec/go-git-url v0.0.4 github.com/armosec/k8s-interface v0.0.70 - github.com/armosec/opa-utils v0.0.137 + github.com/armosec/opa-utils v0.0.139 github.com/armosec/rbac-utils v0.0.14 github.com/armosec/utils-go v0.0.5 github.com/armosec/utils-k8s-go v0.0.6 diff --git a/go.sum b/go.sum index f1d817cd..9b4f788b 100644 --- a/go.sum +++ b/go.sum @@ -113,7 +113,6 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armosec/armoapi-go v0.0.2/go.mod h1:vIK17yoKbJRQyZXWWLe3AqfqCRITxW8qmSkApyq5xFs= github.com/armosec/armoapi-go v0.0.23/go.mod h1:iaVVGyc23QGGzAdv4n+szGQg3Rbpixn9yQTU3qWRpaw= -github.com/armosec/armoapi-go v0.0.67/go.mod h1:/9SQAgtLbYkfFneRRm/zkIn3zz+4Y2xv6N3vtFcyF8s= github.com/armosec/armoapi-go v0.0.73 h1:LMf+eCkkf+W9NVvOzHKFgVUEpBMvh27M7//UQP3aiO8= github.com/armosec/armoapi-go v0.0.73/go.mod h1:/9SQAgtLbYkfFneRRm/zkIn3zz+4Y2xv6N3vtFcyF8s= github.com/armosec/go-git-url v0.0.4 h1:emG9Yfl53rHpuX41fXLD92ehzhRoNSSnGT6Pr7ogWMY= @@ -123,8 +122,8 @@ github.com/armosec/k8s-interface v0.0.37/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2 github.com/armosec/k8s-interface v0.0.70 h1:NU3UIaNl7H3hsRecwggiaQbZXTwXtOKg3GOBjq6/XJw= github.com/armosec/k8s-interface v0.0.70/go.mod h1:8NX4xWXh8mwW7QyZdZea1czNdM2azCK9BbUNmiZYXW0= github.com/armosec/opa-utils v0.0.64/go.mod h1:6tQP8UDq2EvEfSqh8vrUdr/9QVSCG4sJfju1SXQOn4c= -github.com/armosec/opa-utils v0.0.137 h1:KAkxWYnnTef8ofixJ198Zs4Xs7MOh32+yMUyFY7I8DA= -github.com/armosec/opa-utils v0.0.137/go.mod h1:mCFQzz4E227f7V2jQVQ9XCivkNNK3UWCTaZ0HE5rBWk= +github.com/armosec/opa-utils v0.0.139 h1:JPxgPXVJUUIujtIoZk6TejE8PkZhX2pYnpj+E8PhcfA= +github.com/armosec/opa-utils v0.0.139/go.mod h1:VnRVJgDDPFAprGDcibTtKHf9wgkoyTU8wmX2BxEIwok= github.com/armosec/rbac-utils v0.0.1/go.mod h1:pQ8CBiij8kSKV7aeZm9FMvtZN28VgA7LZcYyTWimq40= github.com/armosec/rbac-utils v0.0.14 h1:CKYKcgqJEXWF2Hen/B1pVGtS3nDAG1wp9dDv6oNtq90= github.com/armosec/rbac-utils v0.0.14/go.mod h1:Ex/IdGWhGv9HZq6Hs8N/ApzCKSIvpNe/ETqDfnuyah0= diff --git a/httphandler/README.md b/httphandler/README.md index 8fcdfe06..86cc0767 100644 --- a/httphandler/README.md +++ b/httphandler/README.md @@ -4,50 +4,85 @@ Running `kubescape` will start up a webserver on port `8080` which will serve the following paths: +### Trigger scan + * POST `/v1/scan` - Trigger a kubescape scan. The server will return an ID and will execute the scanning asynchronously * * `wait`: scan synchronously (return results and not ID). Use only in small clusters are with an increased timeout * * `keep`: Do not delete results from local storage after returning + +### Get results * GET `/v1/results` - Request kubescape scan results * * query `id=` -> ID returned when triggering the scan action. If empty will return latest results * * query `keep` -> Do not delete results from local storage after returning + +### Check scanning progress status +Check the scanning status - is the scanning in progress or done. This is meant for a waiting mechanize since the API does not return the entire results object when the scanning is done + +* GET `/v1/status` - Request kubescape scan status +* * query `id=` -> Check status of a specific scan. If empty will check if any scan is in progress + +### Delete cached results * DELETE `/v1/results` - Delete kubescape scan results from storage. If empty will delete latest results * * query `id=`: Delete ID of specific results * * query `all`: Delete all cached results + +### Prometheus support API + * GET/POST `/v1/metrics` - will trigger cluster scan. will respond with prometheus metrics once they have been scanned. This will respond 503 if the scan failed. * `/livez` - will respond 200 is server is alive * `/readyz` - will respond 200 if server can receive requests ## Trigger Kubescape scan -POST /v1/results +POST /v1/scan body: ``` { - "format": , // results format [default: json] (same as 'kubescape scan --format') - "excludedNamespaces": [], // list of namespaces to exclude (same as 'kubescape scan --excluded-namespaces') - "includeNamespaces": [], // list of namespaces to include (same as 'kubescape scan --include-namespaces') - "useCachedArtifacts"`: , // use the cached artifacts instead of downloading (offline support) - "submit": , // submit results to Kubescape cloud (same as 'kubescape scan --submit') - "hostScanner": , // deploy kubescape K8s host-scanner DaemonSet in the scanned cluster (same as 'kubescape scan --enable-host-scan') - "keepLocal": , // do not submit results to Kubescape cloud (same as 'kubescape scan --keep-local') - "account": , // account ID (same as 'kubescape scan --account') - "targetType": , // framework/control - "targetNames": [] // names. e.g. when targetType==framework, targetNames=["nsa", "mitre"] + "format": , // results format [default: json] (same as 'kubescape scan --format') + "excludedNamespaces": [], // list of namespaces to exclude (same as 'kubescape scan --excluded-namespaces') + "includeNamespaces": [], // list of namespaces to include (same as 'kubescape scan --include-namespaces') + "useCachedArtifacts"`: , // use the cached artifacts instead of downloading (offline support) + "submit": , // submit results to Kubescape cloud (same as 'kubescape scan --submit') + "hostScanner": , // deploy kubescape K8s host-scanner DaemonSet in the scanned cluster (same as 'kubescape scan --enable-host-scan') + "keepLocal": , // do not submit results to Kubescape cloud (same as 'kubescape scan --keep-local') + "account": , // account ID (same as 'kubescape scan --account') + "targetType": , // framework/control + "targetNames": [] // names. e.g. when targetType==framework, targetNames=["nsa", "mitre"] } ``` +Response body: +``` +{ + "id": , // scan ID + "type": , // response object type + "response": // response payload as list of bytes +} +``` + +Response body types: +* "v1results" - v1 results object +* "id" - id string +* "error" - error object + +## API Examples #### Default scan 1. Trigger kubescape scan ```bash - curl --header "Content-Type: application/json" --request POST --data '{"hostScanner":true}' http://127.0.0.1:8080/v1/scan -o scan_id + curl --header "Content-Type: application/json" --request POST --data '{"hostScanner":true, "submit": true}' http://127.0.0.1:8080/v1/scan ``` 2. Get kubescape scan results ```bash - curl --request GET http://127.0.0.1:8080/v1/results?id=$(cat scan_id) + curl --request GET http://127.0.0.1:8080/v1/results -o response.json ``` +#### Trigger scan and wait for scan to end + +```bash +curl --header "Content-Type: application/json" --request POST --data '{"hostScanner":true, "submit": true}' http://127.0.0.1:8080/v1/scan?wait -o scan_results.json +``` #### Scan single namespace with a specific framework ```bash curl --header "Content-Type: application/json" \ @@ -55,6 +90,7 @@ curl --header "Content-Type: application/json" \ --data '{"hostScanner":true, "submit":true, "includeNamespaces": ["ks-scanner"], "targetType": "framework", "targetNames": ["nsa"] }' \ http://127.0.0.1:8080/v1/scan ``` + ## Examples * [Prometheus](examples/prometheus/README.md) diff --git a/httphandler/go.mod b/httphandler/go.mod index 3ca38ada..305147d2 100644 --- a/httphandler/go.mod +++ b/httphandler/go.mod @@ -6,10 +6,11 @@ replace github.com/armosec/kubescape/v2 => ../ require ( github.com/armosec/kubescape/v2 v2.0.0-00010101000000-000000000000 - github.com/armosec/opa-utils v0.0.137 + github.com/armosec/opa-utils v0.0.139 github.com/armosec/utils-go v0.0.5 github.com/google/uuid v1.3.0 github.com/gorilla/mux v1.8.0 + github.com/gorilla/schema v1.2.0 github.com/stretchr/testify v1.7.1 ) diff --git a/httphandler/go.sum b/httphandler/go.sum index 2d88666a..91dd0677 100644 --- a/httphandler/go.sum +++ b/httphandler/go.sum @@ -123,8 +123,9 @@ github.com/armosec/k8s-interface v0.0.37/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2 github.com/armosec/k8s-interface v0.0.70 h1:NU3UIaNl7H3hsRecwggiaQbZXTwXtOKg3GOBjq6/XJw= github.com/armosec/k8s-interface v0.0.70/go.mod h1:8NX4xWXh8mwW7QyZdZea1czNdM2azCK9BbUNmiZYXW0= github.com/armosec/opa-utils v0.0.64/go.mod h1:6tQP8UDq2EvEfSqh8vrUdr/9QVSCG4sJfju1SXQOn4c= -github.com/armosec/opa-utils v0.0.137 h1:KAkxWYnnTef8ofixJ198Zs4Xs7MOh32+yMUyFY7I8DA= github.com/armosec/opa-utils v0.0.137/go.mod h1:mCFQzz4E227f7V2jQVQ9XCivkNNK3UWCTaZ0HE5rBWk= +github.com/armosec/opa-utils v0.0.139 h1:JPxgPXVJUUIujtIoZk6TejE8PkZhX2pYnpj+E8PhcfA= +github.com/armosec/opa-utils v0.0.139/go.mod h1:VnRVJgDDPFAprGDcibTtKHf9wgkoyTU8wmX2BxEIwok= github.com/armosec/rbac-utils v0.0.1/go.mod h1:pQ8CBiij8kSKV7aeZm9FMvtZN28VgA7LZcYyTWimq40= github.com/armosec/rbac-utils v0.0.14 h1:CKYKcgqJEXWF2Hen/B1pVGtS3nDAG1wp9dDv6oNtq90= github.com/armosec/rbac-utils v0.0.14/go.mod h1:Ex/IdGWhGv9HZq6Hs8N/ApzCKSIvpNe/ETqDfnuyah0= @@ -462,6 +463,8 @@ github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97Dwqy github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc= +github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= diff --git a/httphandler/handlerequests/v1/datastructuremethods.go b/httphandler/handlerequests/v1/datastructuremethods.go index 83ea6e68..a6c79f18 100644 --- a/httphandler/handlerequests/v1/datastructuremethods.go +++ b/httphandler/handlerequests/v1/datastructuremethods.go @@ -8,7 +8,6 @@ import ( "github.com/armosec/kubescape/v2/core/cautils" "github.com/armosec/kubescape/v2/core/cautils/getter" - "github.com/armosec/opa-utils/reporthandling" ) func ToScanInfo(scanRequest *utilsmetav1.PostScanRequest) *cautils.ScanInfo { @@ -61,7 +60,7 @@ func ToScanInfo(scanRequest *utilsmetav1.PostScanRequest) *cautils.ScanInfo { func setTargetInScanInfo(scanRequest *utilsmetav1.PostScanRequest, scanInfo *cautils.ScanInfo) { if scanRequest.TargetType != "" && len(scanRequest.TargetNames) > 0 { - if strings.EqualFold(string(scanRequest.TargetType), string(reporthandling.KindFramework)) { + if strings.EqualFold(string(scanRequest.TargetType), string(apisv1.KindFramework)) { scanRequest.TargetType = apisv1.KindFramework scanInfo.FrameworkScan = true scanInfo.ScanAll = false @@ -69,7 +68,7 @@ func setTargetInScanInfo(scanRequest *utilsmetav1.PostScanRequest, scanInfo *cau scanRequest.TargetNames = []string{} scanInfo.ScanAll = true } - } else if strings.EqualFold(string(scanRequest.TargetType), string(reporthandling.KindControl)) { + } else if strings.EqualFold(string(scanRequest.TargetType), string(apisv1.KindControl)) { scanRequest.TargetType = apisv1.KindControl scanInfo.ScanAll = false } else { diff --git a/httphandler/handlerequests/v1/datastructuremethods_test.go b/httphandler/handlerequests/v1/datastructuremethods_test.go index eed4a1d7..e3ef997b 100644 --- a/httphandler/handlerequests/v1/datastructuremethods_test.go +++ b/httphandler/handlerequests/v1/datastructuremethods_test.go @@ -6,7 +6,6 @@ import ( "github.com/armosec/kubescape/v2/core/cautils" apisv1 "github.com/armosec/opa-utils/httpserver/apis/v1" utilsmetav1 "github.com/armosec/opa-utils/httpserver/meta/v1" - "github.com/armosec/opa-utils/reporthandling" "github.com/stretchr/testify/assert" ) @@ -34,9 +33,9 @@ func TestToScanInfo(t *testing.T) { assert.False(t, s.ScanAll) assert.True(t, s.FrameworkScan) assert.Equal(t, "nsa", s.PolicyIdentifier[0].Name) - assert.Equal(t, reporthandling.KindFramework, s.PolicyIdentifier[0].Kind) + assert.Equal(t, apisv1.KindFramework, s.PolicyIdentifier[0].Kind) assert.Equal(t, "mitre", s.PolicyIdentifier[1].Name) - assert.Equal(t, reporthandling.KindFramework, s.PolicyIdentifier[1].Kind) + assert.Equal(t, apisv1.KindFramework, s.PolicyIdentifier[1].Kind) } { req := &utilsmetav1.PostScanRequest{ @@ -51,7 +50,7 @@ func TestToScanInfo(t *testing.T) { assert.Equal(t, "", s.ExcludedNamespaces) assert.Equal(t, 1, len(s.PolicyIdentifier)) assert.Equal(t, "c-0001", s.PolicyIdentifier[0].Name) - assert.Equal(t, reporthandling.KindControl, s.PolicyIdentifier[0].Kind) + assert.Equal(t, apisv1.KindControl, s.PolicyIdentifier[0].Kind) } { req := &utilsmetav1.PostScanRequest{} diff --git a/httphandler/handlerequests/v1/requestshandler.go b/httphandler/handlerequests/v1/requestshandler.go index 18737d40..a4cdb928 100644 --- a/httphandler/handlerequests/v1/requestshandler.go +++ b/httphandler/handlerequests/v1/requestshandler.go @@ -9,6 +9,7 @@ import ( utilsapisv1 "github.com/armosec/opa-utils/httpserver/apis/v1" utilsmetav1 "github.com/armosec/opa-utils/httpserver/meta/v1" + "github.com/gorilla/schema" "github.com/armosec/kubescape/v2/core/cautils/logger" "github.com/armosec/kubescape/v2/core/cautils/logger/helpers" @@ -18,6 +19,21 @@ import ( var OutputDir = "./results" var FailedOutputDir = "./failed" +type ScanQueryParams struct { + ReturnResults bool `schema:"wait"` // wait for scanning to complete (synchronized request) + KeepResults bool `schema:"keep"` // do not delete results after returning (relevant only for synchronized requests) +} + +type ResultsQueryParams struct { + ScanID string `schema:"id"` + KeepResults bool `schema:"keep"` // do not delete results after returning (default will delete results) + AllResults bool `schema:"all"` // delete all results +} + +type StatusQueryParams struct { + ScanID string `schema:"id"` +} + type HTTPHandler struct { state *serverState } @@ -28,28 +44,68 @@ func NewHTTPHandler() *HTTPHandler { } } -func (handler *HTTPHandler) Scan(w http.ResponseWriter, r *http.Request) { +// ============================================== STATUS ======================================================== +// Status API +func (handler *HTTPHandler) Status(w http.ResponseWriter, r *http.Request) { + defer handler.recover(w) + + if r.Method != http.MethodGet { + w.WriteHeader(http.StatusMethodNotAllowed) + return + } + response := utilsmetav1.Response{} w.Header().Set("Content-Type", "application/json") + statusQueryParams := &StatusQueryParams{} + if err := schema.NewDecoder().Decode(statusQueryParams, r.URL.Query()); err != nil { + handler.writeError(w, fmt.Errorf("failed to parse query params, reason: %s", err.Error())) + return + } + + if !handler.state.isBusy() { + response.Type = utilsapisv1.NotBusyScanResponseType + w.Write(responseToBytes(&response)) + return + } + + currentScanID := handler.state.getID() + if statusQueryParams.ScanID != "" && currentScanID != statusQueryParams.ScanID { + response.Type = utilsapisv1.NotBusyScanResponseType + w.Write(responseToBytes(&response)) + return + } + + response.Response = currentScanID + response.ID = currentScanID + response.Type = utilsapisv1.BusyScanResponseType + w.Write(responseToBytes(&response)) +} + +// ============================================== SCAN ======================================================== +// Scan API - TODO: break down to functions +func (handler *HTTPHandler) Scan(w http.ResponseWriter, r *http.Request) { + defer handler.recover(w) defer r.Body.Close() - switch r.Method { - case http.MethodGet: // return request template - json.NewEncoder(w).Encode(utilsmetav1.PostScanRequest{}) - w.WriteHeader(http.StatusOK) - return - case http.MethodPost: - default: + if r.Method != http.MethodPost { w.WriteHeader(http.StatusMethodNotAllowed) return } + response := utilsmetav1.Response{} + w.Header().Set("Content-Type", "application/json") + scanQueryParams := &ScanQueryParams{} + if err := schema.NewDecoder().Decode(scanQueryParams, r.URL.Query()); err != nil { + handler.writeError(w, fmt.Errorf("failed to parse query params, reason: %s", err.Error())) + return + } if handler.state.isBusy() { + // TODO - Add to queue w.WriteHeader(http.StatusOK) - response.Response = []byte(handler.state.getID()) + response.Response = handler.state.getID() response.ID = handler.state.getID() response.Type = utilsapisv1.IDScanResponseType w.Write(responseToBytes(&response)) @@ -75,11 +131,8 @@ func (handler *HTTPHandler) Scan(w http.ResponseWriter, r *http.Request) { return } - returnResults := r.URL.Query().Has("wait") - keepResults := r.URL.Query().Has("keep") - var wg sync.WaitGroup - if returnResults { + if scanQueryParams.ReturnResults { wg.Add(1) } else { wg.Add(0) @@ -93,20 +146,20 @@ func (handler *HTTPHandler) Scan(w http.ResponseWriter, r *http.Request) { results, err := scan(&scanRequest, scanID) if err != nil { logger.L().Error("scanning failed", helpers.String("ID", scanID), helpers.Error(err)) - if returnResults { + if scanQueryParams.ReturnResults { response.Type = utilsapisv1.ErrorScanResponseType - response.Response = []byte(err.Error()) + response.Response = err.Error() statusCode = http.StatusInternalServerError } } else { logger.L().Success("done scanning", helpers.String("ID", scanID)) - if returnResults { + if scanQueryParams.ReturnResults { response.Type = utilsapisv1.ResultsV1ScanResponseType response.Response = results wg.Done() } } - if !keepResults { + if scanQueryParams.ReturnResults && !scanQueryParams.KeepResults { logger.L().Debug("deleting results", helpers.String("ID", scanID)) removeResultsFile(scanID) } @@ -118,6 +171,10 @@ func (handler *HTTPHandler) Scan(w http.ResponseWriter, r *http.Request) { w.WriteHeader(statusCode) w.Write(responseToBytes(&response)) } + +// ============================================== RESULTS ======================================================== + +// Results API - TODO: break down to functions func (handler *HTTPHandler) Results(w http.ResponseWriter, r *http.Request) { response := utilsmetav1.Response{} w.Header().Set("Content-Type", "application/json") @@ -126,25 +183,31 @@ func (handler *HTTPHandler) Results(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() - var scanID string - if scanID = r.URL.Query().Get("id"); scanID == "" { - scanID = handler.state.getLatestID() + resultsQueryParams := &ResultsQueryParams{} + if err := schema.NewDecoder().Decode(resultsQueryParams, r.URL.Query()); err != nil { + handler.writeError(w, fmt.Errorf("failed to parse query params, reason: %s", err.Error())) + return } - if scanID == "" { // if no scan found + + if resultsQueryParams.ScanID == "" { + resultsQueryParams.ScanID = handler.state.getLatestID() + } + + if resultsQueryParams.ScanID == "" { // if no scan found logger.L().Info("empty scan ID") w.WriteHeader(http.StatusBadRequest) // Should we return ok? - response.Response = []byte("latest scan not found. trigger again") + response.Response = "latest scan not found. trigger again" response.Type = utilsapisv1.ErrorScanResponseType w.Write(responseToBytes(&response)) return } - response.ID = scanID + response.ID = resultsQueryParams.ScanID if handler.state.isBusy() { // if requested ID is still scanning - if scanID == handler.state.getID() { - logger.L().Info("scan in process", helpers.String("ID", scanID)) + if resultsQueryParams.ScanID == handler.state.getID() { + logger.L().Info("scan in process", helpers.String("ID", resultsQueryParams.ScanID)) w.WriteHeader(http.StatusOK) - response.Response = []byte("scanning in progress") + response.Response = "scanning in progress" w.Write(responseToBytes(&response)) return } @@ -152,29 +215,31 @@ func (handler *HTTPHandler) Results(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: - logger.L().Info("requesting results", helpers.String("ID", scanID)) + logger.L().Info("requesting results", helpers.String("ID", resultsQueryParams.ScanID)) - if !r.URL.Query().Has("keep") { - logger.L().Info("deleting results", helpers.String("ID", scanID)) - defer removeResultsFile(scanID) - } - if res, err := readResultsFile(scanID); err != nil { - logger.L().Info("scan result not found", helpers.String("ID", scanID)) + if res, err := readResultsFile(resultsQueryParams.ScanID); err != nil { + logger.L().Info("scan result not found", helpers.String("ID", resultsQueryParams.ScanID)) w.WriteHeader(http.StatusNoContent) - response.Response = []byte(err.Error()) + response.Response = err.Error() } else { - logger.L().Info("scan result found", helpers.String("ID", scanID)) + logger.L().Info("scan result found", helpers.String("ID", resultsQueryParams.ScanID)) w.WriteHeader(http.StatusOK) response.Response = res + + if !resultsQueryParams.KeepResults { + logger.L().Info("deleting results", helpers.String("ID", resultsQueryParams.ScanID)) + defer removeResultsFile(resultsQueryParams.ScanID) + } + } w.Write(responseToBytes(&response)) case http.MethodDelete: - logger.L().Info("deleting results", helpers.String("ID", scanID)) + logger.L().Info("deleting results", helpers.String("ID", resultsQueryParams.ScanID)) - if r.URL.Query().Has("all") { + if resultsQueryParams.AllResults { removeResultDirs() } else { - removeResultsFile(scanID) + removeResultsFile(resultsQueryParams.ScanID) } w.WriteHeader(http.StatusOK) default: @@ -202,7 +267,7 @@ func (handler *HTTPHandler) recover(w http.ResponseWriter) { handler.state.setNotBusy() logger.L().Error("recover", helpers.Error(fmt.Errorf("%v", err))) w.WriteHeader(http.StatusInternalServerError) - response.Response = []byte(fmt.Sprintf("%v", err)) + response.Response = fmt.Sprintf("%v", err) response.Type = utilsapisv1.ErrorScanResponseType w.Write(responseToBytes(&response)) } @@ -211,7 +276,7 @@ func (handler *HTTPHandler) recover(w http.ResponseWriter) { func (handler *HTTPHandler) writeError(w http.ResponseWriter, err error) { response := utilsmetav1.Response{} w.WriteHeader(http.StatusBadRequest) - response.Response = []byte(err.Error()) + response.Response = err.Error() response.Type = utilsapisv1.ErrorScanResponseType w.Write(responseToBytes(&response)) handler.state.setNotBusy() diff --git a/httphandler/handlerequests/v1/requestshandlerutils.go b/httphandler/handlerequests/v1/requestshandlerutils.go index 15b4118c..f11414c4 100644 --- a/httphandler/handlerequests/v1/requestshandlerutils.go +++ b/httphandler/handlerequests/v1/requestshandlerutils.go @@ -1,6 +1,7 @@ package v1 import ( + "encoding/json" "fmt" "os" "path/filepath" @@ -10,30 +11,33 @@ import ( "github.com/armosec/kubescape/v2/core/cautils/getter" "github.com/armosec/kubescape/v2/core/core" utilsmetav1 "github.com/armosec/opa-utils/httpserver/meta/v1" + reporthandlingv2 "github.com/armosec/opa-utils/reporthandling/v2" "github.com/armosec/utils-go/boolutils" ) -func scan(scanRequest *utilsmetav1.PostScanRequest, scanID string) ([]byte, error) { +func scan(scanRequest *utilsmetav1.PostScanRequest, scanID string) (*reporthandlingv2.PostureReport, error) { scanInfo := getScanCommand(scanRequest, scanID) ks := core.NewKubescape() result, err := ks.Scan(scanInfo) if err != nil { - return []byte{}, writeScanErrorToFile(err, scanID) + return nil, writeScanErrorToFile(err, scanID) } if err := result.HandleResults(); err != nil { return nil, err } - b, err := result.ToJson() - if err != nil { - err = fmt.Errorf("failed to parse scan results to json, reason: %s", err.Error()) - } - return b, err + return result.GetResults(), nil } -func readResultsFile(fileID string) ([]byte, error) { +func readResultsFile(fileID string) (*reporthandlingv2.PostureReport, error) { if fileName := searchFile(fileID); fileName != "" { - return os.ReadFile(fileName) + f, err := os.ReadFile(fileName) + if err != nil { + return nil, err + } + postureReport := &reporthandlingv2.PostureReport{} + err = json.Unmarshal(f, postureReport) + return postureReport, err } return nil, fmt.Errorf("file %s not found", fileID) } diff --git a/httphandler/listener/setup.go b/httphandler/listener/setup.go index e456e6e0..2522da9a 100644 --- a/httphandler/listener/setup.go +++ b/httphandler/listener/setup.go @@ -15,6 +15,7 @@ import ( const ( scanPath = "/v1/scan" + statusPath = "/v1/status" resultsPath = "/v1/results" prometheusMmeticsPath = "/v1/metrics" livePath = "/livez" @@ -44,6 +45,7 @@ func SetupHTTPListener() error { rtr.HandleFunc(prometheusMmeticsPath, httpHandler.Metrics) rtr.HandleFunc(scanPath, httpHandler.Scan) + rtr.HandleFunc(statusPath, httpHandler.Status) rtr.HandleFunc(resultsPath, httpHandler.Results) rtr.HandleFunc(livePath, httpHandler.Live) rtr.HandleFunc(readyPath, httpHandler.Ready) From 0fc569d9d9aa48e78f75516e961359b45142493d Mon Sep 17 00:00:00 2001 From: David Wertenteil Date: Wed, 18 May 2022 00:35:45 +0300 Subject: [PATCH 2/4] fixed import --- cmd/scan/control.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmd/scan/control.go b/cmd/scan/control.go index 9521afe4..7bc00b1c 100644 --- a/cmd/scan/control.go +++ b/cmd/scan/control.go @@ -12,7 +12,6 @@ import ( "github.com/armosec/kubescape/v2/core/cautils/logger" "github.com/armosec/kubescape/v2/core/cautils/logger/helpers" "github.com/armosec/kubescape/v2/core/meta" - "github.com/armosec/opa-utils/reporthandling" "github.com/enescakir/emoji" "github.com/spf13/cobra" ) @@ -59,7 +58,7 @@ func getControlCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comman RunE: func(cmd *cobra.Command, args []string) error { // flagValidationControl(scanInfo) - scanInfo.PolicyIdentifier = []reporthandling.PolicyIdentifier{} + scanInfo.PolicyIdentifier = []cautils.PolicyIdentifier{} if len(args) == 0 { scanInfo.ScanAll = true From 622b1215359f14feb536b4e93cd6b29acfa0e7e8 Mon Sep 17 00:00:00 2001 From: David Wertenteil Date: Wed, 18 May 2022 13:22:33 +0300 Subject: [PATCH 3/4] adding scan request log --- httphandler/handlerequests/v1/requestshandler.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/httphandler/handlerequests/v1/requestshandler.go b/httphandler/handlerequests/v1/requestshandler.go index a4cdb928..72c4b720 100644 --- a/httphandler/handlerequests/v1/requestshandler.go +++ b/httphandler/handlerequests/v1/requestshandler.go @@ -125,6 +125,9 @@ func (handler *HTTPHandler) Scan(w http.ResponseWriter, r *http.Request) { handler.writeError(w, fmt.Errorf("failed to read request body, reason: %s", err.Error())) return } + + logger.L().Info("REST API received scan request", helpers.String("body", string(readBuffer))) + scanRequest := utilsmetav1.PostScanRequest{} if err := json.Unmarshal(readBuffer, &scanRequest); err != nil { handler.writeError(w, fmt.Errorf("failed to parse request payload, reason: %s", err.Error())) From 63968b564ba7751ff0bdbc059aeb16122f73aa11 Mon Sep 17 00:00:00 2001 From: David Wertenteil Date: Wed, 18 May 2022 14:36:55 +0300 Subject: [PATCH 4/4] update k8s-interface pkg --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index d2cc0476..f41d8dff 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,8 @@ go 1.17 require ( github.com/armosec/armoapi-go v0.0.73 github.com/armosec/go-git-url v0.0.4 + github.com/armosec/k8s-interface v0.0.74 github.com/armosec/opa-utils v0.0.139 - github.com/armosec/k8s-interface v0.0.75 github.com/armosec/rbac-utils v0.0.14 github.com/armosec/utils-go v0.0.5 github.com/armosec/utils-k8s-go v0.0.6 diff --git a/go.sum b/go.sum index d30786b2..27f7f837 100644 --- a/go.sum +++ b/go.sum @@ -120,8 +120,8 @@ github.com/armosec/go-git-url v0.0.4/go.mod h1:PJqdEyJyFxTQvawBcyOM0Ies6+uezire5 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.70/go.mod h1:8NX4xWXh8mwW7QyZdZea1czNdM2azCK9BbUNmiZYXW0= -github.com/armosec/k8s-interface v0.0.75 h1:pfheXWGcE6vUlo4TOkwXQ8iGo8Dw/UCXefD3Bx4l0Qs= -github.com/armosec/k8s-interface v0.0.75/go.mod h1:8NX4xWXh8mwW7QyZdZea1czNdM2azCK9BbUNmiZYXW0= +github.com/armosec/k8s-interface v0.0.74 h1:qZ1bkQv9JLfpwzxNcTytpYQpHKTKZ5rIhMze8SU1cPI= +github.com/armosec/k8s-interface v0.0.74/go.mod h1:8NX4xWXh8mwW7QyZdZea1czNdM2azCK9BbUNmiZYXW0= github.com/armosec/opa-utils v0.0.64/go.mod h1:6tQP8UDq2EvEfSqh8vrUdr/9QVSCG4sJfju1SXQOn4c= github.com/armosec/opa-utils v0.0.139 h1:JPxgPXVJUUIujtIoZk6TejE8PkZhX2pYnpj+E8PhcfA= github.com/armosec/opa-utils v0.0.139/go.mod h1:VnRVJgDDPFAprGDcibTtKHf9wgkoyTU8wmX2BxEIwok=