From bd089d76afc293f6e95c787bad872715880a31d9 Mon Sep 17 00:00:00 2001 From: dwertent Date: Sun, 9 Jan 2022 16:13:15 +0200 Subject: [PATCH] adding cluster flag - support submiting yaml file --- README.md | 1 + cautils/customerloader.go | 12 +++-- cautils/scaninfo.go | 1 + clihandler/clidownload.go | 8 ++-- clihandler/clilist.go | 4 +- clihandler/cmd/cluster_get.go | 2 +- clihandler/cmd/cluster_set.go | 2 +- clihandler/cmd/scan.go | 8 ++++ clihandler/cmd/submit.go | 2 +- clihandler/initcli.go | 12 ++++- clihandler/initcliutils.go | 21 ++++----- go.mod | 2 +- go.sum | 3 +- .../v2/controlmapping/prettyprinter.go | 11 ++++- .../reporter/v1/reporteventreceiver.go | 45 ++++++++++++++++--- .../reporter/v2/reporteventreceiver.go | 22 ++++++--- resultshandling/reporter/v2/utils.go | 20 +++++++++ 17 files changed, 134 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index ddee4832..a9d30e55 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,7 @@ Set-ExecutionPolicy RemoteSigned -scope CurrentUser | `--submit` | `false` | If set, Kubescape will send the scan results to Armo management portal where you can see the results in a user-friendly UI, choose your preferred compliance framework, check risk results history and trends, manage exceptions, get remediation recommendations and much more. By default the results are not sent | `true`/`false` | | `--keep-local` | `false` | Kubescape will not send scan results to Armo management portal. Use this flag if you ran with the `--submit` flag in the past and you do not want to submit your current scan results | `true`/`false` | | `--account` | | Armo portal account ID. Default will load account ID from configMap or config file | | +| `--cluster` | current-context | Cluster context to scan | | | `--verbose` | `false` | Display all of the input resources and not only failed resources | `true`/`false` | diff --git a/cautils/customerloader.go b/cautils/customerloader.go index 887e4a3c..f0bb0334 100644 --- a/cautils/customerloader.go +++ b/cautils/customerloader.go @@ -76,7 +76,7 @@ type LocalConfig struct { configObj *ConfigObj } -func NewLocalConfig(backendAPI getter.IBackend, customerGUID string) *LocalConfig { +func NewLocalConfig(backendAPI getter.IBackend, customerGUID, clusterName string) *LocalConfig { var configObj *ConfigObj lc := &LocalConfig{ @@ -95,6 +95,9 @@ func NewLocalConfig(backendAPI getter.IBackend, customerGUID string) *LocalConfi if customerGUID != "" { lc.configObj.CustomerGUID = customerGUID // override config customerGUID } + if clusterName != "" { + lc.configObj.ClusterName = AdoptClusterName(clusterName) // override config clusterName + } if lc.configObj.CustomerGUID != "" { if err := lc.SetTenant(); err != nil { fmt.Println(err) @@ -107,7 +110,7 @@ func NewLocalConfig(backendAPI getter.IBackend, customerGUID string) *LocalConfi func (lc *LocalConfig) GetConfigObj() *ConfigObj { return lc.configObj } func (lc *LocalConfig) GetCustomerGUID() string { return lc.configObj.CustomerGUID } func (lc *LocalConfig) SetCustomerGUID(customerGUID string) { lc.configObj.CustomerGUID = customerGUID } -func (lc *LocalConfig) GetClusterName() string { return "" } +func (lc *LocalConfig) GetClusterName() string { return lc.configObj.ClusterName } func (lc *LocalConfig) IsConfigFound() bool { return existsConfigFile() } func (lc *LocalConfig) SetTenant() error { // ARMO tenant GUID @@ -163,7 +166,7 @@ type ClusterConfig struct { configObj *ConfigObj } -func NewClusterConfig(k8s *k8sinterface.KubernetesApi, backendAPI getter.IBackend, customerGUID string) *ClusterConfig { +func NewClusterConfig(k8s *k8sinterface.KubernetesApi, backendAPI getter.IBackend, customerGUID, clusterName string) *ClusterConfig { var configObj *ConfigObj c := &ClusterConfig{ k8s: k8s, @@ -186,6 +189,9 @@ func NewClusterConfig(k8s *k8sinterface.KubernetesApi, backendAPI getter.IBacken if customerGUID != "" { c.configObj.CustomerGUID = customerGUID // override config customerGUID } + if clusterName != "" { + c.configObj.ClusterName = AdoptClusterName(clusterName) // override config clusterName + } if c.configObj.CustomerGUID != "" { if err := c.SetTenant(); err != nil { fmt.Println(err) diff --git a/cautils/scaninfo.go b/cautils/scaninfo.go index ca1e1961..3175f1d9 100644 --- a/cautils/scaninfo.go +++ b/cautils/scaninfo.go @@ -64,6 +64,7 @@ type ScanInfo struct { HostSensor BoolPtrFlag // Deploy ARMO K8s host sensor to collect data from certain controls Local bool // Do not submit results Account string // account ID + ClusterName string // cluster name FrameworkScan bool // false if scanning control ScanAll bool // true if scan all frameworks } diff --git a/clihandler/clidownload.go b/clihandler/clidownload.go index cca9ada2..038bc082 100644 --- a/clihandler/clidownload.go +++ b/clihandler/clidownload.go @@ -34,7 +34,7 @@ func CliDownload(downloadInfo *cautils.DownloadInfo) error { } func downloadConfigInputs(downloadInfo *cautils.DownloadInfo) error { - tenant := getTenantConfig(downloadInfo.Account, getKubernetesApi()) // change k8sinterface + tenant := getTenantConfig(downloadInfo.Account, "", getKubernetesApi()) // change k8sinterface controlsInputsGetter := getConfigInputsGetter(downloadInfo.Name, tenant.GetCustomerGUID(), nil) controlInputs, err := controlsInputsGetter.GetControlsInputs(tenant.GetClusterName()) if err != nil { @@ -52,7 +52,7 @@ func downloadConfigInputs(downloadInfo *cautils.DownloadInfo) error { } func downloadExceptions(downloadInfo *cautils.DownloadInfo) error { - tenant := getTenantConfig(downloadInfo.Account, getKubernetesApi()) // change k8sinterface + tenant := getTenantConfig(downloadInfo.Account, "", getKubernetesApi()) // change k8sinterface exceptionsGetter := getExceptionsGetter("") exceptions, err := exceptionsGetter.GetExceptions(tenant.GetClusterName()) if err != nil { @@ -70,7 +70,7 @@ func downloadExceptions(downloadInfo *cautils.DownloadInfo) error { } func downloadFramework(downloadInfo *cautils.DownloadInfo) error { - tenant := getTenantConfig(downloadInfo.Account, getKubernetesApi()) // change k8sinterface + tenant := getTenantConfig(downloadInfo.Account, "", getKubernetesApi()) // change k8sinterface g := getPolicyGetter(nil, tenant.GetCustomerGUID(), true, nil) if downloadInfo.Name == "" { @@ -92,7 +92,7 @@ func downloadFramework(downloadInfo *cautils.DownloadInfo) error { } func downloadControl(downloadInfo *cautils.DownloadInfo) error { - tenant := getTenantConfig(downloadInfo.Account, getKubernetesApi()) // change k8sinterface + tenant := getTenantConfig(downloadInfo.Account, "", getKubernetesApi()) // change k8sinterface g := getPolicyGetter(nil, tenant.GetCustomerGUID(), false, nil) if downloadInfo.Name == "" { diff --git a/clihandler/clilist.go b/clihandler/clilist.go index 1754fb83..e0c4878e 100644 --- a/clihandler/clilist.go +++ b/clihandler/clilist.go @@ -41,14 +41,14 @@ func CliList(listPolicies *cautils.ListPolicies) error { } func listFrameworks(listPolicies *cautils.ListPolicies) ([]string, error) { - tenant := getTenantConfig(listPolicies.Account, getKubernetesApi()) // change k8sinterface + tenant := getTenantConfig(listPolicies.Account, "", getKubernetesApi()) // change k8sinterface g := getPolicyGetter(nil, tenant.GetCustomerGUID(), true, nil) return listFrameworksNames(g), nil } func listControls(listPolicies *cautils.ListPolicies) ([]string, error) { - tenant := getTenantConfig(listPolicies.Account, getKubernetesApi()) // change k8sinterface + tenant := getTenantConfig(listPolicies.Account, "", getKubernetesApi()) // change k8sinterface g := getPolicyGetter(nil, tenant.GetCustomerGUID(), false, nil) l := getter.ListName if listPolicies.ListIDs { diff --git a/clihandler/cmd/cluster_get.go b/clihandler/cmd/cluster_get.go index 3910740c..a56ea117 100644 --- a/clihandler/cmd/cluster_get.go +++ b/clihandler/cmd/cluster_get.go @@ -30,7 +30,7 @@ var getCmd = &cobra.Command{ key := keyValue[0] k8s := k8sinterface.NewKubernetesApi() - clusterConfig := cautils.NewClusterConfig(k8s, getter.GetArmoAPIConnector(), scanInfo.Account) + clusterConfig := cautils.NewClusterConfig(k8s, getter.GetArmoAPIConnector(), scanInfo.Account, "") val, err := clusterConfig.GetValueByKeyFromConfigMap(key) if err != nil { if err.Error() == "value does not exist." { diff --git a/clihandler/cmd/cluster_set.go b/clihandler/cmd/cluster_set.go index b76d9658..609d0ca5 100644 --- a/clihandler/cmd/cluster_set.go +++ b/clihandler/cmd/cluster_set.go @@ -30,7 +30,7 @@ var setCmd = &cobra.Command{ data := keyValue[1] k8s := k8sinterface.NewKubernetesApi() - clusterConfig := cautils.NewClusterConfig(k8s, getter.GetArmoAPIConnector(), scanInfo.Account) + clusterConfig := cautils.NewClusterConfig(k8s, getter.GetArmoAPIConnector(), scanInfo.Account, "") if err := clusterConfig.SetKeyValueInConfigmap(key, data); err != nil { return err } diff --git a/clihandler/cmd/scan.go b/clihandler/cmd/scan.go index 6f012c92..00440d62 100644 --- a/clihandler/cmd/scan.go +++ b/clihandler/cmd/scan.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/armosec/k8s-interface/k8sinterface" "github.com/armosec/kubescape/cautils" "github.com/spf13/cobra" ) @@ -33,8 +34,15 @@ var scanCmd = &cobra.Command{ }, } +func frameworkInitConfig() { + k8sinterface.SetClusterContextName(scanInfo.ClusterName) +} + func init() { + cobra.OnInitialize(frameworkInitConfig) + rootCmd.AddCommand(scanCmd) + rootCmd.PersistentFlags().StringVarP(&scanInfo.ClusterName, "cluster", "", "", "Cluster name. Default will use the current-context") scanCmd.PersistentFlags().StringVar(&scanInfo.ControlsInputs, "controls-config", "", "Path to an controls-config obj. If not set will download controls-config from ARMO management portal") scanCmd.PersistentFlags().StringVar(&scanInfo.UseExceptions, "exceptions", "", "Path to an exceptions obj. If not set will download exceptions from ARMO management portal") scanCmd.PersistentFlags().StringVarP(&scanInfo.ExcludedNamespaces, "exclude-namespaces", "e", "", "Namespaces to exclude from scanning. Recommended: kube-system,kube-public") diff --git a/clihandler/cmd/submit.go b/clihandler/cmd/submit.go index e5038aa1..8e412064 100644 --- a/clihandler/cmd/submit.go +++ b/clihandler/cmd/submit.go @@ -20,7 +20,7 @@ func init() { } func getSubmittedClusterConfig(k8s *k8sinterface.KubernetesApi) (*cautils.ClusterConfig, error) { - clusterConfig := cautils.NewClusterConfig(k8s, getter.GetArmoAPIConnector(), scanInfo.Account) // TODO - support none cluster env submit + clusterConfig := cautils.NewClusterConfig(k8s, getter.GetArmoAPIConnector(), scanInfo.Account, scanInfo.ClusterName) // TODO - support none cluster env submit if clusterConfig.GetCustomerGUID() != "" { if err := clusterConfig.SetTenant(); err != nil { return clusterConfig, err diff --git a/clihandler/initcli.go b/clihandler/initcli.go index 9947be19..58fcc1b9 100644 --- a/clihandler/initcli.go +++ b/clihandler/initcli.go @@ -5,6 +5,7 @@ import ( "io/fs" "os" + "github.com/armosec/k8s-interface/k8sinterface" "github.com/armosec/kubescape/resultshandling/printer" printerv1 "github.com/armosec/kubescape/resultshandling/printer/v1" @@ -34,9 +35,16 @@ type componentInterfaces struct { func getInterfaces(scanInfo *cautils.ScanInfo) componentInterfaces { - k8s := getKubernetesApi() + var k8s *k8sinterface.KubernetesApi + if scanInfo.GetScanningEnvironment() == cautils.ScanCluster { + k8s = getKubernetesApi() + if k8s == nil { + fmt.Println("Failed connecting to Kubernetes cluster") + os.Exit(1) + } + } - tenantConfig := getTenantConfig(scanInfo.Account, k8s) + tenantConfig := getTenantConfig(scanInfo.Account, scanInfo.ClusterName, k8s) // Set submit behavior AFTER loading tenant config setSubmitBehavior(scanInfo, tenantConfig) diff --git a/clihandler/initcliutils.go b/clihandler/initcliutils.go index f06d997e..6ac729a2 100644 --- a/clihandler/initcliutils.go +++ b/clihandler/initcliutils.go @@ -16,17 +16,18 @@ import ( // reporterv2 "github.com/armosec/kubescape/resultshandling/reporter/v2" ) +// getKubernetesApi func getKubernetesApi() *k8sinterface.KubernetesApi { if !k8sinterface.IsConnectedToCluster() { return nil } return k8sinterface.NewKubernetesApi() } -func getTenantConfig(Account string, k8s *k8sinterface.KubernetesApi) cautils.ITenantConfig { - if !k8sinterface.IsConnectedToCluster() { - return cautils.NewLocalConfig(getter.GetArmoAPIConnector(), Account) +func getTenantConfig(Account, clusterName string, k8s *k8sinterface.KubernetesApi) cautils.ITenantConfig { + if !k8sinterface.IsConnectedToCluster() || k8s == nil { + return cautils.NewLocalConfig(getter.GetArmoAPIConnector(), Account, clusterName) } - return cautils.NewClusterConfig(k8s, getter.GetArmoAPIConnector(), Account) + return cautils.NewClusterConfig(k8s, getter.GetArmoAPIConnector(), Account, clusterName) } func getExceptionsGetter(useExceptions string) getter.IExceptionsGetter { @@ -51,8 +52,9 @@ func getReporter(tenantConfig cautils.ITenantConfig, submit bool) reporter.IRepo } return reporterv1.NewReportMock() } + func getResourceHandler(scanInfo *cautils.ScanInfo, tenantConfig cautils.ITenantConfig, k8s *k8sinterface.KubernetesApi, hostSensorHandler hostsensorutils.IHostSensor) resourcehandler.IResourceHandler { - if scanInfo.GetScanningEnvironment() == cautils.ScanLocalFiles { + if len(scanInfo.InputPatterns) > 0 || k8s == nil { return resourcehandler.NewFileResourceHandler(scanInfo.InputPatterns) } rbacObjects := getRBACHandler(tenantConfig, k8s, scanInfo.Submit) @@ -60,9 +62,10 @@ func getResourceHandler(scanInfo *cautils.ScanInfo, tenantConfig cautils.ITenant } func getHostSensorHandler(scanInfo *cautils.ScanInfo, k8s *k8sinterface.KubernetesApi) hostsensorutils.IHostSensor { - if scanInfo.GetScanningEnvironment() == cautils.ScanLocalFiles { + if !k8sinterface.IsConnectedToCluster() || k8s == nil { return &hostsensorutils.HostSensorHandlerMock{} } + hasHostSensorControls := true // we need to determined which controls needs host sensor if scanInfo.HostSensor.Get() == nil && hasHostSensorControls { @@ -125,12 +128,6 @@ func setSubmitBehavior(scanInfo *cautils.ScanInfo, tenantConfig cautils.ITenantC return } - // do not submit yaml/url scanning - if scanInfo.GetScanningEnvironment() == cautils.ScanLocalFiles { - scanInfo.Submit = false - return - } - if tenantConfig.IsConfigFound() { // config found in cache (submitted) if !scanInfo.Local { // Submit report diff --git a/go.mod b/go.mod index bcf36aa9..c22c9285 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.17 require ( github.com/armosec/armoapi-go v0.0.40 - github.com/armosec/k8s-interface v0.0.50 + github.com/armosec/k8s-interface v0.0.54 github.com/armosec/opa-utils v0.0.92 github.com/armosec/rbac-utils v0.0.11 github.com/armosec/utils-go v0.0.3 diff --git a/go.sum b/go.sum index 43ebfbec..77624138 100644 --- a/go.sum +++ b/go.sum @@ -89,8 +89,9 @@ github.com/armosec/armoapi-go v0.0.40 h1:KQRJXFqw95s6cV7HoGgw1x8qrRZ9eNVze//yQbo github.com/armosec/armoapi-go v0.0.40/go.mod h1:iaVVGyc23QGGzAdv4n+szGQg3Rbpixn9yQTU3qWRpaw= github.com/armosec/k8s-interface v0.0.8/go.mod h1:xxS+V5QT3gVQTwZyAMMDrYLWGrfKOpiJ7Jfhfa0w9sM= github.com/armosec/k8s-interface v0.0.37/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2dsFVc0XtgRh1ZU= -github.com/armosec/k8s-interface v0.0.50 h1:iLPGI0j85vwKANr9QDAnba4Efjg3DyIJg15jRJdvOnc= github.com/armosec/k8s-interface v0.0.50/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2dsFVc0XtgRh1ZU= +github.com/armosec/k8s-interface v0.0.54 h1:1sQeoEZA5bgpXVibXhEiTSeLd3GKY5NkTOeewdgR0Bs= +github.com/armosec/k8s-interface v0.0.54/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2dsFVc0XtgRh1ZU= github.com/armosec/opa-utils v0.0.64/go.mod h1:6tQP8UDq2EvEfSqh8vrUdr/9QVSCG4sJfju1SXQOn4c= github.com/armosec/opa-utils v0.0.92 h1:RzzORhfLx9Evc2ceFtNRoehxUFzwlvK5iMtR6fLWzZc= github.com/armosec/opa-utils v0.0.92/go.mod h1:ZOXYVTtuyrV4TldcfbzgRqP6F9Drlf4hB0zr210OXgM= diff --git a/resultshandling/printer/v2/controlmapping/prettyprinter.go b/resultshandling/printer/v2/controlmapping/prettyprinter.go index 521b43c1..2d875f79 100644 --- a/resultshandling/printer/v2/controlmapping/prettyprinter.go +++ b/resultshandling/printer/v2/controlmapping/prettyprinter.go @@ -122,10 +122,17 @@ func (prettyPrinter *PrettyPrinter) printGroupedResource(indent string, title st indent += indent } + resources := []string{} for r := range rsc { - relatedObjectsStr := generateRelatedObjectsStr(rsc[r]) - cautils.SimpleDisplay(prettyPrinter.writer, fmt.Sprintf("%s%s - %s %s\n", indent, rsc[r].resource.GetKind(), rsc[r].resource.GetName(), relatedObjectsStr)) + relatedObjectsStr := generateRelatedObjectsStr(rsc[r]) // TODO - + resources = append(resources, fmt.Sprintf("%s%s - %s %s", indent, rsc[r].resource.GetKind(), rsc[r].resource.GetName(), relatedObjectsStr)) } + + sort.Strings(resources) + for i := range resources { + cautils.SimpleDisplay(prettyPrinter.writer, resources[i]+"\n") + } + indent = preIndent } diff --git a/resultshandling/reporter/v1/reporteventreceiver.go b/resultshandling/reporter/v1/reporteventreceiver.go index 7fbfedc6..9e575295 100644 --- a/resultshandling/reporter/v1/reporteventreceiver.go +++ b/resultshandling/reporter/v1/reporteventreceiver.go @@ -6,6 +6,7 @@ import ( "net/http" "net/url" "os" + "strings" "github.com/armosec/k8s-interface/workloadinterface" "github.com/armosec/kubescape/cautils" @@ -23,6 +24,7 @@ type ReportEventReceiver struct { eventReceiverURL *url.URL token string customerAdminEMail string + message string } func NewReportEventReceiver(tenantConfig *cautils.ConfigObj) *ReportEventReceiver { @@ -38,15 +40,22 @@ func NewReportEventReceiver(tenantConfig *cautils.ConfigObj) *ReportEventReceive func (report *ReportEventReceiver) ActionSendReport(opaSessionObj *cautils.OPASessionObj) error { cautils.ReportV2ToV1(opaSessionObj) - if report.customerGUID == "" || report.clusterName == "" { - return fmt.Errorf("missing account ID or cluster name. AccountID: '%s', Cluster name: '%s'", report.customerGUID, report.clusterName) + if report.customerGUID == "" { + report.message = "WARNING: Failed to publish results. Reason: Unknown accout ID. Run kubescape with the '--account ' flag. Contact ARMO team for more details" + return nil } + if report.clusterName == "" { + report.message = "WARNING: Failed to publish results. Reason: Unknown cluster name. Run kubescape with the '--cluster ' flag" + return nil + } + opaSessionObj.PostureReport.ReportID = uuid.NewV4().String() opaSessionObj.PostureReport.CustomerGUID = report.clusterName opaSessionObj.PostureReport.ClusterName = report.customerGUID if err := report.prepareReport(opaSessionObj.PostureReport, opaSessionObj.AllResources); err != nil { - return err + report.message = err.Error() + return nil } return nil } @@ -75,6 +84,8 @@ func (report *ReportEventReceiver) prepareReport(postureReport *reporthandling.P if err := report.sendResources(host, postureReport, allResources); err != nil { return err } + report.generateMessage() + return nil } @@ -120,7 +131,7 @@ func (report *ReportEventReceiver) sendReport(host string, postureReport *report return err } -func (report *ReportEventReceiver) DisplayReportURL() { +func (report *ReportEventReceiver) generateMessage() { message := "You can see the results in a user-friendly UI, choose your preferred compliance framework, check risk results history and trends, manage exceptions, get remediation recommendations and much more by registering here:" u := url.URL{} @@ -128,7 +139,7 @@ func (report *ReportEventReceiver) DisplayReportURL() { u.Host = getter.GetArmoAPIConnector().GetFrontendURL() if report.customerAdminEMail != "" { - cautils.InfoTextDisplay(os.Stderr, fmt.Sprintf("\n\n%s %s/risk/%s\n(Account: %s)\n\n", message, u.String(), report.clusterName, report.customerGUID)) + report.message = fmt.Sprintf("%s %s/risk/%s\n(Account: %s)", message, u.String(), report.clusterName, maskID(report.customerGUID)) return } u.Path = "account/sign-up" @@ -137,5 +148,27 @@ func (report *ReportEventReceiver) DisplayReportURL() { q.Add("customerGUID", report.customerGUID) u.RawQuery = q.Encode() - cautils.InfoTextDisplay(os.Stderr, fmt.Sprintf("\n\n%s %s\n\n", message, u.String())) + report.message = fmt.Sprintf("%s %s", message, u.String()) +} + +func (report *ReportEventReceiver) DisplayReportURL() { + cautils.InfoTextDisplay(os.Stderr, fmt.Sprintf("\n\n%s\n\n", report.message)) +} + +func maskID(id string) string { + sep := "-" + splitted := strings.Split(id, sep) + if len(splitted) != 5 { + return "" + } + str := splitted[0][:4] + splitted[0] = splitted[0][4:] + for i := range splitted { + for j := 0; j < len(splitted[i]); j++ { + str += "X" + } + str += sep + } + + return strings.TrimSuffix(str, sep) } diff --git a/resultshandling/reporter/v2/reporteventreceiver.go b/resultshandling/reporter/v2/reporteventreceiver.go index 74056a27..4d6adb4d 100644 --- a/resultshandling/reporter/v2/reporteventreceiver.go +++ b/resultshandling/reporter/v2/reporteventreceiver.go @@ -24,6 +24,7 @@ type ReportEventReceiver struct { eventReceiverURL *url.URL token string customerAdminEMail string + message string } func NewReportEventReceiver(tenantConfig *cautils.ConfigObj) *ReportEventReceiver { @@ -39,15 +40,20 @@ func NewReportEventReceiver(tenantConfig *cautils.ConfigObj) *ReportEventReceive func (report *ReportEventReceiver) ActionSendReport(opaSessionObj *cautils.OPASessionObj) error { finalizeReport(opaSessionObj) - if report.customerGUID == "" || report.clusterName == "" { - return fmt.Errorf("missing accout ID or cluster name. AccountID: '%s', Cluster name: '%s'", report.customerGUID, report.clusterName) + if report.customerGUID == "" { + report.message = "WARNING: Failed to publish results. Reason: Unknown accout ID. Run kubescape with the '--account ' flag. Contact ARMO team for more details" + return nil + } + if report.clusterName == "" { + report.message = "WARNING: Failed to publish results. Reason: Unknown cluster name. Run kubescape with the '--cluster ' flag" + return nil } opaSessionObj.Report.ReportID = uuid.NewV4().String() opaSessionObj.Report.CustomerGUID = report.clusterName opaSessionObj.Report.ClusterName = report.customerGUID if err := report.prepareReport(opaSessionObj.Report); err != nil { - return err + report.message = err.Error() } return nil } @@ -160,7 +166,7 @@ func (report *ReportEventReceiver) sendReport(host string, postureReport *report return err } -func (report *ReportEventReceiver) DisplayReportURL() { +func (report *ReportEventReceiver) generateMessage() { message := "You can see the results in a user-friendly UI, choose your preferred compliance framework, check risk results history and trends, manage exceptions, get remediation recommendations and much more by registering here:" u := url.URL{} @@ -168,7 +174,7 @@ func (report *ReportEventReceiver) DisplayReportURL() { u.Host = getter.GetArmoAPIConnector().GetFrontendURL() if report.customerAdminEMail != "" { - cautils.InfoTextDisplay(os.Stderr, fmt.Sprintf("\n\n%s %s/risk/%s\n(Account: %s)\n\n", message, u.String(), report.clusterName, report.customerGUID)) + report.message = fmt.Sprintf("%s %s/risk/%s\n(Account: %s)", message, u.String(), report.clusterName, maskID(report.customerGUID)) return } u.Path = "account/sign-up" @@ -177,5 +183,9 @@ func (report *ReportEventReceiver) DisplayReportURL() { q.Add("customerGUID", report.customerGUID) u.RawQuery = q.Encode() - cautils.InfoTextDisplay(os.Stderr, fmt.Sprintf("\n\n%s %s\n\n", message, u.String())) + report.message = fmt.Sprintf("%s %s", message, u.String()) +} + +func (report *ReportEventReceiver) DisplayReportURL() { + cautils.InfoTextDisplay(os.Stderr, fmt.Sprintf("\n\n%s\n\n", report.message)) } diff --git a/resultshandling/reporter/v2/utils.go b/resultshandling/reporter/v2/utils.go index cbc5b84c..0f3ebc03 100644 --- a/resultshandling/reporter/v2/utils.go +++ b/resultshandling/reporter/v2/utils.go @@ -1,6 +1,8 @@ package v2 import ( + "strings" + "github.com/armosec/k8s-interface/workloadinterface" "github.com/armosec/kubescape/cautils" "github.com/armosec/opa-utils/reporthandling/results/v1/resourcesresults" @@ -41,3 +43,21 @@ func finalizeResources(resources []reporthandlingv2.Resource, allResources map[s index++ } } + +func maskID(id string) string { + sep := "-" + splitted := strings.Split(id, sep) + if len(splitted) != 5 { + return "" + } + str := splitted[0][:4] + splitted[0] = splitted[0][4:] + for i := range splitted { + for j := 0; j < len(splitted[i]); j++ { + str += "X" + } + str += sep + } + + return strings.TrimSuffix(str, sep) +}