Merge remote-tracking branch 'prometheus/feature/prometheus'

This commit is contained in:
dwertent
2021-10-31 08:58:57 +02:00
3 changed files with 123 additions and 15 deletions
+18 -13
View File
@@ -69,19 +69,19 @@ Set-ExecutionPolicy RemoteSigned -scope CurrentUser
## Flags
| flag | default | description | options |
| --- | --- | --- | --- |
| `-e`/`--exclude-namespaces` | Scan all namespaces | Namespaces to exclude from scanning. Recommended to exclude `kube-system` and `kube-public` namespaces |
| `-s`/`--silent` | Display progress messages | Silent progress messages |
| `-t`/`--fail-threshold` | `0` (do not fail) | fail command (return exit code 1) if result bellow threshold| `0` -> `100` |
| `-f`/`--format` | `pretty-printer` | Output format | `pretty-printer`/`json`/`junit` |
| `-o`/`--output` | print to stdout | Save scan result in file |
| `--use-from` | | Load local framework object from specified path. If not used will download latest |
| `--use-default` | `false` | Load local framework object from default path. If not used will download latest | `true`/`false` |
| `--exceptions` | | Path to an [exceptions obj](examples/exceptions.json). If not set will download exceptions from Armo management portal |
| `--submit` | `false` | If set, Kubescape will 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 sent | `true`/`false`|
| `--keep-local` | `false` | Kubescape will not send scan results to Armo management portal. Use this flag if you ran with the `--submit` flag in the past and you do not want to submit your current scan results | `true`/`false`|
| `--account` | | Armo portal account ID. Default will load account ID from configMap or config file | |
| flag | default | description | options |
|-----------------------------|---------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------|
| `-e`/`--exclude-namespaces` | Scan all namespaces | Namespaces to exclude from scanning. Recommended to exclude `kube-system` and `kube-public` namespaces | |
| `-s`/`--silent` | Display progress messages | Silent progress messages | |
| `-t`/`--fail-threshold` | `0` (do not fail) | fail command (return exit code 1) if result bellow threshold | `0` -> `100` |
| `-f`/`--format` | `pretty-printer` | Output format | `pretty-printer`/`json`/`junit`/`prometheus` |
| `-o`/`--output` | print to stdout | Save scan result in file | |
| `--use-from` | | Load local framework object from specified path. If not used will download latest | |
| `--use-default` | `false` | Load local framework object from default path. If not used will download latest | `true`/`false` |
| `--exceptions` | | Path to an [exceptions obj](examples/exceptions.json). If not set will download exceptions from Armo management portal | |
| `--submit` | `false` | If set, Kubescape will 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 sent | `true`/`false` |
| `--keep-local` | `false` | Kubescape will not send scan results to Armo management portal. Use this flag if you ran with the `--submit` flag in the past and you do not want to submit your current scan results | `true`/`false` |
| `--account` | | Armo portal account ID. Default will load account ID from configMap or config file | |
## Usage & Examples
@@ -125,6 +125,11 @@ kubescape scan framework nsa --exclude-namespaces kube-system,kube-public --form
kubescape scan framework nsa --exclude-namespaces kube-system,kube-public --format junit --output results.xml
```
* Output in `prometheus` metrics format
```
kubescape scan framework nsa --exclude-namespaces kube-system,kube-public --format prometheus
```
* Scan with exceptions, objects with exceptions will be presented as `exclude` and not `fail`
```
kubescape scan framework nsa --exceptions examples/exceptions.json
+5 -2
View File
@@ -11,7 +11,8 @@ const EmptyPercentage = "NaN"
const (
PrettyFormat string = "pretty-printer"
JsonFormat string = "json"
JunitResultPrinter string = "junit"
JunitResultFormat string = "junit"
PrometheusFormat string = "prometheus"
)
type IPrinter interface {
@@ -24,8 +25,10 @@ func GetPrinter(printFormat string) IPrinter {
switch printFormat {
case JsonFormat:
return NewJsonPrinter()
case JunitResultPrinter:
case JunitResultFormat:
return NewJunitPrinter()
case PrometheusFormat:
return NewPrometheusPrinter()
default:
return NewPrettyPrinter()
}
@@ -0,0 +1,100 @@
package printer
import (
"errors"
"fmt"
"os"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/opa-utils/reporthandling"
)
type PrometheusPrinter struct {
writer *os.File
}
func NewPrometheusPrinter() *PrometheusPrinter {
return &PrometheusPrinter{}
}
func (prometheusPrinter *PrometheusPrinter) SetWriter(outputFile string) {
prometheusPrinter.writer = getWriter(outputFile)
}
func (prometheusPrinter *PrometheusPrinter) Score(score float32) {
fmt.Printf("\n# Overall score out of 100\nkubescape_score %f\n", score*100)
}
func (printer *PrometheusPrinter) printDetails(details []reporthandling.RuleResponse, frameworkName string, controlName string) error {
objs := make(map[string]map[string]map[string]int)
for _, ruleResponses := range details {
for _, k8sObj := range ruleResponses.AlertObject.K8SApiObjects {
kind, ok := k8sObj[`kind`].(string)
if (!ok) {
return errors.New("Found object with non string kind")
}
apiVersion,ok := k8sObj[`apiVersion`].(string)
if (!ok) {
return errors.New("Found object with non string apiVersion")
}
gvk := fmt.Sprintf("%s/%s",apiVersion,kind)
metadata,ok := k8sObj[`metadata`].(map[string]interface{})
if (!ok) {
return errors.New("Found object with non convertable metadata")
}
name,ok := metadata[`name`].(string)
if (!ok) {
return errors.New("Found metadata with non string name")
}
namespace,ok := metadata[`namespace`].(string)
if (!ok) {
namespace = ""
}
if (objs[gvk] == nil) {
objs[gvk] = make(map[string]map[string]int)
}
if (objs[gvk][namespace] == nil) {
objs[gvk][namespace] = make(map[string]int)
}
objs[gvk][namespace][name]++
}
}
for gvk, namespaces := range objs {
for namespace, names := range namespaces {
for name, value := range names {
fmt.Fprintf(printer.writer, "# Failed object from %s control %s\n", frameworkName, controlName)
if namespace != "" {
fmt.Fprintf(printer.writer, "kubescape_object_failed_count{framework=\"%s\",control=\"%s\",namespace=\"%s\",name=\"%s\",groupVersionKind=\"%s\"} %d\n", frameworkName, controlName, namespace, name, gvk, value)
} else {
fmt.Fprintf(printer.writer, "kubescape_object_failed_count{framework=\"%s\",control=\"%s\",name=\"%s\",groupVersionKind=\"%s\"} %d\n", frameworkName, controlName, name, gvk, value)
}
}
}
}
return nil
}
func (printer *PrometheusPrinter) printReports(frameworks []reporthandling.FrameworkReport) error {
for _, framework := range frameworks {
for _, controlReports := range framework.ControlReports {
if len(controlReports.RuleReports[0].RuleResponses) > 0 {
fmt.Fprintf(printer.writer, "# Number of resources found as part of %s control %s\nkubescape_resources_found_count{framework=\"%s\",control=\"%s\"} %d\n", framework.Name, controlReports.Name, framework.Name, controlReports.Name, controlReports.GetNumberOfResources())
fmt.Fprintf(printer.writer, "# Number of resources excluded as part of %s control %s\nkubescape_resources_excluded_count{framework=\"%s\",control=\"%s\"} %d\n", framework.Name, controlReports.Name, framework.Name, controlReports.Name, controlReports.GetNumberOfWarningResources())
fmt.Fprintf(printer.writer, "# Number of resources failed as part of %s control %s\nkubescape_resources_failed_count{framework=\"%s\",control=\"%s\"} %d\n", framework.Name, controlReports.Name, framework.Name, controlReports.Name, controlReports.GetNumberOfFailedResources())
err := printer.printDetails(controlReports.RuleReports[0].RuleResponses, framework.Name, controlReports.Name)
if err != nil {
return err
}
}
}
}
return nil
}
func (printer *PrometheusPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
err := printer.printReports(opaSessionObj.PostureReport.FrameworkReports)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}