fixed rbac submit

This commit is contained in:
David Wertenteil
2022-08-05 00:06:33 +03:00
parent 46696d9eb3
commit 13b37abcb4
23 changed files with 238 additions and 437 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ import (
func getExceptionsCmd(ks meta.IKubescape, submitInfo *metav1.Submit) *cobra.Command {
return &cobra.Command{
Use: "exceptions <full path to exceptins file>",
Use: "exceptions <full path to exceptions file>",
Short: "Submit exceptions to the Kubescape SaaS version",
Args: func(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
+23 -6
View File
@@ -1,27 +1,40 @@
package submit
import (
"fmt"
"github.com/armosec/k8s-interface/k8sinterface"
"github.com/armosec/kubescape/v2/core/cautils"
"github.com/armosec/kubescape/v2/core/cautils/getter"
"github.com/armosec/kubescape/v2/core/meta"
"github.com/armosec/kubescape/v2/core/meta/cliinterfaces"
v1 "github.com/armosec/kubescape/v2/core/meta/datastructures/v1"
reporterv2 "github.com/armosec/kubescape/v2/core/pkg/resultshandling/reporter/v2"
logger "github.com/dwertent/go-logger"
"github.com/dwertent/go-logger/helpers"
reporterv1 "github.com/armosec/kubescape/v2/core/pkg/resultshandling/reporter/v1"
"github.com/google/uuid"
"github.com/armosec/rbac-utils/rbacscanner"
"github.com/spf13/cobra"
)
var (
rbacExamples = `
# Submit cluster's Role-Based Access Control(RBAC)
kubescape submit rbac
# Submit cluster's Role-Based Access Control(RBAC) with account ID
kubescape submit rbac --account-id <account-id>
`
)
// getRBACCmd represents the RBAC command
func getRBACCmd(ks meta.IKubescape, submitInfo *v1.Submit) *cobra.Command {
return &cobra.Command{
Use: "rbac \nExample:\n$ kubescape submit rbac",
Short: "Submit cluster's Role-Based Access Control(RBAC)",
Long: ``,
Use: "rbac",
Example: rbacExamples,
Short: "Submit cluster's Role-Based Access Control(RBAC)",
Long: ``,
RunE: func(cmd *cobra.Command, args []string) error {
k8s := k8sinterface.NewKubernetesApi()
@@ -32,11 +45,15 @@ func getRBACCmd(ks meta.IKubescape, submitInfo *v1.Submit) *cobra.Command {
logger.L().Error("failed setting account ID", helpers.Error(err))
}
if clusterConfig.GetAccountID() == "" {
return fmt.Errorf("account ID is not set, run 'kubescape submit rbac --account-id <account-id>'")
}
// list RBAC
rbacObjects := cautils.NewRBACObjects(rbacscanner.NewRbacScannerFromK8sAPI(k8s, clusterConfig.GetAccountID(), clusterConfig.GetContextName()))
// submit resources
r := reporterv1.NewReportEventReceiver(clusterConfig.GetConfigObj())
r := reporterv2.NewReportEventReceiver(clusterConfig.GetConfigObj(), uuid.NewString(), reporterv2.SubmitContextRBAC)
submitInterfaces := cliinterfaces.SubmitInterfaces{
ClusterConfig: clusterConfig,
+12 -32
View File
@@ -4,20 +4,18 @@ import (
"encoding/json"
"fmt"
"os"
"time"
reporthandlingv2 "github.com/armosec/opa-utils/reporthandling/v2"
"github.com/google/uuid"
"github.com/armosec/k8s-interface/workloadinterface"
"github.com/armosec/kubescape/v2/core/meta"
"github.com/armosec/kubescape/v2/core/meta/cliinterfaces"
v1 "github.com/armosec/kubescape/v2/core/meta/datastructures/v1"
"github.com/armosec/kubescape/v2/core/pkg/resultshandling/reporter"
reporterv1 "github.com/armosec/kubescape/v2/core/pkg/resultshandling/reporter/v1"
reporterv2 "github.com/armosec/kubescape/v2/core/pkg/resultshandling/reporter/v2"
logger "github.com/dwertent/go-logger"
"github.com/dwertent/go-logger/helpers"
"github.com/armosec/opa-utils/reporthandling"
"github.com/google/uuid"
"github.com/spf13/cobra"
)
@@ -37,19 +35,13 @@ func NewResultsObject(customerGUID, clusterName, filePath string) *ResultsObject
}
}
func (resultsObject *ResultsObject) SetResourcesReport() (*reporthandling.PostureReport, error) {
func (resultsObject *ResultsObject) SetResourcesReport() (*reporthandlingv2.PostureReport, error) {
// load framework results from json file
frameworkReports, err := loadResultsFromFile(resultsObject.filePath)
report, err := loadResultsFromFile(resultsObject.filePath)
if err != nil {
return nil, err
}
return &reporthandling.PostureReport{
FrameworkReports: frameworkReports,
ReportID: uuid.NewString(),
ReportGenerationTime: time.Now().UTC(),
CustomerGUID: resultsObject.customerGUID,
ClusterName: resultsObject.clusterName,
}, nil
return report, nil
}
func (resultsObject *ResultsObject) ListAllResources() (map[string]workloadinterface.IMetadata, error) {
@@ -76,15 +68,7 @@ func getResultsCmd(ks meta.IKubescape, submitInfo *v1.Submit) *cobra.Command {
resultsObjects := NewResultsObject(clusterConfig.GetAccountID(), clusterConfig.GetContextName(), args[0])
// submit resources
var r reporter.IReport
switch formatVersion {
case "v2":
r = reporterv2.NewReportEventReceiver(clusterConfig.GetConfigObj(), "")
default:
logger.L().Warning("Deprecated results version. run with '--format-version' flag", helpers.String("your version", formatVersion), helpers.String("latest version", "v2"))
r = reporterv1.NewReportEventReceiver(clusterConfig.GetConfigObj())
}
r := reporterv2.NewReportEventReceiver(clusterConfig.GetConfigObj(), uuid.NewString(), reporterv2.SubmitContextScan)
submitInterfaces := cliinterfaces.SubmitInterfaces{
ClusterConfig: clusterConfig,
@@ -102,18 +86,14 @@ func getResultsCmd(ks meta.IKubescape, submitInfo *v1.Submit) *cobra.Command {
return resultsCmd
}
func loadResultsFromFile(filePath string) ([]reporthandling.FrameworkReport, error) {
frameworkReports := []reporthandling.FrameworkReport{}
func loadResultsFromFile(filePath string) (*reporthandlingv2.PostureReport, error) {
report := &reporthandlingv2.PostureReport{}
f, err := os.ReadFile(filePath)
if err != nil {
return nil, err
}
if err = json.Unmarshal(f, &frameworkReports); err != nil {
frameworkReport := reporthandling.FrameworkReport{}
if err = json.Unmarshal(f, &frameworkReport); err != nil {
return frameworkReports, err
}
frameworkReports = append(frameworkReports, frameworkReport)
if err = json.Unmarshal(f, report); err != nil {
return report, fmt.Errorf("failed to unmarshal results file: %s, make sure you run kubescape with '--format=json --format-version=v2'", err.Error())
}
return frameworkReports, nil
return report, nil
}
+1 -12
View File
@@ -20,7 +20,6 @@ type OPASessionObj struct {
AllResources map[string]workloadinterface.IMetadata // all scanned resources, map[<rtesource ID>]<resource>
ResourcesResult map[string]resourcesresults.Result // resources scan results, map[<rtesource ID>]<resource result>
ResourceSource map[string]reporthandling.Source // resources sources, map[<rtesource ID>]<resource result>
PostureReport *reporthandling.PostureReport // scan results v1 - Remove
Report *reporthandlingv2.PostureReport // scan results v2 - Remove
Exceptions []armotypes.PostureExceptionPolicy // list of exceptions to apply on scan results
RegoInputData RegoInputData // input passed to rgo for scanning. map[<control name>][<input arguments>]
@@ -41,11 +40,7 @@ func NewOPASessionObj(frameworks []reporthandling.Framework, k8sResources *K8SRe
ResourceToControlsMap: make(map[string][]string),
ResourceSource: make(map[string]reporthandling.Source),
SessionID: scanInfo.ScanID,
PostureReport: &reporthandling.PostureReport{
ClusterName: ClusterName,
CustomerGUID: CustomerGUID,
},
Metadata: scanInfoToScanMetadata(scanInfo),
Metadata: scanInfoToScanMetadata(scanInfo),
}
}
@@ -56,12 +51,6 @@ func NewOPASessionObjMock() *OPASessionObj {
AllResources: make(map[string]workloadinterface.IMetadata),
ResourcesResult: make(map[string]resourcesresults.Result),
Report: &reporthandlingv2.PostureReport{},
PostureReport: &reporthandling.PostureReport{
ClusterName: "",
CustomerGUID: "",
ReportID: "",
JobID: "",
},
Metadata: &reporthandlingv2.Metadata{
ScanMetadata: reporthandlingv2.ScanMetadata{
ScanningTarget: 0,
+12 -4
View File
@@ -4,8 +4,9 @@ import (
"encoding/json"
"time"
reporthandlingv2 "github.com/armosec/opa-utils/reporthandling/v2"
"github.com/armosec/k8s-interface/workloadinterface"
"github.com/armosec/opa-utils/reporthandling"
"github.com/armosec/rbac-utils/rbacscanner"
"github.com/armosec/rbac-utils/rbacutils"
"github.com/google/uuid"
@@ -19,12 +20,19 @@ func NewRBACObjects(scanner *rbacscanner.RbacScannerFromK8sAPI) *RBACObjects {
return &RBACObjects{scanner: scanner}
}
func (rbacObjects *RBACObjects) SetResourcesReport() (*reporthandling.PostureReport, error) {
return &reporthandling.PostureReport{
func (rbacObjects *RBACObjects) SetResourcesReport() (*reporthandlingv2.PostureReport, error) {
return &reporthandlingv2.PostureReport{
ReportID: uuid.NewString(),
ReportGenerationTime: time.Now().UTC(),
CustomerGUID: rbacObjects.scanner.CustomerGUID,
ClusterName: rbacObjects.scanner.ClusterName,
Metadata: reporthandlingv2.Metadata{
ContextMetadata: reporthandlingv2.ContextMetadata{
ClusterContextMetadata: &reporthandlingv2.ClusterMetadata{
ContextName: rbacObjects.scanner.ClusterName,
},
},
},
}, nil
}
@@ -53,7 +61,7 @@ func (rbacObjects *RBACObjects) rbacObjectsToResources(resources *rbacutils.Rbac
************************************************************************************************************************
*/
// wrap rbac aggregated objects in IMetadata and add to allresources
// wrap rbac aggregated objects in IMetadata and add to AllResources
// TODO - DEPRECATE SA2WLIDmap
SA2WLIDmapIMeta, err := rbacutils.SA2WLIDmapIMetadataWrapper(resources.SA2WLIDmap)
if err != nil {
+4 -5
View File
@@ -7,10 +7,8 @@ import (
"github.com/armosec/opa-utils/reporthandling/results/v1/reportsummary"
)
func ReportV2ToV1(opaSessionObj *OPASessionObj) {
if len(opaSessionObj.PostureReport.FrameworkReports) > 0 {
return // report already converted
}
func ReportV2ToV1(opaSessionObj *OPASessionObj) *reporthandling.PostureReport {
report := &reporthandling.PostureReport{}
// opaSessionObj.PostureReport.ClusterCloudProvider = opaSessionObj.Report.ClusterCloudProvider
frameworks := []reporthandling.FrameworkReport{}
@@ -53,7 +51,8 @@ func ReportV2ToV1(opaSessionObj *OPASessionObj) {
// scoreutil := score.NewScore(opaSessionObj.AllResources)
// scoreutil.Calculate(frameworks)
opaSessionObj.PostureReport.FrameworkReports = frameworks
report.FrameworkReports = frameworks
return report
}
func controlReportV2ToV1(opaSessionObj *OPASessionObj, frameworkName string, controls map[string]reportsummary.ControlSummary) []reporthandling.ControlReport {
+6 -2
View File
@@ -48,9 +48,13 @@ func getRBACHandler(tenantConfig cautils.ITenantConfig, k8s *k8sinterface.Kubern
return nil
}
func getReporter(tenantConfig cautils.ITenantConfig, reportID string, submit, fwScan bool) reporter.IReport {
func getReporter(tenantConfig cautils.ITenantConfig, reportID string, submit, fwScan bool, scanningContext cautils.ScanningContext) reporter.IReport {
if submit {
return reporterv2.NewReportEventReceiver(tenantConfig.GetConfigObj(), reportID)
submitData := reporterv2.SubmitContextScan
if scanningContext != cautils.ContextCluster {
submitData = reporterv2.SubmitContextRBAC
}
return reporterv2.NewReportEventReceiver(tenantConfig.GetConfigObj(), reportID, submitData)
}
if tenantConfig.GetAccountID() == "" {
// Add link only when scanning a cluster using a framework
+1 -1
View File
@@ -86,7 +86,7 @@ func getInterfaces(scanInfo *cautils.ScanInfo) componentInterfaces {
// ================== setup reporter & printer objects ======================================
// reporting behavior - setup reporter
reportHandler := getReporter(tenantConfig, scanInfo.ScanID, scanInfo.Submit, scanInfo.FrameworkScan)
reportHandler := getReporter(tenantConfig, scanInfo.ScanID, scanInfo.Submit, scanInfo.FrameworkScan, scanInfo.GetScanningContext())
// setup printer
printerHandler := resultshandling.NewPrinter(scanInfo.Format, scanInfo.FormatVersion, scanInfo.VerboseMode, cautils.ViewTypes(scanInfo.View))
+8 -2
View File
@@ -4,6 +4,7 @@ import (
"github.com/armosec/kubescape/v2/core/cautils"
"github.com/armosec/kubescape/v2/core/cautils/getter"
"github.com/armosec/kubescape/v2/core/meta/cliinterfaces"
logger "github.com/dwertent/go-logger"
"github.com/dwertent/go-logger/helpers"
)
@@ -11,7 +12,7 @@ import (
func (ks *Kubescape) Submit(submitInterfaces cliinterfaces.SubmitInterfaces) error {
// list resources
postureReport, err := submitInterfaces.SubmitObjects.SetResourcesReport()
report, err := submitInterfaces.SubmitObjects.SetResourcesReport()
if err != nil {
return err
}
@@ -20,7 +21,12 @@ func (ks *Kubescape) Submit(submitInterfaces cliinterfaces.SubmitInterfaces) err
return err
}
// report
if err := submitInterfaces.Reporter.Submit(&cautils.OPASessionObj{PostureReport: postureReport, AllResources: allresources}); err != nil {
o := &cautils.OPASessionObj{
Report: report,
AllResources: allresources,
Metadata: &report.Metadata,
}
if err := submitInterfaces.Reporter.Submit(o); err != nil {
return err
}
logger.L().Success("Data has been submitted successfully")
+2 -2
View File
@@ -4,11 +4,11 @@ import (
"github.com/armosec/k8s-interface/workloadinterface"
"github.com/armosec/kubescape/v2/core/cautils"
"github.com/armosec/kubescape/v2/core/pkg/resultshandling/reporter"
"github.com/armosec/opa-utils/reporthandling"
reporthandlingv2 "github.com/armosec/opa-utils/reporthandling/v2"
)
type ISubmitObjects interface {
SetResourcesReport() (*reporthandling.PostureReport, error)
SetResourcesReport() (*reporthandlingv2.PostureReport, error)
ListAllResources() (map[string]workloadinterface.IMetadata, error)
}
@@ -6,12 +6,10 @@ import (
"github.com/armosec/armoapi-go/armotypes"
"github.com/armosec/kubescape/v2/core/cautils"
"github.com/armosec/kubescape/v2/core/mocks"
"github.com/armosec/opa-utils/objectsenvelopes"
"github.com/armosec/opa-utils/reporthandling"
"github.com/armosec/opa-utils/resources"
"github.com/stretchr/testify/assert"
"github.com/armosec/k8s-interface/k8sinterface"
"github.com/armosec/k8s-interface/workloadinterface"
// _ "k8s.io/client-go/plugin/pkg/client/auth"
)
@@ -19,43 +17,6 @@ import (
func NewOPAProcessorMock() *OPAProcessor {
return &OPAProcessor{}
}
func TestProcess(t *testing.T) {
// set k8s
k8sResources := make(cautils.K8SResources)
allResources := make(map[string]workloadinterface.IMetadata)
imetaObj := objectsenvelopes.ListMapToMeta(k8sinterface.ConvertUnstructuredSliceToMap(k8sinterface.V1KubeSystemNamespaceMock().Items))
for i := range imetaObj {
allResources[imetaObj[i].GetID()] = imetaObj[i]
}
k8sResources["/v1/pods"] = workloadinterface.ListMetaIDs(imetaObj)
// set opaSessionObj
opaSessionObj := cautils.NewOPASessionObjMock()
opaSessionObj.Policies = []reporthandling.Framework{*reporthandling.MockFrameworkA()}
policies := ConvertFrameworksToPolicies(opaSessionObj.Policies, "")
opaSessionObj.K8SResources = &k8sResources
opaSessionObj.AllResources = allResources
opap := NewOPAProcessor(opaSessionObj, resources.NewRegoDependenciesDataMock()) // ,
opap.Process(policies)
opap.updateResults()
for _, f := range opap.PostureReport.FrameworkReports {
for _, c := range f.ControlReports {
for _, r := range c.RuleReports {
for _, rr := range r.RuleResponses {
// t.Errorf("AlertMessage: %v", rr.AlertMessage)
if rr.Exception != nil {
t.Errorf("Exception: %v", rr.Exception)
}
}
}
}
}
}
func TestProcessResourcesResult(t *testing.T) {
// set k8s
@@ -27,15 +27,15 @@ func (jsonPrinter *JsonPrinter) Score(score float32) {
}
func (jsonPrinter *JsonPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
cautils.ReportV2ToV1(opaSessionObj)
report := cautils.ReportV2ToV1(opaSessionObj)
var postureReportStr []byte
var err error
if len(opaSessionObj.PostureReport.FrameworkReports) == 1 {
postureReportStr, err = json.Marshal(opaSessionObj.PostureReport.FrameworkReports[0])
if len(report.FrameworkReports) == 1 {
postureReportStr, err = json.Marshal(report.FrameworkReports[0])
} else {
postureReportStr, err = json.Marshal(opaSessionObj.PostureReport.FrameworkReports)
postureReportStr, err = json.Marshal(report.FrameworkReports)
}
if err != nil {
@@ -87,9 +87,9 @@ func (printer *PrometheusPrinter) printReports(allResources map[string]workloadi
}
func (printer *PrometheusPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
cautils.ReportV2ToV1(opaSessionObj)
report := cautils.ReportV2ToV1(opaSessionObj)
err := printer.printReports(opaSessionObj.AllResources, opaSessionObj.PostureReport.FrameworkReports)
err := printer.printReports(opaSessionObj.AllResources, report.FrameworkReports)
if err != nil {
logger.L().Fatal(err.Error())
}
@@ -1,185 +0,0 @@
package v1
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"os"
"github.com/armosec/k8s-interface/workloadinterface"
"github.com/armosec/kubescape/v2/core/cautils"
"github.com/armosec/kubescape/v2/core/cautils/getter"
v2 "github.com/armosec/kubescape/v2/core/pkg/resultshandling/reporter/v2"
"github.com/armosec/opa-utils/reporthandling"
logger "github.com/dwertent/go-logger"
"github.com/dwertent/go-logger/helpers"
"github.com/google/uuid"
)
const MAX_REPORT_SIZE = 2097152 // 2 MB
type ReportEventReceiver struct {
httpClient *http.Client
clusterName string
customerGUID string
eventReceiverURL *url.URL
token string
customerAdminEMail string
message string
}
func NewReportEventReceiver(tenantConfig *cautils.ConfigObj) *ReportEventReceiver {
return &ReportEventReceiver{
httpClient: &http.Client{},
clusterName: tenantConfig.ClusterName,
customerGUID: tenantConfig.AccountID,
token: tenantConfig.Token,
customerAdminEMail: tenantConfig.CustomerAdminEMail,
}
}
func (report *ReportEventReceiver) Submit(opaSessionObj *cautils.OPASessionObj) error {
if opaSessionObj.PostureReport == nil && opaSessionObj.Report != nil {
cautils.ReportV2ToV1(opaSessionObj)
}
if report.customerGUID == "" {
report.message = "WARNING: Failed to publish results. Reason: Unknown accout ID. Run kubescape with the '--account <account ID>' 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.Please feel free to contact ARMO team for more details"
return nil
}
opaSessionObj.PostureReport.ReportID = uuid.NewString()
opaSessionObj.PostureReport.CustomerGUID = report.customerGUID
opaSessionObj.PostureReport.ClusterName = report.clusterName
if err := report.prepareReport(opaSessionObj.PostureReport, opaSessionObj.AllResources); err != nil {
report.message = err.Error()
return nil
}
return nil
}
func (report *ReportEventReceiver) SetCustomerGUID(customerGUID string) {
report.customerGUID = customerGUID
}
func (report *ReportEventReceiver) SetClusterName(clusterName string) {
report.clusterName = cautils.AdoptClusterName(clusterName) // clean cluster name
}
func (report *ReportEventReceiver) prepareReport(postureReport *reporthandling.PostureReport, allResources map[string]workloadinterface.IMetadata) error {
report.initEventReceiverURL()
host := hostToString(report.eventReceiverURL, postureReport.ReportID)
cautils.StartSpinner()
// send framework results
if err := report.sendReport(host, postureReport); err != nil {
cautils.StopSpinner()
return err
}
// send resources
if err := report.sendResources(host, postureReport, allResources); err != nil {
cautils.StopSpinner()
return err
}
cautils.StopSpinner()
report.generateMessage()
return nil
}
func (report *ReportEventReceiver) sendResources(host string, postureReport *reporthandling.PostureReport, allResources map[string]workloadinterface.IMetadata) error {
splittedPostureReport := setPaginationReport(postureReport)
counter := 0
for _, v := range allResources {
r, err := json.Marshal(*iMetaToResource(v))
if err != nil {
return fmt.Errorf("failed to unmarshal resource '%s', reason: %v", v.GetID(), err)
}
if counter+len(r) >= MAX_REPORT_SIZE && len(splittedPostureReport.Resources) > 0 {
// send report
if err := report.sendReport(host, splittedPostureReport); err != nil {
return err
}
// delete resources
splittedPostureReport.Resources = []reporthandling.Resource{}
// restart counter
counter = 0
}
counter += len(r)
splittedPostureReport.Resources = append(splittedPostureReport.Resources, *iMetaToResource(v))
}
return report.sendReport(host, splittedPostureReport)
}
func (report *ReportEventReceiver) sendReport(host string, postureReport *reporthandling.PostureReport) error {
reqBody, err := json.Marshal(postureReport)
if err != nil {
return fmt.Errorf("in 'sendReport' failed to json.Marshal, reason: %v", err)
}
msg, err := getter.HttpPost(report.httpClient, host, nil, reqBody)
if err != nil {
return fmt.Errorf("%s, %v:%s", host, err, msg)
}
return nil
}
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.Host = getter.GetArmoAPIConnector().GetFrontendURL()
v2.ParseHost(&u)
if report.customerAdminEMail != "" {
logger.L().Debug("", helpers.String("account ID", report.customerGUID))
report.message = fmt.Sprintf("%s %s/configuration-scanning/%s", message, u.String(), report.clusterName)
return
}
u.Path = "account/sign-up"
q := u.Query()
q.Add("invitationToken", report.token)
q.Add("customerGUID", report.customerGUID)
u.RawQuery = q.Encode()
report.message = fmt.Sprintf("%s %s", message, u.String())
}
func (report *ReportEventReceiver) GetURL() string {
return getter.GetArmoAPIConnector().GetFrontendURL()
}
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)
// }
@@ -1,48 +0,0 @@
package v1
import (
"net/url"
"github.com/armosec/k8s-interface/workloadinterface"
"github.com/armosec/kubescape/v2/core/cautils/getter"
v2 "github.com/armosec/kubescape/v2/core/pkg/resultshandling/reporter/v2"
"github.com/armosec/opa-utils/reporthandling"
"github.com/google/uuid"
)
func (report *ReportEventReceiver) initEventReceiverURL() {
urlObj := url.URL{}
urlObj.Host = getter.GetArmoAPIConnector().GetReportReceiverURL()
v2.ParseHost(&urlObj)
urlObj.Path = "/k8s/postureReport"
q := urlObj.Query()
q.Add("customerGUID", uuid.MustParse(report.customerGUID).String())
q.Add("clusterName", report.clusterName)
urlObj.RawQuery = q.Encode()
report.eventReceiverURL = &urlObj
}
func hostToString(host *url.URL, reportID string) string {
q := host.Query()
q.Add("reportID", reportID) // TODO - do we add the reportID?
host.RawQuery = q.Encode()
return host.String()
}
func setPaginationReport(postureReport *reporthandling.PostureReport) *reporthandling.PostureReport {
return &reporthandling.PostureReport{
CustomerGUID: postureReport.CustomerGUID,
ClusterName: postureReport.ClusterName,
ReportID: postureReport.ReportID,
ReportGenerationTime: postureReport.ReportGenerationTime,
}
}
func iMetaToResource(obj workloadinterface.IMetadata) *reporthandling.Resource {
return &reporthandling.Resource{
ResourceID: obj.GetID(),
Object: obj.GetObject(),
}
}
@@ -1,20 +0,0 @@
package v1
import (
"net/url"
"testing"
)
func TestHostToString(t *testing.T) {
host := url.URL{
Scheme: "https",
Host: "report.eudev3.cyberarmorsoft.com",
Path: "k8srestapi/v1/postureReport",
RawQuery: "cluster=openrasty_seal-7fvz&customerGUID=5d817063-096f-4d91-b39b-8665240080af",
}
expectedHost := "https://report.eudev3.cyberarmorsoft.com/k8srestapi/v1/postureReport?cluster=openrasty_seal-7fvz&customerGUID=5d817063-096f-4d91-b39b-8665240080af&reportID=ffdd2a00-4dc8-4bf3-b97a-a6d4fd198a41"
receivedHost := hostToString(&host, "ffdd2a00-4dc8-4bf3-b97a-a6d4fd198a41")
if receivedHost != expectedHost {
t.Errorf("%s != %s", receivedHost, expectedHost)
}
}
@@ -1,48 +0,0 @@
package v2
import (
"testing"
"github.com/armosec/kubescape/v2/core/cautils"
"github.com/stretchr/testify/assert"
)
func TestGetURL(t *testing.T) {
// Test submit and registered url
{
reporter := NewReportEventReceiver(
&cautils.ConfigObj{
AccountID: "1234",
Token: "token",
CustomerAdminEMail: "my@email",
ClusterName: "test",
},
"",
)
assert.Equal(t, "https://cloud.armosec.io/configuration-scanning/test?utm_campaign=Submit&utm_medium=CLI&utm_source=GitHub", reporter.GetURL())
}
// Test submit and NOT registered url
{
reporter := NewReportEventReceiver(
&cautils.ConfigObj{
AccountID: "1234",
Token: "token",
ClusterName: "test",
},
"",
)
assert.Equal(t, "https://cloud.armosec.io/account/sign-up?customerGUID=1234&invitationToken=token&utm_campaign=Submit&utm_medium=CLI&utm_source=GitHub", reporter.GetURL())
}
// Test None submit url
{
reporter := NewReportMock(NO_SUBMIT_QUERY, "")
assert.Equal(t, "https://cloud.armosec.io/account/sign-up?utm_source=GitHub&utm_medium=CLI&utm_campaign=no_submit", reporter.GetURL())
}
// Test None report url
{
reporter := NewReportMock("", "")
assert.Equal(t, "https://cloud.armosec.io/account/sign-up", reporter.GetURL())
}
}
@@ -20,6 +20,14 @@ import (
const MAX_REPORT_SIZE = 2097152 // 2 MB
type SubmitContext string
const (
SubmitContextScan SubmitContext = "scan"
SubmitContextRBAC SubmitContext = "rbac"
SubmitContextRepository SubmitContext = "repository"
)
type ReportEventReceiver struct {
httpClient *http.Client
clusterName string
@@ -29,9 +37,10 @@ type ReportEventReceiver struct {
customerAdminEMail string
message string
reportID string
submitContext SubmitContext
}
func NewReportEventReceiver(tenantConfig *cautils.ConfigObj, reportID string) *ReportEventReceiver {
func NewReportEventReceiver(tenantConfig *cautils.ConfigObj, reportID string, submitContext SubmitContext) *ReportEventReceiver {
return &ReportEventReceiver{
httpClient: &http.Client{},
clusterName: tenantConfig.ClusterName,
@@ -39,6 +48,7 @@ func NewReportEventReceiver(tenantConfig *cautils.ConfigObj, reportID string) *R
token: tenantConfig.Token,
customerAdminEMail: tenantConfig.CustomerAdminEMail,
reportID: reportID,
submitContext: submitContext,
}
}
@@ -95,21 +105,11 @@ func (report *ReportEventReceiver) prepareReport(opaSessionObj *cautils.OPASessi
func (report *ReportEventReceiver) GetURL() string {
u := url.URL{}
u.Host = getter.GetArmoAPIConnector().GetFrontendURL()
ParseHost(&u)
parseHost(&u)
report.addPathURL(&u)
q := u.Query()
if report.customerAdminEMail != "" || report.token == "" { // data has been submitted
if report.clusterName != "" {
u.Path = fmt.Sprintf("configuration-scanning/%s", report.clusterName)
} else {
u.Path = fmt.Sprintf("repositories-scan/%s", report.reportID)
}
} else {
u.Path = "account/sign-up"
q.Add("invitationToken", report.token)
q.Add("customerGUID", report.customerGUID)
}
q.Add("utm_source", "GitHub")
q.Add("utm_medium", "CLI")
q.Add("utm_campaign", "Submit")
@@ -226,3 +226,24 @@ func (report *ReportEventReceiver) DisplayReportURL() {
cautils.InfoTextDisplay(os.Stderr, fmt.Sprintf("\n\n%s\n\n", report.message))
}
}
func (report *ReportEventReceiver) addPathURL(urlObj *url.URL) {
if report.customerAdminEMail != "" || report.token == "" { // data has been submitted
switch report.submitContext {
case SubmitContextScan:
urlObj.Path = fmt.Sprintf("configuration-scanning/%s", report.clusterName)
case SubmitContextRBAC:
urlObj.Path = fmt.Sprintf("rbac-visualizer")
case SubmitContextRepository:
urlObj.Path = fmt.Sprintf("repository-scanning/%s", report.clusterName)
}
return
}
urlObj.Path = "account/sign-up"
q := urlObj.Query()
q.Add("invitationToken", report.token)
q.Add("customerGUID", report.customerGUID)
urlObj.RawQuery = q.Encode()
}
@@ -0,0 +1,118 @@
package v2
import (
"net/url"
"testing"
"github.com/armosec/kubescape/v2/core/cautils"
"github.com/stretchr/testify/assert"
)
func TestReportEventReceiver_addPathURL(t *testing.T) {
tests := []struct {
name string
report *ReportEventReceiver
urlObj *url.URL
want *url.URL
}{
{
name: "add scan path",
report: &ReportEventReceiver{
clusterName: "test",
customerGUID: "FFFF",
token: "XXXX",
customerAdminEMail: "test@test",
reportID: "1234",
submitContext: SubmitContextScan,
},
urlObj: &url.URL{
Scheme: "https",
Host: "localhost:8080",
},
want: &url.URL{
Scheme: "https",
Host: "localhost:8080",
Path: "configuration-scanning/test",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.report.addPathURL(tt.urlObj)
assert.Equal(t, tt.want.String(), tt.urlObj.String())
})
}
}
func TestGetURL(t *testing.T) {
// Test submit and registered url
{
reporter := NewReportEventReceiver(
&cautils.ConfigObj{
AccountID: "1234",
Token: "token",
CustomerAdminEMail: "my@email",
ClusterName: "test",
},
"",
SubmitContextScan,
)
assert.Equal(t, "https://cloud.armosec.io/configuration-scanning/test?utm_campaign=Submit&utm_medium=CLI&utm_source=GitHub", reporter.GetURL())
}
// Test rbac submit and registered url
{
reporter := NewReportEventReceiver(
&cautils.ConfigObj{
AccountID: "1234",
Token: "token",
CustomerAdminEMail: "my@email",
ClusterName: "test",
},
"",
SubmitContextRBAC,
)
assert.Equal(t, "https://cloud.armosec.io/rbac-visualizer?utm_campaign=Submit&utm_medium=CLI&utm_source=GitHub", reporter.GetURL())
}
// Test repo submit and registered url
{
reporter := NewReportEventReceiver(
&cautils.ConfigObj{
AccountID: "1234",
Token: "token",
CustomerAdminEMail: "my@email",
ClusterName: "test",
},
"",
SubmitContextRepository,
)
assert.Equal(t, "https://cloud.armosec.io/repository-scanning/test?utm_campaign=Submit&utm_medium=CLI&utm_source=GitHub", reporter.GetURL())
}
// Test submit and NOT registered url
{
reporter := NewReportEventReceiver(
&cautils.ConfigObj{
AccountID: "1234",
Token: "token",
ClusterName: "test",
},
"",
SubmitContextScan,
)
assert.Equal(t, "https://cloud.armosec.io/account/sign-up?customerGUID=1234&invitationToken=token&utm_campaign=Submit&utm_medium=CLI&utm_source=GitHub", reporter.GetURL())
}
// Test None submit url
{
reporter := NewReportMock(NO_SUBMIT_QUERY, "")
assert.Equal(t, "https://cloud.armosec.io/account/sign-up?utm_source=GitHub&utm_medium=CLI&utm_campaign=no_submit", reporter.GetURL())
}
// Test None report url
{
reporter := NewReportMock("", "")
assert.Equal(t, "https://cloud.armosec.io/account/sign-up", reporter.GetURL())
}
}
@@ -12,7 +12,8 @@ import (
func (report *ReportEventReceiver) initEventReceiverURL() {
urlObj := url.URL{}
urlObj.Host = getter.GetArmoAPIConnector().GetReportReceiverURL()
ParseHost(&urlObj)
parseHost(&urlObj)
urlObj.Path = "/k8s/v2/postureReport"
q := urlObj.Query()
q.Add("customerGUID", uuid.MustParse(report.customerGUID).String())
@@ -23,7 +23,7 @@ func maskID(id string) string {
return strings.TrimSuffix(str, sep)
}
func ParseHost(urlObj *url.URL) {
func parseHost(urlObj *url.URL) {
if strings.Contains(urlObj.Host, "http://") {
urlObj.Scheme = "http"
urlObj.Host = strings.Replace(urlObj.Host, "http://", "", 1)
@@ -11,27 +11,27 @@ func TestParseHost(t *testing.T) {
urlObj := url.URL{}
urlObj.Host = "http://localhost:7555"
ParseHost(&urlObj)
parseHost(&urlObj)
assert.Equal(t, "http", urlObj.Scheme)
assert.Equal(t, "localhost:7555", urlObj.Host)
urlObj.Host = "https://localhost:7555"
ParseHost(&urlObj)
parseHost(&urlObj)
assert.Equal(t, "https", urlObj.Scheme)
assert.Equal(t, "localhost:7555", urlObj.Host)
urlObj.Host = "http://portal-dev.armo.cloud"
ParseHost(&urlObj)
parseHost(&urlObj)
assert.Equal(t, "http", urlObj.Scheme)
assert.Equal(t, "portal-dev.armo.cloud", urlObj.Host)
urlObj.Host = "https://portal-dev.armo.cloud"
ParseHost(&urlObj)
parseHost(&urlObj)
assert.Equal(t, "https", urlObj.Scheme)
assert.Equal(t, "portal-dev.armo.cloud", urlObj.Host)
urlObj.Host = "portal-dev.armo.cloud"
ParseHost(&urlObj)
parseHost(&urlObj)
assert.Equal(t, "https", urlObj.Scheme)
assert.Equal(t, "portal-dev.armo.cloud", urlObj.Host)
-2
View File
@@ -26,8 +26,6 @@ const (
func (su *ScoreWrapper) Calculate(reportVersion PostureReportVersion) error {
switch reportVersion {
case EPostureReportV1:
return su.scoreUtil.Calculate(su.opaSessionObj.PostureReport.FrameworkReports)
case EPostureReportV2:
return su.scoreUtil.CalculatePostureReportV2(su.opaSessionObj.Report)
}