diff --git a/README.md b/README.md
index ca0c88af..b5dc385d 100644
--- a/README.md
+++ b/README.md
@@ -12,8 +12,12 @@ Kubescape integrates natively with other DevOps tools, including Jenkins, Circle
+# CLI Interface:
+# Web Interface:
+
+
# TL;DR
## Install:
```
diff --git a/cmd/go.mod b/cmd/go.mod
index 8ef4e8bd..6e13399b 100644
--- a/cmd/go.mod
+++ b/cmd/go.mod
@@ -7,7 +7,7 @@ replace github.com/armosec/kubescape/core => ../core
require (
github.com/armosec/k8s-interface v0.0.68
github.com/armosec/kubescape/core v0.0.0-00010101000000-000000000000
- github.com/armosec/opa-utils v0.0.118
+ github.com/armosec/opa-utils v0.0.120
github.com/armosec/rbac-utils v0.0.14
github.com/google/uuid v1.3.0
github.com/mattn/go-isatty v0.0.14
diff --git a/cmd/go.sum b/cmd/go.sum
index ab369692..9e212048 100644
--- a/cmd/go.sum
+++ b/cmd/go.sum
@@ -109,8 +109,8 @@ github.com/armosec/k8s-interface v0.0.66/go.mod h1:vwprS8qn/iowd5yf0JHpqDsLA5I8W
github.com/armosec/k8s-interface v0.0.68 h1:6CtSakISiI47YHkxh+Va9FzZQIBkWa6g9sbiNxq1Zkk=
github.com/armosec/k8s-interface v0.0.68/go.mod h1:PeWn41C2uenZi+xfZdyFF/zG5wXACA00htQyknDUWDE=
github.com/armosec/opa-utils v0.0.64/go.mod h1:6tQP8UDq2EvEfSqh8vrUdr/9QVSCG4sJfju1SXQOn4c=
-github.com/armosec/opa-utils v0.0.118 h1:ZX1crwVQmo+sDv+jmTNLbDYfApUBzlgPhD8QI2GCJX0=
-github.com/armosec/opa-utils v0.0.118/go.mod h1:gap+EaLG5rnyqvIRGxtdNDC9y7VvoGNm90zK8Ls7avQ=
+github.com/armosec/opa-utils v0.0.120 h1:WAtgm2U1o9fgA/2pjYNy+igqNC6ju3/CxQ8qRHdO+5k=
+github.com/armosec/opa-utils v0.0.120/go.mod h1:gap+EaLG5rnyqvIRGxtdNDC9y7VvoGNm90zK8Ls7avQ=
github.com/armosec/rbac-utils v0.0.1/go.mod h1:pQ8CBiij8kSKV7aeZm9FMvtZN28VgA7LZcYyTWimq40=
github.com/armosec/rbac-utils v0.0.14 h1:CKYKcgqJEXWF2Hen/B1pVGtS3nDAG1wp9dDv6oNtq90=
github.com/armosec/rbac-utils v0.0.14/go.mod h1:Ex/IdGWhGv9HZq6Hs8N/ApzCKSIvpNe/ETqDfnuyah0=
diff --git a/core/cautils/datastructures.go b/core/cautils/datastructures.go
index e144fa31..f937ed18 100644
--- a/core/cautils/datastructures.go
+++ b/core/cautils/datastructures.go
@@ -4,35 +4,45 @@ import (
"github.com/armosec/armoapi-go/armotypes"
"github.com/armosec/k8s-interface/workloadinterface"
"github.com/armosec/opa-utils/reporthandling"
+ apis "github.com/armosec/opa-utils/reporthandling/apis"
"github.com/armosec/opa-utils/reporthandling/results/v1/resourcesresults"
reporthandlingv2 "github.com/armosec/opa-utils/reporthandling/v2"
+ v2 "github.com/armosec/opa-utils/reporthandling/v2"
)
// K8SResources map[//][]
type K8SResources map[string][]string
+type ArmoResources map[string][]string
type OPASessionObj struct {
- K8SResources *K8SResources // input k8s objects
- Policies []reporthandling.Framework // list of frameworks to scan
- AllResources map[string]workloadinterface.IMetadata // all scanned resources, map[]
- ResourcesResult map[string]resourcesresults.Result // resources scan results, map[]
- 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[][]
+ K8SResources *K8SResources // input k8s objects
+ ArmoResource *ArmoResources // input ARMO objects
+ Policies []reporthandling.Framework // list of frameworks to scan
+ AllResources map[string]workloadinterface.IMetadata // all scanned resources, map[]
+ ResourcesResult map[string]resourcesresults.Result // resources scan results, map[]
+ 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[][]
+ Metadata *reporthandlingv2.Metadata
+ InfoMap map[string]apis.StatusInfo // Map errors of resources to StatusInfo
+ ResourceToControlsMap map[string][]string // map[] = []
}
func NewOPASessionObj(frameworks []reporthandling.Framework, k8sResources *K8SResources) *OPASessionObj {
return &OPASessionObj{
- Report: &reporthandlingv2.PostureReport{},
- Policies: frameworks,
- K8SResources: k8sResources,
- AllResources: make(map[string]workloadinterface.IMetadata),
- ResourcesResult: make(map[string]resourcesresults.Result),
+ Report: &reporthandlingv2.PostureReport{},
+ Policies: frameworks,
+ K8SResources: k8sResources,
+ AllResources: make(map[string]workloadinterface.IMetadata),
+ ResourcesResult: make(map[string]resourcesresults.Result),
+ InfoMap: make(map[string]apis.StatusInfo),
+ ResourceToControlsMap: make(map[string][]string),
PostureReport: &reporthandling.PostureReport{
ClusterName: ClusterName,
CustomerGUID: CustomerGUID,
},
+ Metadata: &v2.Metadata{},
}
}
diff --git a/core/cautils/reportv2tov1.go b/core/cautils/reportv2tov1.go
index af19aaf7..ba5e6478 100644
--- a/core/cautils/reportv2tov1.go
+++ b/core/cautils/reportv2tov1.go
@@ -11,8 +11,7 @@ func ReportV2ToV1(opaSessionObj *OPASessionObj) {
if len(opaSessionObj.PostureReport.FrameworkReports) > 0 {
return // report already converted
}
-
- opaSessionObj.PostureReport.ClusterCloudProvider = opaSessionObj.Report.ClusterCloudProvider
+ // opaSessionObj.PostureReport.ClusterCloudProvider = opaSessionObj.Report.ClusterCloudProvider
frameworks := []reporthandling.FrameworkReport{}
diff --git a/core/cautils/workloadmappingutils.go b/core/cautils/workloadmappingutils.go
new file mode 100644
index 00000000..4fa94abe
--- /dev/null
+++ b/core/cautils/workloadmappingutils.go
@@ -0,0 +1,52 @@
+package cautils
+
+import (
+ "strings"
+
+ "github.com/armosec/opa-utils/reporthandling/apis"
+)
+
+var (
+ ImageVulnResources = []string{"ImageVulnerabilities"}
+ HostSensorResources = []string{"KubeletConfiguration",
+ "KubeletCommandLine",
+ "OsReleaseFile",
+ "KernelVersion",
+ "LinuxSecurityHardeningStatus",
+ "OpenPortsList",
+ "LinuxKernelVariables"}
+ CloudResources = []string{"ClusterDescribe"}
+)
+
+func MapArmoResource(armoResourceMap *ArmoResources, resources []string) []string {
+ var hostResources []string
+ for k := range *armoResourceMap {
+ for _, resource := range resources {
+ if strings.Contains(k, resource) {
+ hostResources = append(hostResources, k)
+ }
+ }
+ }
+ return hostResources
+}
+
+func MapHostResources(armoResourceMap *ArmoResources) []string {
+ return MapArmoResource(armoResourceMap, HostSensorResources)
+}
+
+func MapImageVulnResources(armoResourceMap *ArmoResources) []string {
+ return MapArmoResource(armoResourceMap, ImageVulnResources)
+}
+
+func MapCloudResources(armoResourceMap *ArmoResources) []string {
+ return MapArmoResource(armoResourceMap, CloudResources)
+}
+
+func SetInfoMapForResources(info string, resources []string, errorMap map[string]apis.StatusInfo) {
+ for _, resource := range resources {
+ errorMap[resource] = apis.StatusInfo{
+ InnerInfo: info,
+ InnerStatus: apis.StatusSkipped,
+ }
+ }
+}
diff --git a/core/go.mod b/core/go.mod
index 941150a2..c96360df 100644
--- a/core/go.mod
+++ b/core/go.mod
@@ -5,7 +5,7 @@ go 1.17
require (
github.com/armosec/armoapi-go v0.0.58
github.com/armosec/k8s-interface v0.0.68
- github.com/armosec/opa-utils v0.0.118
+ github.com/armosec/opa-utils v0.0.120
github.com/armosec/rbac-utils v0.0.14
github.com/armosec/utils-go v0.0.3
github.com/armosec/utils-k8s-go v0.0.3
@@ -25,6 +25,7 @@ require (
k8s.io/api v0.23.4
k8s.io/apimachinery v0.23.4
k8s.io/client-go v0.23.4
+ k8s.io/utils v0.0.0-20211116205334-6203023598ed
sigs.k8s.io/yaml v1.3.0
)
@@ -116,7 +117,6 @@ require (
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
k8s.io/klog/v2 v2.30.0 // indirect
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect
- k8s.io/utils v0.0.0-20211116205334-6203023598ed // indirect
sigs.k8s.io/controller-runtime v0.11.1 // indirect
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
diff --git a/core/go.sum b/core/go.sum
index d279dfff..b645f269 100644
--- a/core/go.sum
+++ b/core/go.sum
@@ -109,8 +109,8 @@ github.com/armosec/k8s-interface v0.0.66/go.mod h1:vwprS8qn/iowd5yf0JHpqDsLA5I8W
github.com/armosec/k8s-interface v0.0.68 h1:6CtSakISiI47YHkxh+Va9FzZQIBkWa6g9sbiNxq1Zkk=
github.com/armosec/k8s-interface v0.0.68/go.mod h1:PeWn41C2uenZi+xfZdyFF/zG5wXACA00htQyknDUWDE=
github.com/armosec/opa-utils v0.0.64/go.mod h1:6tQP8UDq2EvEfSqh8vrUdr/9QVSCG4sJfju1SXQOn4c=
-github.com/armosec/opa-utils v0.0.118 h1:ZX1crwVQmo+sDv+jmTNLbDYfApUBzlgPhD8QI2GCJX0=
-github.com/armosec/opa-utils v0.0.118/go.mod h1:gap+EaLG5rnyqvIRGxtdNDC9y7VvoGNm90zK8Ls7avQ=
+github.com/armosec/opa-utils v0.0.120 h1:WAtgm2U1o9fgA/2pjYNy+igqNC6ju3/CxQ8qRHdO+5k=
+github.com/armosec/opa-utils v0.0.120/go.mod h1:gap+EaLG5rnyqvIRGxtdNDC9y7VvoGNm90zK8Ls7avQ=
github.com/armosec/rbac-utils v0.0.1/go.mod h1:pQ8CBiij8kSKV7aeZm9FMvtZN28VgA7LZcYyTWimq40=
github.com/armosec/rbac-utils v0.0.14 h1:CKYKcgqJEXWF2Hen/B1pVGtS3nDAG1wp9dDv6oNtq90=
github.com/armosec/rbac-utils v0.0.14/go.mod h1:Ex/IdGWhGv9HZq6Hs8N/ApzCKSIvpNe/ETqDfnuyah0=
diff --git a/core/pkg/hostsensorutils/hostsensorgetfrompod.go b/core/pkg/hostsensorutils/hostsensorgetfrompod.go
index bdf35d90..ff3cea72 100644
--- a/core/pkg/hostsensorutils/hostsensorgetfrompod.go
+++ b/core/pkg/hostsensorutils/hostsensorgetfrompod.go
@@ -9,6 +9,7 @@ import (
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
"github.com/armosec/opa-utils/objectsenvelopes/hostsensor"
+ "github.com/armosec/opa-utils/reporthandling/apis"
"sigs.k8s.io/yaml"
)
@@ -156,56 +157,77 @@ func (hsh *HostSensorHandler) GetKubeletConfigurations() ([]hostsensor.HostSenso
return res, err
}
-func (hsh *HostSensorHandler) CollectResources() ([]hostsensor.HostSensorDataEnvelope, error) {
+func (hsh *HostSensorHandler) CollectResources() ([]hostsensor.HostSensorDataEnvelope, map[string]apis.StatusInfo, error) {
res := make([]hostsensor.HostSensorDataEnvelope, 0)
+ infoMap := make(map[string]apis.StatusInfo)
if hsh.DaemonSet == nil {
- return res, nil
+ return res, nil, nil
}
-
+ var kcData []hostsensor.HostSensorDataEnvelope
+ var err error
logger.L().Debug("Accessing host scanner")
- kcData, err := hsh.GetKubeletConfigurations()
+ kcData, err = hsh.GetKubeletConfigurations()
if err != nil {
- return kcData, err
+ addInfoToMap(KubeletConfiguration, infoMap, err)
+ logger.L().Warning(err.Error())
+ }
+ if len(kcData) > 0 {
+ res = append(res, kcData...)
}
- res = append(res, kcData...)
//
kcData, err = hsh.GetKubeletCommandLine()
if err != nil {
- return kcData, err
+ addInfoToMap(KubeletCommandLine, infoMap, err)
+ logger.L().Warning(err.Error())
+ }
+ if len(kcData) > 0 {
+ res = append(res, kcData...)
}
- res = append(res, kcData...)
//
kcData, err = hsh.GetOsReleaseFile()
if err != nil {
- return kcData, err
+ addInfoToMap(OsReleaseFile, infoMap, err)
+ logger.L().Warning(err.Error())
+ }
+ if len(kcData) > 0 {
+ res = append(res, kcData...)
}
- res = append(res, kcData...)
//
kcData, err = hsh.GetKernelVersion()
if err != nil {
- return kcData, err
+ addInfoToMap(KernelVersion, infoMap, err)
+ logger.L().Warning(err.Error())
+ }
+ if len(kcData) > 0 {
+ res = append(res, kcData...)
}
- res = append(res, kcData...)
//
kcData, err = hsh.GetLinuxSecurityHardeningStatus()
if err != nil {
- return kcData, err
+ addInfoToMap(LinuxSecurityHardeningStatus, infoMap, err)
+ logger.L().Warning(err.Error())
+ }
+ if len(kcData) > 0 {
+ res = append(res, kcData...)
}
- res = append(res, kcData...)
//
kcData, err = hsh.GetOpenPortsList()
if err != nil {
- return kcData, err
+ addInfoToMap(OpenPortsList, infoMap, err)
+ logger.L().Warning(err.Error())
+ }
+ if len(kcData) > 0 {
+ res = append(res, kcData...)
}
- res = append(res, kcData...)
// GetKernelVariables
kcData, err = hsh.GetKernelVariables()
if err != nil {
- return kcData, err
+ addInfoToMap(LinuxKernelVariables, infoMap, err)
+ logger.L().Warning(err.Error())
+ }
+ if len(kcData) > 0 {
+ res = append(res, kcData...)
}
- res = append(res, kcData...)
- // finish
-
logger.L().Debug("Done reading information from host scanner")
- return res, nil
+ return res, infoMap, nil
}
diff --git a/core/pkg/hostsensorutils/hostsensorinterface.go b/core/pkg/hostsensorutils/hostsensorinterface.go
index 9b9d9d9b..71d5e6ef 100644
--- a/core/pkg/hostsensorutils/hostsensorinterface.go
+++ b/core/pkg/hostsensorutils/hostsensorinterface.go
@@ -1,10 +1,13 @@
package hostsensorutils
-import "github.com/armosec/opa-utils/objectsenvelopes/hostsensor"
+import (
+ "github.com/armosec/opa-utils/objectsenvelopes/hostsensor"
+ "github.com/armosec/opa-utils/reporthandling/apis"
+)
type IHostSensor interface {
Init() error
TearDown() error
- CollectResources() ([]hostsensor.HostSensorDataEnvelope, error)
+ CollectResources() ([]hostsensor.HostSensorDataEnvelope, map[string]apis.StatusInfo, error)
GetNamespace() string
}
diff --git a/core/pkg/hostsensorutils/hostsensormock.go b/core/pkg/hostsensorutils/hostsensormock.go
index b4518003..f6f22fa0 100644
--- a/core/pkg/hostsensorutils/hostsensormock.go
+++ b/core/pkg/hostsensorutils/hostsensormock.go
@@ -2,6 +2,7 @@ package hostsensorutils
import (
"github.com/armosec/opa-utils/objectsenvelopes/hostsensor"
+ "github.com/armosec/opa-utils/reporthandling/apis"
)
type HostSensorHandlerMock struct {
@@ -15,8 +16,8 @@ func (hshm *HostSensorHandlerMock) TearDown() error {
return nil
}
-func (hshm *HostSensorHandlerMock) CollectResources() ([]hostsensor.HostSensorDataEnvelope, error) {
- return []hostsensor.HostSensorDataEnvelope{}, nil
+func (hshm *HostSensorHandlerMock) CollectResources() ([]hostsensor.HostSensorDataEnvelope, map[string]apis.StatusInfo, error) {
+ return []hostsensor.HostSensorDataEnvelope{}, nil, nil
}
func (hshm *HostSensorHandlerMock) GetNamespace() string {
diff --git a/core/pkg/hostsensorutils/utils.go b/core/pkg/hostsensorutils/utils.go
new file mode 100644
index 00000000..4f3eeb84
--- /dev/null
+++ b/core/pkg/hostsensorutils/utils.go
@@ -0,0 +1,35 @@
+package hostsensorutils
+
+import (
+ "github.com/armosec/k8s-interface/k8sinterface"
+ "github.com/armosec/opa-utils/reporthandling/apis"
+)
+
+var (
+ KubeletConfiguration = "KubeletConfiguration"
+ OsReleaseFile = "OsReleaseFile"
+ KernelVersion = "KernelVersion"
+ LinuxSecurityHardeningStatus = "LinuxSecurityHardeningStatus"
+ OpenPortsList = "OpenPortsList"
+ LinuxKernelVariables = "LinuxKernelVariables"
+ KubeletCommandLine = "KubeletCommandLine"
+
+ MapResourceToApiGroup = map[string]string{
+ KubeletConfiguration: "hostdata.kubescape.cloud/v1beta0",
+ OsReleaseFile: "hostdata.kubescape.cloud/v1beta0/",
+ KubeletCommandLine: "hostdata.kubescape.cloud/v1beta0/",
+ KernelVersion: "hostdata.kubescape.cloud/v1beta0/",
+ LinuxSecurityHardeningStatus: "hostdata.kubescape.cloud/v1beta0/",
+ OpenPortsList: "hostdata.kubescape.cloud/v1beta0/",
+ LinuxKernelVariables: "hostdata.kubescape.cloud/v1beta0/",
+ }
+)
+
+func addInfoToMap(resource string, infoMap map[string]apis.StatusInfo, err error) {
+ group, version := k8sinterface.SplitApiVersion(MapResourceToApiGroup[resource])
+ r := k8sinterface.JoinResourceTriplets(group, version, resource)
+ infoMap[r] = apis.StatusInfo{
+ InnerStatus: apis.StatusSkipped,
+ InnerInfo: err.Error(),
+ }
+}
diff --git a/core/pkg/opaprocessor/processorhandler.go b/core/pkg/opaprocessor/processorhandler.go
index 9223a9e0..4e753a82 100644
--- a/core/pkg/opaprocessor/processorhandler.go
+++ b/core/pkg/opaprocessor/processorhandler.go
@@ -133,7 +133,7 @@ func (opap *OPAProcessor) processRule(rule *reporthandling.PolicyRule) (map[stri
postureControlInputs := opap.regoDependenciesData.GetFilteredPostureControlInputs(rule.ConfigInputs) // get store
- inputResources, err := reporthandling.RegoResourcesAggregator(rule, getAllSupportedObjects(opap.K8SResources, opap.AllResources, rule))
+ inputResources, err := reporthandling.RegoResourcesAggregator(rule, getAllSupportedObjects(opap.K8SResources, opap.ArmoResource, opap.AllResources, rule))
if err != nil {
return nil, fmt.Errorf("error getting aggregated k8sObjects: %s", err.Error())
}
diff --git a/core/pkg/opaprocessor/processorhandlerutils.go b/core/pkg/opaprocessor/processorhandlerutils.go
index dba42288..a3aada18 100644
--- a/core/pkg/opaprocessor/processorhandlerutils.go
+++ b/core/pkg/opaprocessor/processorhandlerutils.go
@@ -9,6 +9,7 @@ import (
"github.com/armosec/k8s-interface/k8sinterface"
"github.com/armosec/k8s-interface/workloadinterface"
"github.com/armosec/opa-utils/reporthandling"
+ "github.com/armosec/opa-utils/reporthandling/apis"
resources "github.com/armosec/opa-utils/resources"
)
@@ -46,8 +47,9 @@ func (opap *OPAProcessor) updateResults() {
}
// set result summary
- opap.Report.SummaryDetails.InitResourcesSummary()
-
+ // map control to error
+ controlToInfoMap := mapControlToInfo(opap.ResourceToControlsMap, opap.InfoMap)
+ opap.Report.SummaryDetails.InitResourcesSummary(controlToInfoMap)
// for f := range opap.PostureReport.FrameworkReports {
// // set exceptions
// exceptions.SetFrameworkExceptions(&opap.PostureReport.FrameworkReports[f], opap.Exceptions, cautils.ClusterName)
@@ -60,13 +62,50 @@ func (opap *OPAProcessor) updateResults() {
// }
}
-func getAllSupportedObjects(k8sResources *cautils.K8SResources, allResources map[string]workloadinterface.IMetadata, rule *reporthandling.PolicyRule) []workloadinterface.IMetadata {
+func mapControlToInfo(mapResourceToControls map[string][]string, infoMap map[string]apis.StatusInfo) map[string]apis.StatusInfo {
+ controlToInfoMap := make(map[string]apis.StatusInfo)
+ for resource, statusInfo := range infoMap {
+ controls := mapResourceToControls[resource]
+ for _, control := range controls {
+ controlToInfoMap[control] = statusInfo
+ }
+ }
+ return controlToInfoMap
+}
+
+func getAllSupportedObjects(k8sResources *cautils.K8SResources, armoResources *cautils.ArmoResources, allResources map[string]workloadinterface.IMetadata, rule *reporthandling.PolicyRule) []workloadinterface.IMetadata {
k8sObjects := []workloadinterface.IMetadata{}
k8sObjects = append(k8sObjects, getKubernetesObjects(k8sResources, allResources, rule.Match)...)
- k8sObjects = append(k8sObjects, getKubernetesObjects(k8sResources, allResources, rule.DynamicMatch)...)
+ k8sObjects = append(k8sObjects, getArmoObjects(armoResources, allResources, rule.DynamicMatch)...)
return k8sObjects
}
+func getArmoObjects(k8sResources *cautils.ArmoResources, allResources map[string]workloadinterface.IMetadata, match []reporthandling.RuleMatchObjects) []workloadinterface.IMetadata {
+ k8sObjects := []workloadinterface.IMetadata{}
+
+ for m := range match {
+ for _, groups := range match[m].APIGroups {
+ for _, version := range match[m].APIVersions {
+ for _, resource := range match[m].Resources {
+ groupResources := k8sinterface.ResourceGroupToString(groups, version, resource)
+ for _, groupResource := range groupResources {
+ if k8sObj, ok := (*k8sResources)[groupResource]; ok {
+ if k8sObj == nil {
+ logger.L().Debug(fmt.Sprintf("resource '%s' is nil, probably failed to pull the resource", groupResource))
+ }
+ for i := range k8sObj {
+ k8sObjects = append(k8sObjects, allResources[k8sObj[i]])
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return filterOutChildResources(k8sObjects, match)
+}
+
func getKubernetesObjects(k8sResources *cautils.K8SResources, allResources map[string]workloadinterface.IMetadata, match []reporthandling.RuleMatchObjects) []workloadinterface.IMetadata {
k8sObjects := []workloadinterface.IMetadata{}
diff --git a/core/pkg/policyhandler/handlenotification.go b/core/pkg/policyhandler/handlenotification.go
index 91c50485..35fd6434 100644
--- a/core/pkg/policyhandler/handlenotification.go
+++ b/core/pkg/policyhandler/handlenotification.go
@@ -2,7 +2,9 @@ package policyhandler
import (
"fmt"
+ "strings"
+ "github.com/armosec/k8s-interface/k8sinterface"
"github.com/armosec/kubescape/core/cautils"
"github.com/armosec/kubescape/core/pkg/resourcehandler"
"github.com/armosec/opa-utils/reporthandling"
@@ -45,16 +47,40 @@ func (policyHandler *PolicyHandler) CollectResources(notification *reporthandlin
return opaSessionObj, nil
}
-func (policyHandler *PolicyHandler) getResources(notification *reporthandling.PolicyNotification, opaSessionObj *cautils.OPASessionObj, scanInfo *cautils.ScanInfo) error {
+func scanInfoToScanMetadata(opaSessionObj *cautils.OPASessionObj, scanInfo *cautils.ScanInfo) {
+ opaSessionObj.Metadata.ClusterMetadata.ContextName = k8sinterface.GetCurrentContext().Cluster
+ opaSessionObj.Metadata.ScanMetadata.Format = scanInfo.Format
+ opaSessionObj.Metadata.ScanMetadata.Submit = scanInfo.Submit
+ if len(scanInfo.ExcludedNamespaces) > 1 {
+ opaSessionObj.Metadata.ScanMetadata.ExcludedNamespaces = strings.Split(scanInfo.ExcludedNamespaces[1:], ",")
+ }
+ // scan type
+ if len(scanInfo.PolicyIdentifier) > 0 {
+ opaSessionObj.Metadata.ScanMetadata.TargetType = string(scanInfo.PolicyIdentifier[0].Kind)
+ }
+ // append frameworks
+ for _, policy := range scanInfo.PolicyIdentifier {
+ opaSessionObj.Metadata.ScanMetadata.TargetNames = append(opaSessionObj.Metadata.ScanMetadata.TargetNames, policy.Name)
+ }
+ opaSessionObj.Metadata.ScanMetadata.VerboseMode = scanInfo.VerboseMode
+ opaSessionObj.Metadata.ScanMetadata.FailThreshold = scanInfo.FailThreshold
+ opaSessionObj.Metadata.ScanMetadata.HostScanner = *scanInfo.HostSensorEnabled.Get()
+ opaSessionObj.Metadata.ScanMetadata.VerboseMode = scanInfo.VerboseMode
+ opaSessionObj.Metadata.ScanMetadata.ControlsInputs = scanInfo.ControlsInputs
+}
+func (policyHandler *PolicyHandler) getResources(notification *reporthandling.PolicyNotification, opaSessionObj *cautils.OPASessionObj, scanInfo *cautils.ScanInfo) error {
opaSessionObj.Report.ClusterAPIServerInfo = policyHandler.resourceHandler.GetClusterAPIServerInfo()
- resourcesMap, allResources, err := policyHandler.resourceHandler.GetResources(opaSessionObj.Policies, ¬ification.Designators)
+ scanInfoToScanMetadata(opaSessionObj, scanInfo)
+
+ resourcesMap, allResources, armoResources, err := policyHandler.resourceHandler.GetResources(opaSessionObj, ¬ification.Designators)
if err != nil {
return err
}
opaSessionObj.K8SResources = resourcesMap
opaSessionObj.AllResources = allResources
+ opaSessionObj.ArmoResource = armoResources
return nil
}
diff --git a/core/pkg/resourcehandler/filesloader.go b/core/pkg/resourcehandler/filesloader.go
index e11366e9..e9d6ff59 100644
--- a/core/pkg/resourcehandler/filesloader.go
+++ b/core/pkg/resourcehandler/filesloader.go
@@ -10,7 +10,6 @@ import (
"github.com/armosec/k8s-interface/k8sinterface"
"github.com/armosec/kubescape/core/cautils"
- "github.com/armosec/opa-utils/reporthandling"
)
// FileResourceHandler handle resources from files and URLs
@@ -27,19 +26,20 @@ func NewFileResourceHandler(inputPatterns []string, registryAdaptors *RegistryAd
}
}
-func (fileHandler *FileResourceHandler) GetResources(frameworks []reporthandling.Framework, designator *armotypes.PortalDesignator) (*cautils.K8SResources, map[string]workloadinterface.IMetadata, error) {
+func (fileHandler *FileResourceHandler) GetResources(sessionObj *cautils.OPASessionObj, designator *armotypes.PortalDesignator) (*cautils.K8SResources, map[string]workloadinterface.IMetadata, *cautils.ArmoResources, error) {
// build resources map
// map resources based on framework required resources: map["/group/version/kind"][]
- k8sResources := setResourceMap(frameworks)
+ k8sResources := setK8sResourceMap(sessionObj.Policies)
allResources := map[string]workloadinterface.IMetadata{}
+ var armoResources *cautils.ArmoResources
workloads := []workloadinterface.IMetadata{}
// load resource from local file system
w, err := cautils.LoadResourcesFromFiles(fileHandler.inputPatterns)
if err != nil {
- return nil, allResources, err
+ return nil, allResources, nil, err
}
if w != nil {
workloads = append(workloads, w...)
@@ -48,14 +48,14 @@ func (fileHandler *FileResourceHandler) GetResources(frameworks []reporthandling
// load resources from url
w, err = loadResourcesFromUrl(fileHandler.inputPatterns)
if err != nil {
- return nil, allResources, err
+ return nil, allResources, nil, err
}
if w != nil {
workloads = append(workloads, w...)
}
if len(workloads) == 0 {
- return nil, allResources, fmt.Errorf("empty list of workloads - no workloads found")
+ return nil, allResources, nil, fmt.Errorf("empty list of workloads - no workloads found")
}
// map all resources: map["/group/version/kind"][]
@@ -73,11 +73,11 @@ func (fileHandler *FileResourceHandler) GetResources(frameworks []reporthandling
}
}
- if err := fileHandler.registryAdaptors.collectImagesVulnerabilities(k8sResources, allResources); err != nil {
+ if err := fileHandler.registryAdaptors.collectImagesVulnerabilities(k8sResources, allResources, armoResources); err != nil {
cautils.WarningDisplay(os.Stderr, "Warning: failed to collect images vulnerabilities: %s\n", err.Error())
}
- return k8sResources, allResources, nil
+ return k8sResources, allResources, armoResources, nil
}
diff --git a/core/pkg/resourcehandler/k8sresources.go b/core/pkg/resourcehandler/k8sresources.go
index a489389a..73dd8207 100644
--- a/core/pkg/resourcehandler/k8sresources.go
+++ b/core/pkg/resourcehandler/k8sresources.go
@@ -10,7 +10,7 @@ import (
"github.com/armosec/kubescape/core/cautils/logger/helpers"
"github.com/armosec/kubescape/core/pkg/hostsensorutils"
"github.com/armosec/opa-utils/objectsenvelopes"
- "github.com/armosec/opa-utils/reporthandling"
+ "github.com/armosec/opa-utils/reporthandling/apis"
"github.com/armosec/k8s-interface/cloudsupport"
"github.com/armosec/k8s-interface/k8sinterface"
@@ -44,46 +44,88 @@ func NewK8sResourceHandler(k8s *k8sinterface.KubernetesApi, fieldSelector IField
}
}
-func (k8sHandler *K8sResourceHandler) GetResources(frameworks []reporthandling.Framework, designator *armotypes.PortalDesignator) (*cautils.K8SResources, map[string]workloadinterface.IMetadata, error) {
+func (k8sHandler *K8sResourceHandler) GetResources(sessionObj *cautils.OPASessionObj, designator *armotypes.PortalDesignator) (*cautils.K8SResources, map[string]workloadinterface.IMetadata, *cautils.ArmoResources, error) {
allResources := map[string]workloadinterface.IMetadata{}
// get k8s resources
logger.L().Info("Accessing Kubernetes objects")
cautils.StartSpinner()
-
+ resourceToControl := make(map[string][]string)
// build resources map
// map resources based on framework required resources: map["/group/version/kind"][]
- k8sResourcesMap := setResourceMap(frameworks)
+ k8sResourcesMap := setK8sResourceMap(sessionObj.Policies)
// get namespace and labels from designator (ignore cluster labels)
_, namespace, labels := armotypes.DigestPortalDesignator(designator)
// pull k8s recourses
+ armoResourceMap := setArmoResourceMap(sessionObj.Policies, resourceToControl)
+
+ // map of armo resources to control_ids
+ sessionObj.ResourceToControlsMap = resourceToControl
+
if err := k8sHandler.pullResources(k8sResourcesMap, allResources, namespace, labels); err != nil {
cautils.StopSpinner()
- return k8sResourcesMap, allResources, err
+ return k8sResourcesMap, allResources, armoResourceMap, err
}
- if err := k8sHandler.registryAdaptors.collectImagesVulnerabilities(k8sResourcesMap, allResources); err != nil {
- logger.L().Warning("failed to collect image vulnerabilities", helpers.Error(err))
+ numberOfWorkerNodes, err := k8sHandler.pullWorkerNodesNumber()
+
+ if err != nil {
+ logger.L().Debug("failed to collect worker nodes number", helpers.Error(err))
+ } else {
+ sessionObj.Metadata.ClusterMetadata.NumberOfWorkerNodes = numberOfWorkerNodes
}
- if err := k8sHandler.collectHostResources(allResources, k8sResourcesMap); err != nil {
- logger.L().Warning("failed to collect host scanner resources", helpers.Error(err))
+ imgVulnResources := cautils.MapImageVulnResources(armoResourceMap)
+ // check that controls use image vulnerability resources
+ if len(imgVulnResources) > 0 {
+ if err := k8sHandler.registryAdaptors.collectImagesVulnerabilities(k8sResourcesMap, allResources, armoResourceMap); err != nil {
+ logger.L().Warning("failed to collect image vulnerabilities", helpers.Error(err))
+ }
+ }
+
+ hostResources := cautils.MapHostResources(armoResourceMap)
+ // check that controls use host sensor resources
+ if len(hostResources) > 0 {
+ if sessionObj.Metadata.ScanMetadata.HostScanner {
+ infoMap, err := k8sHandler.collectHostResources(allResources, armoResourceMap)
+ if err != nil {
+ logger.L().Warning("failed to collect host scanner resources", helpers.Error(err))
+ cautils.SetInfoMapForResources(err.Error(), hostResources, sessionObj.InfoMap)
+ } else if k8sHandler.hostSensorHandler == nil {
+ // using hostSensor mock
+ cautils.SetInfoMapForResources("failed to init host scanner", hostResources, sessionObj.InfoMap)
+ } else {
+ sessionObj.InfoMap = infoMap
+ }
+ } else {
+ cautils.SetInfoMapForResources("enable-host-scan flag not used", hostResources, sessionObj.InfoMap)
+ }
}
if err := k8sHandler.collectRbacResources(allResources); err != nil {
logger.L().Warning("failed to collect rbac resources", helpers.Error(err))
}
- if err := getCloudProviderDescription(allResources, k8sResourcesMap); err != nil {
- logger.L().Warning("failed to collect cloud data", helpers.Error(err))
+
+ cloudResources := cautils.MapCloudResources(armoResourceMap)
+ // check that controls use cloud resources
+ if len(cloudResources) > 0 {
+ provider, err := getCloudProviderDescription(allResources, armoResourceMap)
+ if err != nil {
+ cautils.SetInfoMapForResources(err.Error(), cloudResources, sessionObj.InfoMap)
+ logger.L().Warning("failed to collect cloud data", helpers.Error(err))
+ }
+ if provider != "" {
+ sessionObj.Metadata.ClusterMetadata.CloudProvider = provider
+ }
}
cautils.StopSpinner()
logger.L().Success("Accessed to Kubernetes objects")
- return k8sResourcesMap, allResources, nil
+ return k8sResourcesMap, allResources, armoResourceMap, nil
}
func (k8sHandler *K8sResourceHandler) GetClusterAPIServerInfo() *version.Info {
@@ -180,12 +222,11 @@ func ConvertMapListToMeta(resourceMap []map[string]interface{}) []workloadinterf
// }
// return nil
// }
-func (k8sHandler *K8sResourceHandler) collectHostResources(allResources map[string]workloadinterface.IMetadata, resourcesMap *cautils.K8SResources) error {
+func (k8sHandler *K8sResourceHandler) collectHostResources(allResources map[string]workloadinterface.IMetadata, armoResourceMap *cautils.ArmoResources) (map[string]apis.StatusInfo, error) {
logger.L().Debug("Collecting host scanner resources")
-
- hostResources, err := k8sHandler.hostSensorHandler.CollectResources()
+ hostResources, infoMap, err := k8sHandler.hostSensorHandler.CollectResources()
if err != nil {
- return err
+ return nil, err
}
for rscIdx := range hostResources {
@@ -193,13 +234,13 @@ func (k8sHandler *K8sResourceHandler) collectHostResources(allResources map[stri
groupResource := k8sinterface.JoinResourceTriplets(group, version, hostResources[rscIdx].GetKind())
allResources[hostResources[rscIdx].GetID()] = &hostResources[rscIdx]
- grpResourceList, ok := (*resourcesMap)[groupResource]
+ grpResourceList, ok := (*armoResourceMap)[groupResource]
if !ok {
grpResourceList = make([]string, 0)
}
- (*resourcesMap)[groupResource] = append(grpResourceList, hostResources[rscIdx].GetID())
+ (*armoResourceMap)[groupResource] = append(grpResourceList, hostResources[rscIdx].GetID())
}
- return nil
+ return infoMap, nil
}
func (k8sHandler *K8sResourceHandler) collectRbacResources(allResources map[string]workloadinterface.IMetadata) error {
@@ -218,20 +259,19 @@ func (k8sHandler *K8sResourceHandler) collectRbacResources(allResources map[stri
return nil
}
-func getCloudProviderDescription(allResources map[string]workloadinterface.IMetadata, k8sResourcesMap *cautils.K8SResources) error {
+func getCloudProviderDescription(allResources map[string]workloadinterface.IMetadata, armoResourceMap *cautils.ArmoResources) (string, error) {
logger.L().Debug("Collecting cloud data")
-
cloudProvider := initCloudProvider()
cluster := cloudProvider.getKubeCluster()
clusterName := cloudProvider.getKubeClusterName()
provider := getCloudProvider()
region, err := cloudProvider.getRegion(cluster, provider)
if err != nil {
- return err
+ return provider, err
}
project, err := cloudProvider.getProject(cluster, provider)
if err != nil {
- return err
+ return provider, err
}
if provider != "" {
@@ -242,17 +282,33 @@ func getCloudProviderDescription(allResources map[string]workloadinterface.IMeta
// Return error with useful info on how to configure credentials for getting cloud provider info
switch provider {
case "gke":
- return fmt.Errorf("could not get descriptive information about gke cluster: %s using sdk client. See https://developers.google.com/accounts/docs/application-default-credentials for more information", cluster)
+ return provider, fmt.Errorf("could not get descriptive information about gke cluster: %s using sdk client. See https://developers.google.com/accounts/docs/application-default-credentials for more information", cluster)
case "eks":
- return fmt.Errorf("could not get descriptive information about eks cluster: %s using sdk client. Check out how to configure credentials in https://docs.aws.amazon.com/sdk-for-go/api/", cluster)
+ return provider, fmt.Errorf("could not get descriptive information about eks cluster: %s using sdk client. Check out how to configure credentials in https://docs.aws.amazon.com/sdk-for-go/api/", cluster)
case "aks":
- return fmt.Errorf("could not get descriptive information about aks cluster: %s. %v", cluster, err.Error())
+ return provider, fmt.Errorf("could not get descriptive information about aks cluster: %s. %v", cluster, err.Error())
}
- return err
+ return provider, err
}
allResources[wl.GetID()] = wl
- (*k8sResourcesMap)[fmt.Sprintf("%s/%s", wl.GetApiVersion(), wl.GetKind())] = []string{wl.GetID()}
+ (*armoResourceMap)[fmt.Sprintf("%s/%s", wl.GetApiVersion(), wl.GetKind())] = []string{wl.GetID()}
}
- return nil
+ return provider, nil
}
+
+func (k8sHandler *K8sResourceHandler) pullWorkerNodesNumber() (int, error) {
+ // labels used for control plane
+ listOptions := metav1.ListOptions{
+ LabelSelector: "!node-role.kubernetes.io/control-plane,!node-role.kubernetes.io/master",
+ }
+ nodesList, err := k8sHandler.k8s.KubernetesClient.CoreV1().Nodes().List(context.TODO(), listOptions)
+ if err != nil {
+ return 0, err
+ }
+ nodesNumber := 0
+ if nodesList != nil {
+ nodesNumber = len(nodesList.Items)
+ }
+ return nodesNumber, nil
+}
diff --git a/core/pkg/resourcehandler/k8sresourcesutils.go b/core/pkg/resourcehandler/k8sresourcesutils.go
index 0061c3ea..167a5722 100644
--- a/core/pkg/resourcehandler/k8sresourcesutils.go
+++ b/core/pkg/resourcehandler/k8sresourcesutils.go
@@ -4,14 +4,23 @@ import (
"strings"
"github.com/armosec/kubescape/core/cautils"
+ "github.com/armosec/kubescape/core/pkg/hostsensorutils"
"github.com/armosec/opa-utils/reporthandling"
+ "k8s.io/utils/strings/slices"
"github.com/armosec/k8s-interface/k8sinterface"
)
-func setResourceMap(frameworks []reporthandling.Framework) *cautils.K8SResources {
+var (
+ ClusterDescribe = "ClusterDescribe"
+
+ MapResourceToApiGroupCloud = map[string][]string{
+ ClusterDescribe: {"container.googleapis.com/v1", "eks.amazonaws.com/v1"}}
+)
+
+func setK8sResourceMap(frameworks []reporthandling.Framework) *cautils.K8SResources {
k8sResources := make(cautils.K8SResources)
- complexMap := setComplexResourceMap(frameworks)
+ complexMap := setComplexK8sResourceMap(frameworks)
for group := range complexMap {
for version := range complexMap[group] {
for resource := range complexMap[group][version] {
@@ -25,33 +34,87 @@ func setResourceMap(frameworks []reporthandling.Framework) *cautils.K8SResources
return &k8sResources
}
+func setArmoResourceMap(frameworks []reporthandling.Framework, resourceToControl map[string][]string) *cautils.ArmoResources {
+ armoResources := make(cautils.ArmoResources)
+ complexMap := setComplexArmoResourceMap(frameworks, resourceToControl)
+ for group := range complexMap {
+ for version := range complexMap[group] {
+ for resource := range complexMap[group][version] {
+ groupResources := k8sinterface.ResourceGroupToString(group, version, resource)
+ for _, groupResource := range groupResources {
+ armoResources[groupResource] = nil
+ }
+ }
+ }
+ }
+ return &armoResources
+}
+
func convertComplexResourceMap(frameworks []reporthandling.Framework) map[string]map[string]map[string]interface{} {
k8sResources := make(map[string]map[string]map[string]interface{})
for _, framework := range frameworks {
for _, control := range framework.Controls {
for _, rule := range control.Rules {
for _, match := range rule.Match {
- insertK8sResources(k8sResources, match)
+ insertResources(k8sResources, match)
}
}
}
}
return k8sResources
}
-func setComplexResourceMap(frameworks []reporthandling.Framework) map[string]map[string]map[string]interface{} {
+func setComplexK8sResourceMap(frameworks []reporthandling.Framework) map[string]map[string]map[string]interface{} {
k8sResources := make(map[string]map[string]map[string]interface{})
for _, framework := range frameworks {
for _, control := range framework.Controls {
for _, rule := range control.Rules {
for _, match := range rule.Match {
- insertK8sResources(k8sResources, match)
+ insertResources(k8sResources, match)
}
}
}
}
return k8sResources
}
-func insertK8sResources(k8sResources map[string]map[string]map[string]interface{}, match reporthandling.RuleMatchObjects) {
+
+// [group][versionn][resource]
+func setComplexArmoResourceMap(frameworks []reporthandling.Framework, resourceToControls map[string][]string) map[string]map[string]map[string]interface{} {
+ k8sResources := make(map[string]map[string]map[string]interface{})
+ for _, framework := range frameworks {
+ for _, control := range framework.Controls {
+ for _, rule := range control.Rules {
+ for _, match := range rule.DynamicMatch {
+ insertArmoResourcesAndControls(k8sResources, match, resourceToControls, control)
+ }
+ }
+ }
+ }
+ return k8sResources
+}
+
+func mapArmoResourceToApiGroup(resource string) []string {
+ if val, ok := hostsensorutils.MapResourceToApiGroup[resource]; ok {
+ return []string{val}
+ }
+ return MapResourceToApiGroupCloud[resource]
+}
+
+func insertControls(resource string, resourceToControl map[string][]string, control reporthandling.Control) {
+ armoResources := mapArmoResourceToApiGroup(resource)
+ for _, armoResource := range armoResources {
+ group, version := k8sinterface.SplitApiVersion(armoResource)
+ r := k8sinterface.JoinResourceTriplets(group, version, resource)
+ if _, ok := resourceToControl[r]; !ok {
+ resourceToControl[r] = append(resourceToControl[r], control.ControlID)
+ } else {
+ if !slices.Contains(resourceToControl[r], control.ControlID) {
+ resourceToControl[r] = append(resourceToControl[r], control.ControlID)
+ }
+ }
+ }
+}
+
+func insertResources(k8sResources map[string]map[string]map[string]interface{}, match reporthandling.RuleMatchObjects) {
for _, apiGroup := range match.APIGroups {
if v, ok := k8sResources[apiGroup]; !ok || v == nil {
k8sResources[apiGroup] = make(map[string]map[string]interface{})
@@ -69,6 +132,25 @@ func insertK8sResources(k8sResources map[string]map[string]map[string]interface{
}
}
+func insertArmoResourcesAndControls(k8sResources map[string]map[string]map[string]interface{}, match reporthandling.RuleMatchObjects, resourceToControl map[string][]string, control reporthandling.Control) {
+ for _, apiGroup := range match.APIGroups {
+ if v, ok := k8sResources[apiGroup]; !ok || v == nil {
+ k8sResources[apiGroup] = make(map[string]map[string]interface{})
+ }
+ for _, apiVersions := range match.APIVersions {
+ if v, ok := k8sResources[apiGroup][apiVersions]; !ok || v == nil {
+ k8sResources[apiGroup][apiVersions] = make(map[string]interface{})
+ }
+ for _, resource := range match.Resources {
+ if _, ok := k8sResources[apiGroup][apiVersions][resource]; !ok {
+ k8sResources[apiGroup][apiVersions][resource] = nil
+ }
+ insertControls(resource, resourceToControl, control)
+ }
+ }
+ }
+}
+
func getGroupNVersion(apiVersion string) (string, string) {
gv := strings.Split(apiVersion, "/")
group, version := "", ""
diff --git a/core/pkg/resourcehandler/k8sresourcesutils_test.go b/core/pkg/resourcehandler/k8sresourcesutils_test.go
index ebb0b751..79ea71a3 100644
--- a/core/pkg/resourcehandler/k8sresourcesutils_test.go
+++ b/core/pkg/resourcehandler/k8sresourcesutils_test.go
@@ -13,7 +13,7 @@ func TestGetK8sResources(t *testing.T) {
func TestSetResourceMap(t *testing.T) {
k8sinterface.InitializeMapResourcesMock()
framework := reporthandling.MockFrameworkA()
- k8sResources := setResourceMap([]reporthandling.Framework{*framework})
+ k8sResources := setK8sResourceMap([]reporthandling.Framework{*framework})
resources := k8sinterface.ResourceGroupToString("*", "v1", "Pod")
if len(resources) == 0 {
t.Error("expected resources")
@@ -43,9 +43,9 @@ func TestInsertK8sResources(t *testing.T) {
APIVersions: []string{"v1"},
Resources: []string{"secrets"},
}
- insertK8sResources(k8sResources, match1)
- insertK8sResources(k8sResources, match2)
- insertK8sResources(k8sResources, match3)
+ insertResources(k8sResources, match1)
+ insertResources(k8sResources, match2)
+ insertResources(k8sResources, match3)
apiGroup1, ok := k8sResources["apps"]
if !ok {
diff --git a/core/pkg/resourcehandler/registrydata.go b/core/pkg/resourcehandler/registrydata.go
index 35b3646a..c0a4bee7 100644
--- a/core/pkg/resourcehandler/registrydata.go
+++ b/core/pkg/resourcehandler/registrydata.go
@@ -34,7 +34,7 @@ func NewRegistryAdaptors() (*RegistryAdaptors, error) {
return registryAdaptors, nil
}
-func (registryAdaptors *RegistryAdaptors) collectImagesVulnerabilities(k8sResourcesMap *cautils.K8SResources, allResources map[string]workloadinterface.IMetadata) error {
+func (registryAdaptors *RegistryAdaptors) collectImagesVulnerabilities(k8sResourcesMap *cautils.K8SResources, allResources map[string]workloadinterface.IMetadata, armoResourceMap *cautils.ArmoResources) error {
logger.L().Debug("Collecting images vulnerabilities")
// list cluster images
@@ -64,7 +64,7 @@ func (registryAdaptors *RegistryAdaptors) collectImagesVulnerabilities(k8sResour
for i := range metaObjs {
allResources[metaObjs[i].GetID()] = metaObjs[i]
}
- (*k8sResourcesMap)[k8sinterface.JoinResourceTriplets(ImagevulnerabilitiesObjectGroup, ImagevulnerabilitiesObjectVersion, ImagevulnerabilitiesObjectKind)] = workloadinterface.ListMetaIDs(metaObjs)
+ (*armoResourceMap)[k8sinterface.JoinResourceTriplets(ImagevulnerabilitiesObjectGroup, ImagevulnerabilitiesObjectVersion, ImagevulnerabilitiesObjectKind)] = workloadinterface.ListMetaIDs(metaObjs)
return nil
}
diff --git a/core/pkg/resourcehandler/resourceshandler.go b/core/pkg/resourcehandler/resourceshandler.go
index e8133e90..fa3f439b 100644
--- a/core/pkg/resourcehandler/resourceshandler.go
+++ b/core/pkg/resourcehandler/resourceshandler.go
@@ -4,11 +4,10 @@ import (
"github.com/armosec/armoapi-go/armotypes"
"github.com/armosec/k8s-interface/workloadinterface"
"github.com/armosec/kubescape/core/cautils"
- "github.com/armosec/opa-utils/reporthandling"
"k8s.io/apimachinery/pkg/version"
)
type IResourceHandler interface {
- GetResources([]reporthandling.Framework, *armotypes.PortalDesignator) (*cautils.K8SResources, map[string]workloadinterface.IMetadata, error)
+ GetResources(*cautils.OPASessionObj, *armotypes.PortalDesignator) (*cautils.K8SResources, map[string]workloadinterface.IMetadata, *cautils.ArmoResources, error)
GetClusterAPIServerInfo() *version.Info
}
diff --git a/core/pkg/resultshandling/printer/v2/controltable.go b/core/pkg/resultshandling/printer/v2/controltable.go
index ea26300b..67f9d1c5 100644
--- a/core/pkg/resultshandling/printer/v2/controltable.go
+++ b/core/pkg/resultshandling/printer/v2/controltable.go
@@ -7,7 +7,7 @@ import (
"github.com/armosec/opa-utils/reporthandling/results/v1/reportsummary"
)
-func generateRow(controlSummary reportsummary.IControlSummary) []string {
+func generateRow(controlSummary reportsummary.IControlSummary, infoToPrintInfoMap map[string]string) []string {
row := []string{controlSummary.GetName()}
row = append(row, fmt.Sprintf("%d", controlSummary.NumberOfResources().Failed()))
row = append(row, fmt.Sprintf("%d", controlSummary.NumberOfResources().Excluded()))
@@ -15,8 +15,14 @@ func generateRow(controlSummary reportsummary.IControlSummary) []string {
if !controlSummary.GetStatus().IsSkipped() {
row = append(row, fmt.Sprintf("%d", int(controlSummary.GetScore()))+"%")
+ row = append(row, "")
} else {
- row = append(row, "skipped")
+ row = append(row, string(controlSummary.GetStatus().Status()))
+ if controlSummary.GetStatus().IsSkipped() {
+ row = append(row, infoToPrintInfoMap[controlSummary.GetStatus().Info()])
+ } else {
+ row = append(row, "")
+ }
}
return row
}
@@ -32,5 +38,5 @@ func getSortedControlsNames(controls reportsummary.ControlSummaries) []string {
}
func getControlTableHeaders() []string {
- return []string{"CONTROL NAME", "FAILED RESOURCES", "EXCLUDED RESOURCES", "ALL RESOURCES", "% RISK-SCORE"}
+ return []string{"CONTROL NAME", "FAILED RESOURCES", "EXCLUDED RESOURCES", "ALL RESOURCES", "% RISK-SCORE", "INFO"}
}
diff --git a/core/pkg/resultshandling/printer/v2/pdf.go b/core/pkg/resultshandling/printer/v2/pdf.go
index 9a7d8a27..32090030 100644
--- a/core/pkg/resultshandling/printer/v2/pdf.go
+++ b/core/pkg/resultshandling/printer/v2/pdf.go
@@ -54,15 +54,37 @@ func (pdfPrinter *PdfPrinter) SetWriter(outputFile string) {
func (pdfPrinter *PdfPrinter) Score(score float32) {
fmt.Fprintf(os.Stderr, "\nOverall risk-score (0- Excellent, 100- All failed): %d\n", int(score))
}
+func (pdfPrinter *PdfPrinter) printInfo(m pdf.Maroto, summaryDetails *reportsummary.SummaryDetails, infoMap map[string]string) {
+ emptyRowCounter := 1
+ for key, val := range infoMap {
+ if val != "" {
+ m.Row(5, func() {
+ m.Col(1, func() {
+ m.Text(fmt.Sprintf("%v", val))
+ })
+ m.Col(12, func() {
+ m.Text(fmt.Sprintf("%v", key))
+ })
+ })
+ if emptyRowCounter < len(infoMap) {
+ m.Row(2.5, func() {})
+ emptyRowCounter++
+ }
+ }
+ }
+
+}
func (pdfPrinter *PdfPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
pdfPrinter.sortedControlNames = getSortedControlsNames(opaSessionObj.Report.SummaryDetails.Controls)
+ infoToPrintInfoMap := mapInfoToPrintInfo(opaSessionObj.Report.SummaryDetails.Controls)
m := pdf.NewMaroto(consts.Portrait, consts.A4)
pdfPrinter.printHeader(m)
pdfPrinter.printFramework(m, opaSessionObj.Report.SummaryDetails.ListFrameworks())
pdfPrinter.printTable(m, &opaSessionObj.Report.SummaryDetails)
pdfPrinter.printFinalResult(m, &opaSessionObj.Report.SummaryDetails)
+ pdfPrinter.printInfo(m, &opaSessionObj.Report.SummaryDetails, infoToPrintInfoMap)
// Extrat output buffer.
outBuff, err := m.Output()
@@ -129,12 +151,13 @@ func (pdfPrinter *PdfPrinter) printFramework(m pdf.Maroto, frameworks []reportsu
// Create pdf table
func (pdfPrinter *PdfPrinter) printTable(m pdf.Maroto, summaryDetails *reportsummary.SummaryDetails) {
headers := getControlTableHeaders()
+ infoToPrintInfoMap := mapInfoToPrintInfo(summaryDetails.Controls)
controls := make([][]string, len(pdfPrinter.sortedControlNames))
for i := range controls {
controls[i] = make([]string, len(headers))
}
for i := 0; i < len(pdfPrinter.sortedControlNames); i++ {
- controls[i] = generateRow(summaryDetails.Controls.GetControl(reportsummary.EControlCriteriaName, pdfPrinter.sortedControlNames[i]))
+ controls[i] = generateRow(summaryDetails.Controls.GetControl(reportsummary.EControlCriteriaName, pdfPrinter.sortedControlNames[i]), infoToPrintInfoMap)
}
m.TableList(headers, controls, props.TableList{
diff --git a/core/pkg/resultshandling/printer/v2/prettyprinter.go b/core/pkg/resultshandling/printer/v2/prettyprinter.go
index 30ad8626..4cc3daef 100644
--- a/core/pkg/resultshandling/printer/v2/prettyprinter.go
+++ b/core/pkg/resultshandling/printer/v2/prettyprinter.go
@@ -83,10 +83,17 @@ func (prettyPrinter *PrettyPrinter) printTitle(controlSummary reportsummary.ICon
cautils.FailureDisplay(prettyPrinter.writer, "failed %v\n", emoji.SadButRelievedFace)
case apis.StatusExcluded:
cautils.WarningDisplay(prettyPrinter.writer, "excluded %v\n", emoji.NeutralFace)
+ case apis.StatusIrrelevant:
+ cautils.SuccessDisplay(prettyPrinter.writer, "irrelevant %v\n", emoji.ConfusedFace)
+ case apis.StatusError:
+ cautils.WarningDisplay(prettyPrinter.writer, "error %v\n", emoji.ConfusedFace)
default:
cautils.SuccessDisplay(prettyPrinter.writer, "passed %v\n", emoji.ThumbsUp)
}
cautils.DescriptionDisplay(prettyPrinter.writer, "Description: %s\n", controlSummary.GetDescription())
+ if controlSummary.GetStatus().Info() != "" {
+ cautils.WarningDisplay(prettyPrinter.writer, "Reason: %v\n", controlSummary.GetStatus().Info())
+ }
}
func (prettyPrinter *PrettyPrinter) printResources(controlSummary reportsummary.IControlSummary, allResources map[string]workloadinterface.IMetadata) {
@@ -166,6 +173,7 @@ func generateFooter(summaryDetails *reportsummary.SummaryDetails) []string {
row = append(row, fmt.Sprintf("%d", summaryDetails.NumberOfResources().Excluded()))
row = append(row, fmt.Sprintf("%d", summaryDetails.NumberOfResources().All()))
row = append(row, fmt.Sprintf("%.2f%s", summaryDetails.Score, "%"))
+ row = append(row, " ")
return row
}
@@ -175,30 +183,37 @@ func (prettyPrinter *PrettyPrinter) printSummaryTable(summaryDetails *reportsumm
summaryTable.SetAutoWrapText(false)
summaryTable.SetHeader(getControlTableHeaders())
summaryTable.SetHeaderLine(true)
- alignments := []int{tablewriter.ALIGN_LEFT, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER}
+ alignments := []int{tablewriter.ALIGN_LEFT, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER}
summaryTable.SetColumnAlignment(alignments)
-
+ infoToPrintInfoMap := mapInfoToPrintInfo(summaryDetails.Controls)
for i := 0; i < len(prettyPrinter.sortedControlNames); i++ {
- summaryTable.Append(generateRow(summaryDetails.Controls.GetControl(reportsummary.EControlCriteriaName, prettyPrinter.sortedControlNames[i])))
+ summaryTable.Append(generateRow(summaryDetails.Controls.GetControl(reportsummary.EControlCriteriaName, prettyPrinter.sortedControlNames[i]), infoToPrintInfoMap))
}
summaryTable.SetFooter(generateFooter(summaryDetails))
// summaryTable.SetFooter(generateFooter())
+ cautils.InfoTextDisplay(prettyPrinter.writer, frameworksScoresToString(summaryDetails.ListFrameworks()))
summaryTable.Render()
+ prettyPrinter.printInfo(infoToPrintInfoMap)
// For control scan framework will be nil
- cautils.InfoTextDisplay(prettyPrinter.writer, frameworksScoresToString(summaryDetails.ListFrameworks()))
+}
+
+func (prettyPrinter *PrettyPrinter) printInfo(infoToPrintInfoMap map[string]string) {
+ for info, stars := range infoToPrintInfoMap {
+ cautils.WarningDisplay(prettyPrinter.writer, fmt.Sprintf("%s - %s\n", stars, info))
+ }
}
func frameworksScoresToString(frameworks []reportsummary.IFrameworkSummary) string {
if len(frameworks) == 1 {
if frameworks[0].GetName() != "" {
- return fmt.Sprintf("FRAMEWORK %s\n", frameworks[0].GetName())
+ return fmt.Sprintf("\nFRAMEWORK %s\n", frameworks[0].GetName())
// cautils.InfoTextDisplay(prettyPrinter.writer, ))
}
} else if len(frameworks) > 1 {
- p := "FRAMEWORKS: "
+ p := "\nFRAMEWORKS: "
i := 0
for ; i < len(frameworks)-1; i++ {
p += fmt.Sprintf("%s (risk: %.2f), ", frameworks[i].GetName(), frameworks[i].GetScore())
diff --git a/core/pkg/resultshandling/printer/v2/utils.go b/core/pkg/resultshandling/printer/v2/utils.go
index 08d899d5..45e107e6 100644
--- a/core/pkg/resultshandling/printer/v2/utils.go
+++ b/core/pkg/resultshandling/printer/v2/utils.go
@@ -6,6 +6,7 @@ import (
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
"github.com/armosec/opa-utils/reporthandling"
+ "github.com/armosec/opa-utils/reporthandling/results/v1/reportsummary"
"github.com/armosec/opa-utils/reporthandling/results/v1/resourcesresults"
reporthandlingv2 "github.com/armosec/opa-utils/reporthandling/v2"
)
@@ -38,6 +39,20 @@ func finalizeResults(results []resourcesresults.Result, resourcesResult map[stri
}
}
+func mapInfoToPrintInfo(controls reportsummary.ControlSummaries) map[string]string {
+ infoToPrintInfoMap := make(map[string]string)
+ starCount := "*"
+ for _, control := range controls {
+ if control.GetStatus().IsSkipped() && control.GetStatus().Info() != "" {
+ if _, ok := infoToPrintInfoMap[control.GetStatus().Info()]; !ok {
+ infoToPrintInfoMap[control.GetStatus().Info()] = starCount
+ starCount += starCount
+ }
+ }
+ }
+ return infoToPrintInfoMap
+}
+
func finalizeResources(resources []reporthandling.Resource, results []resourcesresults.Result, allResources map[string]workloadinterface.IMetadata) {
for i := range results {
if obj, ok := allResources[results[i].ResourceID]; ok {
diff --git a/core/pkg/resultshandling/reporter/v2/reporteventreceiver.go b/core/pkg/resultshandling/reporter/v2/reporteventreceiver.go
index d57290e2..fb15248a 100644
--- a/core/pkg/resultshandling/reporter/v2/reporteventreceiver.go
+++ b/core/pkg/resultshandling/reporter/v2/reporteventreceiver.go
@@ -60,6 +60,7 @@ func (report *ReportEventReceiver) ActionSendReport(opaSessionObj *cautils.OPASe
opaSessionObj.Report.ReportID = uuid.NewString()
opaSessionObj.Report.CustomerGUID = report.customerGUID
opaSessionObj.Report.ClusterName = report.clusterName
+ opaSessionObj.Report.Metadata = *opaSessionObj.Metadata
if err := report.prepareReport(opaSessionObj.Report); err != nil {
logger.L().Error("failed to publish results", helpers.Error(err))
diff --git a/docs/ARMO-header-2022.gif b/docs/ARMO-header-2022.gif
new file mode 100644
index 00000000..09d4adab
Binary files /dev/null and b/docs/ARMO-header-2022.gif differ
diff --git a/httphandler/go.mod b/httphandler/go.mod
index 5c09fbdb..e4e173dd 100644
--- a/httphandler/go.mod
+++ b/httphandler/go.mod
@@ -4,6 +4,7 @@ go 1.17
replace github.com/armosec/kubescape/core => ../core
+
require (
github.com/armosec/kubescape/core v0.0.0-00010101000000-000000000000
github.com/armosec/utils-go v0.0.3
diff --git a/httphandler/go.sum b/httphandler/go.sum
index 5193f2eb..c6e3f228 100644
--- a/httphandler/go.sum
+++ b/httphandler/go.sum
@@ -103,15 +103,10 @@ github.com/armosec/armoapi-go v0.0.2/go.mod h1:vIK17yoKbJRQyZXWWLe3AqfqCRITxW8qm
github.com/armosec/armoapi-go v0.0.23/go.mod h1:iaVVGyc23QGGzAdv4n+szGQg3Rbpixn9yQTU3qWRpaw=
github.com/armosec/armoapi-go v0.0.58 h1:gLVLTG1QRphz8vbkZdG8syijwNSh3oBVwNmn91us4gc=
github.com/armosec/armoapi-go v0.0.58/go.mod h1:U/Axd+D5N00x9Ekr7t+5HXqLCMO+98NfJSVAggqJftI=
-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.66/go.mod h1:vwprS8qn/iowd5yf0JHpqDsLA5I8W2muqX9AxKhkb0Q=
github.com/armosec/k8s-interface v0.0.68 h1:6CtSakISiI47YHkxh+Va9FzZQIBkWa6g9sbiNxq1Zkk=
github.com/armosec/k8s-interface v0.0.68/go.mod h1:PeWn41C2uenZi+xfZdyFF/zG5wXACA00htQyknDUWDE=
-github.com/armosec/opa-utils v0.0.64/go.mod h1:6tQP8UDq2EvEfSqh8vrUdr/9QVSCG4sJfju1SXQOn4c=
-github.com/armosec/opa-utils v0.0.118 h1:ZX1crwVQmo+sDv+jmTNLbDYfApUBzlgPhD8QI2GCJX0=
-github.com/armosec/opa-utils v0.0.118/go.mod h1:gap+EaLG5rnyqvIRGxtdNDC9y7VvoGNm90zK8Ls7avQ=
-github.com/armosec/rbac-utils v0.0.1/go.mod h1:pQ8CBiij8kSKV7aeZm9FMvtZN28VgA7LZcYyTWimq40=
github.com/armosec/rbac-utils v0.0.14 h1:CKYKcgqJEXWF2Hen/B1pVGtS3nDAG1wp9dDv6oNtq90=
github.com/armosec/rbac-utils v0.0.14/go.mod h1:Ex/IdGWhGv9HZq6Hs8N/ApzCKSIvpNe/ETqDfnuyah0=
github.com/armosec/utils-go v0.0.2/go.mod h1:itWmRLzRdsnwjpEOomL0mBWGnVNNIxSjDAdyc+b0iUo=