Merge remote-tracking branch 'upstream/dev'

This commit is contained in:
Daniel-GrunbergerCA
2021-12-21 13:37:32 +02:00
17 changed files with 104 additions and 94 deletions
+22 -19
View File
@@ -37,6 +37,18 @@ func getInterfaces(scanInfo *cautils.ScanInfo) componentInterfaces {
setSubmitBehavior(scanInfo, tenantConfig)
hostSensorHandler := getHostSensorHandler(scanInfo, k8s)
if err := hostSensorHandler.Init(); err != nil {
errMsg := "failed to init host sensor"
if scanInfo.VerboseMode {
errMsg = fmt.Sprintf("%s: %v", errMsg, err)
}
cautils.ErrorDisplay(errMsg)
hostSensorHandler = &hostsensorutils.HostSensorHandlerMock{}
}
// excluding hostsensor namespace
if len(scanInfo.IncludeNamespaces) == 0 && hostSensorHandler.GetNamespace() != "" {
scanInfo.ExcludedNamespaces = fmt.Sprintf("%s,%s", scanInfo.ExcludedNamespaces, hostSensorHandler.GetNamespace())
}
resourceHandler := getResourceHandler(scanInfo, tenantConfig, k8s, hostSensorHandler)
@@ -73,28 +85,19 @@ func ScanCliSetup(scanInfo *cautils.ScanInfo) error {
interfaces.report.SetClusterName(interfaces.tenantConfig.GetClusterName())
interfaces.report.SetCustomerGUID(interfaces.tenantConfig.GetCustomerGUID())
if err := interfaces.hostSensorHandler.Init(); err != nil {
errMsg := "failed to init host sensor"
if scanInfo.VerboseMode {
errMsg = fmt.Sprintf("%s: %v", errMsg, err)
}
cautils.ErrorDisplay(errMsg)
} else if len(scanInfo.IncludeNamespaces) == 0 && interfaces.hostSensorHandler.GetNamespace() != "" {
scanInfo.ExcludedNamespaces = fmt.Sprintf("%s,%s", scanInfo.ExcludedNamespaces, interfaces.hostSensorHandler)
defer func() {
if err := interfaces.hostSensorHandler.TearDown(); err != nil {
errMsg := "failed to tear down host sensor"
if scanInfo.VerboseMode {
errMsg = fmt.Sprintf("%s: %v", errMsg, err)
}
cautils.ErrorDisplay(errMsg)
}
}()
}
// set policy getter only after setting the customerGUID
setPolicyGetter(scanInfo, interfaces.tenantConfig.GetCustomerGUID())
defer func() {
if err := interfaces.hostSensorHandler.TearDown(); err != nil {
errMsg := "failed to tear down host sensor"
if scanInfo.VerboseMode {
errMsg = fmt.Sprintf("%s: %v", errMsg, err)
}
cautils.ErrorDisplay(errMsg)
}
}()
// cli handler setup
go func() {
// policy handler setup
-1
View File
@@ -70,7 +70,6 @@ func getHostSensorHandler(scanInfo *cautils.ScanInfo, k8s *k8sinterface.Kubernet
}
return &hostsensorutils.HostSensorHandlerMock{}
}
func getFieldSelector(scanInfo *cautils.ScanInfo) resourcehandler.IFieldSelector {
if scanInfo.IncludeNamespaces != "" {
return resourcehandler.NewIncludeSelector(scanInfo.IncludeNamespaces)
+3 -3
View File
@@ -4,11 +4,11 @@ go 1.17
require (
github.com/armosec/armoapi-go v0.0.23
github.com/armosec/k8s-interface v0.0.45
github.com/armosec/opa-utils v0.0.68
github.com/armosec/k8s-interface v0.0.50
github.com/armosec/opa-utils v0.0.75
github.com/armosec/rbac-utils v0.0.9
github.com/armosec/utils-go v0.0.3
github.com/briandowns/spinner v1.16.0
github.com/briandowns/spinner v1.18.0
github.com/enescakir/emoji v1.0.0
github.com/fatih/color v1.13.0
github.com/gofrs/uuid v4.1.0+incompatible
+6 -7
View File
@@ -88,12 +88,11 @@ github.com/armosec/armoapi-go v0.0.23 h1:jqoLIWM5CR7DCD9fpFgN0ePqtHvOCoZv/XzCwsU
github.com/armosec/armoapi-go v0.0.23/go.mod h1:iaVVGyc23QGGzAdv4n+szGQg3Rbpixn9yQTU3qWRpaw=
github.com/armosec/k8s-interface v0.0.8/go.mod h1:xxS+V5QT3gVQTwZyAMMDrYLWGrfKOpiJ7Jfhfa0w9sM=
github.com/armosec/k8s-interface v0.0.37/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2dsFVc0XtgRh1ZU=
github.com/armosec/k8s-interface v0.0.43/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2dsFVc0XtgRh1ZU=
github.com/armosec/k8s-interface v0.0.45 h1:LnncyBfarM29vXB0JwteSiLphVsiu7ONrNmmWSi377M=
github.com/armosec/k8s-interface v0.0.45/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/opa-utils v0.0.64/go.mod h1:6tQP8UDq2EvEfSqh8vrUdr/9QVSCG4sJfju1SXQOn4c=
github.com/armosec/opa-utils v0.0.68 h1:qsmDjEVPdfJ6+hlSeoBZF5sgeR63HdtPfpVQIg0r1G0=
github.com/armosec/opa-utils v0.0.68/go.mod h1:NVJEQ7695VyylqC7dHw2nD7MHIGJrRIXLgyej1onF64=
github.com/armosec/opa-utils v0.0.75 h1:GBI3K18xc3WXJHIorIu4bGNAsfMYHUc1x7zueDz2ZbY=
github.com/armosec/opa-utils v0.0.75/go.mod h1:L7d+uiIIXAZ3LEyKtmEIbMcI1hWgWaXGpn5zVCqzwSU=
github.com/armosec/rbac-utils v0.0.1/go.mod h1:pQ8CBiij8kSKV7aeZm9FMvtZN28VgA7LZcYyTWimq40=
github.com/armosec/rbac-utils v0.0.9 h1:rIOWp4K7BELUNX32ktSjVbb8d/0SpH7W76W6Tf+8rzw=
github.com/armosec/rbac-utils v0.0.9/go.mod h1:Ex/IdGWhGv9HZq6Hs8N/ApzCKSIvpNe/ETqDfnuyah0=
@@ -118,8 +117,8 @@ github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqO
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
github.com/briandowns/spinner v1.16.0 h1:DFmp6hEaIx2QXXuqSJmtfSBSAjRmpGiKG6ip2Wm/yOs=
github.com/briandowns/spinner v1.16.0/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ=
github.com/briandowns/spinner v1.18.0 h1:SJs0maNOs4FqhBwiJ3Gr7Z1D39/rukIVGQvpNZVHVcM=
github.com/briandowns/spinner v1.18.0/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ=
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/bytecodealliance/wasmtime-go v0.30.0 h1:WfYpr4WdqInt8m5/HvYinf+HrSEAIhItKIcth+qb1h4=
github.com/bytecodealliance/wasmtime-go v0.30.0/go.mod h1:q320gUxqyI8yB+ZqRuaJOEnGkAnHh6WtJjMaT2CW4wI=
+3
View File
@@ -201,5 +201,8 @@ func (hsh *HostSensorHandler) TearDown() error {
}
func (hsh *HostSensorHandler) GetNamespace() string {
if hsh.DaemonSet == nil {
return ""
}
return hsh.DaemonSet.Namespace
}
+1 -10
View File
@@ -9,7 +9,6 @@ import (
"github.com/armosec/k8s-interface/k8sinterface"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/opa-utils/objectsenvelopes/hostsensor"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/yaml"
)
@@ -158,7 +157,7 @@ func (hsh *HostSensorHandler) GetOsReleaseFile() ([]hostsensor.HostSensorDataEnv
// return list of
func (hsh *HostSensorHandler) GetKubeletConfigurations() ([]hostsensor.HostSensorDataEnvelope, error) {
// loop over pods and port-forward it to each of them
res, err := hsh.sendAllPodsHTTPGETRequest("/kubeletConfigurations", "") // empty kind, will be overridden
res, err := hsh.sendAllPodsHTTPGETRequest("/kubeletConfigurations", "KubeletConfigurations") // empty kind, will be overridden
for resIdx := range res {
jsonBytes, err := yaml.YAMLToJSON(res[resIdx].Data)
if err != nil {
@@ -166,14 +165,6 @@ func (hsh *HostSensorHandler) GetKubeletConfigurations() ([]hostsensor.HostSenso
continue
}
res[resIdx].SetData(jsonBytes)
kindDet := metav1.TypeMeta{}
if err = json.Unmarshal(jsonBytes, &kindDet); err != nil {
fmt.Printf("In GetKubeletConfigurations failed to Unmarshal GroupVersionKind: %v;\n%v", err, jsonBytes)
continue
}
res[resIdx].SetKind(kindDet.Kind)
res[resIdx].SetApiVersion(k8sinterface.JoinGroupVersion(kindDet.GroupVersionKind().Group, kindDet.GroupVersionKind().Version))
}
return res, err
}
+1 -1
View File
@@ -107,7 +107,7 @@ func isRuleKubescapeVersionCompatible(rule *reporthandling.PolicyRule) bool {
}
func removeData(obj workloadinterface.IMetadata) {
if !workloadinterface.IsTypeWorkload(obj.GetObject()) {
if !k8sinterface.IsTypeWorkload(obj.GetObject()) {
return // remove data only from kubernetes objects
}
workload := workloadinterface.NewWorkloadObj(obj.GetObject())
@@ -6,6 +6,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/armosec/armoapi-go/armotypes"
"github.com/armosec/k8s-interface/k8sinterface"
"github.com/armosec/k8s-interface/workloadinterface"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/opa-utils/reporthandling"
@@ -57,6 +58,8 @@ func TestIsRuleKubescapeVersionCompatible(t *testing.T) {
}
func TestRemoveData(t *testing.T) {
k8sinterface.InitializeMapResourcesMock()
w := `{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"name":"demoservice-server"},"spec":{"replicas":1,"selector":{"matchLabels":{"app":"demoservice-server"}},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"demoservice-server"}},"spec":{"containers":[{"env":[{"name":"SERVER_PORT","value":"8089"},{"name":"SLEEP_DURATION","value":"1"},{"name":"DEMO_FOLDERS","value":"/app"},{"name":"ARMO_TEST_NAME","value":"auto_attach_deployment"},{"name":"CAA_ENABLE_CRASH_REPORTER","value":"1"}],"image":"quay.io/armosec/demoservice:v25","imagePullPolicy":"IfNotPresent","name":"demoservice","ports":[{"containerPort":8089,"protocol":"TCP"}],"resources":{},"terminationMessagePath":"/dev/termination-log","terminationMessagePolicy":"File"}],"dnsPolicy":"ClusterFirst","restartPolicy":"Always","schedulerName":"default-scheduler","securityContext":{},"terminationGracePeriodSeconds":30}}}}`
obj, _ := workloadinterface.NewWorkload([]byte(w))
removeData(obj)
-1
View File
@@ -59,6 +59,5 @@ func (policyHandler *PolicyHandler) getResources(notification *reporthandling.Po
opaSessionObj.K8SResources = resourcesMap
opaSessionObj.AllResources = allResources
cautils.SuccessTextDisplay("Lets start!!!")
return nil
}
+1 -1
View File
@@ -125,7 +125,7 @@ func mapResources(workloads []workloadinterface.IMetadata) map[string][]workload
continue
}
if workloadinterface.IsTypeWorkload(workloads[i].GetObject()) {
if k8sinterface.IsTypeWorkload(workloads[i].GetObject()) {
w := workloadinterface.NewWorkloadObj(workloads[i].GetObject())
if groupVersionResource.Group != w.GetGroup() || groupVersionResource.Version != w.GetVersion() {
// TODO - print warning
+4
View File
@@ -47,6 +47,8 @@ func (k8sHandler *K8sResourceHandler) GetResources(frameworks []reporthandling.F
// get k8s resources
cautils.ProgressTextDisplay("Accessing Kubernetes objects")
cautils.StartSpinner()
// build resources map
// map resources based on framework required resources: map["/group/version/kind"][]<k8s workloads ids>
k8sResourcesMap := setResourceMap(frameworks)
@@ -69,6 +71,8 @@ func (k8sHandler *K8sResourceHandler) GetResources(frameworks []reporthandling.F
cautils.WarningDisplay(os.Stdout, fmt.Sprintf("Warning: %v\n", err.Error()))
}
cautils.StopSpinner()
cautils.SuccessTextDisplay("Accessed successfully to Kubernetes objects")
return k8sResourcesMap, allResources, nil
}
+18 -34
View File
@@ -4,6 +4,7 @@ import (
"fmt"
"os"
"sort"
"strings"
"github.com/armosec/k8s-interface/workloadinterface"
"github.com/armosec/kubescape/cautils"
@@ -81,6 +82,7 @@ func (printer *PrettyPrinter) summarySetup(fr reporthandling.FrameworkReport, al
//controlSummary
printer.summary[cr.Name] = ResultSummary{
ID: cr.ControlID,
RiskScore: cr.Score,
TotalResources: cr.GetNumberOfResources(),
TotalFailed: cr.GetNumberOfFailedResources(),
@@ -120,11 +122,10 @@ func (printer *PrettyPrinter) printSummary(controlName string, controlSummary *R
cautils.DescriptionDisplay(printer.writer, "\n")
}
func (printer *PrettyPrinter) printTitle(controlName string, controlSummary *ResultSummary) {
cautils.InfoDisplay(printer.writer, "[control: %s] ", controlName)
cautils.InfoDisplay(printer.writer, "[control: %s - %s] ", controlName, getControlURL(controlSummary.ID))
if controlSummary.TotalResources == 0 {
cautils.InfoDisplay(printer.writer, "resources not found %v\n", emoji.ConfusedFace)
cautils.InfoDisplay(printer.writer, "skipped %v\n", emoji.ConfusedFace)
} else if controlSummary.TotalFailed != 0 {
cautils.FailureDisplay(printer.writer, "failed %v\n", emoji.SadButRelievedFace)
} else if controlSummary.TotalWarning != 0 {
@@ -155,32 +156,21 @@ func (printer *PrettyPrinter) printResources(controlSummary *ResultSummary) {
func (printer *PrettyPrinter) printGroupedResources(workloads map[string][]WorkloadSummary) {
indent := INDENT
for ns, rsc := range workloads {
if !isKindToBeGrouped(ns) {
printer.printGroupedResource(indent, ns, rsc)
}
}
if rsc, ok := workloads["User"]; ok {
printer.printGroupedResource(indent, "User", rsc)
}
if rsc, ok := workloads["Group"]; ok {
printer.printGroupedResource(indent, "Group", rsc)
for title, rsc := range workloads {
printer.printGroupedResource(indent, title, rsc)
}
}
func (printer *PrettyPrinter) printGroupedResource(indent string, ns string, rsc []WorkloadSummary) {
func (printer *PrettyPrinter) printGroupedResource(indent string, title string, rsc []WorkloadSummary) {
preIndent := indent
if isKindToBeGrouped(ns) {
cautils.SimpleDisplay(printer.writer, "%s%ss\n", indent, ns)
} else if ns != "" {
cautils.SimpleDisplay(printer.writer, "%sNamespace %s\n", indent, ns)
}
preIndent2 := indent
for r := range rsc {
if title != "" {
cautils.SimpleDisplay(printer.writer, "%s%s\n", indent, title)
indent += indent
}
for r := range rsc {
relatedObjectsStr := generateRelatedObjectsStr(rsc[r])
cautils.SimpleDisplay(printer.writer, fmt.Sprintf("%s%s - %s %s\n", indent, rsc[r].resource.GetKind(), rsc[r].resource.GetName(), relatedObjectsStr))
indent = preIndent2
}
indent = preIndent
}
@@ -206,9 +196,9 @@ func generateRow(control string, cs ResultSummary) []string {
row := []string{control}
row = append(row, cs.ToSlice()...)
if cs.TotalResources != 0 {
row = append(row, fmt.Sprintf("%.2f%s", cs.RiskScore, "%"))
row = append(row, fmt.Sprintf("%d", int(cs.RiskScore))+"%")
} else {
row = append(row, EmptyPercentage)
row = append(row, "skipped")
}
return row
}
@@ -217,16 +207,6 @@ func generateHeader() []string {
return []string{"Control Name", "Failed Resources", "Excluded Resources", "All Resources", "% risk-score"}
}
func percentage(big, small int) int {
if big == 0 {
if small == 0 {
return 100
}
return 0
}
return int(float64(float64(big-small)/float64(big)) * 100)
}
func generateFooter(printer *PrettyPrinter) []string {
// Control name | # failed resources | all resources | % success
row := []string{}
@@ -295,3 +275,7 @@ func getWriter(outputFile string) *os.File {
return os.Stdout
}
func getControlURL(controlID string) string {
return fmt.Sprintf("https://hub.armo.cloud/docs/%s", strings.ToLower(controlID))
}
-2
View File
@@ -6,8 +6,6 @@ import (
var INDENT = " "
const EmptyPercentage = "NaN"
const (
PrettyFormat string = "pretty-printer"
JsonFormat string = "json"
+1
View File
@@ -14,6 +14,7 @@ func NewSummary() Summary {
}
type ResultSummary struct {
ID string
RiskScore float32
TotalResources int
TotalFailed int
+34 -11
View File
@@ -1,7 +1,9 @@
package printer
import (
"github.com/armosec/k8s-interface/k8sinterface"
"github.com/armosec/k8s-interface/workloadinterface"
"github.com/armosec/opa-utils/objectsenvelopes"
"github.com/armosec/opa-utils/reporthandling"
)
@@ -9,19 +11,40 @@ import (
func groupByNamespaceOrKind(resources []WorkloadSummary, status func(workloadSummary *WorkloadSummary) bool) map[string][]WorkloadSummary {
mapResources := make(map[string][]WorkloadSummary)
for i := range resources {
if status(&resources[i]) {
if isKindToBeGrouped(resources[i].resource.GetKind()) {
if r, ok := mapResources[resources[i].resource.GetKind()]; ok {
r = append(r, resources[i])
mapResources[resources[i].resource.GetKind()] = r
} else {
mapResources[resources[i].resource.GetKind()] = []WorkloadSummary{resources[i]}
}
} else if r, ok := mapResources[resources[i].resource.GetNamespace()]; ok {
if !status(&resources[i]) {
continue
}
t := resources[i].resource.GetObjectType()
if t == objectsenvelopes.TypeRegoResponseVectorObject && !isKindToBeGrouped(resources[i].resource.GetKind()) {
t = workloadinterface.TypeWorkloadObject
}
switch t { // TODO - find a better way to defind the groups
case workloadinterface.TypeWorkloadObject:
ns := ""
if resources[i].resource.GetNamespace() != "" {
ns = "Namescape " + resources[i].resource.GetNamespace()
}
if r, ok := mapResources[ns]; ok {
r = append(r, resources[i])
mapResources[resources[i].resource.GetNamespace()] = r
mapResources[ns] = r
} else {
mapResources[resources[i].resource.GetNamespace()] = []WorkloadSummary{resources[i]}
mapResources[ns] = []WorkloadSummary{resources[i]}
}
case objectsenvelopes.TypeRegoResponseVectorObject:
group := resources[i].resource.GetKind() + "s"
if r, ok := mapResources[group]; ok {
r = append(r, resources[i])
mapResources[group] = r
} else {
mapResources[group] = []WorkloadSummary{resources[i]}
}
default:
group, _ := k8sinterface.SplitApiVersion(resources[i].resource.GetApiVersion())
if r, ok := mapResources[group]; ok {
r = append(r, resources[i])
mapResources[group] = r
} else {
mapResources[group] = []WorkloadSummary{resources[i]}
}
}
}
+1 -1
View File
@@ -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\n", getter.GetArmoAPIConnector().GetFrontendURL())
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())
cautils.InfoTextDisplay(os.Stdout, fmt.Sprintf("\n%s\n", message))
}
@@ -61,6 +61,9 @@ func (report *ReportEventReceiver) prepareReport(postureReport *reporthandling.P
report.initEventReceiverURL()
host := hostToString(report.eventReceiverURL, postureReport.ReportID)
cautils.StartSpinner()
defer cautils.StopSpinner()
// send framework results
if err := report.sendReport(host, postureReport); err != nil {
return err
@@ -116,14 +119,14 @@ func (report *ReportEventReceiver) sendReport(host string, postureReport *report
}
func (report *ReportEventReceiver) DisplayReportURL() {
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: "
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 != "" {
cautils.InfoTextDisplay(os.Stdout, "\n\n"+message+u.String()+"\n\n")
cautils.InfoTextDisplay(os.Stdout, fmt.Sprintf("\n\n%s %s/risk/%s\n(Account: %s)\n\n", message, u.String(), report.clusterName, report.customerGUID))
return
}
u.Path = "account/sign-up"
@@ -132,5 +135,5 @@ func (report *ReportEventReceiver) DisplayReportURL() {
q.Add("customerGUID", report.customerGUID)
u.RawQuery = q.Encode()
cautils.InfoTextDisplay(os.Stdout, "\n\n"+message+u.String()+"\n\n")
cautils.InfoTextDisplay(os.Stdout, fmt.Sprintf("\n\n%s %s\n\n", message, u.String()))
}