From b4d712fcb157f939e15ec9eac81348368c2db6be Mon Sep 17 00:00:00 2001 From: Bezalel Brandwine Date: Thu, 10 Feb 2022 17:38:13 +0200 Subject: [PATCH 01/12] add explicit protocol to solve known K8s issue: https://github.com/kubernetes/kubernetes/issues/92332 --- hostsensorutils/hostsensor.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/hostsensorutils/hostsensor.yaml b/hostsensorutils/hostsensor.yaml index bc03b94c..5647a162 100644 --- a/hostsensorutils/hostsensor.yaml +++ b/hostsensorutils/hostsensor.yaml @@ -40,6 +40,7 @@ spec: - name: http hostPort: 7888 containerPort: 7888 + protocol: TCP resources: limits: cpu: 0.1m From 46001e4761f1c8e6f74a585880c26765e9de1e7d Mon Sep 17 00:00:00 2001 From: avicoder Date: Fri, 11 Feb 2022 03:17:10 +0800 Subject: [PATCH 02/12] [Minor] Fixed a Typo Useage to Usage --- clihandler/clilist.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clihandler/clilist.go b/clihandler/clilist.go index dda856ee..928d262b 100644 --- a/clihandler/clilist.go +++ b/clihandler/clilist.go @@ -32,7 +32,7 @@ func CliList(listPolicies *cliobjects.ListPolicies) error { sep := "\n * " usageCmd := strings.TrimSuffix(listPolicies.Target, "s") fmt.Printf("Supported %s:%s%s\n", listPolicies.Target, sep, strings.Join(policies, sep)) - fmt.Printf("\nUseage:\n") + fmt.Printf("\nUsage:\n") fmt.Printf("$ kubescape scan %s \"name\"\n", usageCmd) fmt.Printf("$ kubescape scan %s \"name-0\",\"name-1\"\n\n", usageCmd) return nil From bf7505934749394006f4af174f4843e69ddc4c14 Mon Sep 17 00:00:00 2001 From: dwertent Date: Tue, 15 Feb 2022 14:25:28 +0200 Subject: [PATCH 03/12] update after scan messgae --- cautils/getter/armoapi.go | 2 ++ clihandler/initcliutils.go | 6 ++-- resourcehandler/k8sresources.go | 16 ++++++++++- resultshandling/reporter/v1/mockreporter.go | 2 +- .../reporter/v1/reporteventreceiver.go | 2 +- .../reporter/v2/reporteventreceiver.go | 28 +++++++++++-------- 6 files changed, 39 insertions(+), 17 deletions(-) diff --git a/cautils/getter/armoapi.go b/cautils/getter/armoapi.go index cc6a1fd8..0534f12b 100644 --- a/cautils/getter/armoapi.go +++ b/cautils/getter/armoapi.go @@ -11,6 +11,7 @@ import ( "github.com/armosec/armoapi-go/armotypes" "github.com/armosec/kubescape/cautils/logger" + "github.com/armosec/kubescape/cautils/logger/helpers" "github.com/armosec/opa-utils/reporthandling" ) @@ -50,6 +51,7 @@ type ArmoAPI struct { var globalArmoAPIConnector *ArmoAPI func SetARMOAPIConnector(armoAPI *ArmoAPI) { + logger.L().Debug("Armo URLs", helpers.String("api", armoAPI.apiURL), helpers.String("auth", armoAPI.authURL), helpers.String("report", armoAPI.erURL), helpers.String("UI", armoAPI.feURL)) globalArmoAPIConnector = armoAPI } diff --git a/clihandler/initcliutils.go b/clihandler/initcliutils.go index a03a5d62..1a364ea1 100644 --- a/clihandler/initcliutils.go +++ b/clihandler/initcliutils.go @@ -216,8 +216,8 @@ func getDefaultFrameworksPaths() []string { func listFrameworksNames(policyGetter getter.IPolicyGetter) []string { fw, err := policyGetter.ListFrameworks() - if err != nil { - fw = getDefaultFrameworksPaths() + if err == nil { + return fw } - return fw + return getter.NativeFrameworks } diff --git a/resourcehandler/k8sresources.go b/resourcehandler/k8sresources.go index 2e41daea..0a1fbba2 100644 --- a/resourcehandler/k8sresources.go +++ b/resourcehandler/k8sresources.go @@ -168,6 +168,18 @@ func ConvertMapListToMeta(resourceMap []map[string]interface{}) []workloadinterf return workloads } +// func (k8sHandler *K8sResourceHandler) collectHostResourcesAPI(allResources map[string]workloadinterface.IMetadata, resourcesMap *cautils.K8SResources) error { + +// HostSensorAPI := map[string]string{ +// "bla/v1": "", +// } +// for apiVersion := range allResources { +// if HostSensorAPI == apiVersion { +// k8sHandler.collectHostResources() +// } +// } +// return nil +// } func (k8sHandler *K8sResourceHandler) collectHostResources(allResources map[string]workloadinterface.IMetadata, resourcesMap *cautils.K8SResources) error { logger.L().Debug("Collecting host sensor resources") @@ -175,6 +187,7 @@ func (k8sHandler *K8sResourceHandler) collectHostResources(allResources map[stri if err != nil { return err } + for rscIdx := range hostResources { group, version := getGroupNVersion(hostResources[rscIdx].GetApiVersion()) groupResource := k8sinterface.JoinResourceTriplets(group, version, hostResources[rscIdx].GetKind()) @@ -220,9 +233,10 @@ func getCloudProviderDescription(allResources map[string]workloadinterface.IMeta if err != nil { return err } - logger.L().Debug("cloud", helpers.String("cluster", cluster), helpers.String("clusterName", clusterName), helpers.String("provider", provider), helpers.String("region", region), helpers.String("project", project)) if provider != "" { + logger.L().Debug("cloud", helpers.String("cluster", cluster), helpers.String("clusterName", clusterName), helpers.String("provider", provider), helpers.String("region", region), helpers.String("project", project)) + wl, err := cloudsupport.GetDescriptiveInfoFromCloudProvider(clusterName, provider, region, project) if err != nil { // Return error with useful info on how to configure credentials for getting cloud provider info diff --git a/resultshandling/reporter/v1/mockreporter.go b/resultshandling/reporter/v1/mockreporter.go index 451a59f4..8ffc01fe 100644 --- a/resultshandling/reporter/v1/mockreporter.go +++ b/resultshandling/reporter/v1/mockreporter.go @@ -25,6 +25,6 @@ func (reportMock *ReportMock) SetClusterName(clusterName string) { } func (reportMock *ReportMock) DisplayReportURL() { - message := fmt.Sprintf("\nYou can see the results in a user-friendly UI, choose your preferred compliance framework, check risk results history and trends, manage exceptions, get remediation recommendations and much more by registering here: https://%s/cli-signup \n", getter.GetArmoAPIConnector().GetFrontendURL()) + message := fmt.Sprintf("\nScan results have not been submitted.\nYou can see the results in a user-friendly UI, choose your preferred compliance framework, check risk results history and trends, manage exceptions, get remediation recommendations and much more by registering here: https://%s/cli-signup \n", getter.GetArmoAPIConnector().GetFrontendURL()) cautils.InfoTextDisplay(os.Stderr, fmt.Sprintf("\n%s\n", message)) } diff --git a/resultshandling/reporter/v1/reporteventreceiver.go b/resultshandling/reporter/v1/reporteventreceiver.go index 4b815b65..cc2cd34a 100644 --- a/resultshandling/reporter/v1/reporteventreceiver.go +++ b/resultshandling/reporter/v1/reporteventreceiver.go @@ -144,7 +144,7 @@ func (report *ReportEventReceiver) generateMessage() { if report.customerAdminEMail != "" { logger.L().Debug("", helpers.String("account ID", report.customerGUID)) - report.message = fmt.Sprintf("%s %s/risk/%s", message, u.String(), report.clusterName) + report.message = fmt.Sprintf("%s %s/configuration-scanning/%s", message, u.String(), report.clusterName) return } u.Path = "account/sign-up" diff --git a/resultshandling/reporter/v2/reporteventreceiver.go b/resultshandling/reporter/v2/reporteventreceiver.go index db29b77f..77ba546e 100644 --- a/resultshandling/reporter/v2/reporteventreceiver.go +++ b/resultshandling/reporter/v2/reporteventreceiver.go @@ -60,6 +60,8 @@ func (report *ReportEventReceiver) ActionSendReport(opaSessionObj *cautils.OPASe } else { report.generateMessage() } + logger.L().Debug("", helpers.String("account ID", report.customerGUID)) + return nil } @@ -202,24 +204,28 @@ func (report *ReportEventReceiver) sendReport(host string, postureReport *report } 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{} u.Scheme = "https" u.Host = getter.GetArmoAPIConnector().GetFrontendURL() - if report.customerAdminEMail != "" { - logger.L().Debug("", helpers.String("account ID", report.customerGUID)) - report.message = fmt.Sprintf("%s %s/risk/%s", message, u.String(), report.clusterName) - return + if report.customerAdminEMail != "" { // data has been submitted + u.Path = fmt.Sprintf("configuration-scanning/%s", report.clusterName) + } else { + u.Path = "account/sign-up" + q := u.Query() + q.Add("invitationToken", report.token) + q.Add("customerGUID", report.customerGUID) + + u.RawQuery = q.Encode() } - u.Path = "account/sign-up" - q := u.Query() - q.Add("invitationToken", report.token) - q.Add("customerGUID", report.customerGUID) + + sep := "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + report.message = sep + report.message += " << WOW! Now you can see the scan results on the web >>\n\n" + report.message += fmt.Sprintf(" %s\n", u.String()) + report.message += sep - u.RawQuery = q.Encode() - report.message = fmt.Sprintf("%s %s", message, u.String()) } func (report *ReportEventReceiver) DisplayReportURL() { From 9de73dab29ad943a978acdfd012772c2f840371e Mon Sep 17 00:00:00 2001 From: dwertent Date: Wed, 16 Feb 2022 13:15:44 +0200 Subject: [PATCH 04/12] updalead sha --- .github/workflows/build.yaml | 14 +++++++++++++- build.py | 19 +++++++++++++------ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index d5bba495..7523cbb4 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -53,7 +53,7 @@ jobs: KUBESCAPE_SKIP_UPDATE_CHECK: "true" run: python3 smoke_testing/init.py ${PWD}/build/${{ matrix.os }}/kubescape - - name: Upload Release binaries + - name: Upload release binaries id: upload-release-asset uses: actions/upload-release-asset@v1 env: @@ -64,6 +64,18 @@ jobs: asset_name: kubescape-${{ matrix.os }} asset_content_type: application/octet-stream + - name: Upload release hash + id: upload-release-hash + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ needs.once.outputs.upload_url }} + asset_path: build/${{ matrix.os }}/kubescape.sha256 + asset_name: kubescape-${{ matrix.os }}-sha256 + asset_content_type: application/octet-stream + + build-docker: name: Build docker container, tag and upload to registry diff --git a/build.py b/build.py index fc8a19d3..abf816ff 100644 --- a/build.py +++ b/build.py @@ -49,6 +49,9 @@ def main(): ArmoWebsite = os.getenv("ArmoWebsite") ArmoAuthServer = os.getenv("ArmoAuthServer") + ks_file = os.path.join(buildDir, packageName) + hash_file = os.path.join(buildDir, packageName + ".sha256") + # Create build directory buildDir = getBuildDir() @@ -60,14 +63,18 @@ def main(): % (buildUrl, releaseVersion, BE_SERVER_CONST, ArmoBEServer, ER_SERVER_CONST, ArmoERServer, WEBSITE_CONST, ArmoWebsite, AUTH_SERVER_CONST, ArmoAuthServer) - status = subprocess.call(["go", "build", "-o", "%s/%s" % (buildDir, packageName), "-ldflags" ,ldflags]) + + print("Building kubescape and saving here: {}".format(ks_file)) + status = subprocess.call(["go", "build", "-o", ks_file, "-ldflags" ,ldflags]) checkStatus(status, "Failed to build kubescape") - sha1 = hashlib.sha1() - with open(buildDir + "/" + packageName, "rb") as kube: - sha1.update(kube.read()) - with open(buildDir + "/" + packageName + ".sha1", "w") as kube_sha: - kube_sha.write(sha1.hexdigest()) + sha256 = hashlib.sha256() + with open(ks_file, "rb") as kube: + sha256.update(kube.read()) + with open(hash_file, "w") as kube_sha: + hash = sha256.hexdigest() + print("kubescape hash: {}, file: {}".format(hash, hash_file)) + kube_sha.write(sha256.hexdigest()) print("Build Done") From d288fdc7f2df8d5746a7a181f94ade3266ef0bb9 Mon Sep 17 00:00:00 2001 From: dwertent Date: Wed, 16 Feb 2022 13:59:29 +0200 Subject: [PATCH 05/12] set tenant only when submiiting data --- cautils/customerloader.go | 12 +++++++----- cautils/getter/armoapiutils.go | 17 ++++++++++++----- clihandler/clidownload.go | 4 ++++ clihandler/clilist.go | 1 + clihandler/clisubmit.go | 3 ++- clihandler/cmd/rbac.go | 1 + clihandler/cmd/results.go | 1 + 7 files changed, 28 insertions(+), 11 deletions(-) diff --git a/cautils/customerloader.go b/cautils/customerloader.go index adec4e65..174b3380 100644 --- a/cautils/customerloader.go +++ b/cautils/customerloader.go @@ -118,6 +118,7 @@ func NewLocalConfig(backendAPI getter.IBackend, customerGUID, clusterName string logger.L().Error(err.Error()) } } + lc.UpdateCachedConfig() return lc } @@ -228,11 +229,12 @@ func NewClusterConfig(k8s *k8sinterface.KubernetesApi, backendAPI getter.IBacken c.backendAPI.SetClientID(c.configObj.ClientID) c.backendAPI.SetSecretKey(c.configObj.SecretKey) - if c.configObj.AccountID != "" { - if err := c.SetTenant(); err != nil { - logger.L().Error(err.Error()) - } - } + // if c.configObj.AccountID != "" { + // if err := c.SetTenant(); err != nil { + // logger.L().Error(err.Error()) + // } + // } + c.UpdateCachedConfig() return c } diff --git a/cautils/getter/armoapiutils.go b/cautils/getter/armoapiutils.go index 39674036..0b213b48 100644 --- a/cautils/getter/armoapiutils.go +++ b/cautils/getter/armoapiutils.go @@ -17,7 +17,7 @@ func (armoAPI *ArmoAPI) getFrameworkURL(frameworkName string) string { u.Host = armoAPI.apiURL u.Path = "api/v1/armoFrameworks" q := u.Query() - q.Add("customerGUID", armoAPI.accountID) + q.Add("customerGUID", armoAPI.getCustomerGUIDFallBack()) if isNativeFramework(frameworkName) { q.Add("frameworkName", strings.ToUpper(frameworkName)) } else { @@ -35,7 +35,7 @@ func (armoAPI *ArmoAPI) getListFrameworkURL() string { u.Host = armoAPI.apiURL u.Path = "api/v1/armoFrameworks" q := u.Query() - q.Add("customerGUID", armoAPI.accountID) + q.Add("customerGUID", armoAPI.getCustomerGUIDFallBack()) u.RawQuery = q.Encode() return u.String() @@ -47,7 +47,7 @@ func (armoAPI *ArmoAPI) getExceptionsURL(clusterName string) string { u.Path = "api/v1/armoPostureExceptions" q := u.Query() - q.Add("customerGUID", armoAPI.accountID) + q.Add("customerGUID", armoAPI.getCustomerGUIDFallBack()) // if clusterName != "" { // TODO - fix customer name support in Armo BE // q.Add("clusterName", clusterName) // } @@ -63,7 +63,7 @@ func (armoAPI *ArmoAPI) postExceptionsURL() string { u.Path = "api/v1/postureExceptionPolicy" q := u.Query() - q.Add("customerGUID", armoAPI.accountID) + q.Add("customerGUID", armoAPI.getCustomerGUIDFallBack()) u.RawQuery = q.Encode() return u.String() @@ -76,7 +76,7 @@ func (armoAPI *ArmoAPI) getAccountConfig(clusterName string) string { u.Path = "api/v1/armoCustomerConfiguration" q := u.Query() - q.Add("customerGUID", armoAPI.accountID) + q.Add("customerGUID", armoAPI.getCustomerGUIDFallBack()) if clusterName != "" { // TODO - fix customer name support in Armo BE q.Add("clusterName", clusterName) } @@ -156,3 +156,10 @@ func (armoAPI *ArmoAPI) appendAuthHeaders(headers map[string]string) { headers["Cookie"] = fmt.Sprintf("auth=%s", armoAPI.authCookie) } } + +func (armoAPI *ArmoAPI) getCustomerGUIDFallBack() string { + if armoAPI.accountID != "" { + return armoAPI.accountID + } + return "11111111-1111-1111-1111-111111111111" +} diff --git a/clihandler/clidownload.go b/clihandler/clidownload.go index 35c1fdf9..ec9b02d3 100644 --- a/clihandler/clidownload.go +++ b/clihandler/clidownload.go @@ -77,6 +77,7 @@ func downloadArtifacts(downloadInfo *cautils.DownloadInfo) error { func downloadConfigInputs(downloadInfo *cautils.DownloadInfo) error { tenant := getTenantConfig(downloadInfo.Account, "", getKubernetesApi()) + controlsInputsGetter := getConfigInputsGetter(downloadInfo.Name, tenant.GetAccountID(), nil) controlInputs, err := controlsInputsGetter.GetControlsInputs(tenant.GetClusterName()) if err != nil { @@ -97,6 +98,7 @@ func downloadConfigInputs(downloadInfo *cautils.DownloadInfo) error { func downloadExceptions(downloadInfo *cautils.DownloadInfo) error { var err error tenant := getTenantConfig(downloadInfo.Account, "", getKubernetesApi()) + exceptionsGetter := getExceptionsGetter("") exceptions := []armotypes.PostureExceptionPolicy{} if tenant.GetAccountID() != "" { @@ -120,6 +122,7 @@ func downloadExceptions(downloadInfo *cautils.DownloadInfo) error { func downloadFramework(downloadInfo *cautils.DownloadInfo) error { tenant := getTenantConfig(downloadInfo.Account, "", getKubernetesApi()) + g := getPolicyGetter(nil, tenant.GetAccountID(), true, nil) if downloadInfo.Name == "" { @@ -156,6 +159,7 @@ func downloadFramework(downloadInfo *cautils.DownloadInfo) error { func downloadControl(downloadInfo *cautils.DownloadInfo) error { tenant := getTenantConfig(downloadInfo.Account, "", getKubernetesApi()) + g := getPolicyGetter(nil, tenant.GetAccountID(), false, nil) if downloadInfo.Name == "" { diff --git a/clihandler/clilist.go b/clihandler/clilist.go index dda856ee..128537fc 100644 --- a/clihandler/clilist.go +++ b/clihandler/clilist.go @@ -49,6 +49,7 @@ func listFrameworks(listPolicies *cliobjects.ListPolicies) ([]string, error) { func listControls(listPolicies *cliobjects.ListPolicies) ([]string, error) { tenant := getTenantConfig(listPolicies.Account, "", getKubernetesApi()) // change k8sinterface + g := getPolicyGetter(nil, tenant.GetAccountID(), false, nil) l := getter.ListName if listPolicies.ListIDs { diff --git a/clihandler/clisubmit.go b/clihandler/clisubmit.go index 2f19aff0..c8370335 100644 --- a/clihandler/clisubmit.go +++ b/clihandler/clisubmit.go @@ -33,7 +33,8 @@ func SubmitExceptions(accountID, excPath string) error { logger.L().Info("submitting exceptions", helpers.String("path", excPath)) // load cached config - getTenantConfig(accountID, "", getKubernetesApi()) + tenantConfig := getTenantConfig(accountID, "", getKubernetesApi()) + tenantConfig.SetTenant() // load exceptions from file loader := getter.NewLoadPolicy([]string{excPath}) diff --git a/clihandler/cmd/rbac.go b/clihandler/cmd/rbac.go index 938b73b9..8d8fbec0 100644 --- a/clihandler/cmd/rbac.go +++ b/clihandler/cmd/rbac.go @@ -23,6 +23,7 @@ var rabcCmd = &cobra.Command{ // get config clusterConfig := getTenantConfig(submitInfo.Account, "", k8s) + clusterConfig.SetTenant() // list RBAC rbacObjects := cautils.NewRBACObjects(rbacscanner.NewRbacScannerFromK8sAPI(k8s, clusterConfig.GetAccountID(), clusterConfig.GetClusterName())) diff --git a/clihandler/cmd/results.go b/clihandler/cmd/results.go index ccf2d536..d6b25cfa 100644 --- a/clihandler/cmd/results.go +++ b/clihandler/cmd/results.go @@ -63,6 +63,7 @@ var resultsCmd = &cobra.Command{ // get config clusterConfig := getTenantConfig(submitInfo.Account, "", k8s) + clusterConfig.SetTenant() resultsObjects := NewResultsObject(clusterConfig.GetAccountID(), clusterConfig.GetClusterName(), args[0]) From e47eb9cb4e7bfce9d52196457f25e958cee7c213 Mon Sep 17 00:00:00 2001 From: dwertent Date: Wed, 16 Feb 2022 14:02:28 +0200 Subject: [PATCH 06/12] adding logs to python file --- build.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/build.py b/build.py index abf816ff..e695e811 100644 --- a/build.py +++ b/build.py @@ -49,11 +49,12 @@ def main(): ArmoWebsite = os.getenv("ArmoWebsite") ArmoAuthServer = os.getenv("ArmoAuthServer") - ks_file = os.path.join(buildDir, packageName) - hash_file = os.path.join(buildDir, packageName + ".sha256") # Create build directory buildDir = getBuildDir() + + ks_file = os.path.join(buildDir, packageName) + hash_file = ks_file + ".sha256" if not os.path.isdir(buildDir): os.makedirs(buildDir) From fd135e9e49d2ff1bcafbcace52b4108c5aec3f01 Mon Sep 17 00:00:00 2001 From: dwertent Date: Thu, 17 Feb 2022 09:23:17 +0200 Subject: [PATCH 07/12] Cache accountID only when submitting data --- README.md | 3 +++ cautils/customerloader.go | 15 --------------- clihandler/clisubmit.go | 4 +++- clihandler/cmd/rbac.go | 5 ++++- clihandler/cmd/results.go | 5 ++++- 5 files changed, 14 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index ebaa5320..91011846 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ [![build](https://github.com/armosec/kubescape/actions/workflows/build.yaml/badge.svg)](https://github.com/armosec/kubescape/actions/workflows/build.yaml) [![Go Report Card](https://goreportcard.com/badge/github.com/armosec/kubescape)](https://goreportcard.com/report/github.com/armosec/kubescape) + + Kubescape is a K8s open-source tool providing a multi-cloud K8s single pane of glass, including risk analysis, security compliance, RBAC visualizer and image vulnerabilities scanning. Kubescape scans K8s clusters, YAML files, and HELM charts, detecting misconfigurations according to multiple frameworks (such as the [NSA-CISA](https://www.armosec.io/blog/kubernetes-hardening-guidance-summary-by-armo) , [MITRE ATT&CK®](https://www.microsoft.com/security/blog/2021/03/23/secure-containerized-environments-with-updated-threat-matrix-for-kubernetes/)), software vulnerabilities, and RBAC (role-based-access-control) violations at early stages of the CI/CD pipeline, calculates risk score instantly and shows risk trends over time. It became one of the fastest-growing Kubernetes tools among developers due to its easy-to-use CLI interface, flexible output formats, and automated scanning capabilities, saving Kubernetes users and admins’ precious time, effort, and resources. @@ -48,6 +50,7 @@ Want to contribute? Want to discuss something? Have an issue? * Open a issue, we are trying to respond within 48 hours * [Join us](https://armosec.github.io/kubescape/) in a discussion on our discord server! +[![discord](https://goreportcard.com/badge/github.com/armosec/kubescape)](https://img.shields.io/discord/893048809884643379) [logo](https://armosec.github.io/kubescape/) diff --git a/cautils/customerloader.go b/cautils/customerloader.go index 174b3380..b156e2b2 100644 --- a/cautils/customerloader.go +++ b/cautils/customerloader.go @@ -11,7 +11,6 @@ import ( "github.com/armosec/k8s-interface/k8sinterface" "github.com/armosec/kubescape/cautils/getter" - "github.com/armosec/kubescape/cautils/logger" corev1 "k8s.io/api/core/v1" ) @@ -113,13 +112,6 @@ func NewLocalConfig(backendAPI getter.IBackend, customerGUID, clusterName string lc.backendAPI.SetClientID(lc.configObj.ClientID) lc.backendAPI.SetSecretKey(lc.configObj.SecretKey) - if lc.configObj.AccountID != "" { - if err := lc.SetTenant(); err != nil { - logger.L().Error(err.Error()) - } - } - lc.UpdateCachedConfig() - return lc } @@ -229,13 +221,6 @@ func NewClusterConfig(k8s *k8sinterface.KubernetesApi, backendAPI getter.IBacken c.backendAPI.SetClientID(c.configObj.ClientID) c.backendAPI.SetSecretKey(c.configObj.SecretKey) - // if c.configObj.AccountID != "" { - // if err := c.SetTenant(); err != nil { - // logger.L().Error(err.Error()) - // } - // } - c.UpdateCachedConfig() - return c } diff --git a/clihandler/clisubmit.go b/clihandler/clisubmit.go index c8370335..878fc5f7 100644 --- a/clihandler/clisubmit.go +++ b/clihandler/clisubmit.go @@ -34,7 +34,9 @@ func SubmitExceptions(accountID, excPath string) error { // load cached config tenantConfig := getTenantConfig(accountID, "", getKubernetesApi()) - tenantConfig.SetTenant() + if err := tenantConfig.SetTenant(); err != nil { + logger.L().Error("failed setting account ID", helpers.Error(err)) + } // load exceptions from file loader := getter.NewLoadPolicy([]string{excPath}) diff --git a/clihandler/cmd/rbac.go b/clihandler/cmd/rbac.go index 8d8fbec0..a666a58e 100644 --- a/clihandler/cmd/rbac.go +++ b/clihandler/cmd/rbac.go @@ -5,6 +5,7 @@ import ( "github.com/armosec/kubescape/cautils" "github.com/armosec/kubescape/cautils/getter" "github.com/armosec/kubescape/cautils/logger" + "github.com/armosec/kubescape/cautils/logger/helpers" "github.com/armosec/kubescape/clihandler" "github.com/armosec/kubescape/clihandler/cliinterfaces" reporterv1 "github.com/armosec/kubescape/resultshandling/reporter/v1" @@ -23,7 +24,9 @@ var rabcCmd = &cobra.Command{ // get config clusterConfig := getTenantConfig(submitInfo.Account, "", k8s) - clusterConfig.SetTenant() + if err := clusterConfig.SetTenant(); err != nil { + logger.L().Error("failed setting account ID", helpers.Error(err)) + } // list RBAC rbacObjects := cautils.NewRBACObjects(rbacscanner.NewRbacScannerFromK8sAPI(k8s, clusterConfig.GetAccountID(), clusterConfig.GetClusterName())) diff --git a/clihandler/cmd/results.go b/clihandler/cmd/results.go index d6b25cfa..f7c09896 100644 --- a/clihandler/cmd/results.go +++ b/clihandler/cmd/results.go @@ -8,6 +8,7 @@ import ( "github.com/armosec/k8s-interface/workloadinterface" "github.com/armosec/kubescape/cautils/logger" + "github.com/armosec/kubescape/cautils/logger/helpers" "github.com/armosec/kubescape/clihandler" "github.com/armosec/kubescape/clihandler/cliinterfaces" reporterv1 "github.com/armosec/kubescape/resultshandling/reporter/v1" @@ -63,7 +64,9 @@ var resultsCmd = &cobra.Command{ // get config clusterConfig := getTenantConfig(submitInfo.Account, "", k8s) - clusterConfig.SetTenant() + if err := clusterConfig.SetTenant(); err != nil { + logger.L().Error("failed setting account ID", helpers.Error(err)) + } resultsObjects := NewResultsObject(clusterConfig.GetAccountID(), clusterConfig.GetClusterName(), args[0]) From e95b0f840a53de47bf79fbc1d9f0e0657192f7c7 Mon Sep 17 00:00:00 2001 From: dwertent Date: Thu, 17 Feb 2022 17:47:57 +0200 Subject: [PATCH 08/12] Support zap logger --- cautils/logger/methods.go | 12 +++++---- cautils/logger/zaplogger/logger.go | 26 ++++++++++++++++--- .../reporter/v1/reporteventreceiver.go | 4 +-- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/cautils/logger/methods.go b/cautils/logger/methods.go index 959abe42..e767775e 100644 --- a/cautils/logger/methods.go +++ b/cautils/logger/methods.go @@ -5,6 +5,8 @@ import ( "github.com/armosec/kubescape/cautils/logger/helpers" "github.com/armosec/kubescape/cautils/logger/prettylogger" + "github.com/armosec/kubescape/cautils/logger/zaplogger" + "github.com/mattn/go-isatty" ) type ILogger interface { @@ -32,10 +34,10 @@ func L() ILogger { } func InitializeLogger() { - initializeLogger() -} -func initializeLogger() { - // TODO - support zap logger - l = prettylogger.NewPrettyLogger() + if isatty.IsTerminal(os.Stdout.Fd()) { + l = prettylogger.NewPrettyLogger() + } else { + l = zaplogger.NewZapLogger() + } } diff --git a/cautils/logger/zaplogger/logger.go b/cautils/logger/zaplogger/logger.go index 5300ccfb..bd2c33c5 100644 --- a/cautils/logger/zaplogger/logger.go +++ b/cautils/logger/zaplogger/logger.go @@ -10,20 +10,40 @@ import ( type ZapLogger struct { zapL *zap.Logger + cfg zap.Config } func NewZapLogger() *ZapLogger { + ec := zap.NewProductionEncoderConfig() + ec.EncodeTime = zapcore.RFC3339TimeEncoder + cfg := zap.NewProductionConfig() + cfg.DisableCaller = true + cfg.DisableStacktrace = true + cfg.Encoding = "json" + cfg.EncoderConfig = ec + + zapLogger, err := cfg.Build() + if err != nil { + panic(err) + } return &ZapLogger{ - zapL: zap.L(), + zapL: zapLogger, + cfg: cfg, } } -func (zl *ZapLogger) GetLevel() string { return "" } +func (zl *ZapLogger) GetLevel() string { return zl.cfg.Level.Level().String() } func (zl *ZapLogger) SetWriter(w *os.File) {} +func (zl *ZapLogger) GetWriter() *os.File { return nil } func GetWriter() *os.File { return nil } func (zl *ZapLogger) SetLevel(level string) error { - return nil + l := zapcore.Level(1) + err := l.Set(level) + if err == nil { + zl.cfg.Level.SetLevel(l) + } + return err } func (zl *ZapLogger) Fatal(msg string, details ...helpers.IDetails) { zl.zapL.Fatal(msg, detailsToZapFields(details)...) diff --git a/resultshandling/reporter/v1/reporteventreceiver.go b/resultshandling/reporter/v1/reporteventreceiver.go index cc2cd34a..abdbdcc9 100644 --- a/resultshandling/reporter/v1/reporteventreceiver.go +++ b/resultshandling/reporter/v1/reporteventreceiver.go @@ -44,11 +44,11 @@ func (report *ReportEventReceiver) ActionSendReport(opaSessionObj *cautils.OPASe } 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" + report.message = "WARNING: Failed to publish results. Reason: Unknown accout ID. Run kubescape with the '--account ' flag. Please feel free to contact ARMO team for more details" return nil } if report.clusterName == "" { - report.message = "WARNING: Failed to publish results because the cluster name is Unknown. If you are scanning YAML files the results are not submitted to the Kubescape SaaS" + report.message = "WARNING: Failed to publish results because the cluster name is Unknown. If you are scanning YAML files the results are not submitted to the Kubescape SaaS.Please feel free to contact ARMO team for more details" return nil } From 830ee271690f342267848ed7ffd34f3c5c435bae Mon Sep 17 00:00:00 2001 From: Avinash Upadhyaya Date: Sun, 20 Feb 2022 10:26:40 +0530 Subject: [PATCH 09/12] build: fix release version in Dockerfile --- build/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/Dockerfile b/build/Dockerfile index 20474310..e3e6ff6c 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -3,7 +3,7 @@ FROM golang:1.17-alpine as builder ARG image_version -ENV RELEASE=image_version +ENV RELEASE=$image_version ENV GO111MODULE= From 9d528a80755b466e410d7db9f59d5d06466d38dd Mon Sep 17 00:00:00 2001 From: dwertent Date: Sun, 20 Feb 2022 13:30:05 +0200 Subject: [PATCH 10/12] support setting default cach --- cautils/getter/armoapi.go | 16 +++++++++++++++ cautils/getter/getpoliciesutils.go | 6 +----- cautils/getter/loadpolicy.go | 11 +++++++++- cautils/logger/methods.go | 18 +++++++++++----- cautils/scaninfo.go | 1 + clihandler/cmd/root.go | 33 +++++++++++++++++++++++++++--- 6 files changed, 71 insertions(+), 14 deletions(-) diff --git a/cautils/getter/armoapi.go b/cautils/getter/armoapi.go index 0534f12b..dc482553 100644 --- a/cautils/getter/armoapi.go +++ b/cautils/getter/armoapi.go @@ -27,6 +27,11 @@ var ( armoFEURL = "portal.armo.cloud" armoAUTHURL = "auth.armo.cloud" + armoStageERURL = "report-ks.eustage2.cyberarmorsoft" + armoStageBEURL = "api-stage.armo.cloud" + armoStageFEURL = "armoui.eustage2.cyberarmorsoft.com" + armoStageAUTHURL = "eggauth.eustage2.cyberarmorsoft.com" + armoDevERURL = "report.eudev3.cyberarmorsoft.com" armoDevBEURL = "api-dev.armo.cloud" armoDevFEURL = "armoui-dev.eudev3.cyberarmorsoft.com" @@ -84,6 +89,17 @@ func NewARMOAPIProd() *ArmoAPI { return apiObj } +func NewARMOAPIStaging() *ArmoAPI { + apiObj := newArmoAPI() + + apiObj.apiURL = armoStageBEURL + apiObj.erURL = armoStageERURL + apiObj.feURL = armoStageFEURL + apiObj.authURL = armoStageAUTHURL + + return apiObj +} + func NewARMOAPICustomized(armoERURL, armoBEURL, armoFEURL, armoAUTHURL string) *ArmoAPI { apiObj := newArmoAPI() diff --git a/cautils/getter/getpoliciesutils.go b/cautils/getter/getpoliciesutils.go index 30b82e80..d577234a 100644 --- a/cautils/getter/getpoliciesutils.go +++ b/cautils/getter/getpoliciesutils.go @@ -13,11 +13,7 @@ import ( ) func GetDefaultPath(name string) string { - defaultfilePath := filepath.Join(DefaultLocalStore, name) - if homeDir, err := os.UserHomeDir(); err == nil { - defaultfilePath = filepath.Join(homeDir, defaultfilePath) - } - return defaultfilePath + return filepath.Join(DefaultLocalStore, name) } func SaveInFile(policy interface{}, pathStr string) error { diff --git a/cautils/getter/loadpolicy.go b/cautils/getter/loadpolicy.go index 7ae8c8f5..12d56555 100644 --- a/cautils/getter/loadpolicy.go +++ b/cautils/getter/loadpolicy.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "os" + "path/filepath" "strings" "github.com/armosec/armoapi-go/armotypes" @@ -13,7 +14,15 @@ import ( // ======================================================================================================================= // ============================================== LoadPolicy ============================================================= // ======================================================================================================================= -const DefaultLocalStore = ".kubescape" +var DefaultLocalStore = getCacheDir() + +func getCacheDir() string { + defaultDirPath := ".kubescape" + if homeDir, err := os.UserHomeDir(); err == nil { + defaultDirPath = filepath.Join(homeDir, defaultDirPath) + } + return defaultDirPath +} // Load policies from a local repository type LoadPolicy struct { diff --git a/cautils/logger/methods.go b/cautils/logger/methods.go index e767775e..be208fd2 100644 --- a/cautils/logger/methods.go +++ b/cautils/logger/methods.go @@ -2,6 +2,7 @@ package logger import ( "os" + "strings" "github.com/armosec/kubescape/cautils/logger/helpers" "github.com/armosec/kubescape/cautils/logger/prettylogger" @@ -28,16 +29,23 @@ var l ILogger func L() ILogger { if l == nil { - InitializeLogger() + InitializeLogger("") } return l } -func InitializeLogger() { +func InitializeLogger(loggerName string) { - if isatty.IsTerminal(os.Stdout.Fd()) { - l = prettylogger.NewPrettyLogger() - } else { + switch strings.ToLower(loggerName) { + case "zap": l = zaplogger.NewZapLogger() + case "pretty": + l = prettylogger.NewPrettyLogger() + default: + if isatty.IsTerminal(os.Stdout.Fd()) { + l = prettylogger.NewPrettyLogger() + } else { + l = zaplogger.NewZapLogger() + } } } diff --git a/cautils/scaninfo.go b/cautils/scaninfo.go index eb0c4a4c..128d4ce1 100644 --- a/cautils/scaninfo.go +++ b/cautils/scaninfo.go @@ -73,6 +73,7 @@ type ScanInfo struct { Local bool // Do not submit results Account string // account ID Logger string // logger level + CacheDir string // cached dir KubeContext string // context name FrameworkScan bool // false if scanning control ScanAll bool // true if scan all frameworks diff --git a/clihandler/cmd/root.go b/clihandler/cmd/root.go index 8c20df28..96245611 100644 --- a/clihandler/cmd/root.go +++ b/clihandler/cmd/root.go @@ -3,8 +3,10 @@ package cmd import ( "flag" "fmt" + "os" "strings" + "github.com/armosec/kubescape/cautils" "github.com/armosec/kubescape/cautils/getter" "github.com/armosec/kubescape/cautils/logger" "github.com/armosec/kubescape/cautils/logger/helpers" @@ -31,6 +33,7 @@ var ksExamples = ` var rootCmd = &cobra.Command{ Use: "kubescape", + Version: cautils.BuildNumber, Short: "Kubescape is a tool for testing Kubernetes security posture", Long: `Kubescape is a tool for testing Kubernetes security posture based on NSA \ MITRE ATT&CK® and other frameworks specifications`, Example: ksExamples, @@ -40,20 +43,42 @@ func Execute() { rootCmd.Execute() } func init() { - cobra.OnInitialize(initLogger, initEnvironment) + cobra.OnInitialize(initLogger, initLoggerLevel, initEnvironment, initCacheDir) flag.CommandLine.StringVar(&armoBEURLs, "environment", "", envFlagUsage) rootCmd.PersistentFlags().StringVar(&armoBEURLs, "environment", "", envFlagUsage) rootCmd.PersistentFlags().MarkHidden("environment") - rootCmd.PersistentFlags().StringVar(&scanInfo.Logger, "logger", "info", fmt.Sprintf("Logger level. Supported: %s", strings.Join(helpers.SupportedLevels(), "/"))) + rootCmd.PersistentFlags().StringVarP(&scanInfo.Logger, "logger", "l", helpers.InfoLevel.String(), fmt.Sprintf("Logger level. Supported: %s [$KS_LOGGER]", strings.Join(helpers.SupportedLevels(), "/"))) + rootCmd.PersistentFlags().StringVar(&scanInfo.CacheDir, "cache-dir", getter.DefaultLocalStore, "Cache directory [$KS_CACHE_DIR]") flag.Parse() } func initLogger() { + if l := os.Getenv("KS_LOGGER_NAME"); l != "" { + logger.InitializeLogger(l) + } +} +func initLoggerLevel() { + if scanInfo.Logger != helpers.InfoLevel.String() { + } else if l := os.Getenv("KS_LOGGER"); l != "" { + scanInfo.Logger = l + } if err := logger.L().SetLevel(scanInfo.Logger); err != nil { logger.L().Fatal(fmt.Sprintf("supported levels: %s", strings.Join(helpers.SupportedLevels(), "/")), helpers.Error(err)) } } + +func initCacheDir() { + if scanInfo.CacheDir != getter.DefaultLocalStore { + getter.DefaultLocalStore = scanInfo.CacheDir + } else if cacheDir := os.Getenv("KS_CACHE_DIR"); cacheDir != "" { + getter.DefaultLocalStore = cacheDir + } else { + return // using default cache di location + } + + logger.L().Debug("cache dir updated", helpers.String("path", getter.DefaultLocalStore)) +} func initEnvironment() { urlSlices := strings.Split(armoBEURLs, ",") if len(urlSlices) != 1 && len(urlSlices) < 3 { @@ -62,8 +87,10 @@ func initEnvironment() { switch len(urlSlices) { case 1: switch urlSlices[0] { - case "dev": + case "dev", "development": getter.SetARMOAPIConnector(getter.NewARMOAPIDev()) + case "stage", "staging": + getter.SetARMOAPIConnector(getter.NewARMOAPIStaging()) case "": getter.SetARMOAPIConnector(getter.NewARMOAPIProd()) default: From a6497c1252b3bc21cd00027df204940f19f33ef7 Mon Sep 17 00:00:00 2001 From: dwertent Date: Sun, 20 Feb 2022 19:04:16 +0200 Subject: [PATCH 11/12] fixed python build file --- build.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/build.py b/build.py index e695e811..eeeee049 100644 --- a/build.py +++ b/build.py @@ -49,10 +49,9 @@ def main(): ArmoWebsite = os.getenv("ArmoWebsite") ArmoAuthServer = os.getenv("ArmoAuthServer") - # Create build directory buildDir = getBuildDir() - + ks_file = os.path.join(buildDir, packageName) hash_file = ks_file + ".sha256" @@ -60,13 +59,24 @@ def main(): os.makedirs(buildDir) # Build kubescape - ldflags = "-w -s -X %s=%s -X %s=%s -X %s=%s -X %s=%s -X %s=%s" \ - % (buildUrl, releaseVersion, BE_SERVER_CONST, ArmoBEServer, - ER_SERVER_CONST, ArmoERServer, WEBSITE_CONST, ArmoWebsite, - AUTH_SERVER_CONST, ArmoAuthServer) + ldflags = "-w -s" + if releaseVersion: + ldflags += " -X {}={}".format(buildUrl, releaseVersion) + if ArmoBEServer: + ldflags += " -X {}={}".format(BE_SERVER_CONST, ArmoBEServer) + if ArmoERServer: + ldflags += " -X {}={}".format(ER_SERVER_CONST, ArmoERServer) + if ArmoWebsite: + ldflags += " -X {}={}".format(WEBSITE_CONST, ArmoWebsite) + if ArmoAuthServer: + ldflags += " -X {}={}".format(AUTH_SERVER_CONST, ArmoAuthServer) + + build_command = ["go", "build", "-o", ks_file, "-ldflags" ,ldflags] print("Building kubescape and saving here: {}".format(ks_file)) - status = subprocess.call(["go", "build", "-o", ks_file, "-ldflags" ,ldflags]) + print("Build command: {}".format(" ".join(build_command))) + + status = subprocess.call(build_command) checkStatus(status, "Failed to build kubescape") sha256 = hashlib.sha256() From 990be3afe8ed5e450c05754a8689104d531029db Mon Sep 17 00:00:00 2001 From: dwertent Date: Sun, 20 Feb 2022 20:55:22 +0200 Subject: [PATCH 12/12] remove cat command --- build/Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/build/Dockerfile b/build/Dockerfile index e3e6ff6c..600bcb5e 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -21,7 +21,6 @@ ADD . . RUN python build.py RUN ls -ltr build/ubuntu-latest -RUN cat /work/build/ubuntu-latest/kubescape.sha1 FROM alpine COPY --from=builder /work/build/ubuntu-latest/kubescape /usr/bin/kubescape