mirror of
https://github.com/kubescape/kubescape.git
synced 2026-04-15 06:58:11 +00:00
Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d7336ae01 | ||
|
|
e5e608324d | ||
|
|
569c1444f7 | ||
|
|
dc5ef28324 | ||
|
|
aea6c0eab8 | ||
|
|
c80a15d0cf | ||
|
|
1ddd57aa1d | ||
|
|
55adb0da6b | ||
|
|
a716289cc8 | ||
|
|
093d71fff4 | ||
|
|
4fe40e348d | ||
|
|
29a67b806d | ||
|
|
0169f42747 | ||
|
|
92e100c497 | ||
|
|
536fe970f7 | ||
|
|
85526b06b6 | ||
|
|
d9b6c048d5 | ||
|
|
7e46a6529a | ||
|
|
2dc5fd80da | ||
|
|
e89cc8ca24 | ||
|
|
d39aeb0691 | ||
|
|
da9d98134a | ||
|
|
9992a9a0e4 | ||
|
|
adc8a16e85 | ||
|
|
cb424eab00 | ||
|
|
9f2e18c3ee | ||
|
|
9c5759286f | ||
|
|
efbb123fce | ||
|
|
6372ce5647 | ||
|
|
9733178228 |
@@ -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,7 +7,7 @@ replace github.com/armosec/kubescape/core => ../core
|
||||
require (
|
||||
github.com/armosec/k8s-interface v0.0.68
|
||||
github.com/armosec/kubescape/core v0.0.0-00010101000000-000000000000
|
||||
github.com/armosec/opa-utils v0.0.127
|
||||
github.com/armosec/opa-utils v0.0.129
|
||||
github.com/armosec/rbac-utils v0.0.14
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/mattn/go-isatty v0.0.14
|
||||
|
||||
@@ -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.129 h1:5ezMd558f9MtLlwLWHBeyrBGThaFYSeGhY9f1KQPemw=
|
||||
github.com/armosec/opa-utils v0.0.129/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' flag for full scan details\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' flag for full scan details\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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -233,7 +233,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"
|
||||
|
||||
@@ -104,6 +104,7 @@ func (scanInfo *ScanInfo) Init() {
|
||||
if scanInfo.ScanID == "" {
|
||||
scanInfo.ScanID = uuid.NewString()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (scanInfo *ScanInfo) setUseArtifactsFrom() {
|
||||
@@ -197,7 +198,6 @@ 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.Submit = scanInfo.Submit
|
||||
|
||||
@@ -226,8 +226,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
|
||||
|
||||
@@ -151,11 +151,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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -119,7 +119,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.129
|
||||
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.129 h1:5ezMd558f9MtLlwLWHBeyrBGThaFYSeGhY9f1KQPemw=
|
||||
github.com/armosec/opa-utils v0.0.129/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=
|
||||
|
||||
@@ -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()}
|
||||
|
||||
@@ -4,46 +4,124 @@ import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"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, infoToPrintInfo []infoStars) []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
|
||||
columnInfo = 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() {
|
||||
stars := ""
|
||||
for i := range infoToPrintInfo {
|
||||
if infoToPrintInfo[i].info == controlSummary.GetStatus().Info() {
|
||||
stars = infoToPrintInfo[i].stars
|
||||
break
|
||||
}
|
||||
}
|
||||
row = append(row, stars)
|
||||
} 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)
|
||||
row[columnInfo] = getInfoColumn(controlSummary, infoToPrintInfo)
|
||||
|
||||
return row
|
||||
}
|
||||
|
||||
func getSortedControlsNames(controls reportsummary.ControlSummaries) []string {
|
||||
controlNames := make([]string, 0, len(controls))
|
||||
func getInfoColumn(controlSummary reportsummary.IControlSummary, infoToPrintInfo []infoStars) string {
|
||||
if !controlSummary.GetStatus().IsSkipped() {
|
||||
return ""
|
||||
}
|
||||
|
||||
if controlSummary.GetStatus().IsSkipped() {
|
||||
for i := range infoToPrintInfo {
|
||||
if infoToPrintInfo[i].info == controlSummary.GetStatus().Info() {
|
||||
return infoToPrintInfo[i].stars
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getRiskScoreColumn(controlSummary reportsummary.IControlSummary) string {
|
||||
if controlSummary.GetStatus().IsSkipped() {
|
||||
return string(controlSummary.GetStatus().Status())
|
||||
}
|
||||
return fmt.Sprintf("%d", int(controlSummary.GetScore())) + "%"
|
||||
}
|
||||
|
||||
func getSeverityColumn(controlSummary reportsummary.IControlSummary) string {
|
||||
// if controlSummary.GetStatus().IsPassed() || controlSummary.GetStatus().IsSkipped() {
|
||||
// return " "
|
||||
// }
|
||||
severity := apis.ControlSeverityToString(controlSummary.GetScoreFactor())
|
||||
return color.New(getColor(severity), color.Bold).SprintFunc()(severity)
|
||||
}
|
||||
func getColor(controlSeverity string) color.Attribute {
|
||||
switch controlSeverity {
|
||||
case "Critical":
|
||||
return color.FgRed
|
||||
case "High":
|
||||
return color.FgYellow
|
||||
case "Medium":
|
||||
return color.FgCyan
|
||||
case "Low":
|
||||
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"
|
||||
headers[columnInfo] = "INFO"
|
||||
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
|
||||
alignments[columnRiskScore] = tablewriter.ALIGN_CENTER
|
||||
return alignments
|
||||
}
|
||||
|
||||
@@ -31,8 +31,7 @@ var (
|
||||
)
|
||||
|
||||
type PdfPrinter struct {
|
||||
writer *os.File
|
||||
sortedControlNames []string
|
||||
writer *os.File
|
||||
}
|
||||
|
||||
func NewPdfPrinter() *PdfPrinter {
|
||||
@@ -76,13 +75,13 @@ 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)
|
||||
|
||||
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, infoToPrintInfo)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -17,10 +17,9 @@ import (
|
||||
)
|
||||
|
||||
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 +30,16 @@ func NewPrettyPrinter(verboseMode bool, formatVersion string) *PrettyPrinter {
|
||||
}
|
||||
|
||||
func (prettyPrinter *PrettyPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
|
||||
prettyPrinter.sortedControlNames = getSortedControlsNames(opaSessionObj.Report.SummaryDetails.Controls) // ListControls().All())
|
||||
sortedControlNames := getSortedControlsNames(opaSessionObj.Report.SummaryDetails.Controls) // ListControls().All())
|
||||
|
||||
if prettyPrinter.formatVersion == "v1" {
|
||||
prettyPrinter.printResults(&opaSessionObj.Report.SummaryDetails.Controls, opaSessionObj.AllResources)
|
||||
} else if prettyPrinter.formatVersion == "v2" {
|
||||
prettyPrinter.resourceTable(opaSessionObj.ResourcesResult, opaSessionObj.AllResources)
|
||||
if prettyPrinter.verboseMode {
|
||||
if prettyPrinter.formatVersion == "v1" {
|
||||
prettyPrinter.printResults(&opaSessionObj.Report.SummaryDetails.Controls, opaSessionObj.AllResources, sortedControlNames)
|
||||
} else if prettyPrinter.formatVersion == "v2" {
|
||||
prettyPrinter.resourceTable(opaSessionObj.ResourcesResult, opaSessionObj.AllResources)
|
||||
}
|
||||
}
|
||||
prettyPrinter.printSummaryTable(&opaSessionObj.Report.SummaryDetails)
|
||||
prettyPrinter.printSummaryTable(&opaSessionObj.Report.SummaryDetails, sortedControlNames)
|
||||
|
||||
}
|
||||
|
||||
@@ -49,13 +50,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,27 +169,33 @@ 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, "%")
|
||||
row[columnInfo] = " "
|
||||
|
||||
return row
|
||||
}
|
||||
func (prettyPrinter *PrettyPrinter) printSummaryTable(summaryDetails *reportsummary.SummaryDetails) {
|
||||
func (prettyPrinter *PrettyPrinter) printSummaryTable(summaryDetails *reportsummary.SummaryDetails, sortedControlNames [][]string) {
|
||||
|
||||
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)
|
||||
summaryTable.SetColumnAlignment(getColumnsAlignments())
|
||||
|
||||
infoToPrintInfo := mapInfoToPrintInfo(summaryDetails.Controls)
|
||||
for i := 0; i < len(prettyPrinter.sortedControlNames); i++ {
|
||||
summaryTable.Append(generateRow(summaryDetails.Controls.GetControl(reportsummary.EControlCriteriaName, prettyPrinter.sortedControlNames[i]), infoToPrintInfo))
|
||||
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))
|
||||
@@ -226,14 +234,6 @@ 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))
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package v2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/armosec/k8s-interface/workloadinterface"
|
||||
"github.com/armosec/opa-utils/reporthandling/apis"
|
||||
@@ -12,88 +13,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 +202,7 @@ type mRiskScore struct {
|
||||
controlsCountFailed int
|
||||
controlsCountExcluded int
|
||||
controlsCountSkipped int
|
||||
riskScore int // metric
|
||||
riskScore int
|
||||
}
|
||||
|
||||
type mControlRiskScore struct {
|
||||
@@ -118,7 +214,7 @@ type mControlRiskScore struct {
|
||||
resourcesCountPassed int
|
||||
resourcesCountFailed int
|
||||
resourcesCountExcluded int
|
||||
riskScore int // metric
|
||||
riskScore int
|
||||
}
|
||||
|
||||
type mFrameworkRiskScore struct {
|
||||
@@ -130,23 +226,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) {
|
||||
@@ -229,24 +325,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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -57,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())
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
```
|
||||
@@ -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.129
|
||||
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.129 h1:5ezMd558f9MtLlwLWHBeyrBGThaFYSeGhY9f1KQPemw=
|
||||
github.com/armosec/opa-utils v0.0.129/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=
|
||||
|
||||
@@ -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 --verbose"
|
||||
|
||||
echo -e "\033[0m"
|
||||
|
||||
Reference in New Issue
Block a user