Compare commits

...

7 Commits

Author SHA1 Message Date
David Wertenteil
e09bb2e310 revert dockerfile
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-08-17 14:36:58 +03:00
Daniel Grunberger
f7b3cdcf35 Improve logs (#1349)
* use stop-success

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* improve logger

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* RBAC

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

---------

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>
Co-authored-by: Daniel Grunberger <danielgrunberger@armosec.io>
2023-08-17 14:18:40 +03:00
Daniel Grunberger
d6a47a82d2 improve cli output (#1347)
Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>
Co-authored-by: Daniel Grunberger <danielgrunberger@armosec.io>
2023-08-16 13:01:32 +03:00
Daniel Grunberger
936cb26c06 fix panic and improve logs (#1344)
Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>
Co-authored-by: Daniel Grunberger <danielgrunberger@armosec.io>
2023-08-16 13:00:52 +03:00
DRAGON2002
9265a5d6d0 fix: icons formatting (#1343)
Signed-off-by: DRAGON <anantvijay3@gmail.com>
2023-08-16 12:58:55 +03:00
Daniel Grunberger
e6f5c7e0dd bump k8s-interface version (#1345)
* bump version

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* bump httphandler

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

---------

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>
Co-authored-by: Daniel Grunberger <danielgrunberger@armosec.io>
2023-08-15 10:34:45 +03:00
rcohencyberarmor
4e48148d40 Support unified configuration (#1304)
* support scanning scope

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update go mod

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update white list

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update go mod

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* scope empty return control should tested

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update rego scope for system test

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update test + mock

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* add comment

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update rego library

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update k8s-interface

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update opa utils - lots of file changes in this commit since armoapi-go bump up in opa-utils

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* move to temp k8s-interface - till PR in k8s-interface repo will approved

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update k8s-interface with released tag

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update go mod in httphandler

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* support unified configuration

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* unitest adjustment

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* config-unified

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* CR corrections

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* remove system test till it will be merged

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* add relevant system test

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* remove delete test

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* return config delete system test

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

---------

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>
Co-authored-by: rcohencyberarmor <rcohen@armosec.io>
2023-08-15 10:34:23 +03:00
18 changed files with 378 additions and 73 deletions

View File

@@ -62,7 +62,7 @@ on:
default: 1
BINARY_TESTS:
type: string
default: '[ "scan_nsa", "scan_mitre", "scan_with_exceptions", "scan_repository", "scan_local_file", "scan_local_glob_files", "scan_local_list_of_files", "scan_nsa_and_submit_to_backend", "scan_mitre_and_submit_to_backend", "scan_local_repository_and_submit_to_backend", "scan_repository_from_url_and_submit_to_backend", "scan_with_exception_to_backend", "scan_with_custom_framework", "scan_customer_configuration", "host_scanner", "scan_compliance_score", "scan_custom_framework_scanning_file_scope_testing", "scan_custom_framework_scanning_cluster_scope_testing", "scan_custom_framework_scanning_cluster_and_file_scope_testing" ]'
default: '[ "scan_nsa", "scan_mitre", "scan_with_exceptions", "scan_repository", "scan_local_file", "scan_local_glob_files", "scan_local_list_of_files", "scan_nsa_and_submit_to_backend", "scan_mitre_and_submit_to_backend", "scan_local_repository_and_submit_to_backend", "scan_repository_from_url_and_submit_to_backend", "scan_with_exception_to_backend", "scan_with_custom_framework", "scan_customer_configuration", "host_scanner", "scan_compliance_score", "scan_custom_framework_scanning_file_scope_testing", "scan_custom_framework_scanning_cluster_scope_testing", "scan_custom_framework_scanning_cluster_and_file_scope_testing", "unified_configuration_config_view", "unified_configuration_config_set", "unified_configuration_config_delete" ]'
OS_MATRIX:
type: string
required: false

View File

@@ -1,38 +1,50 @@
FROM golang:1.20-bullseye as builder
ARG image_version client
ENV GO111MODULE=on CGO_ENABLED=1 PYTHONUNBUFFERED=1 RELEASE=$image_version CLIENT=$client
FROM golang:1.20-alpine as builder
ARG image_version
ARG client
ENV RELEASE=$image_version
ENV CLIENT=$client
ENV GO111MODULE=
ENV CGO_ENABLED=1
# Install required python/pip
RUN apt update
RUN apt install -y cmake python3-pip
ENV PYTHONUNBUFFERED=1
RUN apk add --update --no-cache python3 gcc make git libc-dev binutils-gold cmake pkgconfig && ln -sf python3 /usr/bin/python
RUN python3 -m ensurepip
RUN pip3 install --no-cache --upgrade pip setuptools
WORKDIR /work
ADD . .
# install libgit2
RUN --mount=type=cache,target=/root/.cache/go-build \
--mount=type=cache,target=/go/pkg \
make libgit2
RUN rm -rf git2go && make libgit2
# build kubescape server
WORKDIR /work/httphandler
RUN --mount=type=cache,target=/root/.cache/go-build \
--mount=type=cache,target=/go/pkg \
python3 build.py
RUN python build.py
RUN ls -ltr build/
# build kubescape cmd
WORKDIR /work
RUN --mount=type=cache,target=/root/.cache/go-build \
--mount=type=cache,target=/go/pkg \
python3 build.py
RUN python build.py
RUN /work/build/kubescape-ubuntu-latest download artifacts -o /work/artifacts
FROM gcr.io/distroless/base-debian11:nonroot
FROM alpine:3.16.2
RUN addgroup -S ks && adduser -S ks -G ks
COPY --from=builder /work/artifacts/ /home/ks/.kubescape
RUN chown -R ks:ks /home/ks/.kubescape
USER ks
WORKDIR /home/ks
COPY --from=builder /work/artifacts/ /home/nonroot/.kubescape
COPY --from=builder /work/httphandler/build/kubescape-ubuntu-latest /usr/bin/ksserver
COPY --from=builder /work/build/kubescape-ubuntu-latest /usr/bin/kubescape

View File

@@ -5,6 +5,7 @@ import (
"fmt"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/iconlogger"
"github.com/kubescape/kubescape/v2/core/cautils"
"github.com/kubescape/kubescape/v2/core/core"
"github.com/kubescape/kubescape/v2/core/meta"
@@ -53,6 +54,9 @@ func getImageCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo, imgScanInfo *im
failOnSeverity := imagescan.ParseSeverity(scanInfo.FailThresholdSeverity)
ctx := context.Background()
logger.InitLogger(iconlogger.LoggerName)
dbCfg, _ := imagescan.NewDefaultDBConfig()
svc := imagescan.NewScanService(dbCfg)

View File

@@ -6,6 +6,7 @@ import (
"fmt"
"strings"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/kubescape/v2/core/cautils"
"github.com/kubescape/kubescape/v2/core/meta"
v1 "github.com/kubescape/opa-utils/httpserver/apis/v1"
@@ -70,11 +71,11 @@ func getWorkloadCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comma
ctx := context.TODO()
results, err := ks.Scan(ctx, scanInfo)
if err != nil {
return err
logger.L().Fatal(err.Error())
}
if err = results.HandleResults(ctx); err != nil {
return err
logger.L().Fatal(err.Error())
}
return nil

View File

@@ -17,7 +17,11 @@ import (
corev1 "k8s.io/api/core/v1"
)
const configFileName = "config"
const (
configFileName string = "config"
kubescapeNamespace string = "kubescape"
kubescapeConfigMapName string = "kubescape-config"
)
func ConfigFileFullPath() string { return getter.GetDefaultPath(configFileName + ".json") }
@@ -29,7 +33,6 @@ type ConfigObj struct {
AccountID string `json:"accountID,omitempty"`
ClientID string `json:"clientID,omitempty"`
SecretKey string `json:"secretKey,omitempty"`
CustomerGUID string `json:"customerGUID,omitempty"` // Deprecated
Token string `json:"invitationParam,omitempty"`
CustomerAdminEMail string `json:"adminMail,omitempty"`
ClusterName string `json:"clusterName,omitempty"`
@@ -63,6 +66,35 @@ func (co *ConfigObj) Config() []byte {
return []byte{}
}
func (co *ConfigObj) updateEmptyFields(inCO *ConfigObj) error {
if inCO.AccountID != "" {
co.AccountID = inCO.AccountID
}
if inCO.CloudAPIURL != "" {
co.CloudAPIURL = inCO.CloudAPIURL
}
if inCO.CloudAuthURL != "" {
co.CloudAuthURL = inCO.CloudAuthURL
}
if inCO.CloudReportURL != "" {
co.CloudReportURL = inCO.CloudReportURL
}
if inCO.CloudUIURL != "" {
co.CloudUIURL = inCO.CloudUIURL
}
if inCO.ClusterName != "" {
co.ClusterName = inCO.ClusterName
}
if inCO.CustomerAdminEMail != "" {
co.CustomerAdminEMail = inCO.CustomerAdminEMail
}
if inCO.Token != "" {
co.Token = inCO.Token
}
return nil
}
// ======================================================================================
// =============================== interface ============================================
// ======================================================================================
@@ -245,15 +277,16 @@ func NewClusterConfig(k8s *k8sinterface.KubernetesApi, backendAPI getter.IBacken
configMapNamespace: GetConfigMapNamespace(),
}
// first, load from configMap
if c.existsConfigMap() {
c.loadConfigFromConfigMap()
}
// second, load from file
// first, load from file
if existsConfigFile() { // get from file
loadConfigFromFile(c.configObj)
}
// second, load from configMap
if c.existsConfigMap() {
c.updateConfigEmptyFieldsFromConfigMap()
}
updateCredentials(c.configObj, credentials)
updateCloudURLs(c.configObj)
@@ -359,6 +392,22 @@ func (c *ClusterConfig) ToMapString() map[string]interface{} {
}
return m
}
func (c *ClusterConfig) updateConfigEmptyFieldsFromConfigMap() error {
configMap, err := c.k8s.KubernetesClient.CoreV1().ConfigMaps(c.configMapNamespace).Get(context.Background(), c.configMapName, metav1.GetOptions{})
if err != nil {
return err
}
tempCO := ConfigObj{}
if jsonConf, ok := configMap.Data["config.json"]; ok {
json.Unmarshal([]byte(jsonConf), &tempCO)
return c.configObj.updateEmptyFields(&tempCO)
}
return err
}
func (c *ClusterConfig) loadConfigFromConfigMap() error {
configMap, err := c.k8s.KubernetesClient.CoreV1().ConfigMaps(c.configMapNamespace).Get(context.Background(), c.configMapName, metav1.GetOptions{})
if err != nil {
@@ -509,10 +558,6 @@ func readConfig(dat []byte, configObj *ConfigObj) error {
if err := json.Unmarshal(dat, configObj); err != nil {
return err
}
if configObj.AccountID == "" {
configObj.AccountID = configObj.CustomerGUID
}
configObj.CustomerGUID = ""
return nil
}
@@ -554,7 +599,7 @@ func getConfigMapName() string {
if n := os.Getenv("KS_DEFAULT_CONFIGMAP_NAME"); n != "" {
return n
}
return "kubescape"
return kubescapeConfigMapName
}
// GetConfigMapNamespace returns the namespace of the cluster config, which is the same for all in-cluster components
@@ -562,7 +607,7 @@ func GetConfigMapNamespace() string {
if n := os.Getenv("KS_DEFAULT_CONFIGMAP_NAMESPACE"); n != "" {
return n
}
return "default"
return kubescapeNamespace
}
func getAccountFromEnv(credentials *Credentials) {

View File

@@ -308,12 +308,12 @@ func TestGetConfigMapNamespace(t *testing.T) {
}{
{
name: "no env",
want: "default",
want: kubescapeNamespace,
},
{
name: "default ns",
env: "kubescape",
want: "kubescape",
env: kubescapeNamespace,
want: kubescapeNamespace,
},
{
name: "custom ns",
@@ -330,3 +330,128 @@ func TestGetConfigMapNamespace(t *testing.T) {
})
}
}
const (
anyString string = "anyString"
shouldNotUpdate string = "shouldNotUpdate"
shouldUpdate string = "shouldUpdate"
)
func checkIsUpdateCorrectly(t *testing.T, beforeField string, afterField string) {
switch beforeField {
case anyString:
assert.Equal(t, anyString, afterField)
case "":
assert.Equal(t, shouldUpdate, afterField)
}
}
func TestUpdateEmptyFields(t *testing.T) {
tests := []struct {
inCo *ConfigObj
outCo *ConfigObj
}{
{
outCo: &ConfigObj{
AccountID: "",
Token: "",
CustomerAdminEMail: "",
ClusterName: "",
CloudReportURL: "",
CloudAPIURL: "",
CloudUIURL: "",
CloudAuthURL: "",
},
inCo: &ConfigObj{
AccountID: shouldUpdate,
Token: shouldUpdate,
CustomerAdminEMail: shouldUpdate,
ClusterName: shouldUpdate,
CloudReportURL: shouldUpdate,
CloudAPIURL: shouldUpdate,
CloudUIURL: shouldUpdate,
CloudAuthURL: shouldUpdate,
},
},
{
outCo: &ConfigObj{
AccountID: anyString,
Token: anyString,
CustomerAdminEMail: "",
ClusterName: "",
CloudReportURL: "",
CloudAPIURL: "",
CloudUIURL: "",
CloudAuthURL: "",
},
inCo: &ConfigObj{
AccountID: shouldNotUpdate,
Token: shouldNotUpdate,
CustomerAdminEMail: shouldUpdate,
ClusterName: shouldUpdate,
CloudReportURL: shouldUpdate,
CloudAPIURL: shouldUpdate,
CloudUIURL: shouldUpdate,
CloudAuthURL: shouldUpdate,
},
},
{
outCo: &ConfigObj{
AccountID: "",
Token: "",
CustomerAdminEMail: anyString,
ClusterName: anyString,
CloudReportURL: anyString,
CloudAPIURL: anyString,
CloudUIURL: anyString,
CloudAuthURL: anyString,
},
inCo: &ConfigObj{
AccountID: shouldUpdate,
Token: shouldUpdate,
CustomerAdminEMail: shouldNotUpdate,
ClusterName: shouldNotUpdate,
CloudReportURL: shouldNotUpdate,
CloudAPIURL: shouldNotUpdate,
CloudUIURL: shouldNotUpdate,
CloudAuthURL: shouldNotUpdate,
},
},
{
outCo: &ConfigObj{
AccountID: anyString,
Token: anyString,
CustomerAdminEMail: "",
ClusterName: anyString,
CloudReportURL: "",
CloudAPIURL: anyString,
CloudUIURL: "",
CloudAuthURL: anyString,
},
inCo: &ConfigObj{
AccountID: shouldNotUpdate,
Token: shouldNotUpdate,
CustomerAdminEMail: shouldUpdate,
ClusterName: shouldNotUpdate,
CloudReportURL: shouldUpdate,
CloudAPIURL: shouldNotUpdate,
CloudUIURL: shouldUpdate,
CloudAuthURL: shouldNotUpdate,
},
},
}
for i := range tests {
beforeChangesOutCO := tests[i].outCo
tests[i].outCo.updateEmptyFields(tests[i].inCo)
checkIsUpdateCorrectly(t, beforeChangesOutCO.AccountID, tests[i].outCo.AccountID)
checkIsUpdateCorrectly(t, beforeChangesOutCO.CloudAPIURL, tests[i].outCo.CloudAPIURL)
checkIsUpdateCorrectly(t, beforeChangesOutCO.CloudAuthURL, tests[i].outCo.CloudAuthURL)
checkIsUpdateCorrectly(t, beforeChangesOutCO.CloudReportURL, tests[i].outCo.CloudReportURL)
checkIsUpdateCorrectly(t, beforeChangesOutCO.CloudUIURL, tests[i].outCo.CloudUIURL)
checkIsUpdateCorrectly(t, beforeChangesOutCO.ClusterName, tests[i].outCo.ClusterName)
checkIsUpdateCorrectly(t, beforeChangesOutCO.CustomerAdminEMail, tests[i].outCo.CustomerAdminEMail)
checkIsUpdateCorrectly(t, beforeChangesOutCO.Token, tests[i].outCo.Token)
}
}

View File

@@ -9,7 +9,7 @@ import (
func (ks *Kubescape) SetCachedConfig(setConfig *metav1.SetConfig) error {
tenant := getTenantConfig(nil, "", "", getKubernetesApi())
tenant := getTenantConfig(nil, "", "", nil)
if setConfig.Account != "" {
tenant.GetConfigObj().AccountID = setConfig.Account
@@ -45,6 +45,6 @@ func (ks *Kubescape) ViewCachedConfig(viewConfig *metav1.ViewConfig) error {
func (ks *Kubescape) DeleteCachedConfig(ctx context.Context, deleteConfig *metav1.DeleteConfig) error {
tenant := getTenantConfig(nil, "", "", getKubernetesApi()) // change k8sinterface
tenant := getTenantConfig(nil, "", "", nil) // change k8sinterface
return tenant.DeleteCachedConfig(ctx)
}

View File

@@ -6,6 +6,7 @@ import (
"github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/go-logger/iconlogger"
"github.com/kubescape/k8s-interface/k8sinterface"
"github.com/kubescape/k8s-interface/workloadinterface"
"github.com/kubescape/kubescape/v2/core/cautils"
@@ -125,6 +126,7 @@ func GetOutputPrinters(scanInfo *cautils.ScanInfo, ctx context.Context) []printe
func (ks *Kubescape) Scan(ctx context.Context, scanInfo *cautils.ScanInfo) (*resultshandling.ResultsHandler, error) {
ctxInit, spanInit := otel.Tracer("").Start(ctx, "initialization")
logger.InitLogger(iconlogger.LoggerName)
logger.L().Start("Kubescape scanner initializing")
// ===================== Initialization =====================

View File

@@ -112,7 +112,7 @@ func findScanObjectResource(mappedResources map[string][]workloadinterface.IMeta
if len(wls) == 0 {
return nil, fmt.Errorf("k8s resource '%s' not found", getReadableID(resource))
} else if len(wls) > 1 {
return nil, fmt.Errorf("more than one k8s resource found for '%s'", resource.GetID())
return nil, fmt.Errorf("more than one k8s resource found for '%s'", getReadableID(resource))
}
return wls[0], nil

View File

@@ -54,6 +54,7 @@ func NewK8sResourceHandler(k8s *k8sinterface.KubernetesApi, hostSensorHandler ho
}
func (k8sHandler *K8sResourceHandler) GetResources(ctx context.Context, sessionObj *cautils.OPASessionObj, progressListener opaprocessor.IJobProgressNotificationClient, scanInfo *cautils.ScanInfo) (cautils.K8SResources, map[string]workloadinterface.IMetadata, cautils.ExternalResources, map[string]bool, error) {
logger.L().Start("Accessing Kubernetes objects")
var err error
globalFieldSelectors := getFieldSelectorFromScanInfo(scanInfo)
@@ -62,11 +63,6 @@ func (k8sHandler *K8sResourceHandler) GetResources(ctx context.Context, sessionO
return nil, nil, nil, nil, err
}
// we don't scan resources which have a parent
if sessionObj.SingleResourceScan != nil && k8sinterface.WorkloadHasParent(sessionObj.SingleResourceScan) {
return nil, nil, nil, nil, fmt.Errorf("resource %s has a parent and cannot be scanned", sessionObj.SingleResourceScan.GetID())
}
resourceToControl := make(map[string][]string)
// build resources map
// map resources based on framework required resources: map["/group/version/kind"][]<k8s workloads ids>
@@ -96,7 +92,7 @@ func (k8sHandler *K8sResourceHandler) GetResources(ctx context.Context, sessionO
metrics.UpdateWorkerNodesCount(ctx, int64(numberOfWorkerNodes))
}
logger.L().Success("Accessed to Kubernetes objects")
logger.L().StopSuccess("Accessed Kubernetes objects")
// backswords compatibility - get image vulnerability resources
if k8sHandler.registryAdaptors != nil {
@@ -183,20 +179,24 @@ func (k8sHandler *K8sResourceHandler) findScanObjectResource(resource *objectsen
}
result, err := k8sHandler.pullSingleResource(&gvr, nil, fieldSelectors, globalFieldSelector)
if err != nil {
return nil, fmt.Errorf("failed to get resource %s, reason: %v", resource.GetID(), err)
return nil, fmt.Errorf("failed to get resource %s, reason: %v", getReadableID(resource), err)
}
if len(result) == 0 {
return nil, fmt.Errorf("%s was not found", resource.GetID())
}
if len(result) > 1 {
return nil, fmt.Errorf("more than one resource found for %s", resource.GetID())
return nil, fmt.Errorf("resource %s was not found", getReadableID(resource))
}
metaObjs := ConvertMapListToMeta(k8sinterface.ConvertUnstructuredSliceToMap(result))
if len(metaObjs) == 0 {
return nil, fmt.Errorf("resource %s has a parent and cannot be scanned", getReadableID(resource))
}
if len(metaObjs) > 1 {
return nil, fmt.Errorf("more than one resource found for %s", getReadableID(resource))
}
if !k8sinterface.IsTypeWorkload(metaObjs[0].GetObject()) {
return nil, fmt.Errorf("%s is not a valid Kubernetes workload", resource.GetID())
return nil, fmt.Errorf("%s is not a valid Kubernetes workload", getReadableID(resource))
}
wl := workloadinterface.NewWorkloadObj(metaObjs[0].GetObject())
@@ -210,12 +210,13 @@ func (k8sHandler *K8sResourceHandler) collectCloudResources(ctx context.Context,
return fmt.Errorf("failed to get cloud provider, cluster: %s", clusterName)
}
logger.L().Start("Downloading cloud resources")
if sessionObj.Metadata != nil && sessionObj.Metadata.ContextMetadata.ClusterContextMetadata != nil {
sessionObj.Metadata.ContextMetadata.ClusterContextMetadata.CloudProvider = provider
}
logger.L().Debug("cloud", helpers.String("cluster", clusterName), helpers.String("clusterName", clusterName), helpers.String("provider", provider))
logger.L().Info("Downloading cloud resources")
for resourceKind, resourceGetter := range cloudResourceGetterMapping {
if !cloudResourceRequired(cloudResources, resourceKind) {
continue
@@ -237,7 +238,7 @@ func (k8sHandler *K8sResourceHandler) collectCloudResources(ctx context.Context,
allResources[wl.GetID()] = wl
externalResourceMap[fmt.Sprintf("%s/%s", wl.GetApiVersion(), wl.GetKind())] = []string{wl.GetID()}
}
logger.L().Success("Downloaded cloud resources")
logger.L().StopSuccess("Downloaded cloud resources")
// get api server info resource
if cloudResourceRequired(cloudResources, string(cloudsupport.TypeApiServerInfo)) {
@@ -415,7 +416,7 @@ func (k8sHandler *K8sResourceHandler) collectHostResources(ctx context.Context,
}
func (k8sHandler *K8sResourceHandler) collectRbacResources(allResources map[string]workloadinterface.IMetadata) error {
logger.L().Debug("Collecting rbac resources")
logger.L().Start("Collecting RBAC resources")
if k8sHandler.rbacObjectsAPI == nil {
return nil
@@ -427,6 +428,9 @@ func (k8sHandler *K8sResourceHandler) collectRbacResources(allResources map[stri
for k, v := range allRbacResources {
allResources[k] = v
}
logger.L().StopSuccess("Collected RBAC resources")
return nil
}

View File

@@ -5,7 +5,6 @@ import (
"github.com/kubescape/kubescape/v2/core/cautils"
"github.com/kubescape/kubescape/v2/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/imageprinter"
"github.com/kubescape/opa-utils/reporthandling/apis"
"github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
)
@@ -37,8 +36,7 @@ func (ip *ImagePrinter) PrintImageScanning(summary *imageprinter.ImageScanSummar
func (ip *ImagePrinter) PrintImageScanningTable(summary imageprinter.ImageScanSummary) {
if !ip.verboseMode {
// filter out vulnerabilities with severity lower than High
summary.CVEs = filterCVEsBySeverities(summary.CVEs, []string{apis.SeverityCriticalString, apis.SeverityHighString})
summary.CVEs = getFilteredCVEs(summary.CVEs)
}
ip.imageTablePrinter.PrintImageScanningTable(ip.writer, summary)

View File

@@ -77,7 +77,7 @@ func getImageScanningColumnsAlignments() []int {
return []int{tablewriter.ALIGN_CENTER, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT}
}
func getColor(severity string) (func(...string) string) {
func getColor(severity string) func(...string) string {
switch severity {
case apis.SeverityCriticalString:
return gchalk.WithAnsi256(1).Bold
@@ -88,8 +88,8 @@ func getColor(severity string) (func(...string) string) {
case apis.SeverityLowString:
return gchalk.WithAnsi256(220).Bold
case apis.SeverityNegligibleString:
return gchalk.WithAnsi256(16).Bold
return gchalk.WithAnsi256(39).Bold
default:
return gchalk.WithAnsi256(16).Bold
return gchalk.WithAnsi256(30).Bold
}
}

View File

@@ -102,6 +102,19 @@ func addEmptySeverities(mapSeverityTSummary map[string]*imageprinter.SeveritySum
}
}
// getFilteredCVEs returns a list of CVEs to show in the table. If there are no vulnerabilities with severity Critical or High, it will return vulnerabilities with severity Medium. Otherwise it will return vulnerabilities with severity Critical or High
func getFilteredCVEs(cves []imageprinter.CVE) []imageprinter.CVE {
// filter out vulnerabilities with severity lower than High
filteredCVEs := filterCVEsBySeverities(cves, []string{apis.SeverityCriticalString, apis.SeverityHighString})
// if there are no vulnerabilities with severity Critical or High, add vulnerabilities with severity Medium
if len(filteredCVEs) == 0 {
filteredCVEs = filterCVEsBySeverities(cves, []string{apis.SeverityMediumString})
}
return filteredCVEs
}
// filterCVEsBySeverities returns a list of CVEs only with the severities that are in the severities list
func filterCVEsBySeverities(cves []imageprinter.CVE, severities []string) []imageprinter.CVE {
var filteredCVEs []imageprinter.CVE

View File

@@ -535,3 +535,104 @@ func TestGetSortedCVEsBySeverity(t *testing.T) {
})
}
}
func TestGetFilteredCVEs(t *testing.T) {
tests := []struct {
name string
cves []imageprinter.CVE
expectedCVEs []imageprinter.CVE
}{
{
name: "High and Critical",
cves: []imageprinter.CVE{
{
Severity: "High",
},
{
Severity: "Critical",
},
{
Severity: "Medium",
},
{
Severity: "Low",
},
{
Severity: "Negligible",
},
},
expectedCVEs: []imageprinter.CVE{
{
Severity: "High",
},
{
Severity: "Critical",
},
},
},
{
name: "Only High",
cves: []imageprinter.CVE{
{
Severity: "High",
},
{
Severity: "Medium",
}},
expectedCVEs: []imageprinter.CVE{
{
Severity: "High",
},
},
},
{
name: "Only Critical",
cves: []imageprinter.CVE{
{
Severity: "Critical",
},
{
Severity: "Medium",
}},
expectedCVEs: []imageprinter.CVE{
{
Severity: "Critical",
},
},
},
{
name: "No High or Critical",
cves: []imageprinter.CVE{
{
Severity: "Low",
},
{
Severity: "Medium",
}},
expectedCVEs: []imageprinter.CVE{
{
Severity: "Medium",
},
},
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
filteredCVEs := getFilteredCVEs(tc.cves)
for _, cve := range filteredCVEs {
found := false
for _, expectedCVE := range tc.expectedCVEs {
if cve.Severity == expectedCVE.Severity {
found = true
break
}
}
if !found {
t.Errorf("Expected: %v, Got: %v", tc.expectedCVEs, filteredCVEs)
}
}
})
}
}

4
go.mod
View File

@@ -22,8 +22,8 @@ require (
github.com/json-iterator/go v1.1.12
github.com/jwalton/gchalk v1.3.0
github.com/kubescape/go-git-url v0.0.25
github.com/kubescape/go-logger v0.0.18
github.com/kubescape/k8s-interface v0.0.136
github.com/kubescape/go-logger v0.0.20
github.com/kubescape/k8s-interface v0.0.138
github.com/kubescape/opa-utils v0.0.261
github.com/kubescape/rbac-utils v0.0.21-0.20230806101615-07e36f555520
github.com/kubescape/regolibrary v1.0.291-rc.0

8
go.sum
View File

@@ -1292,10 +1292,10 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kubescape/go-git-url v0.0.25 h1:i7SSSC1+1m/Dg+4LV3erp0YklnWj1Z0cVlRxCT3Zy/0=
github.com/kubescape/go-git-url v0.0.25/go.mod h1:IbVT7Wsxlghsa+YxI5KOx4k9VQJaa3z0kTaQz5D3nKM=
github.com/kubescape/go-logger v0.0.18 h1:59tYxL623xrPkjgDBU0FheFxjp4JoIuUuX/RJ0MmO1o=
github.com/kubescape/go-logger v0.0.18/go.mod h1:BAWhQMYc/gnC5wMtPvc9Z4VXFqykFFMaXaPkq0+txBY=
github.com/kubescape/k8s-interface v0.0.136 h1:/BMuj5ixYA48ODyAQTK2ZLgID+KXU3rQei8eNiXQTcg=
github.com/kubescape/k8s-interface v0.0.136/go.mod h1:5sz+5Cjvo98lTbTVDiDA4MmlXxeHSVMW/wR0V3hV4K8=
github.com/kubescape/go-logger v0.0.20 h1:ZU3T6Za7maCiChdoTrqpD6TI11DGJwd9xU/TFtRlMOI=
github.com/kubescape/go-logger v0.0.20/go.mod h1:BAWhQMYc/gnC5wMtPvc9Z4VXFqykFFMaXaPkq0+txBY=
github.com/kubescape/k8s-interface v0.0.138 h1:JjqLExOQiV1iG6jDLVQ/KpPzH8T9U7jQOtpUe5frF2o=
github.com/kubescape/k8s-interface v0.0.138/go.mod h1:5sz+5Cjvo98lTbTVDiDA4MmlXxeHSVMW/wR0V3hV4K8=
github.com/kubescape/opa-utils v0.0.261 h1:NEASuRRHfbQRf/9wAEdm+7VV+UDg5tr+VgIfsedbdas=
github.com/kubescape/opa-utils v0.0.261/go.mod h1:0Be6E+vHqjavl/JneqgyC+oXOdfs6s+V6YnFvBkIAsA=
github.com/kubescape/rbac-utils v0.0.21-0.20230806101615-07e36f555520 h1:SqlwF8G+oFazeYmZQKoPczLEflBQpwpHCU8DoLLyfj8=

View File

@@ -10,8 +10,8 @@ require (
github.com/google/uuid v1.3.0
github.com/gorilla/mux v1.8.0
github.com/gorilla/schema v1.2.0
github.com/kubescape/go-logger v0.0.18
github.com/kubescape/k8s-interface v0.0.136
github.com/kubescape/go-logger v0.0.20
github.com/kubescape/k8s-interface v0.0.138
github.com/kubescape/kubescape/v2 v2.0.0-00010101000000-000000000000
github.com/kubescape/opa-utils v0.0.261
github.com/stretchr/testify v1.8.4

View File

@@ -1296,10 +1296,10 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kubescape/go-git-url v0.0.25 h1:i7SSSC1+1m/Dg+4LV3erp0YklnWj1Z0cVlRxCT3Zy/0=
github.com/kubescape/go-git-url v0.0.25/go.mod h1:IbVT7Wsxlghsa+YxI5KOx4k9VQJaa3z0kTaQz5D3nKM=
github.com/kubescape/go-logger v0.0.18 h1:59tYxL623xrPkjgDBU0FheFxjp4JoIuUuX/RJ0MmO1o=
github.com/kubescape/go-logger v0.0.18/go.mod h1:BAWhQMYc/gnC5wMtPvc9Z4VXFqykFFMaXaPkq0+txBY=
github.com/kubescape/k8s-interface v0.0.136 h1:/BMuj5ixYA48ODyAQTK2ZLgID+KXU3rQei8eNiXQTcg=
github.com/kubescape/k8s-interface v0.0.136/go.mod h1:5sz+5Cjvo98lTbTVDiDA4MmlXxeHSVMW/wR0V3hV4K8=
github.com/kubescape/go-logger v0.0.20 h1:ZU3T6Za7maCiChdoTrqpD6TI11DGJwd9xU/TFtRlMOI=
github.com/kubescape/go-logger v0.0.20/go.mod h1:BAWhQMYc/gnC5wMtPvc9Z4VXFqykFFMaXaPkq0+txBY=
github.com/kubescape/k8s-interface v0.0.138 h1:JjqLExOQiV1iG6jDLVQ/KpPzH8T9U7jQOtpUe5frF2o=
github.com/kubescape/k8s-interface v0.0.138/go.mod h1:5sz+5Cjvo98lTbTVDiDA4MmlXxeHSVMW/wR0V3hV4K8=
github.com/kubescape/opa-utils v0.0.261 h1:NEASuRRHfbQRf/9wAEdm+7VV+UDg5tr+VgIfsedbdas=
github.com/kubescape/opa-utils v0.0.261/go.mod h1:0Be6E+vHqjavl/JneqgyC+oXOdfs6s+V6YnFvBkIAsA=
github.com/kubescape/rbac-utils v0.0.21-0.20230806101615-07e36f555520 h1:SqlwF8G+oFazeYmZQKoPczLEflBQpwpHCU8DoLLyfj8=