mirror of
https://github.com/kubescape/kubescape.git
synced 2026-02-19 12:30:16 +00:00
Compare commits
7 Commits
v2.9.0
...
github-act
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e09bb2e310 | ||
|
|
f7b3cdcf35 | ||
|
|
d6a47a82d2 | ||
|
|
936cb26c06 | ||
|
|
9265a5d6d0 | ||
|
|
e6f5c7e0dd | ||
|
|
4e48148d40 |
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 =====================
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
4
go.mod
@@ -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
8
go.sum
@@ -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=
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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=
|
||||
|
||||
Reference in New Issue
Block a user