mirror of
https://github.com/kubescape/kubescape.git
synced 2026-04-15 06:58:11 +00:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0cfdabd25a | ||
|
|
8b6cb6c5d8 | ||
|
|
3df3b7766c | ||
|
|
0d83654197 | ||
|
|
bd9e44382e | ||
|
|
2a7c20ea94 | ||
|
|
bde0dc9a17 | ||
|
|
7d7336ae01 | ||
|
|
e5e608324d | ||
|
|
569c1444f7 | ||
|
|
dc5ef28324 | ||
|
|
aea6c0eab8 | ||
|
|
c80a15d0cf | ||
|
|
1ddd57aa1d | ||
|
|
55adb0da6b | ||
|
|
a716289cc8 | ||
|
|
093d71fff4 | ||
|
|
4fe40e348d | ||
|
|
29a67b806d | ||
|
|
0169f42747 | ||
|
|
92e100c497 | ||
|
|
536fe970f7 | ||
|
|
85526b06b6 | ||
|
|
d9b6c048d5 | ||
|
|
7e46a6529a | ||
|
|
2dc5fd80da | ||
|
|
e89cc8ca24 | ||
|
|
d39aeb0691 | ||
|
|
da9d98134a | ||
|
|
9992a9a0e4 | ||
|
|
adc8a16e85 | ||
|
|
58b833c18a | ||
|
|
6372ce5647 |
@@ -38,7 +38,7 @@ curl -s https://raw.githubusercontent.com/armosec/kubescape/master/install.sh |
|
||||
|
||||
## Run:
|
||||
```
|
||||
kubescape scan --submit --enable-host-scan
|
||||
kubescape scan --submit --enable-host-scan --format-version v2 --verbose
|
||||
```
|
||||
|
||||
<img src="docs/summary.png">
|
||||
@@ -115,7 +115,7 @@ Set-ExecutionPolicy RemoteSigned -scope CurrentUser
|
||||
|
||||
#### Scan a running Kubernetes cluster and submit results to the [Kubescape SaaS version](https://portal.armo.cloud/)
|
||||
```
|
||||
kubescape scan --submit --enable-host-scan
|
||||
kubescape scan --submit --enable-host-scan --verbose
|
||||
```
|
||||
|
||||
> Read [here](https://hub.armo.cloud/docs/host-sensor) more about the `enable-host-scan` flag
|
||||
|
||||
@@ -7,8 +7,9 @@ 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.127
|
||||
github.com/armosec/opa-utils v0.0.130
|
||||
github.com/armosec/rbac-utils v0.0.14
|
||||
github.com/enescakir/emoji v1.0.0
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/mattn/go-isatty v0.0.14
|
||||
github.com/spf13/cobra v1.4.0
|
||||
@@ -51,7 +52,6 @@ require (
|
||||
github.com/docker/docker v20.10.9+incompatible // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-units v0.4.0 // indirect
|
||||
github.com/enescakir/emoji v1.0.0 // indirect
|
||||
github.com/envoyproxy/go-control-plane v0.10.1 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v0.6.2 // indirect
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
|
||||
@@ -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.127 h1:uVyH/+pjpiA0oBO6QODjtdCiPgHx7KQ/TcxxkPvAl4c=
|
||||
github.com/armosec/opa-utils v0.0.127/go.mod h1:gap+EaLG5rnyqvIRGxtdNDC9y7VvoGNm90zK8Ls7avQ=
|
||||
github.com/armosec/opa-utils v0.0.130 h1:uP60M0PzmDtLqvsA/jX8BED9/Ava4n2QG7VCkuI+hwI=
|
||||
github.com/armosec/opa-utils v0.0.130/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=
|
||||
|
||||
@@ -84,5 +84,8 @@ func getRootCmd(ks meta.IKubescape) *cobra.Command {
|
||||
|
||||
func main() {
|
||||
ks := NewDefaultKubescapeCommand()
|
||||
ks.Execute()
|
||||
err := ks.Execute()
|
||||
if err != nil {
|
||||
logger.L().Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,10 @@ import (
|
||||
|
||||
"github.com/armosec/kubescape/core/cautils"
|
||||
"github.com/armosec/kubescape/core/cautils/logger"
|
||||
"github.com/armosec/kubescape/core/cautils/logger/helpers"
|
||||
"github.com/armosec/kubescape/core/meta"
|
||||
"github.com/armosec/opa-utils/reporthandling"
|
||||
"github.com/enescakir/emoji"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -66,7 +68,7 @@ func getControlCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comman
|
||||
|
||||
if len(args) > 1 {
|
||||
if len(args[1:]) == 0 || args[1] != "-" {
|
||||
scanInfo.InputPatterns = args[1:]
|
||||
scanInfo.InputPatterns = []string{args[1]}
|
||||
} else { // store stdin to file - do NOT move to separate function !!
|
||||
tempFile, err := os.CreateTemp(".", "tmp-kubescape*.yaml")
|
||||
if err != nil {
|
||||
@@ -88,36 +90,16 @@ func getControlCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comman
|
||||
if err != nil {
|
||||
logger.L().Fatal(err.Error())
|
||||
}
|
||||
results.HandleResults()
|
||||
if err := results.HandleResults(); err != nil {
|
||||
logger.L().Fatal(err.Error())
|
||||
}
|
||||
if !scanInfo.VerboseMode {
|
||||
cautils.SimpleDisplay(os.Stderr, "%s Run with '--verbose'/'-v' flag for detailed resources view\n\n", emoji.Detective)
|
||||
}
|
||||
if results.GetRiskScore() > float32(scanInfo.FailThreshold) {
|
||||
return fmt.Errorf("scan risk-score %.2f is above permitted threshold %.2f", results.GetRiskScore(), scanInfo.FailThreshold)
|
||||
logger.L().Fatal("scan risk-score is above permitted threshold", helpers.String("risk-score", fmt.Sprintf("%.2f", results.GetRiskScore())), helpers.String("fail-threshold", fmt.Sprintf("%.2f", scanInfo.FailThreshold)))
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// func flagValidationControl() {
|
||||
// if 100 < scanInfo.FailThreshold {
|
||||
// logger.L().Fatal("bad argument: out of range threshold")
|
||||
// }
|
||||
// }
|
||||
|
||||
// func setScanForFirstControl(scanInfo, controls []string) []reporthandling.PolicyIdentifier {
|
||||
// newPolicy := reporthandling.PolicyIdentifier{}
|
||||
// newPolicy.Kind = reporthandling.KindControl
|
||||
// newPolicy.Name = controls[0]
|
||||
// scanInfo.PolicyIdentifier = append(scanInfo.PolicyIdentifier, newPolicy)
|
||||
// return scanInfo.PolicyIdentifier
|
||||
// }
|
||||
|
||||
// func SetScanForGivenControls(scanInfo, controls []string) []reporthandling.PolicyIdentifier {
|
||||
// for _, control := range controls {
|
||||
// control := strings.TrimLeft(control, " ")
|
||||
// newPolicy := reporthandling.PolicyIdentifier{}
|
||||
// newPolicy.Kind = reporthandling.KindControl
|
||||
// newPolicy.Name = control
|
||||
// scanInfo.PolicyIdentifier = append(scanInfo.PolicyIdentifier, newPolicy)
|
||||
// }
|
||||
// return scanInfo.PolicyIdentifier
|
||||
// }
|
||||
|
||||
@@ -8,8 +8,10 @@ import (
|
||||
|
||||
"github.com/armosec/kubescape/core/cautils"
|
||||
"github.com/armosec/kubescape/core/cautils/logger"
|
||||
"github.com/armosec/kubescape/core/cautils/logger/helpers"
|
||||
"github.com/armosec/kubescape/core/meta"
|
||||
"github.com/armosec/opa-utils/reporthandling"
|
||||
"github.com/enescakir/emoji"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -27,7 +29,7 @@ var (
|
||||
# Scan all frameworks
|
||||
kubescape scan framework all
|
||||
|
||||
# Scan kubernetes YAML manifest files
|
||||
# Scan kubernetes YAML manifest files (single file or glob)
|
||||
kubescape scan framework nsa *.yaml
|
||||
|
||||
Run 'kubescape list frameworks' for the list of supported frameworks
|
||||
@@ -58,7 +60,9 @@ func getFrameworkCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comm
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
||||
flagValidationFramework(scanInfo)
|
||||
if err := flagValidationFramework(scanInfo); err != nil {
|
||||
return err
|
||||
}
|
||||
scanInfo.FrameworkScan = true
|
||||
|
||||
var frameworks []string
|
||||
@@ -74,7 +78,7 @@ func getFrameworkCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comm
|
||||
}
|
||||
if len(args) > 1 {
|
||||
if len(args[1:]) == 0 || args[1] != "-" {
|
||||
scanInfo.InputPatterns = args[1:]
|
||||
scanInfo.InputPatterns = []string{args[1]}
|
||||
} else { // store stdin to file - do NOT move to separate function !!
|
||||
tempFile, err := os.CreateTemp(".", "tmp-kubescape*.yaml")
|
||||
if err != nil {
|
||||
@@ -97,34 +101,27 @@ func getFrameworkCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comm
|
||||
if err != nil {
|
||||
logger.L().Fatal(err.Error())
|
||||
}
|
||||
results.HandleResults()
|
||||
|
||||
if err = results.HandleResults(); err != nil {
|
||||
logger.L().Fatal(err.Error())
|
||||
}
|
||||
if !scanInfo.VerboseMode {
|
||||
cautils.SimpleDisplay(os.Stderr, "%s Run with '--verbose'/'-v' flag for detailed resources view\n\n", emoji.Detective)
|
||||
}
|
||||
if results.GetRiskScore() > float32(scanInfo.FailThreshold) {
|
||||
return fmt.Errorf("scan risk-score %.2f is above permitted threshold %.2f", results.GetRiskScore(), scanInfo.FailThreshold)
|
||||
logger.L().Fatal("scan risk-score is above permitted threshold", helpers.String("risk-score", fmt.Sprintf("%.2f", results.GetRiskScore())), helpers.String("fail-threshold", fmt.Sprintf("%.2f", scanInfo.FailThreshold)))
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// func init() {
|
||||
// scanCmd.AddCommand(frameworkCmd)
|
||||
// scanInfo = cautils.ScanInfo{}
|
||||
|
||||
// }
|
||||
|
||||
// func SetScanForFirstFramework(frameworks []string) []reporthandling.PolicyIdentifier {
|
||||
// newPolicy := reporthandling.PolicyIdentifier{}
|
||||
// newPolicy.Kind = reporthandling.KindFramework
|
||||
// newPolicy.Name = frameworks[0]
|
||||
// scanInfo.PolicyIdentifier = append(scanInfo.PolicyIdentifier, newPolicy)
|
||||
// return scanInfo.PolicyIdentifier
|
||||
// }
|
||||
|
||||
func flagValidationFramework(scanInfo *cautils.ScanInfo) {
|
||||
func flagValidationFramework(scanInfo *cautils.ScanInfo) error {
|
||||
if scanInfo.Submit && scanInfo.Local {
|
||||
logger.L().Fatal("you can use `keep-local` or `submit`, but not both")
|
||||
return fmt.Errorf("you can use `keep-local` or `submit`, but not both")
|
||||
}
|
||||
if 100 < scanInfo.FailThreshold {
|
||||
logger.L().Fatal("bad argument: out of range threshold")
|
||||
if 100 < scanInfo.FailThreshold || 0 > scanInfo.FailThreshold {
|
||||
return fmt.Errorf("bad argument: out of range threshold")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ var scanCmdExamples = `
|
||||
Scan command is for scanning an existing cluster or kubernetes manifest files based on pre-defind frameworks
|
||||
|
||||
# Scan current cluster with all frameworks
|
||||
kubescape scan --submit --enable-host-scan
|
||||
kubescape scan --submit --enable-host-scan --verbose
|
||||
|
||||
# Scan kubernetes YAML manifest files
|
||||
kubescape scan *.yaml
|
||||
@@ -72,7 +72,7 @@ func GetScanCommand(ks meta.IKubescape) *cobra.Command {
|
||||
scanCmd.PersistentFlags().StringVar(&scanInfo.IncludeNamespaces, "include-namespaces", "", "scan specific namespaces. e.g: --include-namespaces ns-a,ns-b")
|
||||
scanCmd.PersistentFlags().BoolVarP(&scanInfo.Local, "keep-local", "", false, "If you do not want your Kubescape results reported to ARMO backend. Use this flag if you ran with the '--submit' flag in the past and you do not want to submit your current scan results")
|
||||
scanCmd.PersistentFlags().StringVarP(&scanInfo.Output, "output", "o", "", "Output file. Print output to file and not stdout")
|
||||
scanCmd.PersistentFlags().BoolVar(&scanInfo.VerboseMode, "verbose", false, "Display all of the input resources and not only failed resources")
|
||||
scanCmd.PersistentFlags().BoolVarP(&scanInfo.VerboseMode, "verbose", "v", false, "Display all of the input resources and not only failed resources")
|
||||
scanCmd.PersistentFlags().BoolVar(&scanInfo.UseDefault, "use-default", false, "Load local policy object from default path. If not used will download latest")
|
||||
scanCmd.PersistentFlags().StringSliceVar(&scanInfo.UseFrom, "use-from", nil, "Load local policy object from specified path. If not used will download latest")
|
||||
scanCmd.PersistentFlags().BoolVarP(&scanInfo.Submit, "submit", "", false, "Send the scan results to ARMO management portal where you can see the results in a user-friendly UI, choose your preferred compliance framework, check risk results history and trends, manage exceptions, get remediation recommendations and much more. By default the results are not submitted")
|
||||
|
||||
@@ -69,6 +69,7 @@ type ITenantConfig interface {
|
||||
// getters
|
||||
GetClusterName() string
|
||||
GetAccountID() string
|
||||
GetTennatEmail() string
|
||||
GetConfigObj() *ConfigObj
|
||||
// GetBackendAPI() getter.IBackend
|
||||
// GenerateURL()
|
||||
@@ -118,6 +119,7 @@ func NewLocalConfig(
|
||||
}
|
||||
|
||||
func (lc *LocalConfig) GetConfigObj() *ConfigObj { return lc.configObj }
|
||||
func (lc *LocalConfig) GetTennatEmail() string { return lc.configObj.CustomerAdminEMail }
|
||||
func (lc *LocalConfig) GetAccountID() string { return lc.configObj.AccountID }
|
||||
func (lc *LocalConfig) GetClusterName() string { return lc.configObj.ClusterName }
|
||||
func (lc *LocalConfig) IsConfigFound() bool { return existsConfigFile() }
|
||||
@@ -232,6 +234,7 @@ func NewClusterConfig(k8s *k8sinterface.KubernetesApi, backendAPI getter.IBacken
|
||||
func (c *ClusterConfig) GetConfigObj() *ConfigObj { return c.configObj }
|
||||
func (c *ClusterConfig) GetDefaultNS() string { return c.configMapNamespace }
|
||||
func (c *ClusterConfig) GetAccountID() string { return c.configObj.AccountID }
|
||||
func (c *ClusterConfig) GetTennatEmail() string { return c.configObj.CustomerAdminEMail }
|
||||
func (c *ClusterConfig) IsConfigFound() bool { return existsConfigFile() || c.existsConfigMap() }
|
||||
|
||||
func (c *ClusterConfig) SetTenant() error {
|
||||
|
||||
18
core/cautils/floatutils.go
Normal file
18
core/cautils/floatutils.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package cautils
|
||||
|
||||
import "math"
|
||||
|
||||
// Float64ToInt convert float64 to int
|
||||
func Float64ToInt(x float64) int {
|
||||
return int(math.Round(x))
|
||||
}
|
||||
|
||||
// Float32ToInt convert float32 to int
|
||||
func Float32ToInt(x float32) int {
|
||||
return Float64ToInt(float64(x))
|
||||
}
|
||||
|
||||
// Float16ToInt convert float16 to int
|
||||
func Float16ToInt(x float32) int {
|
||||
return Float64ToInt(float64(x))
|
||||
}
|
||||
24
core/cautils/floatutils_test.go
Normal file
24
core/cautils/floatutils_test.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package cautils
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestFloat64ToInt(t *testing.T) {
|
||||
assert.Equal(t, 3, Float64ToInt(3.49))
|
||||
assert.Equal(t, 4, Float64ToInt(3.5))
|
||||
assert.Equal(t, 4, Float64ToInt(3.51))
|
||||
}
|
||||
|
||||
func TestFloat32ToInt(t *testing.T) {
|
||||
assert.Equal(t, 3, Float32ToInt(3.49))
|
||||
assert.Equal(t, 4, Float32ToInt(3.5))
|
||||
assert.Equal(t, 4, Float32ToInt(3.51))
|
||||
}
|
||||
func TestFloat16ToInt(t *testing.T) {
|
||||
assert.Equal(t, 3, Float16ToInt(3.49))
|
||||
assert.Equal(t, 4, Float16ToInt(3.5))
|
||||
assert.Equal(t, 4, Float16ToInt(3.51))
|
||||
}
|
||||
@@ -163,7 +163,6 @@ func (armoAPI *ArmoAPI) GetFramework(name string) (*reporthandling.Framework, er
|
||||
if err = JSONDecoder(respStr).Decode(framework); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
SaveInFile(framework, GetDefaultPath(name+".json"))
|
||||
|
||||
return framework, err
|
||||
}
|
||||
@@ -233,7 +232,14 @@ func (armoAPI *ArmoAPI) GetAccountConfig(clusterName string) (*armotypes.Custome
|
||||
}
|
||||
|
||||
if err = JSONDecoder(respStr).Decode(&accountConfig); err != nil {
|
||||
return nil, err
|
||||
// try with default scope
|
||||
respStr, err = armoAPI.Get(armoAPI.getAccountConfigDefault(clusterName), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = JSONDecoder(respStr).Decode(&accountConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return accountConfig, nil
|
||||
|
||||
@@ -73,6 +73,12 @@ func (armoAPI *ArmoAPI) exceptionsURL(exceptionsPolicyName string) string {
|
||||
return u.String()
|
||||
}
|
||||
|
||||
func (armoAPI *ArmoAPI) getAccountConfigDefault(clusterName string) string {
|
||||
config := armoAPI.getAccountConfig(clusterName)
|
||||
url := config + "&scope=default"
|
||||
return url
|
||||
}
|
||||
|
||||
func (armoAPI *ArmoAPI) getAccountConfig(clusterName string) string {
|
||||
u := url.URL{}
|
||||
u.Scheme = "https"
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/armosec/kubescape/core/cautils/logger/helpers"
|
||||
"github.com/armosec/opa-utils/reporthandling"
|
||||
reporthandlingv2 "github.com/armosec/opa-utils/reporthandling/v2"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -100,6 +101,10 @@ func (scanInfo *ScanInfo) Init() {
|
||||
scanInfo.setUseFrom()
|
||||
scanInfo.setOutputFile()
|
||||
scanInfo.setUseArtifactsFrom()
|
||||
if scanInfo.ScanID == "" {
|
||||
scanInfo.ScanID = uuid.NewString()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (scanInfo *ScanInfo) setUseArtifactsFrom() {
|
||||
@@ -193,8 +198,8 @@ func (scanInfo *ScanInfo) contains(policyName string) bool {
|
||||
func scanInfoToScanMetadata(scanInfo *ScanInfo) *reporthandlingv2.Metadata {
|
||||
metadata := &reporthandlingv2.Metadata{}
|
||||
|
||||
metadata.ClusterMetadata.ContextName = k8sinterface.GetClusterName()
|
||||
metadata.ScanMetadata.Format = scanInfo.Format
|
||||
metadata.ScanMetadata.FormatVersion = scanInfo.FormatVersion
|
||||
metadata.ScanMetadata.Submit = scanInfo.Submit
|
||||
|
||||
// TODO - Add excluded and included namespaces
|
||||
@@ -222,8 +227,61 @@ func scanInfoToScanMetadata(scanInfo *ScanInfo) *reporthandlingv2.Metadata {
|
||||
|
||||
metadata.ScanMetadata.ScanningTarget = reporthandlingv2.Cluster
|
||||
if scanInfo.GetScanningEnvironment() == ScanLocalFiles {
|
||||
metadata.ScanMetadata.ScanningTarget = reporthandlingv2.Files
|
||||
metadata.ScanMetadata.ScanningTarget = reporthandlingv2.File
|
||||
}
|
||||
|
||||
inputFiles := ""
|
||||
if len(scanInfo.InputPatterns) > 0 {
|
||||
inputFiles = scanInfo.InputPatterns[0]
|
||||
}
|
||||
setContextMetadata(&metadata.ContextMetadata, inputFiles)
|
||||
|
||||
return metadata
|
||||
}
|
||||
|
||||
func setContextMetadata(contextMetadata *reporthandlingv2.ContextMetadata, input string) {
|
||||
// if cluster
|
||||
if input == "" {
|
||||
contextMetadata.ClusterContextMetadata = &reporthandlingv2.ClusterMetadata{
|
||||
ContextName: k8sinterface.GetClusterName(),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// if url
|
||||
if strings.HasPrefix(input, "http") { // TODO - check if can parse
|
||||
return
|
||||
}
|
||||
|
||||
if !filepath.IsAbs(input) {
|
||||
if o, err := os.Getwd(); err == nil {
|
||||
input = filepath.Join(o, input)
|
||||
}
|
||||
}
|
||||
|
||||
// if single file
|
||||
if IsFile(input) {
|
||||
contextMetadata.FileContextMetadata = &reporthandlingv2.FileContextMetadata{
|
||||
FilePath: input,
|
||||
HostName: getHostname(),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// if dir/glob
|
||||
if !IsFile(input) {
|
||||
contextMetadata.DirectoryContextMetadata = &reporthandlingv2.DirectoryContextMetadata{
|
||||
BasePath: input,
|
||||
HostName: getHostname(),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func getHostname() string {
|
||||
if h, e := os.Hostname(); e == nil {
|
||||
return h
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
65
core/cautils/scaninfo_test.go
Normal file
65
core/cautils/scaninfo_test.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package cautils
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
reporthandlingv2 "github.com/armosec/opa-utils/reporthandling/v2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// func TestSetInputPatterns(t *testing.T) { //Unitest
|
||||
// {
|
||||
// scanInfo := ScanInfo{
|
||||
// InputPatterns: []string{"file"},
|
||||
// }
|
||||
// scanInfo.setInputPatterns()
|
||||
// assert.Equal(t, "file", scanInfo.InputPatterns[0])
|
||||
// }
|
||||
// }
|
||||
|
||||
func TestSetContextMetadata(t *testing.T) {
|
||||
{
|
||||
ctx := reporthandlingv2.ContextMetadata{}
|
||||
setContextMetadata(&ctx, "")
|
||||
|
||||
assert.NotNil(t, ctx.ClusterContextMetadata)
|
||||
assert.Nil(t, ctx.DirectoryContextMetadata)
|
||||
assert.Nil(t, ctx.FileContextMetadata)
|
||||
assert.Nil(t, ctx.HelmContextMetadata)
|
||||
assert.Nil(t, ctx.RepoContextMetadata)
|
||||
}
|
||||
{
|
||||
ctx := reporthandlingv2.ContextMetadata{}
|
||||
setContextMetadata(&ctx, "file")
|
||||
|
||||
assert.Nil(t, ctx.ClusterContextMetadata)
|
||||
assert.NotNil(t, ctx.DirectoryContextMetadata)
|
||||
assert.Nil(t, ctx.FileContextMetadata)
|
||||
assert.Nil(t, ctx.HelmContextMetadata)
|
||||
assert.Nil(t, ctx.RepoContextMetadata)
|
||||
}
|
||||
{
|
||||
ctx := reporthandlingv2.ContextMetadata{}
|
||||
setContextMetadata(&ctx, "scaninfo_test.go")
|
||||
|
||||
assert.Nil(t, ctx.ClusterContextMetadata)
|
||||
assert.Nil(t, ctx.DirectoryContextMetadata)
|
||||
assert.NotNil(t, ctx.FileContextMetadata)
|
||||
assert.Nil(t, ctx.HelmContextMetadata)
|
||||
assert.Nil(t, ctx.RepoContextMetadata)
|
||||
}
|
||||
{
|
||||
ctx := reporthandlingv2.ContextMetadata{}
|
||||
setContextMetadata(&ctx, "https://github.com/armosec/kubescape")
|
||||
|
||||
assert.Nil(t, ctx.ClusterContextMetadata)
|
||||
assert.Nil(t, ctx.DirectoryContextMetadata)
|
||||
assert.Nil(t, ctx.FileContextMetadata)
|
||||
assert.Nil(t, ctx.HelmContextMetadata)
|
||||
assert.Nil(t, ctx.RepoContextMetadata) // TODO
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetHostname(t *testing.T) {
|
||||
assert.NotEqual(t, "", getHostname())
|
||||
}
|
||||
@@ -130,7 +130,7 @@ func downloadFramework(downloadInfo *metav1.DownloadInfo) error {
|
||||
|
||||
tenant := getTenantConfig(downloadInfo.Account, "", getKubernetesApi())
|
||||
|
||||
g := getPolicyGetter(nil, tenant.GetAccountID(), true, nil)
|
||||
g := getPolicyGetter(nil, tenant.GetTennatEmail(), true, nil)
|
||||
|
||||
if downloadInfo.Name == "" {
|
||||
// if framework name not specified - download all frameworks
|
||||
@@ -172,7 +172,7 @@ func downloadControl(downloadInfo *metav1.DownloadInfo) error {
|
||||
|
||||
tenant := getTenantConfig(downloadInfo.Account, "", getKubernetesApi())
|
||||
|
||||
g := getPolicyGetter(nil, tenant.GetAccountID(), false, nil)
|
||||
g := getPolicyGetter(nil, tenant.GetTennatEmail(), false, nil)
|
||||
|
||||
if downloadInfo.Name == "" {
|
||||
// TODO - support
|
||||
|
||||
@@ -2,7 +2,6 @@ package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/armosec/k8s-interface/k8sinterface"
|
||||
"github.com/armosec/kubescape/core/cautils"
|
||||
@@ -48,11 +47,11 @@ func getRBACHandler(tenantConfig cautils.ITenantConfig, k8s *k8sinterface.Kubern
|
||||
return nil
|
||||
}
|
||||
|
||||
func getReporter(tenantConfig cautils.ITenantConfig, reportID string, submit, fwScan, clusterScan bool) reporter.IReport {
|
||||
if submit && clusterScan {
|
||||
func getReporter(tenantConfig cautils.ITenantConfig, reportID string, submit, fwScan bool) reporter.IReport {
|
||||
if submit {
|
||||
return reporterv2.NewReportEventReceiver(tenantConfig.GetConfigObj(), reportID)
|
||||
}
|
||||
if tenantConfig.GetAccountID() == "" && fwScan && clusterScan {
|
||||
if tenantConfig.GetAccountID() == "" {
|
||||
// Add link only when scanning a cluster using a framework
|
||||
return reporterv2.NewReportMock(reporterv2.NO_SUBMIT_QUERY, "run kubescape with the '--submit' flag")
|
||||
}
|
||||
@@ -60,9 +59,7 @@ func getReporter(tenantConfig cautils.ITenantConfig, reportID string, submit, fw
|
||||
if !fwScan {
|
||||
message = "Kubescape does not submit scan results when scanning controls"
|
||||
}
|
||||
if !clusterScan {
|
||||
message = "Kubescape will submit scan results only when scanning a cluster (not YAML files)"
|
||||
}
|
||||
|
||||
return reporterv2.NewReportMock("", message)
|
||||
}
|
||||
|
||||
@@ -153,11 +150,11 @@ func setSubmitBehavior(scanInfo *cautils.ScanInfo, tenantConfig cautils.ITenantC
|
||||
}
|
||||
|
||||
// setPolicyGetter set the policy getter - local file/github release/ArmoAPI
|
||||
func getPolicyGetter(loadPoliciesFromFile []string, accountID string, frameworkScope bool, downloadReleasedPolicy *getter.DownloadReleasedPolicy) getter.IPolicyGetter {
|
||||
func getPolicyGetter(loadPoliciesFromFile []string, tennatEmail string, frameworkScope bool, downloadReleasedPolicy *getter.DownloadReleasedPolicy) getter.IPolicyGetter {
|
||||
if len(loadPoliciesFromFile) > 0 {
|
||||
return getter.NewLoadPolicy(loadPoliciesFromFile)
|
||||
}
|
||||
if accountID != "" && frameworkScope {
|
||||
if tennatEmail != "" && frameworkScope {
|
||||
g := getter.GetArmoAPIConnector() // download policy from ARMO backend
|
||||
return g
|
||||
}
|
||||
@@ -195,7 +192,7 @@ func getConfigInputsGetter(ControlsInputs string, accountID string, downloadRele
|
||||
downloadReleasedPolicy = getter.NewDownloadReleasedPolicy()
|
||||
}
|
||||
if err := downloadReleasedPolicy.SetRegoObjects(); err != nil { // if failed to pull config inputs, fallback to BE
|
||||
cautils.WarningDisplay(os.Stderr, "Warning: failed to get config inputs from github release, this may affect the scanning results\n")
|
||||
logger.L().Warning("failed to get config inputs from github release, this may affect the scanning results", helpers.Error(err))
|
||||
}
|
||||
return downloadReleasedPolicy
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ func (ks *Kubescape) List(listPolicies *metav1.ListPolicies) error {
|
||||
|
||||
func listFrameworks(listPolicies *metav1.ListPolicies) ([]string, error) {
|
||||
tenant := getTenantConfig(listPolicies.Account, "", getKubernetesApi()) // change k8sinterface
|
||||
g := getPolicyGetter(nil, tenant.GetAccountID(), true, nil)
|
||||
g := getPolicyGetter(nil, tenant.GetTennatEmail(), true, nil)
|
||||
|
||||
return listFrameworksNames(g), nil
|
||||
}
|
||||
@@ -53,7 +53,7 @@ func listFrameworks(listPolicies *metav1.ListPolicies) ([]string, error) {
|
||||
func listControls(listPolicies *metav1.ListPolicies) ([]string, error) {
|
||||
tenant := getTenantConfig(listPolicies.Account, "", getKubernetesApi()) // change k8sinterface
|
||||
|
||||
g := getPolicyGetter(nil, tenant.GetAccountID(), false, nil)
|
||||
g := getPolicyGetter(nil, tenant.GetTennatEmail(), false, nil)
|
||||
l := getter.ListName
|
||||
if listPolicies.ListIDs {
|
||||
l = getter.ListID
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/armosec/armoapi-go/armotypes"
|
||||
"github.com/armosec/k8s-interface/k8sinterface"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/armosec/kubescape/core/cautils"
|
||||
"github.com/armosec/kubescape/core/cautils/getter"
|
||||
@@ -32,9 +31,6 @@ type componentInterfaces struct {
|
||||
}
|
||||
|
||||
func getInterfaces(scanInfo *cautils.ScanInfo) componentInterfaces {
|
||||
if scanInfo.ScanID == "" {
|
||||
scanInfo.ScanID = uuid.NewString()
|
||||
}
|
||||
|
||||
// ================== setup k8s interface object ======================================
|
||||
var k8s *k8sinterface.KubernetesApi
|
||||
@@ -52,6 +48,11 @@ func getInterfaces(scanInfo *cautils.ScanInfo) componentInterfaces {
|
||||
// Set submit behavior AFTER loading tenant config
|
||||
setSubmitBehavior(scanInfo, tenantConfig)
|
||||
|
||||
// Do not submit yaml scanning
|
||||
if len(scanInfo.InputPatterns) > 0 {
|
||||
scanInfo.Submit = false
|
||||
}
|
||||
|
||||
if scanInfo.Submit {
|
||||
// submit - Create tenant & Submit report
|
||||
if err := tenantConfig.SetTenant(); err != nil {
|
||||
@@ -90,7 +91,7 @@ func getInterfaces(scanInfo *cautils.ScanInfo) componentInterfaces {
|
||||
// ================== setup reporter & printer objects ======================================
|
||||
|
||||
// reporting behavior - setup reporter
|
||||
reportHandler := getReporter(tenantConfig, scanInfo.ScanID, scanInfo.Submit, scanInfo.FrameworkScan, len(scanInfo.InputPatterns) == 0)
|
||||
reportHandler := getReporter(tenantConfig, scanInfo.ScanID, scanInfo.Submit, scanInfo.FrameworkScan)
|
||||
|
||||
// setup printer
|
||||
printerHandler := resultshandling.NewPrinter(scanInfo.Format, scanInfo.FormatVersion, scanInfo.VerboseMode)
|
||||
@@ -123,7 +124,7 @@ func (ks *Kubescape) Scan(scanInfo *cautils.ScanInfo) (*resultshandling.ResultsH
|
||||
downloadReleasedPolicy := getter.NewDownloadReleasedPolicy() // download config inputs from github release
|
||||
|
||||
// set policy getter only after setting the customerGUID
|
||||
scanInfo.Getters.PolicyGetter = getPolicyGetter(scanInfo.UseFrom, interfaces.tenantConfig.GetAccountID(), scanInfo.FrameworkScan, downloadReleasedPolicy)
|
||||
scanInfo.Getters.PolicyGetter = getPolicyGetter(scanInfo.UseFrom, interfaces.tenantConfig.GetTennatEmail(), scanInfo.FrameworkScan, downloadReleasedPolicy)
|
||||
scanInfo.Getters.ControlsInputsGetter = getConfigInputsGetter(scanInfo.ControlsInputs, interfaces.tenantConfig.GetAccountID(), downloadReleasedPolicy)
|
||||
scanInfo.Getters.ExceptionsGetter = getExceptionsGetter(scanInfo.UseExceptions)
|
||||
|
||||
|
||||
@@ -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.127
|
||||
github.com/armosec/opa-utils v0.0.130
|
||||
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
|
||||
|
||||
@@ -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.127 h1:uVyH/+pjpiA0oBO6QODjtdCiPgHx7KQ/TcxxkPvAl4c=
|
||||
github.com/armosec/opa-utils v0.0.127/go.mod h1:gap+EaLG5rnyqvIRGxtdNDC9y7VvoGNm90zK8Ls7avQ=
|
||||
github.com/armosec/opa-utils v0.0.130 h1:uP60M0PzmDtLqvsA/jX8BED9/Ava4n2QG7VCkuI+hwI=
|
||||
github.com/armosec/opa-utils v0.0.130/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=
|
||||
|
||||
@@ -3,7 +3,6 @@ package opaprocessor
|
||||
import (
|
||||
"github.com/armosec/kubescape/core/cautils"
|
||||
"github.com/armosec/kubescape/core/cautils/logger"
|
||||
"github.com/armosec/kubescape/core/cautils/logger/helpers"
|
||||
|
||||
"github.com/armosec/k8s-interface/k8sinterface"
|
||||
"github.com/armosec/k8s-interface/workloadinterface"
|
||||
@@ -116,7 +115,7 @@ func getKubernetesObjects(k8sResources *cautils.K8SResources, allResources map[s
|
||||
for _, groupResource := range groupResources {
|
||||
if k8sObj, ok := (*k8sResources)[groupResource]; ok {
|
||||
if k8sObj == nil {
|
||||
logger.L().Debug("skipping", helpers.String("resource", groupResource))
|
||||
// logger.L().Debug("skipping", helpers.String("resource", groupResource))
|
||||
}
|
||||
for i := range k8sObj {
|
||||
k8sObjects = append(k8sObjects, allResources[k8sObj[i]])
|
||||
|
||||
@@ -5,7 +5,9 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/armosec/kubescape/core/cautils"
|
||||
"github.com/armosec/kubescape/core/cautils/getter"
|
||||
"github.com/armosec/kubescape/core/cautils/logger"
|
||||
"github.com/armosec/kubescape/core/cautils/logger/helpers"
|
||||
"github.com/armosec/opa-utils/reporthandling"
|
||||
)
|
||||
|
||||
@@ -54,6 +56,11 @@ func (policyHandler *PolicyHandler) getScanPolicies(notification *reporthandling
|
||||
}
|
||||
if receivedFramework != nil {
|
||||
frameworks = append(frameworks, *receivedFramework)
|
||||
|
||||
cache := getter.GetDefaultPath(rule.Name + ".json")
|
||||
if err := getter.SaveInFile(receivedFramework, cache); err != nil {
|
||||
logger.L().Warning("failed to cache file", helpers.String("file", cache), helpers.Error(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
case reporthandling.KindControl: // Download controls
|
||||
@@ -67,6 +74,11 @@ func (policyHandler *PolicyHandler) getScanPolicies(notification *reporthandling
|
||||
}
|
||||
if receivedControl != nil {
|
||||
f.Controls = append(f.Controls, *receivedControl)
|
||||
|
||||
cache := getter.GetDefaultPath(rule.Name + ".json")
|
||||
if err := getter.SaveInFile(receivedControl, cache); err != nil {
|
||||
logger.L().Warning("failed to cache file", helpers.String("file", cache), helpers.Error(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
frameworks = append(frameworks, f)
|
||||
|
||||
@@ -2,7 +2,6 @@ package resourcehandler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/armosec/armoapi-go/armotypes"
|
||||
"github.com/armosec/k8s-interface/workloadinterface"
|
||||
@@ -10,6 +9,8 @@ import (
|
||||
|
||||
"github.com/armosec/k8s-interface/k8sinterface"
|
||||
"github.com/armosec/kubescape/core/cautils"
|
||||
"github.com/armosec/kubescape/core/cautils/logger"
|
||||
"github.com/armosec/kubescape/core/cautils/logger/helpers"
|
||||
)
|
||||
|
||||
// FileResourceHandler handle resources from files and URLs
|
||||
@@ -38,23 +39,24 @@ func (fileHandler *FileResourceHandler) GetResources(sessionObj *cautils.OPASess
|
||||
workloads := []workloadinterface.IMetadata{}
|
||||
|
||||
// load resource from local file system
|
||||
w, err := cautils.LoadResourcesFromFiles(fileHandler.inputPatterns)
|
||||
sourceToWorkloads, err := cautils.LoadResourcesFromFiles(fileHandler.inputPatterns)
|
||||
if err != nil {
|
||||
return nil, allResources, nil, err
|
||||
}
|
||||
for source, ws := range w {
|
||||
for source, ws := range sourceToWorkloads {
|
||||
workloads = append(workloads, ws...)
|
||||
for i := range ws {
|
||||
workloadIDToSource[ws[i].GetID()] = source
|
||||
}
|
||||
}
|
||||
logger.L().Debug("files found in local storage", helpers.Int("files", len(sourceToWorkloads)), helpers.Int("workloads", len(workloads)))
|
||||
|
||||
// load resources from url
|
||||
w, err = loadResourcesFromUrl(fileHandler.inputPatterns)
|
||||
sourceToWorkloads, err = loadResourcesFromUrl(fileHandler.inputPatterns)
|
||||
if err != nil {
|
||||
return nil, allResources, nil, err
|
||||
}
|
||||
for source, ws := range w {
|
||||
for source, ws := range sourceToWorkloads {
|
||||
workloads = append(workloads, ws...)
|
||||
for i := range ws {
|
||||
workloadIDToSource[ws[i].GetID()] = source
|
||||
@@ -64,6 +66,8 @@ func (fileHandler *FileResourceHandler) GetResources(sessionObj *cautils.OPASess
|
||||
if len(workloads) == 0 {
|
||||
return nil, allResources, nil, fmt.Errorf("empty list of workloads - no workloads found")
|
||||
}
|
||||
logger.L().Debug("files found in git repo", helpers.Int("files", len(sourceToWorkloads)), helpers.Int("workloads", len(workloads)))
|
||||
|
||||
sessionObj.ResourceSource = workloadIDToSource
|
||||
|
||||
// map all resources: map["/group/version/kind"][]<k8s workloads>
|
||||
@@ -82,7 +86,7 @@ func (fileHandler *FileResourceHandler) GetResources(sessionObj *cautils.OPASess
|
||||
}
|
||||
|
||||
if err := fileHandler.registryAdaptors.collectImagesVulnerabilities(k8sResources, allResources, armoResources); err != nil {
|
||||
cautils.WarningDisplay(os.Stderr, "Warning: failed to collect images vulnerabilities: %s\n", err.Error())
|
||||
logger.L().Warning("failed to collect images vulnerabilities", helpers.Error(err))
|
||||
}
|
||||
|
||||
return k8sResources, allResources, armoResources, nil
|
||||
|
||||
@@ -75,7 +75,9 @@ func (k8sHandler *K8sResourceHandler) GetResources(sessionObj *cautils.OPASessio
|
||||
if err != nil {
|
||||
logger.L().Debug("failed to collect worker nodes number", helpers.Error(err))
|
||||
} else {
|
||||
sessionObj.Metadata.ClusterMetadata.NumberOfWorkerNodes = numberOfWorkerNodes
|
||||
if sessionObj.Metadata != nil && sessionObj.Metadata.ContextMetadata.ClusterContextMetadata != nil {
|
||||
sessionObj.Metadata.ContextMetadata.ClusterContextMetadata.NumberOfWorkerNodes = numberOfWorkerNodes
|
||||
}
|
||||
}
|
||||
|
||||
imgVulnResources := cautils.MapImageVulnResources(armoResourceMap)
|
||||
@@ -118,7 +120,9 @@ func (k8sHandler *K8sResourceHandler) GetResources(sessionObj *cautils.OPASessio
|
||||
logger.L().Warning("failed to collect cloud data", helpers.Error(err))
|
||||
}
|
||||
if provider != "" {
|
||||
sessionObj.Metadata.ClusterMetadata.CloudProvider = provider
|
||||
if sessionObj.Metadata != nil && sessionObj.Metadata.ContextMetadata.ClusterContextMetadata != nil {
|
||||
sessionObj.Metadata.ContextMetadata.ClusterContextMetadata.CloudProvider = provider
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,15 +284,8 @@ func getCloudProviderDescription(allResources map[string]workloadinterface.IMeta
|
||||
wl, err := cloudsupport.GetDescriptiveInfoFromCloudProvider(clusterName, provider, region, project)
|
||||
if err != nil {
|
||||
// Return error with useful info on how to configure credentials for getting cloud provider info
|
||||
switch provider {
|
||||
case "gke":
|
||||
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 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 provider, fmt.Errorf("could not get descriptive information about aks cluster: %s. %v", cluster, err.Error())
|
||||
}
|
||||
return provider, err
|
||||
logger.L().Debug("failed to get descriptive information", helpers.Error(err))
|
||||
return provider, fmt.Errorf("failed to get %s descriptive information. Read more: https://hub.armo.cloud/docs/kubescape-integration-with-cloud-providers", strings.ToUpper(provider))
|
||||
}
|
||||
allResources[wl.GetID()] = wl
|
||||
(*armoResourceMap)[fmt.Sprintf("%s/%s", wl.GetApiVersion(), wl.GetKind())] = []string{wl.GetID()}
|
||||
|
||||
@@ -23,7 +23,7 @@ func (jsonPrinter *JsonPrinter) SetWriter(outputFile string) {
|
||||
}
|
||||
|
||||
func (jsonPrinter *JsonPrinter) Score(score float32) {
|
||||
fmt.Fprintf(os.Stderr, "\nOverall risk-score (0- Excellent, 100- All failed): %d\n", int(score))
|
||||
fmt.Fprintf(os.Stderr, "\nOverall risk-score (0- Excellent, 100- All failed): %d\n", cautils.Float32ToInt(score))
|
||||
}
|
||||
|
||||
func (jsonPrinter *JsonPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
|
||||
|
||||
@@ -27,7 +27,7 @@ func (prometheusPrinter *PrometheusPrinter) SetWriter(outputFile string) {
|
||||
}
|
||||
|
||||
func (prometheusPrinter *PrometheusPrinter) Score(score float32) {
|
||||
fmt.Printf("\n# Overall risk-score (0- Excellent, 100- All failed)\nkubescape_score %d\n", int(score))
|
||||
fmt.Printf("\n# Overall risk-score (0- Excellent, 100- All failed)\nkubescape_score %d\n", cautils.Float32ToInt(score))
|
||||
}
|
||||
|
||||
func (printer *PrometheusPrinter) printResources(allResources map[string]workloadinterface.IMetadata, resourcesIDs *reporthandling.ResourcesIDs, frameworkName, controlName string) {
|
||||
|
||||
@@ -4,39 +4,111 @@ import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/armosec/kubescape/core/cautils"
|
||||
"github.com/armosec/opa-utils/reporthandling/apis"
|
||||
"github.com/armosec/opa-utils/reporthandling/results/v1/reportsummary"
|
||||
"github.com/fatih/color"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
)
|
||||
|
||||
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()))
|
||||
row = append(row, fmt.Sprintf("%d", controlSummary.NumberOfResources().All()))
|
||||
const (
|
||||
columnSeverity = iota
|
||||
columnName = iota
|
||||
columnCounterFailed = iota
|
||||
columnCounterExclude = iota
|
||||
columnCounterAll = iota
|
||||
columnRiskScore = iota
|
||||
_rowLen = iota
|
||||
)
|
||||
|
||||
if !controlSummary.GetStatus().IsSkipped() {
|
||||
row = append(row, fmt.Sprintf("%d", int(controlSummary.GetScore()))+"%")
|
||||
row = append(row, "")
|
||||
} else {
|
||||
row = append(row, string(controlSummary.GetStatus().Status()))
|
||||
if controlSummary.GetStatus().IsSkipped() {
|
||||
row = append(row, infoToPrintInfoMap[controlSummary.GetStatus().Info()])
|
||||
} else {
|
||||
row = append(row, "")
|
||||
}
|
||||
func generateRow(controlSummary reportsummary.IControlSummary, infoToPrintInfo []infoStars, verbose bool) []string {
|
||||
row := make([]string, _rowLen)
|
||||
|
||||
// ignore passed results
|
||||
if !verbose && (controlSummary.GetStatus().IsPassed()) {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
// ignore irelevant results
|
||||
if !verbose && (controlSummary.GetStatus().IsSkipped() && controlSummary.GetStatus().Status() == apis.StatusIrrelevant) {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
row[columnSeverity] = getSeverityColumn(controlSummary)
|
||||
row[columnName] = controlSummary.GetName()
|
||||
row[columnCounterFailed] = fmt.Sprintf("%d", controlSummary.NumberOfResources().Failed())
|
||||
row[columnCounterExclude] = fmt.Sprintf("%d", controlSummary.NumberOfResources().Excluded())
|
||||
row[columnCounterAll] = fmt.Sprintf("%d", controlSummary.NumberOfResources().All())
|
||||
row[columnRiskScore] = getRiskScoreColumn(controlSummary, infoToPrintInfo)
|
||||
|
||||
return row
|
||||
}
|
||||
|
||||
func getSortedControlsNames(controls reportsummary.ControlSummaries) []string {
|
||||
controlNames := make([]string, 0, len(controls))
|
||||
func getInfoColumn(controlSummary reportsummary.IControlSummary, infoToPrintInfo []infoStars) string {
|
||||
for i := range infoToPrintInfo {
|
||||
if infoToPrintInfo[i].info == controlSummary.GetStatus().Info() {
|
||||
return infoToPrintInfo[i].stars
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getRiskScoreColumn(controlSummary reportsummary.IControlSummary, infoToPrintInfo []infoStars) string {
|
||||
if controlSummary.GetStatus().IsSkipped() {
|
||||
return fmt.Sprintf("%s%s", controlSummary.GetStatus().Status(), getInfoColumn(controlSummary, infoToPrintInfo))
|
||||
}
|
||||
return fmt.Sprintf("%d", cautils.Float32ToInt(controlSummary.GetScore())) + "%"
|
||||
}
|
||||
|
||||
func getSeverityColumn(controlSummary reportsummary.IControlSummary) string {
|
||||
return color.New(getColor(apis.ControlSeverityToInt(controlSummary.GetScoreFactor())), color.Bold).SprintFunc()(apis.ControlSeverityToString(controlSummary.GetScoreFactor()))
|
||||
}
|
||||
func getColor(controlSeverity int) color.Attribute {
|
||||
switch controlSeverity {
|
||||
case apis.SeverityCritical:
|
||||
return color.FgRed
|
||||
case apis.SeverityHigh:
|
||||
return color.FgYellow
|
||||
case apis.SeverityMedium:
|
||||
return color.FgCyan
|
||||
case apis.SeverityLow:
|
||||
return color.FgWhite
|
||||
default:
|
||||
return color.FgWhite
|
||||
}
|
||||
}
|
||||
|
||||
func getSortedControlsNames(controls reportsummary.ControlSummaries) [][]string {
|
||||
controlNames := make([][]string, 5)
|
||||
for k := range controls {
|
||||
c := controls[k]
|
||||
controlNames = append(controlNames, c.GetName())
|
||||
i := apis.ControlSeverityToInt(c.GetScoreFactor())
|
||||
controlNames[i] = append(controlNames[i], c.GetName())
|
||||
}
|
||||
for i := range controlNames {
|
||||
sort.Strings(controlNames[i])
|
||||
}
|
||||
sort.Strings(controlNames)
|
||||
return controlNames
|
||||
}
|
||||
|
||||
func getControlTableHeaders() []string {
|
||||
return []string{"CONTROL NAME", "FAILED RESOURCES", "EXCLUDED RESOURCES", "ALL RESOURCES", "% RISK-SCORE", "INFO"}
|
||||
headers := make([]string, _rowLen)
|
||||
headers[columnName] = "CONTROL NAME"
|
||||
headers[columnCounterFailed] = "FAILED RESOURCES"
|
||||
headers[columnCounterExclude] = "EXCLUDED RESOURCES"
|
||||
headers[columnCounterAll] = "ALL RESOURCES"
|
||||
headers[columnSeverity] = "SEVERITY"
|
||||
headers[columnRiskScore] = "% RISK-SCORE"
|
||||
return headers
|
||||
}
|
||||
|
||||
func getColumnsAlignments() []int {
|
||||
alignments := make([]int, _rowLen)
|
||||
alignments[columnName] = tablewriter.ALIGN_LEFT
|
||||
alignments[columnCounterFailed] = tablewriter.ALIGN_CENTER
|
||||
alignments[columnCounterExclude] = tablewriter.ALIGN_CENTER
|
||||
alignments[columnCounterAll] = tablewriter.ALIGN_CENTER
|
||||
alignments[columnSeverity] = tablewriter.ALIGN_LEFT
|
||||
alignments[columnRiskScore] = tablewriter.ALIGN_CENTER
|
||||
return alignments
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ func (jsonPrinter *JsonPrinter) SetWriter(outputFile string) {
|
||||
}
|
||||
|
||||
func (jsonPrinter *JsonPrinter) Score(score float32) {
|
||||
fmt.Fprintf(os.Stderr, "\nOverall risk-score (0- Excellent, 100- All failed): %d\n", int(score))
|
||||
fmt.Fprintf(os.Stderr, "\nOverall risk-score (0- Excellent, 100- All failed): %d\n", cautils.Float32ToInt(score))
|
||||
}
|
||||
|
||||
func (jsonPrinter *JsonPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
|
||||
|
||||
@@ -100,7 +100,7 @@ func (junitPrinter *JunitPrinter) SetWriter(outputFile string) {
|
||||
}
|
||||
|
||||
func (junitPrinter *JunitPrinter) Score(score float32) {
|
||||
fmt.Fprintf(os.Stderr, "\nOverall risk-score (0- Excellent, 100- All failed): %d\n", int(score))
|
||||
fmt.Fprintf(os.Stderr, "\nOverall risk-score (0- Excellent, 100- All failed): %d\n", cautils.Float32ToInt(score))
|
||||
}
|
||||
|
||||
func (junitPrinter *JunitPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
|
||||
|
||||
@@ -31,8 +31,7 @@ var (
|
||||
)
|
||||
|
||||
type PdfPrinter struct {
|
||||
writer *os.File
|
||||
sortedControlNames []string
|
||||
writer *os.File
|
||||
}
|
||||
|
||||
func NewPdfPrinter() *PdfPrinter {
|
||||
@@ -52,18 +51,18 @@ 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))
|
||||
fmt.Fprintf(os.Stderr, "\nOverall risk-score (0- Excellent, 100- All failed): %d\n", cautils.Float32ToInt(score))
|
||||
}
|
||||
func (pdfPrinter *PdfPrinter) printInfo(m pdf.Maroto, summaryDetails *reportsummary.SummaryDetails, infoMap map[string]string) {
|
||||
func (pdfPrinter *PdfPrinter) printInfo(m pdf.Maroto, summaryDetails *reportsummary.SummaryDetails, infoMap []infoStars) {
|
||||
emptyRowCounter := 1
|
||||
for key, val := range infoMap {
|
||||
if val != "" {
|
||||
for i := range infoMap {
|
||||
if infoMap[i].info != "" {
|
||||
m.Row(5, func() {
|
||||
m.Col(1, func() {
|
||||
m.Text(fmt.Sprintf("%v", val))
|
||||
m.Text(fmt.Sprintf("%v", infoMap[i].info))
|
||||
})
|
||||
m.Col(12, func() {
|
||||
m.Text(fmt.Sprintf("%v", key))
|
||||
m.Text(fmt.Sprintf("%v", infoMap[i].stars))
|
||||
})
|
||||
})
|
||||
if emptyRowCounter < len(infoMap) {
|
||||
@@ -76,15 +75,15 @@ func (pdfPrinter *PdfPrinter) printInfo(m pdf.Maroto, summaryDetails *reportsumm
|
||||
}
|
||||
|
||||
func (pdfPrinter *PdfPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
|
||||
pdfPrinter.sortedControlNames = getSortedControlsNames(opaSessionObj.Report.SummaryDetails.Controls)
|
||||
sortedControlNames := getSortedControlsNames(opaSessionObj.Report.SummaryDetails.Controls)
|
||||
|
||||
infoToPrintInfoMap := mapInfoToPrintInfo(opaSessionObj.Report.SummaryDetails.Controls)
|
||||
infoToPrintInfo := 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.printTable(m, &opaSessionObj.Report.SummaryDetails, sortedControlNames)
|
||||
pdfPrinter.printFinalResult(m, &opaSessionObj.Report.SummaryDetails)
|
||||
pdfPrinter.printInfo(m, &opaSessionObj.Report.SummaryDetails, infoToPrintInfoMap)
|
||||
pdfPrinter.printInfo(m, &opaSessionObj.Report.SummaryDetails, infoToPrintInfo)
|
||||
|
||||
// Extrat output buffer.
|
||||
outBuff, err := m.Output()
|
||||
@@ -149,15 +148,17 @@ func (pdfPrinter *PdfPrinter) printFramework(m pdf.Maroto, frameworks []reportsu
|
||||
}
|
||||
|
||||
// Create pdf table
|
||||
func (pdfPrinter *PdfPrinter) printTable(m pdf.Maroto, summaryDetails *reportsummary.SummaryDetails) {
|
||||
func (pdfPrinter *PdfPrinter) printTable(m pdf.Maroto, summaryDetails *reportsummary.SummaryDetails, sortedControlNames [][]string) {
|
||||
headers := getControlTableHeaders()
|
||||
infoToPrintInfoMap := mapInfoToPrintInfo(summaryDetails.Controls)
|
||||
controls := make([][]string, len(pdfPrinter.sortedControlNames))
|
||||
controls := make([][]string, len(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]), infoToPrintInfoMap)
|
||||
for i := len(sortedControlNames) - 1; i >= 0; i-- {
|
||||
for _, c := range sortedControlNames[i] {
|
||||
controls[i] = generateRow(summaryDetails.Controls.GetControl(reportsummary.EControlCriteriaName, c), infoToPrintInfoMap, true)
|
||||
}
|
||||
}
|
||||
|
||||
m.TableList(headers, controls, props.TableList{
|
||||
@@ -186,7 +187,7 @@ func (pdfPrinter *PdfPrinter) printTable(m pdf.Maroto, summaryDetails *reportsum
|
||||
|
||||
// Add final results.
|
||||
func (pdfPrinter *PdfPrinter) printFinalResult(m pdf.Maroto, summaryDetails *reportsummary.SummaryDetails) {
|
||||
m.Row(5, func() {
|
||||
m.Row(_rowLen, func() {
|
||||
m.Col(3, func() {
|
||||
m.Text("Resource summary", props.Text{
|
||||
Align: consts.Left,
|
||||
|
||||
@@ -11,16 +11,16 @@ import (
|
||||
"github.com/armosec/kubescape/core/pkg/resultshandling/printer"
|
||||
"github.com/armosec/opa-utils/objectsenvelopes"
|
||||
"github.com/armosec/opa-utils/reporthandling/apis"
|
||||
helpersv1 "github.com/armosec/opa-utils/reporthandling/helpers/v1"
|
||||
"github.com/armosec/opa-utils/reporthandling/results/v1/reportsummary"
|
||||
"github.com/enescakir/emoji"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
)
|
||||
|
||||
type PrettyPrinter struct {
|
||||
formatVersion string
|
||||
writer *os.File
|
||||
verboseMode bool
|
||||
sortedControlNames []string
|
||||
formatVersion string
|
||||
writer *os.File
|
||||
verboseMode bool
|
||||
}
|
||||
|
||||
func NewPrettyPrinter(verboseMode bool, formatVersion string) *PrettyPrinter {
|
||||
@@ -31,14 +31,14 @@ func NewPrettyPrinter(verboseMode bool, formatVersion string) *PrettyPrinter {
|
||||
}
|
||||
|
||||
func (prettyPrinter *PrettyPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
|
||||
prettyPrinter.sortedControlNames = getSortedControlsNames(opaSessionObj.Report.SummaryDetails.Controls) // ListControls().All())
|
||||
fmt.Fprintf(prettyPrinter.writer, "\n"+getSperator("^")+"\n")
|
||||
|
||||
if prettyPrinter.formatVersion == "v1" {
|
||||
prettyPrinter.printResults(&opaSessionObj.Report.SummaryDetails.Controls, opaSessionObj.AllResources)
|
||||
} else if prettyPrinter.formatVersion == "v2" {
|
||||
prettyPrinter.resourceTable(opaSessionObj.ResourcesResult, opaSessionObj.AllResources)
|
||||
sortedControlNames := getSortedControlsNames(opaSessionObj.Report.SummaryDetails.Controls) // ListControls().All())
|
||||
|
||||
if prettyPrinter.verboseMode {
|
||||
prettyPrinter.resourceTable(opaSessionObj)
|
||||
}
|
||||
prettyPrinter.printSummaryTable(&opaSessionObj.Report.SummaryDetails)
|
||||
prettyPrinter.printSummaryTable(&opaSessionObj.Report.SummaryDetails, sortedControlNames)
|
||||
|
||||
}
|
||||
|
||||
@@ -49,13 +49,14 @@ func (prettyPrinter *PrettyPrinter) SetWriter(outputFile string) {
|
||||
func (prettyPrinter *PrettyPrinter) Score(score float32) {
|
||||
}
|
||||
|
||||
func (prettyPrinter *PrettyPrinter) printResults(controls *reportsummary.ControlSummaries, allResources map[string]workloadinterface.IMetadata) {
|
||||
for i := 0; i < len(prettyPrinter.sortedControlNames); i++ {
|
||||
|
||||
controlSummary := controls.GetControl(reportsummary.EControlCriteriaName, prettyPrinter.sortedControlNames[i]) // summaryDetails.Controls ListControls().All() Controls.GetControl(ca)
|
||||
prettyPrinter.printTitle(controlSummary)
|
||||
prettyPrinter.printResources(controlSummary, allResources)
|
||||
prettyPrinter.printSummary(prettyPrinter.sortedControlNames[i], controlSummary)
|
||||
func (prettyPrinter *PrettyPrinter) printResults(controls *reportsummary.ControlSummaries, allResources map[string]workloadinterface.IMetadata, sortedControlNames [][]string) {
|
||||
for i := len(sortedControlNames) - 1; i >= 0; i-- {
|
||||
for _, c := range sortedControlNames[i] {
|
||||
controlSummary := controls.GetControl(reportsummary.EControlCriteriaName, c) // summaryDetails.Controls ListControls().All() Controls.GetControl(ca)
|
||||
prettyPrinter.printTitle(controlSummary)
|
||||
prettyPrinter.printResources(controlSummary, allResources)
|
||||
prettyPrinter.printSummary(c, controlSummary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,53 +168,62 @@ func generateRelatedObjectsStr(workload WorkloadSummary) string {
|
||||
}
|
||||
func generateFooter(summaryDetails *reportsummary.SummaryDetails) []string {
|
||||
// Control name | # failed resources | all resources | % success
|
||||
row := []string{}
|
||||
row = append(row, "Resource Summary") //fmt.Sprintf(""%d", numControlers"))
|
||||
row = append(row, fmt.Sprintf("%d", summaryDetails.NumberOfResources().Failed()))
|
||||
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, " ")
|
||||
row := make([]string, _rowLen)
|
||||
row[columnName] = "Resource Summary"
|
||||
row[columnCounterFailed] = fmt.Sprintf("%d", summaryDetails.NumberOfResources().Failed())
|
||||
row[columnCounterExclude] = fmt.Sprintf("%d", summaryDetails.NumberOfResources().Excluded())
|
||||
row[columnCounterAll] = fmt.Sprintf("%d", summaryDetails.NumberOfResources().All())
|
||||
row[columnSeverity] = " "
|
||||
row[columnRiskScore] = fmt.Sprintf("%.2f%s", summaryDetails.Score, "%")
|
||||
|
||||
return row
|
||||
}
|
||||
func (prettyPrinter *PrettyPrinter) printSummaryTable(summaryDetails *reportsummary.SummaryDetails) {
|
||||
func (prettyPrinter *PrettyPrinter) printSummaryTable(summaryDetails *reportsummary.SummaryDetails, sortedControlNames [][]string) {
|
||||
|
||||
cautils.InfoTextDisplay(prettyPrinter.writer, "\n"+controlCountersForSummary(summaryDetails.NumberOfControls())+"\n\n")
|
||||
|
||||
summaryTable := tablewriter.NewWriter(prettyPrinter.writer)
|
||||
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, 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]), infoToPrintInfoMap))
|
||||
summaryTable.SetColumnAlignment(getColumnsAlignments())
|
||||
|
||||
infoToPrintInfo := mapInfoToPrintInfo(summaryDetails.Controls)
|
||||
for i := len(sortedControlNames) - 1; i >= 0; i-- {
|
||||
for _, c := range sortedControlNames[i] {
|
||||
row := generateRow(summaryDetails.Controls.GetControl(reportsummary.EControlCriteriaName, c), infoToPrintInfo, prettyPrinter.verboseMode)
|
||||
if len(row) > 0 {
|
||||
summaryTable.Append(row)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
// When scanning controls the framework list will be empty
|
||||
cautils.InfoTextDisplay(prettyPrinter.writer, frameworksScoresToString(summaryDetails.ListFrameworks()))
|
||||
|
||||
prettyPrinter.printInfo(infoToPrintInfo)
|
||||
|
||||
}
|
||||
|
||||
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 (prettyPrinter *PrettyPrinter) printInfo(infoToPrintInfo []infoStars) {
|
||||
fmt.Println()
|
||||
for i := range infoToPrintInfo {
|
||||
cautils.InfoDisplay(prettyPrinter.writer, fmt.Sprintf("%s %s\n", infoToPrintInfo[i].stars, infoToPrintInfo[i].info))
|
||||
}
|
||||
}
|
||||
|
||||
func frameworksScoresToString(frameworks []reportsummary.IFrameworkSummary) string {
|
||||
if len(frameworks) == 1 {
|
||||
if frameworks[0].GetName() != "" {
|
||||
return fmt.Sprintf("\nFRAMEWORK %s\n", frameworks[0].GetName())
|
||||
return fmt.Sprintf("FRAMEWORK %s\n", frameworks[0].GetName())
|
||||
// cautils.InfoTextDisplay(prettyPrinter.writer, ))
|
||||
}
|
||||
} else if len(frameworks) > 1 {
|
||||
p := "\nFRAMEWORKS: "
|
||||
p := "FRAMEWORKS: "
|
||||
i := 0
|
||||
for ; i < len(frameworks)-1; i++ {
|
||||
p += fmt.Sprintf("%s (risk: %.2f), ", frameworks[i].GetName(), frameworks[i].GetScore())
|
||||
@@ -224,14 +234,21 @@ func frameworksScoresToString(frameworks []reportsummary.IFrameworkSummary) stri
|
||||
return ""
|
||||
}
|
||||
|
||||
// func getSortedControlsNames(controls []reportsummary.IPolicies) []string {
|
||||
// controlNames := make([]string, 0, len(controls))
|
||||
// for k := range controls {
|
||||
// controlNames = append(controlNames, controls[k].Get())
|
||||
// }
|
||||
// sort.Strings(controlNames)
|
||||
// return controlNames
|
||||
// }
|
||||
func getControlLink(controlID string) string {
|
||||
return fmt.Sprintf("https://hub.armo.cloud/docs/%s", strings.ToLower(controlID))
|
||||
}
|
||||
|
||||
func controlCountersForSummary(counters reportsummary.ICounters) string {
|
||||
return fmt.Sprintf("Controls: %d (Failed: %d, Excluded: %d, Skipped: %d)", counters.All(), counters.Failed(), counters.Excluded(), counters.Skipped())
|
||||
}
|
||||
|
||||
func controlCountersForResource(l *helpersv1.AllLists) string {
|
||||
return fmt.Sprintf("Controls: %d (Failed: %d, Excluded: %d)", len(l.All()), len(l.Failed()), len(l.Excluded()))
|
||||
}
|
||||
func getSperator(sep string) string {
|
||||
s := ""
|
||||
for i := 0; i < 80; i++ {
|
||||
s += sep
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ func (prometheusPrinter *PrometheusPrinter) SetWriter(outputFile string) {
|
||||
}
|
||||
|
||||
func (prometheusPrinter *PrometheusPrinter) Score(score float32) {
|
||||
fmt.Printf("\n# Overall risk-score (0- Excellent, 100- All failed)\nkubescape_score %d\n", int(score))
|
||||
fmt.Printf("\n# Overall risk-score (0- Excellent, 100- All failed)\nkubescape_score %d\n", cautils.Float32ToInt(score))
|
||||
}
|
||||
|
||||
func (printer *PrometheusPrinter) generatePrometheusFormat(
|
||||
@@ -39,7 +39,7 @@ func (printer *PrometheusPrinter) generatePrometheusFormat(
|
||||
|
||||
m := &Metrics{}
|
||||
m.setRiskScores(summaryDetails)
|
||||
m.setResourcesCounters(resources, results)
|
||||
// m.setResourcesCounters(resources, results)
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
@@ -2,8 +2,10 @@ package v2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/armosec/k8s-interface/workloadinterface"
|
||||
"github.com/armosec/kubescape/core/cautils"
|
||||
"github.com/armosec/opa-utils/reporthandling/apis"
|
||||
"github.com/armosec/opa-utils/reporthandling/results/v1/reportsummary"
|
||||
"github.com/armosec/opa-utils/reporthandling/results/v1/resourcesresults"
|
||||
@@ -12,88 +14,183 @@ import (
|
||||
type metricsName string
|
||||
|
||||
const (
|
||||
metricsFrameworkScore metricsName = "kubescape_risk_score_framework"
|
||||
metricsControlScore metricsName = "kubescape_risk_score_control"
|
||||
metricsScore metricsName = "kubescape_risk_score"
|
||||
metricsresourceFailed metricsName = "kubescape_resource_controls_number_of_failed"
|
||||
metricsresourcePassed metricsName = "kubescape_resource_controls_number_of_passed"
|
||||
metricsresourceExcluded metricsName = "kubescape_resource_controls_number_of_exclude"
|
||||
ksMetrics metricsName = "kubescape"
|
||||
metricsCluster metricsName = "cluster"
|
||||
metricsScore metricsName = "riskScore"
|
||||
metricsCount metricsName = "count"
|
||||
metricsFailed metricsName = "failed"
|
||||
metricsExcluded metricsName = "exclude"
|
||||
metricsPassed metricsName = "passed"
|
||||
metricsControl metricsName = "control"
|
||||
metricsControls metricsName = "controls"
|
||||
metricsResource metricsName = "resource"
|
||||
metricsResources metricsName = "resources"
|
||||
metricsFramework metricsName = "framework"
|
||||
)
|
||||
|
||||
func (mrs *mRiskScore) string() string {
|
||||
r := fmt.Sprintf("resourcesCountFailed=\"%d\"", mrs.resourcesCountFailed) + ","
|
||||
r += fmt.Sprintf("resourcesCountExcluded=\"%d\"", mrs.resourcesCountExcluded) + ","
|
||||
r += fmt.Sprintf("resourcesCountPassed=\"%d\"", mrs.resourcesCountPassed) + ","
|
||||
r += fmt.Sprintf("controlsCountFailed=\"%d\"", mrs.controlsCountFailed) + ","
|
||||
r += fmt.Sprintf("controlsCountExcluded=\"%d\"", mrs.controlsCountExcluded) + ","
|
||||
r += fmt.Sprintf("controlsCountPassed=\"%d\"", mrs.controlsCountPassed) + ","
|
||||
r += fmt.Sprintf("controlsCountSkipped=\"%d\"", mrs.controlsCountSkipped)
|
||||
return r
|
||||
// ============================================ CLUSTER ============================================================
|
||||
func (mrs *mRiskScore) metrics() []string {
|
||||
/*
|
||||
##### Overall risk score
|
||||
kubescape_cluster_riskScore{} <risk score>
|
||||
|
||||
###### Overall resources counters
|
||||
kubescape_cluster_count_resources_failed{} <counter>
|
||||
kubescape_cluster_count_resources_excluded{} <counter>
|
||||
kubescape_cluster_count_resources_passed{} <counter>
|
||||
|
||||
###### Overall controls counters
|
||||
kubescape_cluster_count_controls_failed{} <counter>
|
||||
kubescape_cluster_count_controls_excluded{} <counter>
|
||||
kubescape_cluster_count_controls_passed{} <counter>
|
||||
*/
|
||||
|
||||
m := []string{}
|
||||
// overall
|
||||
m = append(m, toRowInMetrics(fmt.Sprintf("%s_%s", mrs.prefix(), metricsScore), mrs.labels(), mrs.riskScore))
|
||||
|
||||
// resources
|
||||
m = append(m, toRowInMetrics(fmt.Sprintf("%s_%s_%s_%s", mrs.prefix(), metricsCount, metricsResources, metricsFailed), mrs.labels(), mrs.resourcesCountFailed))
|
||||
m = append(m, toRowInMetrics(fmt.Sprintf("%s_%s_%s_%s", mrs.prefix(), metricsCount, metricsResources, metricsExcluded), mrs.labels(), mrs.resourcesCountExcluded))
|
||||
m = append(m, toRowInMetrics(fmt.Sprintf("%s_%s_%s_%s", mrs.prefix(), metricsCount, metricsResources, metricsPassed), mrs.labels(), mrs.resourcesCountPassed))
|
||||
|
||||
// controls
|
||||
m = append(m, toRowInMetrics(fmt.Sprintf("%s_%s_%s_%s", mrs.prefix(), metricsCount, metricsControl, metricsFailed), mrs.labels(), mrs.controlsCountFailed))
|
||||
m = append(m, toRowInMetrics(fmt.Sprintf("%s_%s_%s_%s", mrs.prefix(), metricsCount, metricsControl, metricsExcluded), mrs.labels(), mrs.controlsCountExcluded))
|
||||
m = append(m, toRowInMetrics(fmt.Sprintf("%s_%s_%s_%s", mrs.prefix(), metricsCount, metricsControl, metricsPassed), mrs.labels(), mrs.controlsCountPassed))
|
||||
|
||||
return m
|
||||
}
|
||||
func (mrs *mRiskScore) value() int {
|
||||
return mrs.riskScore
|
||||
func (mrs *mRiskScore) labels() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (mcrs *mControlRiskScore) string() string {
|
||||
r := fmt.Sprintf("controlName=\"%s\"", mcrs.controlName) + ","
|
||||
r += fmt.Sprintf("controlID=\"%s\"", mcrs.controlID) + ","
|
||||
func (mrs *mRiskScore) prefix() string {
|
||||
return fmt.Sprintf("%s_%s", ksMetrics, metricsCluster)
|
||||
}
|
||||
|
||||
// ============================================ CONTROL ============================================================
|
||||
|
||||
func (mcrs *mControlRiskScore) metrics() []string {
|
||||
/*
|
||||
# Risk score
|
||||
kubescape_control_riskScore{name="<control name>",url="<docs url>",severity="<control severity>"} <risk score>
|
||||
|
||||
# Resources counters
|
||||
kubescape_control_count_resources_failed{name="<control name>",url="<docs url>",severity="<control severity>"} <counter>
|
||||
kubescape_control_count_resources_excluded{name="<control name>",url="<docs url>",severity="<control severity>"} <counter>
|
||||
kubescape_control_count_resources_passed{name="<control name>",url="<docs url>",severity="<control severity>"} <counter>
|
||||
*/
|
||||
|
||||
m := []string{}
|
||||
// overall
|
||||
m = append(m, toRowInMetrics(fmt.Sprintf("%s_%s", mcrs.prefix(), metricsScore), mcrs.labels(), mcrs.riskScore))
|
||||
|
||||
// resources
|
||||
m = append(m, toRowInMetrics(fmt.Sprintf("%s_%s_%s_%s", mcrs.prefix(), metricsCount, metricsResources, metricsFailed), mcrs.labels(), mcrs.resourcesCountFailed))
|
||||
m = append(m, toRowInMetrics(fmt.Sprintf("%s_%s_%s_%s", mcrs.prefix(), metricsCount, metricsResources, metricsExcluded), mcrs.labels(), mcrs.resourcesCountExcluded))
|
||||
m = append(m, toRowInMetrics(fmt.Sprintf("%s_%s_%s_%s", mcrs.prefix(), metricsCount, metricsResources, metricsPassed), mcrs.labels(), mcrs.resourcesCountPassed))
|
||||
|
||||
return m
|
||||
}
|
||||
func (mcrs *mControlRiskScore) labels() string {
|
||||
r := fmt.Sprintf("name=\"%s\"", mcrs.controlName) + ","
|
||||
r += fmt.Sprintf("severity=\"%s\"", mcrs.severity) + ","
|
||||
r += fmt.Sprintf("resourcesCountFailed=\"%d\"", mcrs.resourcesCountFailed) + ","
|
||||
r += fmt.Sprintf("resourcesCountExcluded=\"%d\"", mcrs.resourcesCountExcluded) + ","
|
||||
r += fmt.Sprintf("resourcesCountPassed=\"%d\"", mcrs.resourcesCountPassed) + ","
|
||||
r += fmt.Sprintf("link=\"%s\"", mcrs.link) + ","
|
||||
r += fmt.Sprintf("remediation=\"%s\"", mcrs.remediation)
|
||||
r += fmt.Sprintf("link=\"%s\"", mcrs.link)
|
||||
return r
|
||||
}
|
||||
func (mcrs *mControlRiskScore) value() int {
|
||||
return mcrs.riskScore
|
||||
func (mcrs *mControlRiskScore) prefix() string {
|
||||
return fmt.Sprintf("%s_%s", ksMetrics, metricsControl)
|
||||
}
|
||||
|
||||
func (mfrs *mFrameworkRiskScore) string() string {
|
||||
r := fmt.Sprintf("frameworkName=\"%s\"", mfrs.frameworkName) + ","
|
||||
r += fmt.Sprintf("resourcesCountFailed=\"%d\"", mfrs.resourcesCountFailed) + ","
|
||||
r += fmt.Sprintf("resourcesCountExcluded=\"%d\"", mfrs.resourcesCountExcluded) + ","
|
||||
r += fmt.Sprintf("resourcesCountPassed=\"%d\"", mfrs.resourcesCountPassed) + ","
|
||||
r += fmt.Sprintf("controlsCountFailed=\"%d\"", mfrs.controlsCountFailed) + ","
|
||||
r += fmt.Sprintf("controlsCountExcluded=\"%d\"", mfrs.controlsCountExcluded) + ","
|
||||
r += fmt.Sprintf("controlsCountPassed=\"%d\"", mfrs.controlsCountPassed) + ","
|
||||
r += fmt.Sprintf("controlsCountSkipped=\"%d\"", mfrs.controlsCountSkipped)
|
||||
// ============================================ FRAMEWORK ============================================================
|
||||
|
||||
func (mfrs *mFrameworkRiskScore) metrics() []string {
|
||||
/*
|
||||
#### Frameworks metrics
|
||||
kubescape_framework_riskScore{name="<framework name>"} <risk score>
|
||||
|
||||
###### Frameworks resources counters
|
||||
kubescape_framework_count_resources_failed{} <counter>
|
||||
kubescape_framework_count_resources_excluded{} <counter>
|
||||
kubescape_framework_count_resources_passed{} <counter>
|
||||
|
||||
###### Frameworks controls counters
|
||||
kubescape_framework_count_controls_failed{name="<framework name>"} <counter>
|
||||
kubescape_framework_count_controls_excluded{name="<framework name>"} <counter>
|
||||
kubescape_framework_count_controls_passed{name="<framework name>"} <counter>
|
||||
|
||||
*/
|
||||
|
||||
m := []string{}
|
||||
// overall
|
||||
m = append(m, toRowInMetrics(fmt.Sprintf("%s_%s", mfrs.prefix(), metricsScore), mfrs.labels(), mfrs.riskScore))
|
||||
|
||||
// resources
|
||||
m = append(m, toRowInMetrics(fmt.Sprintf("%s_%s_%s_%s", mfrs.prefix(), metricsCount, metricsResources, metricsFailed), mfrs.labels(), mfrs.resourcesCountFailed))
|
||||
m = append(m, toRowInMetrics(fmt.Sprintf("%s_%s_%s_%s", mfrs.prefix(), metricsCount, metricsResources, metricsExcluded), mfrs.labels(), mfrs.resourcesCountExcluded))
|
||||
m = append(m, toRowInMetrics(fmt.Sprintf("%s_%s_%s_%s", mfrs.prefix(), metricsCount, metricsResources, metricsPassed), mfrs.labels(), mfrs.resourcesCountPassed))
|
||||
|
||||
// controls
|
||||
m = append(m, toRowInMetrics(fmt.Sprintf("%s_%s_%s_%s", mfrs.prefix(), metricsCount, metricsControl, metricsFailed), mfrs.labels(), mfrs.controlsCountFailed))
|
||||
m = append(m, toRowInMetrics(fmt.Sprintf("%s_%s_%s_%s", mfrs.prefix(), metricsCount, metricsControl, metricsExcluded), mfrs.labels(), mfrs.controlsCountExcluded))
|
||||
m = append(m, toRowInMetrics(fmt.Sprintf("%s_%s_%s_%s", mfrs.prefix(), metricsCount, metricsControl, metricsPassed), mfrs.labels(), mfrs.controlsCountPassed))
|
||||
|
||||
return m
|
||||
}
|
||||
func (mfrs *mFrameworkRiskScore) labels() string {
|
||||
r := fmt.Sprintf("name=\"%s\"", mfrs.frameworkName)
|
||||
return r
|
||||
}
|
||||
func (mfrs *mFrameworkRiskScore) value() int {
|
||||
return mfrs.riskScore
|
||||
func (mfrs *mFrameworkRiskScore) prefix() string {
|
||||
return fmt.Sprintf("%s_%s", ksMetrics, metricsFramework)
|
||||
}
|
||||
func (mrc *mResourceControls) string() string {
|
||||
|
||||
// ============================================ RESOURCES ============================================================
|
||||
|
||||
func (mrc *mResources) metrics() []string {
|
||||
/*
|
||||
#### Resources metrics
|
||||
kubescape_resource_count_controls_failed{apiVersion="<>",kind="<>",namespace="<>",name="<>"} <counter>
|
||||
kubescape_resource_count_controls_excluded{apiVersion="<>",kind="<>",namespace="<>",name="<>"} <counter>
|
||||
*/
|
||||
|
||||
m := []string{}
|
||||
|
||||
// controls
|
||||
m = append(m, toRowInMetrics(fmt.Sprintf("%s_%s_%s_%s", mrc.prefix(), metricsCount, metricsControls, metricsFailed), mrc.labels(), mrc.controlsCountFailed))
|
||||
m = append(m, toRowInMetrics(fmt.Sprintf("%s_%s_%s_%s", mrc.prefix(), metricsCount, metricsControls, metricsExcluded), mrc.labels(), mrc.controlsCountExcluded))
|
||||
return m
|
||||
}
|
||||
|
||||
func (mrc *mResources) labels() string {
|
||||
r := fmt.Sprintf("apiVersion=\"%s\"", mrc.apiVersion) + ","
|
||||
r += fmt.Sprintf("kind=\"%s\"", mrc.kind) + ","
|
||||
r += fmt.Sprintf("namespace=\"%s\"", mrc.namespace) + ","
|
||||
r += fmt.Sprintf("name=\"%s\"", mrc.name)
|
||||
return r
|
||||
}
|
||||
func (mrc *mResourceControls) value() int {
|
||||
return mrc.controls
|
||||
func (mrc *mResources) prefix() string {
|
||||
return fmt.Sprintf("%s_%s", ksMetrics, metricsResource)
|
||||
}
|
||||
func toRowInMetrics(name metricsName, row string, value int) string {
|
||||
return fmt.Sprintf("%s{%s} %d\n", name, row, value)
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
func toRowInMetrics(name string, row string, value int) string {
|
||||
return fmt.Sprintf("%s{%s} %d", name, row, value)
|
||||
|
||||
}
|
||||
func (m *Metrics) String() string {
|
||||
|
||||
r := toRowInMetrics(metricsScore, m.rs.string(), m.rs.value())
|
||||
r := strings.Join(m.rs.metrics(), "\n") + "\n"
|
||||
for i := range m.listFrameworks {
|
||||
r += toRowInMetrics(metricsFrameworkScore, m.listFrameworks[i].string(), m.listFrameworks[i].value())
|
||||
r += strings.Join(m.listFrameworks[i].metrics(), "\n") + "\n"
|
||||
}
|
||||
for i := range m.listControls {
|
||||
r += toRowInMetrics(metricsControlScore, m.listControls[i].string(), m.listControls[i].value())
|
||||
r += strings.Join(m.listControls[i].metrics(), "\n") + "\n"
|
||||
}
|
||||
for i := range m.listResourcesControlsFiled {
|
||||
r += toRowInMetrics(metricsresourceFailed, m.listResourcesControlsFiled[i].string(), m.listResourcesControlsFiled[i].value())
|
||||
}
|
||||
for i := range m.listResourcesControlsExcluded {
|
||||
r += toRowInMetrics(metricsresourceExcluded, m.listResourcesControlsExcluded[i].string(), m.listResourcesControlsExcluded[i].value())
|
||||
}
|
||||
for i := range m.listResourcesControlsPassed {
|
||||
r += toRowInMetrics(metricsresourcePassed, m.listResourcesControlsPassed[i].string(), m.listResourcesControlsPassed[i].value())
|
||||
for i := range m.listResources {
|
||||
r += strings.Join(m.listResources[i].metrics(), "\n") + "\n"
|
||||
}
|
||||
return r
|
||||
}
|
||||
@@ -106,7 +203,7 @@ type mRiskScore struct {
|
||||
controlsCountFailed int
|
||||
controlsCountExcluded int
|
||||
controlsCountSkipped int
|
||||
riskScore int // metric
|
||||
riskScore int
|
||||
}
|
||||
|
||||
type mControlRiskScore struct {
|
||||
@@ -118,7 +215,7 @@ type mControlRiskScore struct {
|
||||
resourcesCountPassed int
|
||||
resourcesCountFailed int
|
||||
resourcesCountExcluded int
|
||||
riskScore int // metric
|
||||
riskScore int
|
||||
}
|
||||
|
||||
type mFrameworkRiskScore struct {
|
||||
@@ -130,23 +227,23 @@ type mFrameworkRiskScore struct {
|
||||
controlsCountFailed int
|
||||
controlsCountExcluded int
|
||||
controlsCountSkipped int
|
||||
riskScore int // metric
|
||||
riskScore int
|
||||
}
|
||||
|
||||
type mResourceControls struct {
|
||||
name string
|
||||
namespace string
|
||||
apiVersion string
|
||||
kind string
|
||||
controls int // metric
|
||||
type mResources struct {
|
||||
name string
|
||||
namespace string
|
||||
apiVersion string
|
||||
kind string
|
||||
controlsCountPassed int
|
||||
controlsCountFailed int
|
||||
controlsCountExcluded int
|
||||
}
|
||||
type Metrics struct {
|
||||
rs mRiskScore
|
||||
listFrameworks []mFrameworkRiskScore
|
||||
listControls []mControlRiskScore
|
||||
listResourcesControlsFiled []mResourceControls
|
||||
listResourcesControlsPassed []mResourceControls
|
||||
listResourcesControlsExcluded []mResourceControls
|
||||
rs mRiskScore
|
||||
listFrameworks []mFrameworkRiskScore
|
||||
listControls []mControlRiskScore
|
||||
listResources []mResources
|
||||
}
|
||||
|
||||
func (mrs *mRiskScore) set(resources reportsummary.ICounters, controls reportsummary.ICounters) {
|
||||
@@ -176,12 +273,12 @@ func (mcrs *mControlRiskScore) set(resources reportsummary.ICounters) {
|
||||
}
|
||||
func (m *Metrics) setRiskScores(summaryDetails *reportsummary.SummaryDetails) {
|
||||
m.rs.set(summaryDetails.NumberOfResources(), summaryDetails.NumberOfControls())
|
||||
m.rs.riskScore = int(summaryDetails.GetScore())
|
||||
m.rs.riskScore = cautils.Float32ToInt(summaryDetails.GetScore())
|
||||
|
||||
for _, fw := range summaryDetails.ListFrameworks() {
|
||||
mfrs := mFrameworkRiskScore{
|
||||
frameworkName: fw.GetName(),
|
||||
riskScore: int(fw.GetScore()),
|
||||
riskScore: cautils.Float32ToInt(fw.GetScore()),
|
||||
}
|
||||
mfrs.set(fw.NumberOfResources(), fw.NumberOfControls())
|
||||
m.listFrameworks = append(m.listFrameworks, mfrs)
|
||||
@@ -191,7 +288,7 @@ func (m *Metrics) setRiskScores(summaryDetails *reportsummary.SummaryDetails) {
|
||||
mcrs := mControlRiskScore{
|
||||
controlName: control.GetName(),
|
||||
controlID: control.GetID(),
|
||||
riskScore: int(control.GetScore()),
|
||||
riskScore: cautils.Float32ToInt(control.GetScore()),
|
||||
link: getControlLink(control.GetID()),
|
||||
severity: apis.ControlSeverityToString(control.GetScoreFactor()),
|
||||
remediation: control.GetRemediation(),
|
||||
@@ -229,24 +326,18 @@ func (m *Metrics) setResourcesCounters(
|
||||
}
|
||||
passed, excluded, failed := resourceControlStatusCounters(&result)
|
||||
|
||||
mrc := mResourceControls{}
|
||||
mrc := mResources{}
|
||||
mrc.apiVersion = r.GetApiVersion()
|
||||
mrc.namespace = r.GetNamespace()
|
||||
mrc.kind = r.GetKind()
|
||||
mrc.name = r.GetName()
|
||||
|
||||
// append
|
||||
if passed > 0 {
|
||||
mrc.controls = passed
|
||||
m.listResourcesControlsPassed = append(m.listResourcesControlsPassed, mrc)
|
||||
}
|
||||
if failed > 0 {
|
||||
mrc.controls = failed
|
||||
m.listResourcesControlsFiled = append(m.listResourcesControlsFiled, mrc)
|
||||
}
|
||||
if excluded > 0 {
|
||||
mrc.controls = excluded
|
||||
m.listResourcesControlsExcluded = append(m.listResourcesControlsExcluded, mrc)
|
||||
}
|
||||
mrc.controlsCountPassed = passed
|
||||
mrc.controlsCountFailed = failed
|
||||
mrc.controlsCountExcluded = excluded
|
||||
|
||||
m.listResources = append(m.listResources, mrc)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,58 +5,82 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/armosec/k8s-interface/workloadinterface"
|
||||
"github.com/armosec/kubescape/core/cautils"
|
||||
"github.com/armosec/opa-utils/reporthandling/results/v1/reportsummary"
|
||||
"github.com/armosec/opa-utils/reporthandling/results/v1/resourcesresults"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
)
|
||||
|
||||
func (prettyPrinter *PrettyPrinter) resourceTable(results map[string]resourcesresults.Result, allResources map[string]workloadinterface.IMetadata) {
|
||||
const (
|
||||
resourceColumnSeverity = iota
|
||||
resourceColumnName = iota
|
||||
resourceColumnURL = iota
|
||||
resourceColumnPath = iota
|
||||
_resourceRowLen = iota
|
||||
)
|
||||
|
||||
summaryTable := tablewriter.NewWriter(prettyPrinter.writer)
|
||||
summaryTable.SetAutoWrapText(true)
|
||||
summaryTable.SetAutoMergeCells(true)
|
||||
summaryTable.SetHeader(generateResourceHeader())
|
||||
summaryTable.SetHeaderLine(true)
|
||||
summaryTable.SetRowLine(true)
|
||||
// summaryTable.SetFooter([]string{"", "", "Total", "", "$146.93"})
|
||||
// For control scan framework will be nil
|
||||
data := Matrix{}
|
||||
for i := range results {
|
||||
resource, ok := allResources[i]
|
||||
func (prettyPrinter *PrettyPrinter) resourceTable(opaSessionObj *cautils.OPASessionObj) {
|
||||
|
||||
for resourceID, result := range opaSessionObj.ResourcesResult {
|
||||
if !result.GetStatus(nil).IsFailed() {
|
||||
continue
|
||||
}
|
||||
resource, ok := opaSessionObj.AllResources[resourceID]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
s := results[i]
|
||||
if raw := generateResourceRows(resource, s.ListControls(), prettyPrinter.verboseMode); len(raw) > 0 {
|
||||
fmt.Fprintf(prettyPrinter.writer, "\n"+getSperator("#")+"\n\n")
|
||||
|
||||
if source, ok := opaSessionObj.ResourceSource[resourceID]; ok {
|
||||
fmt.Fprintf(prettyPrinter.writer, "Source: %s\n", source)
|
||||
}
|
||||
fmt.Fprintf(prettyPrinter.writer, "ApiVersion: %s\n", resource.GetApiVersion())
|
||||
fmt.Fprintf(prettyPrinter.writer, "Kind: %s\n", resource.GetKind())
|
||||
fmt.Fprintf(prettyPrinter.writer, "Name: %s\n", resource.GetName())
|
||||
if resource.GetNamespace() != "" {
|
||||
fmt.Fprintf(prettyPrinter.writer, "Namespace: %s\n", resource.GetNamespace())
|
||||
}
|
||||
fmt.Fprintf(prettyPrinter.writer, "\n"+controlCountersForResource(result.ListControlsIDs(nil))+"\n\n")
|
||||
|
||||
summaryTable := tablewriter.NewWriter(prettyPrinter.writer)
|
||||
summaryTable.SetAutoWrapText(true)
|
||||
summaryTable.SetAutoMergeCells(true)
|
||||
summaryTable.SetHeader(generateResourceHeader())
|
||||
summaryTable.SetHeaderLine(true)
|
||||
summaryTable.SetRowLine(true)
|
||||
data := Matrix{}
|
||||
|
||||
if raw := generateResourceRows(result.ListControls(), &opaSessionObj.Report.SummaryDetails); len(raw) > 0 {
|
||||
data = append(data, raw...)
|
||||
}
|
||||
}
|
||||
sort.Sort(data)
|
||||
summaryTable.AppendBulk(data)
|
||||
// For control scan framework will be nil
|
||||
|
||||
sort.Sort(data)
|
||||
summaryTable.AppendBulk(data)
|
||||
|
||||
summaryTable.Render()
|
||||
}
|
||||
|
||||
summaryTable.Render()
|
||||
}
|
||||
|
||||
func generateResourceRows(resource workloadinterface.IMetadata, controls []resourcesresults.ResourceAssociatedControl, verboseMode bool) [][]string {
|
||||
func generateResourceRows(controls []resourcesresults.ResourceAssociatedControl, summaryDetails *reportsummary.SummaryDetails) [][]string {
|
||||
rows := [][]string{}
|
||||
|
||||
for i := range controls {
|
||||
row := make([]string, _resourceRowLen)
|
||||
|
||||
if controls[i].GetName() == "" {
|
||||
continue
|
||||
}
|
||||
row := []string{}
|
||||
|
||||
if !verboseMode && controls[i].GetStatus(nil).IsPassed() {
|
||||
if !controls[i].GetStatus(nil).IsFailed() {
|
||||
continue
|
||||
}
|
||||
|
||||
row = append(row, fmt.Sprintf("%s\nhttps://hub.armo.cloud/docs/%s", controls[i].GetName(), strings.ToLower(controls[i].GetID())))
|
||||
row = append(row, resource.GetNamespace())
|
||||
paths := failedPathsToString(&controls[i])
|
||||
row[resourceColumnURL] = fmt.Sprintf("https://hub.armo.cloud/docs/%s", strings.ToLower(controls[i].GetID()))
|
||||
row[resourceColumnPath] = strings.Join(failedPathsToString(&controls[i]), "\n")
|
||||
row[resourceColumnName] = controls[i].GetName()
|
||||
|
||||
if c := summaryDetails.Controls.GetControl(reportsummary.EControlCriteriaName, controls[i].GetName()); c != nil {
|
||||
row[resourceColumnSeverity] = getSeverityColumn(c)
|
||||
}
|
||||
|
||||
row = append(row, fmt.Sprintf("%s/%s\n%s", resource.GetKind(), resource.GetName(), strings.Join(paths, ";\n")))
|
||||
row = append(row, string(controls[i].GetStatus(nil).Status()))
|
||||
rows = append(rows, row)
|
||||
}
|
||||
|
||||
@@ -64,7 +88,12 @@ func generateResourceRows(resource workloadinterface.IMetadata, controls []resou
|
||||
}
|
||||
|
||||
func generateResourceHeader() []string {
|
||||
return []string{"Control", "Namespace", "Kind/Name", "Statues"}
|
||||
headers := make([]string, _resourceRowLen)
|
||||
headers[resourceColumnSeverity] = "Severity"
|
||||
headers[resourceColumnName] = "Control Name"
|
||||
headers[resourceColumnURL] = "Docs"
|
||||
headers[resourceColumnPath] = "Assistant Remediation"
|
||||
return headers
|
||||
}
|
||||
|
||||
type Matrix [][]string
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
package v2
|
||||
@@ -26,7 +26,7 @@ func DataToJson(data *cautils.OPASessionObj) *reporthandlingv2.PostureReport {
|
||||
report.Results = make([]resourcesresults.Result, len(data.ResourcesResult))
|
||||
finalizeResults(report.Results, data.ResourcesResult)
|
||||
|
||||
report.Resources = finalizeResources(report.Results, data.AllResources)
|
||||
report.Resources = finalizeResources(report.Results, data.AllResources, data.ResourceSource)
|
||||
|
||||
return &report
|
||||
}
|
||||
@@ -38,27 +38,39 @@ func finalizeResults(results []resourcesresults.Result, resourcesResult map[stri
|
||||
}
|
||||
}
|
||||
|
||||
func mapInfoToPrintInfo(controls reportsummary.ControlSummaries) map[string]string {
|
||||
infoToPrintInfoMap := make(map[string]string)
|
||||
type infoStars struct {
|
||||
stars string
|
||||
info string
|
||||
}
|
||||
|
||||
func mapInfoToPrintInfo(controls reportsummary.ControlSummaries) []infoStars {
|
||||
infoToPrintInfo := []infoStars{}
|
||||
infoToPrintInfoMap := map[string]interface{}{}
|
||||
starCount := "*"
|
||||
for _, control := range controls {
|
||||
if control.GetStatus().IsSkipped() && control.GetStatus().Info() != "" {
|
||||
if _, ok := infoToPrintInfoMap[control.GetStatus().Info()]; !ok {
|
||||
infoToPrintInfoMap[control.GetStatus().Info()] = starCount
|
||||
infoToPrintInfo = append(infoToPrintInfo, infoStars{
|
||||
info: control.GetStatus().Info(),
|
||||
stars: starCount,
|
||||
})
|
||||
starCount += starCount
|
||||
infoToPrintInfoMap[control.GetStatus().Info()] = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return infoToPrintInfoMap
|
||||
return infoToPrintInfo
|
||||
}
|
||||
|
||||
func finalizeResources(results []resourcesresults.Result, allResources map[string]workloadinterface.IMetadata) []reporthandling.Resource {
|
||||
func finalizeResources(results []resourcesresults.Result, allResources map[string]workloadinterface.IMetadata, resourcesSource map[string]string) []reporthandling.Resource {
|
||||
resources := make([]reporthandling.Resource, 0)
|
||||
for i := range results {
|
||||
if obj, ok := allResources[results[i].ResourceID]; ok {
|
||||
r := *reporthandling.NewResource(obj.GetObject())
|
||||
r.ResourceID = results[i].ResourceID
|
||||
resources = append(resources, r)
|
||||
resource := *reporthandling.NewResourceIMetadata(obj)
|
||||
if r, ok := resourcesSource[results[i].ResourceID]; ok {
|
||||
resource.SetSource(&reporthandling.Source{Path: r})
|
||||
}
|
||||
resources = append(resources, resource)
|
||||
}
|
||||
}
|
||||
return resources
|
||||
|
||||
@@ -48,8 +48,7 @@ func (report *ReportEventReceiver) Submit(opaSessionObj *cautils.OPASessionObj)
|
||||
logger.L().Warning("failed to publish results. Reason: Unknown accout ID. Run kubescape with the '--account <account ID>' flag. Contact ARMO team for more details")
|
||||
return nil
|
||||
}
|
||||
// if opaSessionObj.Metadata.ScanMetadata.ScanningTarget == reporthandlingv2.Cluster && report.clusterName == "" {
|
||||
if report.clusterName == "" {
|
||||
if opaSessionObj.Metadata.ScanMetadata.ScanningTarget == reporthandlingv2.Cluster && report.clusterName == "" {
|
||||
logger.L().Warning("failed to publish results because the cluster name is Unknown. If you are scanning YAML files the results are not submitted to the Kubescape SaaS")
|
||||
return nil
|
||||
}
|
||||
@@ -58,7 +57,7 @@ func (report *ReportEventReceiver) Submit(opaSessionObj *cautils.OPASessionObj)
|
||||
if err == nil {
|
||||
report.generateMessage()
|
||||
} else {
|
||||
logger.L().Debug(err.Error()) // print original error only in debug mode
|
||||
|
||||
err = fmt.Errorf("failed to submit scan results. url: '%s'", report.GetURL())
|
||||
}
|
||||
|
||||
@@ -93,6 +92,8 @@ func (report *ReportEventReceiver) GetURL() string {
|
||||
u.Scheme = "https"
|
||||
u.Host = getter.GetArmoAPIConnector().GetFrontendURL()
|
||||
|
||||
q := u.Query()
|
||||
|
||||
if report.customerAdminEMail != "" || report.token == "" { // data has been submitted
|
||||
u.Path = fmt.Sprintf("configuration-scanning/%s", report.clusterName)
|
||||
} else {
|
||||
@@ -100,9 +101,14 @@ func (report *ReportEventReceiver) GetURL() string {
|
||||
q := u.Query()
|
||||
q.Add("invitationToken", report.token)
|
||||
q.Add("customerGUID", report.customerGUID)
|
||||
|
||||
u.RawQuery = q.Encode()
|
||||
}
|
||||
|
||||
q.Add("utm_source", "GitHub")
|
||||
q.Add("utm_medium", "CLI")
|
||||
q.Add("utm_campaign", "Submit")
|
||||
|
||||
u.RawQuery = q.Encode()
|
||||
|
||||
return u.String()
|
||||
|
||||
}
|
||||
@@ -110,7 +116,7 @@ func (report *ReportEventReceiver) sendResources(host string, opaSessionObj *cau
|
||||
splittedPostureReport := report.setSubReport(opaSessionObj)
|
||||
counter := 0
|
||||
reportCounter := 0
|
||||
if err := report.setResources(splittedPostureReport, opaSessionObj.AllResources, &counter, &reportCounter, host); err != nil {
|
||||
if err := report.setResources(splittedPostureReport, opaSessionObj.AllResources, opaSessionObj.ResourceSource, &counter, &reportCounter, host); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := report.setResults(splittedPostureReport, opaSessionObj.ResourcesResult, &counter, &reportCounter, host); err != nil {
|
||||
@@ -148,9 +154,12 @@ func (report *ReportEventReceiver) setResults(reportObj *reporthandlingv2.Postur
|
||||
return nil
|
||||
}
|
||||
|
||||
func (report *ReportEventReceiver) setResources(reportObj *reporthandlingv2.PostureReport, allResources map[string]workloadinterface.IMetadata, counter, reportCounter *int, host string) error {
|
||||
func (report *ReportEventReceiver) setResources(reportObj *reporthandlingv2.PostureReport, allResources map[string]workloadinterface.IMetadata, resourcesSource map[string]string, counter, reportCounter *int, host string) error {
|
||||
for resourceID, v := range allResources {
|
||||
resource := reporthandling.NewResourceIMetadata(v)
|
||||
if r, ok := resourcesSource[resourceID]; ok {
|
||||
resource.SetSource(&reporthandling.Source{Path: r})
|
||||
}
|
||||
r, err := json.Marshal(resource)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to unmarshal resource '%s', reason: %v", resourceID, err)
|
||||
|
||||
@@ -43,8 +43,11 @@ func (report *ReportEventReceiver) setSubReport(opaSessionObj *cautils.OPASessio
|
||||
ClusterAPIServerInfo: opaSessionObj.Report.ClusterAPIServerInfo,
|
||||
}
|
||||
if opaSessionObj.Metadata != nil {
|
||||
reportObj.ClusterCloudProvider = opaSessionObj.Metadata.ClusterMetadata.CloudProvider
|
||||
reportObj.Metadata = *opaSessionObj.Metadata
|
||||
if opaSessionObj.Metadata.ContextMetadata.ClusterContextMetadata != nil {
|
||||
reportObj.ClusterCloudProvider = opaSessionObj.Metadata.ContextMetadata.ClusterContextMetadata.CloudProvider // DEPRECATED
|
||||
reportObj.Metadata.ClusterMetadata = *opaSessionObj.Metadata.ContextMetadata.ClusterContextMetadata
|
||||
}
|
||||
}
|
||||
return reportObj
|
||||
}
|
||||
|
||||
@@ -56,17 +56,19 @@ func (resultsHandler *ResultsHandler) ToJson() ([]byte, error) {
|
||||
}
|
||||
|
||||
// HandleResults handle the scan results according to the pre defind interfaces
|
||||
func (resultsHandler *ResultsHandler) HandleResults() {
|
||||
func (resultsHandler *ResultsHandler) HandleResults() error {
|
||||
|
||||
resultsHandler.printerObj.ActionPrint(resultsHandler.scanData)
|
||||
|
||||
if err := resultsHandler.reporterObj.Submit(resultsHandler.scanData); err != nil {
|
||||
logger.L().Error(err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
resultsHandler.printerObj.Score(resultsHandler.GetRiskScore())
|
||||
|
||||
resultsHandler.reporterObj.DisplayReportURL()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewPrinter defind output format
|
||||
|
||||
@@ -5,33 +5,33 @@
|
||||
Kubescape roadmap items are labeled based on where the feature is used and by their maturity.
|
||||
|
||||
The features serve different stages of the workflow of the users:
|
||||
* **Development phase** (writing Kubernetes manifests) - example: VS Code extension is used while editing YAMLs
|
||||
* **Development phase** (writing Kubernetes manifests) - example: The VS Code extension is used while editing YAMLs.
|
||||
* **CI phase** (integrating manifests to GIT repo) - example: GitHub action validating HELM charts on PRs
|
||||
* **CD phase** (deploying applications in Kubernetes) - example: running cluster scan after a new deployment
|
||||
* **Monitoring phase** (scanning application in Kubernetes) - example: Prometheus scraping the cluster security risk
|
||||
* **CD phase** (deploying applications in Kubernetes) - example: running a cluster scan after a new deployment
|
||||
* **Monitoring phase** (scanning application in Kubernetes) - example: Prometheus scraping the cluster security risk
|
||||
|
||||
The items in Kubescape roadmap are split to 3 major groups based on the feature planning maturity:
|
||||
The items in the Kubescape roadmap are split into 3 major groups based on the feature planning maturity:
|
||||
|
||||
* [Planning](#planning) - we have tickets open for these issues with more or less clear vision of design
|
||||
* [Backlog](#backlog) - feature which were discussed at a high level but are not ready for development
|
||||
* [Wishlist](#wishlist) - features we are dreaming of 😀 and want to push them gradually forward
|
||||
* [Planning](#planning) - we have tickets open for these issues with a more or less clear vision of design.
|
||||
* [Backlog](#backlog) - features that were discussed at a high level but are not ready for development
|
||||
* [Wishlist](#wishlist) - features we are dreaming of in 😀 and want to push them gradually forward
|
||||
|
||||
|
||||
## Planning 👷
|
||||
* ##### Integration with image registries
|
||||
We want to expand Kubescape to integrate with differnet image registries and read image vulnerability information from there. This will allow Kubescape to give contextual security information about vulnerabilities [Container registry integration](/docs/proposals/container-image-vulnerability-adaptor.md)
|
||||
We want to expand Kubescape to integrate with different image registries and read image vulnerability information from there. This will allow Kubescape to give contextual security information about vulnerabilities. Container registry integration
|
||||
* ##### Kubescape as a microservice
|
||||
Create a REST API for Kubescape so it can run constantly in a cluster and other components like Prometheus can scrape results
|
||||
Create a REST API for Kubescape so it can constantly run in a cluster, and other components like Prometheus can scrape results.
|
||||
* ##### Kubescape CLI control over cluster operations
|
||||
Add functionality to Kubescape CLI to trigger operations in Kubescape cluster components (example: trigger images scans and etc.)
|
||||
Add functionality to Kubescape CLI to trigger operations in Kubescape cluster components (example: trigger image scans, etc.)
|
||||
* ##### Produce md/HTML reports
|
||||
Create scan reports for different output formats
|
||||
Create scan reports for different output formats.
|
||||
* ##### Git integration for pull requests
|
||||
Create insightful GitHub actions for Kubescape
|
||||
|
||||
## Backlog 📅
|
||||
* ##### JSON path for HELM charts
|
||||
Today Kubescape can point to issues in the Kubernetes object, we want to develop this feature so Kubescape will be able to point to the misconfigured source file (HELM)
|
||||
Today, Kubescape can point to issues in the Kubernetes object. We want to develop this feature so Kubescape will be able to point to the misconfigured source file (HELM).
|
||||
* ##### Create Kubescape HELM plugin
|
||||
* ##### Kubescape based admission controller
|
||||
Implement admission controller API for Kubescape microservice to enable users to use Kubescape rules as policies
|
||||
|
||||
BIN
docs/summary.png
BIN
docs/summary.png
Binary file not shown.
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 163 KiB |
@@ -12,7 +12,7 @@ Running `kubescape` will start up a webserver on port `8080` which will serve th
|
||||
* DELETE `/v1/results` - Delete kubescape scan results from storage. ~If empty will delete latest results~ (not supported)
|
||||
* * query `id=<string>`: Delete ID of specific results
|
||||
* * query `all`: Delete all cached results
|
||||
* GET/POST `/metrics` - will trigger cluster scan. will respond with prometheus metrics once they have been scanned. This will respond 503 if the scan failed.
|
||||
* GET/POST `/v1/metrics` - will trigger cluster scan. will respond with prometheus metrics once they have been scanned. This will respond 503 if the scan failed.
|
||||
* `/livez` - will respond 200 is server is alive
|
||||
* `/readyz` - will respond 200 if server can receive requests
|
||||
|
||||
|
||||
@@ -17,4 +17,106 @@
|
||||
```bash
|
||||
kubectl apply -f podmonitor.yaml
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Metrics
|
||||
|
||||
All kubescape related metrics begin with `kubescape`
|
||||
|
||||
> `riskScore` is the output of an algorithm calculating the risk of the vulinrability. `0` indicates there is no risk and `100` indicates highest risk.
|
||||
|
||||
#### Cluster scope metrics
|
||||
|
||||
##### Overall risk score
|
||||
```
|
||||
# Overall riskScore of the scan
|
||||
kubescape_cluster_riskScore{} <risk score>
|
||||
```
|
||||
|
||||
###### Overall resources counters
|
||||
```
|
||||
# Number of resources that failed
|
||||
kubescape_cluster_count_resources_failed{} <counter>
|
||||
|
||||
# Number of resources that where excluded
|
||||
kubescape_cluster_count_resources_excluded{} <counter>
|
||||
|
||||
# Number of resources that passed
|
||||
kubescape_cluster_count_resources_passed{} <counter>
|
||||
```
|
||||
|
||||
###### Overall controls counters
|
||||
```
|
||||
# Number of controls that failed
|
||||
kubescape_cluster_count_controls_failed{} <counter>
|
||||
|
||||
# Number of controls that where excluded
|
||||
kubescape_cluster_count_controls_excluded{} <counter>
|
||||
|
||||
# Number of controls that passed
|
||||
kubescape_cluster_count_controls_passed{} <counter>
|
||||
```
|
||||
|
||||
#### Frameworks metrics
|
||||
|
||||
##### Frameworks risk score
|
||||
```
|
||||
kubescape_framework_riskScore{name="<framework name>"} <risk score>
|
||||
```
|
||||
|
||||
###### Frameworks resources counters
|
||||
|
||||
```
|
||||
# Number of resources that failed
|
||||
kubescape_framework_count_resources_failed{} <counter>
|
||||
|
||||
# Number of resources that where excluded
|
||||
kubescape_framework_count_resources_excluded{} <counter>
|
||||
|
||||
# Number of resources that passed
|
||||
kubescape_framework_count_resources_passed{} <counter>
|
||||
```
|
||||
###### Frameworks controls counters
|
||||
|
||||
```
|
||||
# Number of controls that failed
|
||||
kubescape_framework_count_controls_failed{name="<framework name>"} <counter>
|
||||
|
||||
# Number of controls that where excluded
|
||||
kubescape_framework_count_controls_excluded{name="<framework name>"} <counter>
|
||||
|
||||
# Number of controls that passed
|
||||
kubescape_framework_count_controls_passed{name="<framework name>"} <counter>
|
||||
```
|
||||
|
||||
#### Controls metrics
|
||||
|
||||
##### Controls risk score
|
||||
|
||||
```
|
||||
kubescape_control_riskScore{name="<control name>",url="<docs url>",severity="<control severity>"} <risk score>
|
||||
```
|
||||
|
||||
###### Controls resources counters
|
||||
|
||||
```
|
||||
# Number of resources that failed
|
||||
kubescape_control_count_resources_failed{name="<control name>",url="<docs url>",severity="<control severity>"} <counter>
|
||||
|
||||
# Number of resources that where excluded
|
||||
kubescape_control_count_resources_excluded{name="<control name>",url="<docs url>",severity="<control severity>"} <counter>
|
||||
|
||||
# Number of resources that passed
|
||||
kubescape_control_count_resources_passed{name="<control name>",url="<docs url>",severity="<control severity>"} <counter>
|
||||
```
|
||||
|
||||
#### Resources metrics
|
||||
The resources metrics give you the ability to prioritize fixing the resources by the number of controls that failed
|
||||
|
||||
```
|
||||
# Number of controls that failed for this particular resource
|
||||
kubescape_resource_count_controls_failed{apiVersion="<>",kind="<>",namespace="<>",name="<>"} <counter>
|
||||
|
||||
# Number of controls that where excluded for this particular resource
|
||||
kubescape_resource_count_controls_excluded{apiVersion="<>",kind="<>",namespace="<>",name="<>"} <counter>
|
||||
```
|
||||
@@ -89,7 +89,8 @@ spec:
|
||||
port: 8080
|
||||
initialDelaySeconds: 3
|
||||
periodSeconds: 3
|
||||
image: quay.io/armosec/kubescape:prometheus.v2
|
||||
image: quay.io/armosec/kubescape:latest
|
||||
imagePullPolicy: Always
|
||||
env:
|
||||
- name: KS_DEFAULT_CONFIGMAP_NAMESPACE
|
||||
valueFrom:
|
||||
|
||||
@@ -11,6 +11,6 @@ spec:
|
||||
app: kubescape
|
||||
podMetricsEndpoints:
|
||||
- port: http
|
||||
# path: v1
|
||||
path: /v1/metrics
|
||||
interval: 120s
|
||||
scrapeTimeout: 100s
|
||||
|
||||
@@ -6,7 +6,7 @@ replace github.com/armosec/kubescape/core => ../core
|
||||
|
||||
require (
|
||||
github.com/armosec/kubescape/core v0.0.0-00010101000000-000000000000
|
||||
github.com/armosec/opa-utils v0.0.127
|
||||
github.com/armosec/opa-utils v0.0.130
|
||||
github.com/armosec/utils-go v0.0.3
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/gorilla/mux v1.8.0
|
||||
|
||||
@@ -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.127 h1:uVyH/+pjpiA0oBO6QODjtdCiPgHx7KQ/TcxxkPvAl4c=
|
||||
github.com/armosec/opa-utils v0.0.127/go.mod h1:gap+EaLG5rnyqvIRGxtdNDC9y7VvoGNm90zK8Ls7avQ=
|
||||
github.com/armosec/opa-utils v0.0.130 h1:uP60M0PzmDtLqvsA/jX8BED9/Ava4n2QG7VCkuI+hwI=
|
||||
github.com/armosec/opa-utils v0.0.130/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=
|
||||
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
const (
|
||||
scanPath = "/v1/scan"
|
||||
resultsPath = "/v1/results"
|
||||
prometheusMmeticsPath = "/metrics"
|
||||
prometheusMmeticsPath = "/v1/metrics"
|
||||
livePath = "/livez"
|
||||
readyPath = "/readyz"
|
||||
)
|
||||
|
||||
@@ -54,6 +54,6 @@ echo -e "\033[0m"
|
||||
$KUBESCAPE_EXEC version
|
||||
echo
|
||||
|
||||
echo -e "\033[35mUsage: $ $KUBESCAPE_EXEC scan --submit --enable-host-scan"
|
||||
echo -e "\033[35mUsage: $ $KUBESCAPE_EXEC scan --submit --enable-host-scan --format-version v2 --verbose"
|
||||
|
||||
echo -e "\033[0m"
|
||||
|
||||
Reference in New Issue
Block a user