mirror of
https://github.com/kubescape/kubescape.git
synced 2026-04-15 06:58:11 +00:00
Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c5bb977cb | ||
|
|
cddf7dd8f6 | ||
|
|
306c18147e | ||
|
|
84815eb97d | ||
|
|
890c13a91f | ||
|
|
3887ec8091 | ||
|
|
726b06bb70 | ||
|
|
c8e07c283e | ||
|
|
88a5128c03 | ||
|
|
01f2d3b04f | ||
|
|
fef85a4467 | ||
|
|
e0eadc1f2d | ||
|
|
a881b73e8d | ||
|
|
606f5cfb62 | ||
|
|
40737d545b | ||
|
|
990be3afe8 | ||
|
|
7020c2d025 | ||
|
|
a6497c1252 | ||
|
|
9d528a8075 | ||
|
|
5aec8b6f28 | ||
|
|
830ee27169 | ||
|
|
5f2e5c6f4e | ||
|
|
cf4317b5f6 | ||
|
|
2453aea6f3 | ||
|
|
e95b0f840a | ||
|
|
83680d1207 | ||
|
|
f0afc20ec6 | ||
|
|
78835a58c4 | ||
|
|
fdccae9a1e | ||
|
|
6d97d42f67 | ||
|
|
46001e4761 | ||
|
|
b4d712fcb1 | ||
|
|
7847a4593b | ||
|
|
b2036e64f1 | ||
|
|
fd0bbcccfe | ||
|
|
3fff1b750a | ||
|
|
bd9ade4d15 | ||
|
|
d630811386 |
18
README.md
18
README.md
@@ -49,10 +49,11 @@ We invite you to our team! We are excited about this project and want to return
|
||||
Want to contribute? Want to discuss something? Have an issue?
|
||||
|
||||
* Open a issue, we are trying to respond within 48 hours
|
||||
* [Join us](https://armosec.github.io/kubescape/) in a discussion on our discord server!
|
||||
[](https://img.shields.io/discord/893048809884643379)
|
||||
* [Join us](https://armosec.github.io/kubescape/) in a discussion on our discord server!
|
||||
|
||||
|
||||
[<img src="docs/discord-banner.png" width="100" alt="logo" align="center">](https://armosec.github.io/kubescape/)
|
||||

|
||||
|
||||
|
||||
# Options and examples
|
||||
@@ -99,12 +100,12 @@ Set-ExecutionPolicy RemoteSigned -scope CurrentUser
|
||||
| `--include-namespaces` | Scan all namespaces | Scan specific namespaces | |
|
||||
| `-s`/`--silent` | Display progress messages | Silent progress messages | |
|
||||
| `-t`/`--fail-threshold` | `100` (do not fail) | fail command (return exit code 1) if result is above threshold | `0` -> `100` |
|
||||
| `-f`/`--format` | `pretty-printer` | Output format | `pretty-printer`/`json`/`junit`/`prometheus` |
|
||||
| `-f`/`--format` | `pretty-printer` | Output format | `pretty-printer`/`json`/`junit`/`prometheus`/`pdf` |
|
||||
| `-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-from` | | Load local framework object from specified path. If not used will download latest ||
|
||||
| `--use-artifacts-from` | | Load artifacts (frameworks, control-config, exceptions) from local directory. If not used will download them | |
|
||||
| `--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](examples/exceptions/README.md). Default will download exceptions from Kubescape SaaS |
|
||||
| `--exceptions` | | Path to an exceptions obj, [examples](examples/exceptions/README.md). Default will download exceptions from Kubescape SaaS ||
|
||||
| `--controls-config` | | Path to a controls-config obj. If not set will download controls-config 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` |
|
||||
@@ -176,7 +177,14 @@ kubescape scan --format json --output results.json
|
||||
kubescape scan --format junit --output results.xml
|
||||
```
|
||||
|
||||
#### Output in `pdf` format - Contributed by [@alegrey91](https://github.com/alegrey91)
|
||||
|
||||
```
|
||||
kubescape scan --format pdf --output results.pdf
|
||||
```
|
||||
|
||||
#### Output in `prometheus` metrics format - Contributed by [@Joibel](https://github.com/Joibel)
|
||||
|
||||
```
|
||||
kubescape scan --format prometheus
|
||||
```
|
||||
|
||||
24
build.py
24
build.py
@@ -49,10 +49,9 @@ def main():
|
||||
ArmoWebsite = os.getenv("ArmoWebsite")
|
||||
ArmoAuthServer = os.getenv("ArmoAuthServer")
|
||||
|
||||
|
||||
# Create build directory
|
||||
buildDir = getBuildDir()
|
||||
|
||||
|
||||
ks_file = os.path.join(buildDir, packageName)
|
||||
hash_file = ks_file + ".sha256"
|
||||
|
||||
@@ -60,13 +59,24 @@ def main():
|
||||
os.makedirs(buildDir)
|
||||
|
||||
# Build kubescape
|
||||
ldflags = "-w -s -X %s=%s -X %s=%s -X %s=%s -X %s=%s -X %s=%s" \
|
||||
% (buildUrl, releaseVersion, BE_SERVER_CONST, ArmoBEServer,
|
||||
ER_SERVER_CONST, ArmoERServer, WEBSITE_CONST, ArmoWebsite,
|
||||
AUTH_SERVER_CONST, ArmoAuthServer)
|
||||
ldflags = "-w -s"
|
||||
if releaseVersion:
|
||||
ldflags += " -X {}={}".format(buildUrl, releaseVersion)
|
||||
if ArmoBEServer:
|
||||
ldflags += " -X {}={}".format(BE_SERVER_CONST, ArmoBEServer)
|
||||
if ArmoERServer:
|
||||
ldflags += " -X {}={}".format(ER_SERVER_CONST, ArmoERServer)
|
||||
if ArmoWebsite:
|
||||
ldflags += " -X {}={}".format(WEBSITE_CONST, ArmoWebsite)
|
||||
if ArmoAuthServer:
|
||||
ldflags += " -X {}={}".format(AUTH_SERVER_CONST, ArmoAuthServer)
|
||||
|
||||
build_command = ["go", "build", "-o", ks_file, "-ldflags" ,ldflags]
|
||||
|
||||
print("Building kubescape and saving here: {}".format(ks_file))
|
||||
status = subprocess.call(["go", "build", "-o", ks_file, "-ldflags" ,ldflags])
|
||||
print("Build command: {}".format(" ".join(build_command)))
|
||||
|
||||
status = subprocess.call(build_command)
|
||||
checkStatus(status, "Failed to build kubescape")
|
||||
|
||||
sha256 = hashlib.sha256()
|
||||
|
||||
@@ -3,7 +3,7 @@ FROM golang:1.17-alpine as builder
|
||||
|
||||
ARG image_version
|
||||
|
||||
ENV RELEASE=image_version
|
||||
ENV RELEASE=$image_version
|
||||
|
||||
ENV GO111MODULE=
|
||||
|
||||
@@ -21,7 +21,6 @@ ADD . .
|
||||
RUN python build.py
|
||||
|
||||
RUN ls -ltr build/ubuntu-latest
|
||||
RUN cat /work/build/ubuntu-latest/kubescape.sha1
|
||||
|
||||
FROM alpine
|
||||
COPY --from=builder /work/build/ubuntu-latest/kubescape /usr/bin/kubescape
|
||||
|
||||
@@ -15,7 +15,7 @@ func NewPolicies() *Policies {
|
||||
|
||||
func (policies *Policies) Set(frameworks []reporthandling.Framework, version string) {
|
||||
for i := range frameworks {
|
||||
if frameworks[i].Name != "" {
|
||||
if frameworks[i].Name != "" && len(frameworks[i].Controls) > 0 {
|
||||
policies.Frameworks = append(policies.Frameworks, frameworks[i].Name)
|
||||
}
|
||||
for j := range frameworks[i].Controls {
|
||||
@@ -30,6 +30,7 @@ func (policies *Policies) Set(frameworks []reporthandling.Framework, version str
|
||||
policies.Controls[frameworks[i].Controls[j].ControlID] = frameworks[i].Controls[j]
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,11 @@ var (
|
||||
armoFEURL = "portal.armo.cloud"
|
||||
armoAUTHURL = "auth.armo.cloud"
|
||||
|
||||
armoStageERURL = "report-ks.eustage2.cyberarmorsoft.com"
|
||||
armoStageBEURL = "api-stage.armo.cloud"
|
||||
armoStageFEURL = "armoui.eustage2.cyberarmorsoft.com"
|
||||
armoStageAUTHURL = "eggauth.eustage2.cyberarmorsoft.com"
|
||||
|
||||
armoDevERURL = "report.eudev3.cyberarmorsoft.com"
|
||||
armoDevBEURL = "api-dev.armo.cloud"
|
||||
armoDevFEURL = "armoui-dev.eudev3.cyberarmorsoft.com"
|
||||
@@ -84,6 +89,17 @@ func NewARMOAPIProd() *ArmoAPI {
|
||||
return apiObj
|
||||
}
|
||||
|
||||
func NewARMOAPIStaging() *ArmoAPI {
|
||||
apiObj := newArmoAPI()
|
||||
|
||||
apiObj.apiURL = armoStageBEURL
|
||||
apiObj.erURL = armoStageERURL
|
||||
apiObj.feURL = armoStageFEURL
|
||||
apiObj.authURL = armoStageAUTHURL
|
||||
|
||||
return apiObj
|
||||
}
|
||||
|
||||
func NewARMOAPICustomized(armoERURL, armoBEURL, armoFEURL, armoAUTHURL string) *ArmoAPI {
|
||||
apiObj := newArmoAPI()
|
||||
|
||||
|
||||
@@ -13,11 +13,7 @@ import (
|
||||
)
|
||||
|
||||
func GetDefaultPath(name string) string {
|
||||
defaultfilePath := filepath.Join(DefaultLocalStore, name)
|
||||
if homeDir, err := os.UserHomeDir(); err == nil {
|
||||
defaultfilePath = filepath.Join(homeDir, defaultfilePath)
|
||||
}
|
||||
return defaultfilePath
|
||||
return filepath.Join(DefaultLocalStore, name)
|
||||
}
|
||||
|
||||
func SaveInFile(policy interface{}, pathStr string) error {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/armosec/armoapi-go/armotypes"
|
||||
@@ -13,7 +14,15 @@ import (
|
||||
// =======================================================================================================================
|
||||
// ============================================== LoadPolicy =============================================================
|
||||
// =======================================================================================================================
|
||||
const DefaultLocalStore = ".kubescape"
|
||||
var DefaultLocalStore = getCacheDir()
|
||||
|
||||
func getCacheDir() string {
|
||||
defaultDirPath := ".kubescape"
|
||||
if homeDir, err := os.UserHomeDir(); err == nil {
|
||||
defaultDirPath = filepath.Join(homeDir, defaultDirPath)
|
||||
}
|
||||
return defaultDirPath
|
||||
}
|
||||
|
||||
// Load policies from a local repository
|
||||
type LoadPolicy struct {
|
||||
|
||||
@@ -2,9 +2,12 @@ package logger
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/armosec/kubescape/cautils/logger/helpers"
|
||||
"github.com/armosec/kubescape/cautils/logger/prettylogger"
|
||||
"github.com/armosec/kubescape/cautils/logger/zaplogger"
|
||||
"github.com/mattn/go-isatty"
|
||||
)
|
||||
|
||||
type ILogger interface {
|
||||
@@ -26,16 +29,23 @@ var l ILogger
|
||||
|
||||
func L() ILogger {
|
||||
if l == nil {
|
||||
InitializeLogger()
|
||||
InitializeLogger("")
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
func InitializeLogger() {
|
||||
initializeLogger()
|
||||
}
|
||||
func InitializeLogger(loggerName string) {
|
||||
|
||||
func initializeLogger() {
|
||||
// TODO - support zap logger
|
||||
l = prettylogger.NewPrettyLogger()
|
||||
switch strings.ToLower(loggerName) {
|
||||
case "zap":
|
||||
l = zaplogger.NewZapLogger()
|
||||
case "pretty":
|
||||
l = prettylogger.NewPrettyLogger()
|
||||
default:
|
||||
if isatty.IsTerminal(os.Stdout.Fd()) {
|
||||
l = prettylogger.NewPrettyLogger()
|
||||
} else {
|
||||
l = zaplogger.NewZapLogger()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,20 +10,40 @@ import (
|
||||
|
||||
type ZapLogger struct {
|
||||
zapL *zap.Logger
|
||||
cfg zap.Config
|
||||
}
|
||||
|
||||
func NewZapLogger() *ZapLogger {
|
||||
ec := zap.NewProductionEncoderConfig()
|
||||
ec.EncodeTime = zapcore.RFC3339TimeEncoder
|
||||
cfg := zap.NewProductionConfig()
|
||||
cfg.DisableCaller = true
|
||||
cfg.DisableStacktrace = true
|
||||
cfg.Encoding = "json"
|
||||
cfg.EncoderConfig = ec
|
||||
|
||||
zapLogger, err := cfg.Build()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &ZapLogger{
|
||||
zapL: zap.L(),
|
||||
zapL: zapLogger,
|
||||
cfg: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
func (zl *ZapLogger) GetLevel() string { return "" }
|
||||
func (zl *ZapLogger) GetLevel() string { return zl.cfg.Level.Level().String() }
|
||||
func (zl *ZapLogger) SetWriter(w *os.File) {}
|
||||
func (zl *ZapLogger) GetWriter() *os.File { return nil }
|
||||
func GetWriter() *os.File { return nil }
|
||||
|
||||
func (zl *ZapLogger) SetLevel(level string) error {
|
||||
return nil
|
||||
l := zapcore.Level(1)
|
||||
err := l.Set(level)
|
||||
if err == nil {
|
||||
zl.cfg.Level.SetLevel(l)
|
||||
}
|
||||
return err
|
||||
}
|
||||
func (zl *ZapLogger) Fatal(msg string, details ...helpers.IDetails) {
|
||||
zl.zapL.Fatal(msg, detailsToZapFields(details)...)
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/armosec/opa-utils/reporthandling"
|
||||
"github.com/armosec/rbac-utils/rbacscanner"
|
||||
"github.com/armosec/rbac-utils/rbacutils"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type RBACObjects struct {
|
||||
@@ -21,7 +21,7 @@ func NewRBACObjects(scanner *rbacscanner.RbacScannerFromK8sAPI) *RBACObjects {
|
||||
|
||||
func (rbacObjects *RBACObjects) SetResourcesReport() (*reporthandling.PostureReport, error) {
|
||||
return &reporthandling.PostureReport{
|
||||
ReportID: uuid.NewV4().String(),
|
||||
ReportID: uuid.NewString(),
|
||||
ReportGenerationTime: time.Now().UTC(),
|
||||
CustomerGUID: rbacObjects.scanner.CustomerGUID,
|
||||
ClusterName: rbacObjects.scanner.ClusterName,
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"github.com/armosec/opa-utils/reporthandling"
|
||||
helpersv1 "github.com/armosec/opa-utils/reporthandling/helpers/v1"
|
||||
"github.com/armosec/opa-utils/reporthandling/results/v1/reportsummary"
|
||||
"github.com/armosec/opa-utils/score"
|
||||
)
|
||||
|
||||
func ReportV2ToV1(opaSessionObj *OPASessionObj) {
|
||||
@@ -22,7 +21,6 @@ func ReportV2ToV1(opaSessionObj *OPASessionObj) {
|
||||
fwv1 := reporthandling.FrameworkReport{}
|
||||
fwv1.Name = fwv2.GetName()
|
||||
fwv1.Score = fwv2.GetScore()
|
||||
|
||||
fwv1.ControlReports = append(fwv1.ControlReports, controlReportV2ToV1(opaSessionObj, fwv2.GetName(), fwv2.Controls)...)
|
||||
frameworks = append(frameworks, fwv1)
|
||||
|
||||
@@ -30,10 +28,10 @@ func ReportV2ToV1(opaSessionObj *OPASessionObj) {
|
||||
} else {
|
||||
fwv1 := reporthandling.FrameworkReport{}
|
||||
fwv1.Name = ""
|
||||
fwv1.Score = 0
|
||||
|
||||
fwv1.ControlReports = append(fwv1.ControlReports, controlReportV2ToV1(opaSessionObj, "", opaSessionObj.Report.SummaryDetails.Controls)...)
|
||||
frameworks = append(frameworks, fwv1)
|
||||
fwv1.Score = opaSessionObj.Report.SummaryDetails.Score
|
||||
}
|
||||
|
||||
// // remove unused data
|
||||
@@ -49,36 +47,14 @@ func ReportV2ToV1(opaSessionObj *OPASessionObj) {
|
||||
reporthandling.SetUniqueResourcesCounter(&frameworks[f])
|
||||
|
||||
// set default score
|
||||
reporthandling.SetDefaultScore(&frameworks[f])
|
||||
// reporthandling.SetDefaultScore(&frameworks[f])
|
||||
}
|
||||
|
||||
// update score
|
||||
scoreutil := score.NewScore(opaSessionObj.AllResources)
|
||||
scoreutil.Calculate(frameworks)
|
||||
// // update score
|
||||
// scoreutil := score.NewScore(opaSessionObj.AllResources)
|
||||
// scoreutil.Calculate(frameworks)
|
||||
|
||||
opaSessionObj.PostureReport.FrameworkReports = frameworks
|
||||
|
||||
// opaSessionObj.Report.SummaryDetails.Score = 0
|
||||
// for i := range frameworks {
|
||||
// for j := range frameworks[i].ControlReports {
|
||||
// // frameworks[i].ControlReports[j].Score
|
||||
// for w := range opaSessionObj.Report.SummaryDetails.Frameworks {
|
||||
// if opaSessionObj.Report.SummaryDetails.Frameworks[w].Name == frameworks[i].Name {
|
||||
// opaSessionObj.Report.SummaryDetails.Frameworks[w].Score = frameworks[i].Score
|
||||
// }
|
||||
// if c, ok := opaSessionObj.Report.SummaryDetails.Frameworks[w].Controls[frameworks[i].ControlReports[j].ControlID]; ok {
|
||||
// c.Score = frameworks[i].ControlReports[j].Score
|
||||
// opaSessionObj.Report.SummaryDetails.Frameworks[w].Controls[frameworks[i].ControlReports[j].ControlID] = c
|
||||
// }
|
||||
// }
|
||||
// if c, ok := opaSessionObj.Report.SummaryDetails.Controls[frameworks[i].ControlReports[j].ControlID]; ok {
|
||||
// c.Score = frameworks[i].ControlReports[j].Score
|
||||
// opaSessionObj.Report.SummaryDetails.Controls[frameworks[i].ControlReports[j].ControlID] = c
|
||||
// }
|
||||
// }
|
||||
// opaSessionObj.Report.SummaryDetails.Score += opaSessionObj.PostureReport.FrameworkReports[i].Score
|
||||
// }
|
||||
// opaSessionObj.Report.SummaryDetails.Score /= float32(len(opaSessionObj.Report.SummaryDetails.Frameworks))
|
||||
}
|
||||
|
||||
func controlReportV2ToV1(opaSessionObj *OPASessionObj, frameworkName string, controls map[string]reportsummary.ControlSummary) []reporthandling.ControlReport {
|
||||
@@ -88,9 +64,9 @@ func controlReportV2ToV1(opaSessionObj *OPASessionObj, frameworkName string, con
|
||||
crv1.ControlID = controlID
|
||||
crv1.BaseScore = crv2.ScoreFactor
|
||||
crv1.Name = crv2.GetName()
|
||||
crv1.Score = crv2.GetScore()
|
||||
crv1.Control_ID = controlID
|
||||
// crv1.Attributes = crv2.
|
||||
crv1.Score = crv2.GetScore()
|
||||
|
||||
// TODO - add fields
|
||||
crv1.Description = crv2.Description
|
||||
|
||||
@@ -4,12 +4,13 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/armosec/kubescape/cautils/getter"
|
||||
"github.com/armosec/kubescape/cautils/logger"
|
||||
"github.com/armosec/kubescape/cautils/logger/helpers"
|
||||
"github.com/armosec/opa-utils/reporthandling"
|
||||
)
|
||||
|
||||
@@ -73,6 +74,7 @@ type ScanInfo struct {
|
||||
Local bool // Do not submit results
|
||||
Account string // account ID
|
||||
Logger string // logger level
|
||||
CacheDir string // cached dir
|
||||
KubeContext string // context name
|
||||
FrameworkScan bool // false if scanning control
|
||||
ScanAll bool // true if scan all frameworks
|
||||
@@ -104,7 +106,7 @@ func (scanInfo *ScanInfo) setUseArtifactsFrom() {
|
||||
// set frameworks files
|
||||
files, err := ioutil.ReadDir(scanInfo.UseArtifactsFrom)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
logger.L().Fatal("failed to read files from directory", helpers.String("dir", scanInfo.UseArtifactsFrom), helpers.Error(err))
|
||||
}
|
||||
framework := &reporthandling.Framework{}
|
||||
for _, f := range files {
|
||||
@@ -153,6 +155,11 @@ func (scanInfo *ScanInfo) setOutputFile() {
|
||||
scanInfo.Output += ".xml"
|
||||
}
|
||||
}
|
||||
if scanInfo.Format == "pdf" {
|
||||
if filepath.Ext(scanInfo.Output) != ".pdf" {
|
||||
scanInfo.Output += ".pdf"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (scanInfo *ScanInfo) GetScanningEnvironment() string {
|
||||
|
||||
@@ -132,11 +132,12 @@ func downloadFramework(downloadInfo *cautils.DownloadInfo) error {
|
||||
return err
|
||||
}
|
||||
for _, fw := range frameworks {
|
||||
err = getter.SaveInFile(fw, filepath.Join(downloadInfo.Path, (strings.ToLower(fw.Name)+".json")))
|
||||
downloadTo := filepath.Join(downloadInfo.Path, (strings.ToLower(fw.Name) + ".json"))
|
||||
err = getter.SaveInFile(fw, downloadTo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger.L().Success("Downloaded", helpers.String("artifact", downloadInfo.Target), helpers.String("name", fw.Name), helpers.String("path", filepath.Join(downloadInfo.Path, downloadInfo.FileName)))
|
||||
logger.L().Success("Downloaded", helpers.String("artifact", downloadInfo.Target), helpers.String("name", fw.Name), helpers.String("path", downloadTo))
|
||||
}
|
||||
// return fmt.Errorf("missing framework name")
|
||||
} else {
|
||||
@@ -147,11 +148,12 @@ func downloadFramework(downloadInfo *cautils.DownloadInfo) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = getter.SaveInFile(framework, filepath.Join(downloadInfo.Path, downloadInfo.FileName))
|
||||
downloadTo := filepath.Join(downloadInfo.Path, downloadInfo.FileName)
|
||||
err = getter.SaveInFile(framework, downloadTo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger.L().Success("Downloaded", helpers.String("artifact", downloadInfo.Target), helpers.String("name", framework.Name), helpers.String("path", filepath.Join(downloadInfo.Path, downloadInfo.FileName)))
|
||||
logger.L().Success("Downloaded", helpers.String("artifact", downloadInfo.Target), helpers.String("name", framework.Name), helpers.String("path", downloadTo))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -173,10 +175,11 @@ func downloadControl(downloadInfo *cautils.DownloadInfo) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = getter.SaveInFile(controls, filepath.Join(downloadInfo.Path, downloadInfo.FileName))
|
||||
downloadTo := filepath.Join(downloadInfo.Path, downloadInfo.FileName)
|
||||
err = getter.SaveInFile(controls, downloadTo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger.L().Success("Downloaded", helpers.String("artifact", downloadInfo.Target), helpers.String("name", downloadInfo.Name), helpers.String("path", filepath.Join(downloadInfo.Path, downloadInfo.FileName)))
|
||||
logger.L().Success("Downloaded", helpers.String("artifact", downloadInfo.Target), helpers.String("name", downloadInfo.Name), helpers.String("path", downloadTo))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package clihandler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
@@ -14,6 +15,11 @@ var listFunc = map[string]func(*cliobjects.ListPolicies) ([]string, error){
|
||||
"frameworks": listFrameworks,
|
||||
}
|
||||
|
||||
var listFormatFunc = map[string]func(*cliobjects.ListPolicies, []string){
|
||||
"pretty-print": prettyPrintListFormat,
|
||||
"json": jsonListFormat,
|
||||
}
|
||||
|
||||
func ListSupportCommands() []string {
|
||||
commands := []string{}
|
||||
for k := range listFunc {
|
||||
@@ -29,12 +35,8 @@ func CliList(listPolicies *cliobjects.ListPolicies) error {
|
||||
}
|
||||
sort.Strings(policies)
|
||||
|
||||
sep := "\n * "
|
||||
usageCmd := strings.TrimSuffix(listPolicies.Target, "s")
|
||||
fmt.Printf("Supported %s:%s%s\n", listPolicies.Target, sep, strings.Join(policies, sep))
|
||||
fmt.Printf("\nUseage:\n")
|
||||
fmt.Printf("$ kubescape scan %s \"name\"\n", usageCmd)
|
||||
fmt.Printf("$ kubescape scan %s \"name-0\",\"name-1\"\n\n", usageCmd)
|
||||
listFormatFunc[listPolicies.Format](listPolicies, policies)
|
||||
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown command to download")
|
||||
@@ -57,3 +59,17 @@ func listControls(listPolicies *cliobjects.ListPolicies) ([]string, error) {
|
||||
}
|
||||
return g.ListControls(l)
|
||||
}
|
||||
|
||||
func prettyPrintListFormat(listPolicies *cliobjects.ListPolicies, policies []string) {
|
||||
sep := "\n * "
|
||||
usageCmd := strings.TrimSuffix(listPolicies.Target, "s")
|
||||
fmt.Printf("Supported %s:%s%s\n", listPolicies.Target, sep, strings.Join(policies, sep))
|
||||
fmt.Printf("\nUsage:\n")
|
||||
fmt.Printf("$ kubescape scan %s \"name\"\n", usageCmd)
|
||||
fmt.Printf("$ kubescape scan %s \"name-0\",\"name-1\"\n\n", usageCmd)
|
||||
}
|
||||
|
||||
func jsonListFormat(listPolicies *cliobjects.ListPolicies, policies []string) {
|
||||
j, _ := json.MarshalIndent(policies, "", " ")
|
||||
fmt.Printf("%s\n", j)
|
||||
}
|
||||
|
||||
@@ -4,4 +4,5 @@ type ListPolicies struct {
|
||||
Target string
|
||||
ListIDs bool
|
||||
Account string
|
||||
Format string
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/armosec/kubescape/cautils/logger"
|
||||
"github.com/armosec/kubescape/clihandler"
|
||||
"github.com/armosec/kubescape/clihandler/cliobjects"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -53,8 +53,7 @@ var configSetCmd = &cobra.Command{
|
||||
return err
|
||||
}
|
||||
if err := clihandler.CliSetConfig(&setConfig); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
||||
os.Exit(1)
|
||||
logger.L().Fatal(err.Error())
|
||||
}
|
||||
return nil
|
||||
},
|
||||
@@ -100,8 +99,7 @@ var configDeleteCmd = &cobra.Command{
|
||||
Long: ``,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if err := clihandler.CliDelete(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
||||
os.Exit(1)
|
||||
logger.L().Fatal(err.Error())
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -113,8 +111,7 @@ var configViewCmd = &cobra.Command{
|
||||
Long: ``,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if err := clihandler.CliView(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
||||
os.Exit(1)
|
||||
logger.L().Fatal(err.Error())
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/armosec/kubescape/cautils"
|
||||
"github.com/armosec/kubescape/cautils/logger"
|
||||
"github.com/armosec/kubescape/clihandler"
|
||||
"github.com/armosec/kubescape/clihandler/cliobjects"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -51,8 +51,7 @@ var listCmd = &cobra.Command{
|
||||
listPolicies.Target = args[0]
|
||||
|
||||
if err := clihandler.CliList(&listPolicies); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
||||
os.Exit(1)
|
||||
logger.L().Fatal(err.Error())
|
||||
}
|
||||
return nil
|
||||
},
|
||||
@@ -62,6 +61,7 @@ func init() {
|
||||
// cobra.OnInitialize(initConfig)
|
||||
|
||||
rootCmd.AddCommand(listCmd)
|
||||
listCmd.PersistentFlags().StringVarP(&listPolicies.Account, "account", "", "", "Armo portal account ID. Default will load account ID from configMap or config file")
|
||||
listCmd.PersistentFlags().StringVar(&listPolicies.Account, "account", "", "Armo portal account ID. Default will load account ID from configMap or config file")
|
||||
listCmd.PersistentFlags().StringVar(&listPolicies.Format, "format", "pretty-print", "output format. supported: 'pretty-printer'/'json'")
|
||||
listCmd.PersistentFlags().BoolVarP(&listPolicies.ListIDs, "id", "", false, "List control ID's instead of controls names")
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
"github.com/armosec/kubescape/clihandler/cliinterfaces"
|
||||
reporterv1 "github.com/armosec/kubescape/resultshandling/reporter/v1"
|
||||
"github.com/armosec/opa-utils/reporthandling"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
"github.com/google/uuid"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -37,10 +37,9 @@ func (resultsObject *ResultsObject) SetResourcesReport() (*reporthandling.Postur
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &reporthandling.PostureReport{
|
||||
FrameworkReports: frameworkReports,
|
||||
ReportID: uuid.NewV4().String(),
|
||||
ReportID: uuid.NewString(),
|
||||
ReportGenerationTime: time.Now().UTC(),
|
||||
CustomerGUID: resultsObject.customerGUID,
|
||||
ClusterName: resultsObject.clusterName,
|
||||
|
||||
@@ -3,8 +3,10 @@ package cmd
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/armosec/kubescape/cautils"
|
||||
"github.com/armosec/kubescape/cautils/getter"
|
||||
"github.com/armosec/kubescape/cautils/logger"
|
||||
"github.com/armosec/kubescape/cautils/logger/helpers"
|
||||
@@ -31,6 +33,7 @@ var ksExamples = `
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "kubescape",
|
||||
Version: cautils.BuildNumber,
|
||||
Short: "Kubescape is a tool for testing Kubernetes security posture",
|
||||
Long: `Kubescape is a tool for testing Kubernetes security posture based on NSA \ MITRE ATT&CK® and other frameworks specifications`,
|
||||
Example: ksExamples,
|
||||
@@ -40,20 +43,42 @@ func Execute() {
|
||||
rootCmd.Execute()
|
||||
}
|
||||
func init() {
|
||||
cobra.OnInitialize(initLogger, initEnvironment)
|
||||
cobra.OnInitialize(initLogger, initLoggerLevel, initEnvironment, initCacheDir)
|
||||
|
||||
flag.CommandLine.StringVar(&armoBEURLs, "environment", "", envFlagUsage)
|
||||
rootCmd.PersistentFlags().StringVar(&armoBEURLs, "environment", "", envFlagUsage)
|
||||
rootCmd.PersistentFlags().MarkHidden("environment")
|
||||
rootCmd.PersistentFlags().StringVar(&scanInfo.Logger, "logger", "info", fmt.Sprintf("Logger level. Supported: %s", strings.Join(helpers.SupportedLevels(), "/")))
|
||||
rootCmd.PersistentFlags().StringVarP(&scanInfo.Logger, "logger", "l", helpers.InfoLevel.String(), fmt.Sprintf("Logger level. Supported: %s [$KS_LOGGER]", strings.Join(helpers.SupportedLevels(), "/")))
|
||||
rootCmd.PersistentFlags().StringVar(&scanInfo.CacheDir, "cache-dir", getter.DefaultLocalStore, "Cache directory [$KS_CACHE_DIR]")
|
||||
flag.Parse()
|
||||
}
|
||||
|
||||
func initLogger() {
|
||||
if l := os.Getenv("KS_LOGGER_NAME"); l != "" {
|
||||
logger.InitializeLogger(l)
|
||||
}
|
||||
}
|
||||
func initLoggerLevel() {
|
||||
if scanInfo.Logger != helpers.InfoLevel.String() {
|
||||
} else if l := os.Getenv("KS_LOGGER"); l != "" {
|
||||
scanInfo.Logger = l
|
||||
}
|
||||
if err := logger.L().SetLevel(scanInfo.Logger); err != nil {
|
||||
logger.L().Fatal(fmt.Sprintf("supported levels: %s", strings.Join(helpers.SupportedLevels(), "/")), helpers.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
func initCacheDir() {
|
||||
if scanInfo.CacheDir != getter.DefaultLocalStore {
|
||||
getter.DefaultLocalStore = scanInfo.CacheDir
|
||||
} else if cacheDir := os.Getenv("KS_CACHE_DIR"); cacheDir != "" {
|
||||
getter.DefaultLocalStore = cacheDir
|
||||
} else {
|
||||
return // using default cache di location
|
||||
}
|
||||
|
||||
logger.L().Debug("cache dir updated", helpers.String("path", getter.DefaultLocalStore))
|
||||
}
|
||||
func initEnvironment() {
|
||||
urlSlices := strings.Split(armoBEURLs, ",")
|
||||
if len(urlSlices) != 1 && len(urlSlices) < 3 {
|
||||
@@ -62,8 +87,10 @@ func initEnvironment() {
|
||||
switch len(urlSlices) {
|
||||
case 1:
|
||||
switch urlSlices[0] {
|
||||
case "dev":
|
||||
case "dev", "development":
|
||||
getter.SetARMOAPIConnector(getter.NewARMOAPIDev())
|
||||
case "stage", "staging":
|
||||
getter.SetARMOAPIConnector(getter.NewARMOAPIStaging())
|
||||
case "":
|
||||
getter.SetARMOAPIConnector(getter.NewARMOAPIProd())
|
||||
default:
|
||||
|
||||
@@ -48,7 +48,7 @@ func init() {
|
||||
scanCmd.PersistentFlags().StringVar(&scanInfo.UseArtifactsFrom, "use-artifacts-from", "", "Load artifacts from local directory. If not used will download them")
|
||||
scanCmd.PersistentFlags().StringVarP(&scanInfo.ExcludedNamespaces, "exclude-namespaces", "e", "", "Namespaces to exclude from scanning. Recommended: kube-system,kube-public")
|
||||
scanCmd.PersistentFlags().Uint16VarP(&scanInfo.FailThreshold, "fail-threshold", "t", 100, "Failure threshold is the percent above which the command fails and returns exit code 1")
|
||||
scanCmd.PersistentFlags().StringVarP(&scanInfo.Format, "format", "f", "pretty-printer", `Output format. Supported formats: "pretty-printer"/"json"/"junit"/"prometheus"`)
|
||||
scanCmd.PersistentFlags().StringVarP(&scanInfo.Format, "format", "f", "pretty-printer", `Output format. Supported formats: "pretty-printer","json","junit","prometheus","pdf"`)
|
||||
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")
|
||||
|
||||
@@ -8,9 +8,6 @@ import (
|
||||
"github.com/armosec/armoapi-go/armotypes"
|
||||
"github.com/armosec/k8s-interface/k8sinterface"
|
||||
"github.com/armosec/kubescape/resultshandling/printer"
|
||||
printerv1 "github.com/armosec/kubescape/resultshandling/printer/v1"
|
||||
|
||||
// printerv2 "github.com/armosec/kubescape/resultshandling/printer/v2"
|
||||
|
||||
"github.com/armosec/kubescape/cautils"
|
||||
"github.com/armosec/kubescape/cautils/getter"
|
||||
@@ -86,8 +83,7 @@ func getInterfaces(scanInfo *cautils.ScanInfo) componentInterfaces {
|
||||
reportHandler := getReporter(tenantConfig, scanInfo.Submit)
|
||||
|
||||
// setup printer
|
||||
printerHandler := printerv1.GetPrinter(scanInfo.Format, scanInfo.VerboseMode)
|
||||
// printerHandler = printerv2.GetPrinter(scanInfo.Format, scanInfo.VerboseMode)
|
||||
printerHandler := resultshandling.NewPrinter(scanInfo.Format, scanInfo.VerboseMode)
|
||||
printerHandler.SetWriter(scanInfo.Output)
|
||||
|
||||
// ================== return interface ======================================
|
||||
|
||||
13
go.mod
13
go.mod
@@ -3,7 +3,7 @@ module github.com/armosec/kubescape
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/armosec/armoapi-go v0.0.49
|
||||
github.com/armosec/armoapi-go v0.0.54
|
||||
github.com/armosec/k8s-interface v0.0.60
|
||||
github.com/armosec/opa-utils v0.0.110
|
||||
github.com/armosec/rbac-utils v0.0.14
|
||||
@@ -13,11 +13,11 @@ require (
|
||||
github.com/enescakir/emoji v1.0.0
|
||||
github.com/fatih/color v1.13.0
|
||||
github.com/francoispqt/gojay v1.2.13
|
||||
github.com/gofrs/uuid v4.1.0+incompatible
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/johnfercher/maroto v0.34.0
|
||||
github.com/mattn/go-isatty v0.0.14
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/open-policy-agent/opa v0.33.1
|
||||
github.com/satori/go.uuid v1.2.0
|
||||
github.com/spf13/cobra v1.2.1
|
||||
github.com/stretchr/testify v1.7.0
|
||||
go.uber.org/zap v1.19.1
|
||||
@@ -50,6 +50,7 @@ require (
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.8.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.13.0 // indirect
|
||||
github.com/aws/smithy-go v1.9.1 // indirect
|
||||
github.com/boombuler/barcode v1.0.0 // indirect
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/docker/docker v20.10.9+incompatible // indirect
|
||||
@@ -60,6 +61,7 @@ require (
|
||||
github.com/go-gota/gota v0.12.0 // indirect
|
||||
github.com/go-logr/logr v0.4.0 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/gofrs/uuid v4.1.0+incompatible // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/glog v1.0.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
@@ -72,6 +74,7 @@ require (
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/json-iterator/go v1.1.11 // indirect
|
||||
github.com/jung-kurt/gofpdf v1.4.2 // indirect
|
||||
github.com/mattn/go-colorable v0.1.9 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
@@ -82,6 +85,8 @@ require (
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/pquerna/cachecontrol v0.1.0 // indirect
|
||||
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect
|
||||
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58 // indirect
|
||||
github.com/satori/go.uuid v1.2.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
@@ -94,7 +99,7 @@ require (
|
||||
golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1 // indirect
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect
|
||||
golang.org/x/text v0.3.6 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
|
||||
gonum.org/v1/gonum v0.9.1 // indirect
|
||||
google.golang.org/api v0.44.0 // indirect
|
||||
|
||||
10
go.sum
10
go.sum
@@ -141,6 +141,7 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB
|
||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
||||
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/boombuler/barcode v1.0.0 h1:s1TvRnXwL2xJRaccrdcBQMZxq6X7DvsMogtmJeHDdrc=
|
||||
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
||||
github.com/briandowns/spinner v1.18.0 h1:SJs0maNOs4FqhBwiJ3Gr7Z1D39/rukIVGQvpNZVHVcM=
|
||||
@@ -362,6 +363,7 @@ github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLe
|
||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go v2.0.0+incompatible h1:j0GKcs05QVmm7yesiZq2+9cxHkNK9YM6zKx4D2qucQU=
|
||||
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
|
||||
@@ -416,6 +418,8 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/johnfercher/maroto v0.34.0 h1:kmqlO280WbjzeaPn8HtqUE3gooauVwqO/3cmrBtCL4A=
|
||||
github.com/johnfercher/maroto v0.34.0/go.mod h1:UeLY7evCe2Au8KwHFzaSGffKGADEZK+u6O8C74mdudM=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
@@ -431,6 +435,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
|
||||
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
|
||||
github.com/jung-kurt/gofpdf v1.4.2 h1:3u2ojTwxPPu3ysIOc5iTwcECpvkFCAe2RJ/tQrvfLi0=
|
||||
github.com/jung-kurt/gofpdf v1.4.2/go.mod h1:rZsO0wEsunjT/L9stF3fJjYbAHgqNYuQB4B8FWvBck0=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
@@ -573,6 +579,7 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58 h1:nlG4Wa5+minh3S9LVFtNoY+GVRiudA2e3EVfcCi3RCA=
|
||||
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||
@@ -636,6 +643,8 @@ github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH
|
||||
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
@@ -742,6 +751,7 @@ golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190507092727-e4e5bf290fec/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
|
||||
@@ -40,6 +40,7 @@ spec:
|
||||
- name: http
|
||||
hostPort: 7888
|
||||
containerPort: 7888
|
||||
protocol: TCP
|
||||
resources:
|
||||
limits:
|
||||
cpu: 0.1m
|
||||
|
||||
@@ -42,7 +42,7 @@ func (eksProviderEnvVar *EKSProviderEnvVar) getRegionForEKS(cluster string) (str
|
||||
}
|
||||
splittedClusterContext := strings.Split(cluster, ".")
|
||||
if len(splittedClusterContext) < 2 {
|
||||
return "", fmt.Errorf("error: failed to get region")
|
||||
return "", fmt.Errorf("failed to get region")
|
||||
}
|
||||
region = splittedClusterContext[1]
|
||||
return region, nil
|
||||
@@ -90,7 +90,7 @@ func (eksProviderContext *EKSProviderContext) getKubeCluster() string {
|
||||
func (eksProviderContext *EKSProviderContext) getRegion(cluster string, provider string) (string, error) {
|
||||
splittedClusterContext := strings.Split(cluster, ".")
|
||||
if len(splittedClusterContext) < 2 {
|
||||
return "", fmt.Errorf("error: failed to get region")
|
||||
return "", fmt.Errorf("failed to get region")
|
||||
}
|
||||
region := splittedClusterContext[1]
|
||||
return region, nil
|
||||
|
||||
@@ -15,6 +15,7 @@ const (
|
||||
JsonFormat string = "json"
|
||||
JunitResultFormat string = "junit"
|
||||
PrometheusFormat string = "prometheus"
|
||||
PdfFormat string = "pdf"
|
||||
)
|
||||
|
||||
type IPrinter interface {
|
||||
|
||||
@@ -31,6 +31,7 @@ func NewPrettyPrinter(verboseMode bool) *PrettyPrinter {
|
||||
}
|
||||
|
||||
func (prettyPrinter *PrettyPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
|
||||
overallRiskScore := opaSessionObj.Report.SummaryDetails.Score
|
||||
cautils.ReportV2ToV1(opaSessionObj)
|
||||
|
||||
// score := calculatePostureScore(opaSessionObj.PostureReport)
|
||||
@@ -40,7 +41,6 @@ func (prettyPrinter *PrettyPrinter) ActionPrint(opaSessionObj *cautils.OPASessio
|
||||
frameworkNames := []string{}
|
||||
frameworkScores := []float32{}
|
||||
|
||||
var overallRiskScore float32 = 0
|
||||
for _, frameworkReport := range opaSessionObj.PostureReport.FrameworkReports {
|
||||
frameworkNames = append(frameworkNames, frameworkReport.Name)
|
||||
frameworkScores = append(frameworkScores, frameworkReport.Score)
|
||||
@@ -48,11 +48,8 @@ func (prettyPrinter *PrettyPrinter) ActionPrint(opaSessionObj *cautils.OPASessio
|
||||
warningResources = reporthandling.GetUniqueResourcesIDs(append(warningResources, frameworkReport.ListResourcesIDs().GetWarningResources()...))
|
||||
allResources = reporthandling.GetUniqueResourcesIDs(append(allResources, frameworkReport.ListResourcesIDs().GetAllResources()...))
|
||||
prettyPrinter.summarySetup(frameworkReport, opaSessionObj.AllResources)
|
||||
overallRiskScore += frameworkReport.Score
|
||||
}
|
||||
|
||||
overallRiskScore /= float32(len(opaSessionObj.PostureReport.FrameworkReports))
|
||||
|
||||
prettyPrinter.frameworkSummary = ResultSummary{
|
||||
RiskScore: overallRiskScore,
|
||||
TotalResources: len(allResources),
|
||||
|
||||
@@ -1,21 +1,3 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/armosec/kubescape/resultshandling/printer"
|
||||
"github.com/armosec/kubescape/resultshandling/printer/v2/controlmapping"
|
||||
)
|
||||
|
||||
var INDENT = " "
|
||||
|
||||
func GetPrinter(printFormat string, verboseMode bool) printer.IPrinter {
|
||||
switch printFormat {
|
||||
case printer.JsonFormat:
|
||||
return NewJsonPrinter()
|
||||
case printer.JunitResultFormat:
|
||||
return NewJunitPrinter()
|
||||
case printer.PrometheusFormat:
|
||||
return NewPrometheusPrinter(verboseMode)
|
||||
default:
|
||||
return controlmapping.NewPrettyPrinter(verboseMode)
|
||||
}
|
||||
}
|
||||
|
||||
246
resultshandling/printer/v2/pdf.go
Normal file
246
resultshandling/printer/v2/pdf.go
Normal file
@@ -0,0 +1,246 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
b64 "encoding/base64"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/armosec/kubescape/cautils"
|
||||
"github.com/armosec/kubescape/resultshandling/printer"
|
||||
"github.com/armosec/opa-utils/reporthandling/results/v1/reportsummary"
|
||||
"github.com/johnfercher/maroto/pkg/color"
|
||||
"github.com/johnfercher/maroto/pkg/consts"
|
||||
"github.com/johnfercher/maroto/pkg/pdf"
|
||||
"github.com/johnfercher/maroto/pkg/props"
|
||||
)
|
||||
|
||||
const (
|
||||
pdfOutputFile = "report"
|
||||
pdfOutputExt = ".pdf"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed pdf/logo.png
|
||||
kubescapeLogo []byte
|
||||
)
|
||||
|
||||
type PdfPrinter struct {
|
||||
writer *os.File
|
||||
sortedControlNames []string
|
||||
}
|
||||
|
||||
func NewPdfPrinter() *PdfPrinter {
|
||||
return &PdfPrinter{}
|
||||
}
|
||||
|
||||
func (pdfPrinter *PdfPrinter) SetWriter(outputFile string) {
|
||||
// Ensure to have an available output file, otherwise create it.
|
||||
if outputFile == "" {
|
||||
outputFile = pdfOutputFile
|
||||
}
|
||||
// Ensure to have the right file extension.
|
||||
if filepath.Ext(strings.TrimSpace(outputFile)) != pdfOutputExt {
|
||||
outputFile = outputFile + pdfOutputExt
|
||||
}
|
||||
pdfPrinter.writer = printer.GetWriter(outputFile)
|
||||
}
|
||||
|
||||
func (pdfPrinter *PdfPrinter) Score(score float32) {
|
||||
fmt.Fprintf(os.Stderr, "\nOverall risk-score (0- Excellent, 100- All failed): %d\n", int(score))
|
||||
}
|
||||
|
||||
func (pdfPrinter *PdfPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
|
||||
pdfPrinter.sortedControlNames = getSortedControlsNames(opaSessionObj.Report.SummaryDetails.Controls)
|
||||
|
||||
m := pdf.NewMaroto(consts.Portrait, consts.A4)
|
||||
pdfPrinter.printHeader(m)
|
||||
pdfPrinter.printFramework(m, opaSessionObj.Report.SummaryDetails.ListFrameworks().All())
|
||||
pdfPrinter.printTable(m, &opaSessionObj.Report.SummaryDetails)
|
||||
pdfPrinter.printFinalResult(m, &opaSessionObj.Report.SummaryDetails)
|
||||
|
||||
// Extrat output buffer.
|
||||
outBuff, err := m.Output()
|
||||
if err != nil {
|
||||
fmt.Println("Could not save PDF:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
pdfPrinter.writer.Write(outBuff.Bytes())
|
||||
}
|
||||
|
||||
// Print Kubescape logo and report date.
|
||||
func (pdfPrinter *PdfPrinter) printHeader(m pdf.Maroto) {
|
||||
// Retrieve current time (we need it for the report timestamp).
|
||||
t := time.Now()
|
||||
// Enconde PNG into Base64 to embed it into the pdf.
|
||||
kubescapeLogoEnc := b64.StdEncoding.EncodeToString(kubescapeLogo)
|
||||
|
||||
m.SetPageMargins(10, 15, 10)
|
||||
m.Row(40, func() {
|
||||
//m.Text(fmt.Sprintf("Security Assessment"), props.Text{
|
||||
// Align: consts.Center,
|
||||
// Size: 24,
|
||||
// Family: consts.Arial,
|
||||
// Style: consts.Bold,
|
||||
//})
|
||||
_ = m.Base64Image(kubescapeLogoEnc, consts.Png, props.Rect{
|
||||
Center: true,
|
||||
Percent: 100,
|
||||
})
|
||||
})
|
||||
m.Row(6, func() {
|
||||
m.Text(fmt.Sprintf("Report date: %d-%02d-%02dT%02d:%02d:%02d",
|
||||
t.Year(),
|
||||
t.Month(),
|
||||
t.Day(),
|
||||
t.Hour(),
|
||||
t.Minute(),
|
||||
t.Second()), props.Text{
|
||||
Align: consts.Left,
|
||||
Size: 6.0,
|
||||
Style: consts.Bold,
|
||||
Family: consts.Arial,
|
||||
})
|
||||
})
|
||||
m.Line(1)
|
||||
}
|
||||
|
||||
// Print pdf frameworks after pdf header.
|
||||
func (pdfPrinter *PdfPrinter) printFramework(m pdf.Maroto, frameworks []reportsummary.IPolicies) {
|
||||
var p string
|
||||
if len(frameworks) == 1 {
|
||||
if frameworks[0].GetName() != "" {
|
||||
p = fmt.Sprintf("FRAMEWORK %s\n", frameworks[0].GetName())
|
||||
}
|
||||
} else if len(frameworks) > 1 {
|
||||
p = "FRAMEWORKS: "
|
||||
i := 0
|
||||
for ; i < len(frameworks)-1; i++ {
|
||||
p += fmt.Sprintf("%s (risk: %.2f), ", frameworks[i].GetName(), frameworks[i].GetScore())
|
||||
}
|
||||
p += fmt.Sprintf("%s (risk: %.2f)\n", frameworks[i].GetName(), frameworks[i].GetScore())
|
||||
}
|
||||
m.Row(10, func() {
|
||||
m.Text(p, props.Text{
|
||||
Align: consts.Center,
|
||||
Size: 8,
|
||||
Family: consts.Arial,
|
||||
Style: consts.Bold,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Create pdf table
|
||||
func (pdfPrinter *PdfPrinter) printTable(m pdf.Maroto, summaryDetails *reportsummary.SummaryDetails) {
|
||||
headers := []string{"CONTROL NAME", "FAILED RESOURCES", "EXCLUDED RESOURCES", "ALL RESOURCES", "% RISK-SCORE"}
|
||||
|
||||
controls := make([][]string, len(pdfPrinter.sortedControlNames))
|
||||
for i := range controls {
|
||||
controls[i] = make([]string, len(headers))
|
||||
}
|
||||
for i := 0; i < len(pdfPrinter.sortedControlNames); i++ {
|
||||
controls[i] = generateRow(summaryDetails.Controls.GetControl(reportsummary.EControlCriteriaName, pdfPrinter.sortedControlNames[i]))
|
||||
}
|
||||
|
||||
m.TableList(headers, controls, props.TableList{
|
||||
HeaderProp: props.TableListContent{
|
||||
Family: consts.Arial,
|
||||
Style: consts.Bold,
|
||||
Size: 8.0,
|
||||
},
|
||||
ContentProp: props.TableListContent{
|
||||
Family: consts.Courier,
|
||||
Style: consts.Normal,
|
||||
Size: 8.0,
|
||||
},
|
||||
Align: consts.Center,
|
||||
AlternatedBackground: &color.Color{
|
||||
Red: 224,
|
||||
Green: 224,
|
||||
Blue: 224,
|
||||
},
|
||||
HeaderContentSpace: 2.0,
|
||||
Line: false,
|
||||
})
|
||||
m.Line(1)
|
||||
m.Row(2, func() {})
|
||||
}
|
||||
|
||||
// Add final results.
|
||||
func (pdfPrinter *PdfPrinter) printFinalResult(m pdf.Maroto, summaryDetails *reportsummary.SummaryDetails) {
|
||||
m.Row(5, func() {
|
||||
m.Col(3, func() {
|
||||
m.Text("Resource summary", props.Text{
|
||||
Align: consts.Left,
|
||||
Size: 8.0,
|
||||
Style: consts.Bold,
|
||||
Family: consts.Arial,
|
||||
})
|
||||
})
|
||||
m.Col(2, func() {
|
||||
m.Text(fmt.Sprintf("%d", summaryDetails.NumberOfResources().Failed()), props.Text{
|
||||
Align: consts.Left,
|
||||
Size: 8.0,
|
||||
Style: consts.Bold,
|
||||
Family: consts.Arial,
|
||||
})
|
||||
})
|
||||
m.Col(2, func() {
|
||||
m.Text(fmt.Sprintf("%d", summaryDetails.NumberOfResources().Excluded()), props.Text{
|
||||
Align: consts.Left,
|
||||
Size: 8.0,
|
||||
Style: consts.Bold,
|
||||
Family: consts.Arial,
|
||||
})
|
||||
})
|
||||
m.Col(2, func() {
|
||||
m.Text(fmt.Sprintf("%d", summaryDetails.NumberOfResources().All()), props.Text{
|
||||
Align: consts.Left,
|
||||
Size: 8.0,
|
||||
Style: consts.Bold,
|
||||
Family: consts.Arial,
|
||||
})
|
||||
})
|
||||
m.Col(2, func() {
|
||||
m.Text(fmt.Sprintf("%.2f%s", summaryDetails.Score, "%"), props.Text{
|
||||
Align: consts.Left,
|
||||
Size: 8.0,
|
||||
Style: consts.Bold,
|
||||
Family: consts.Arial,
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Return sorted control names.
|
||||
func getSortedControlsNames(controls reportsummary.ControlSummaries) []string {
|
||||
controlNames := make([]string, 0, len(controls))
|
||||
for k := range controls {
|
||||
c := controls[k]
|
||||
controlNames = append(controlNames, c.GetName())
|
||||
}
|
||||
sort.Strings(controlNames)
|
||||
return controlNames
|
||||
}
|
||||
|
||||
// Generate rows to be appended to the table.
|
||||
func generateRow(controlSummary reportsummary.IControlSummary) []string {
|
||||
// We use ReplaceAll because some control name
|
||||
// has a too long name that unformat the pdf view.
|
||||
controlName := strings.ReplaceAll(controlSummary.GetName(), "-", " ")
|
||||
row := []string{controlName}
|
||||
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()))
|
||||
|
||||
if !controlSummary.GetStatus().IsSkipped() {
|
||||
row = append(row, fmt.Sprintf("%d", int(controlSummary.GetScore()))+"%")
|
||||
} else {
|
||||
row = append(row, "skipped")
|
||||
}
|
||||
return row
|
||||
}
|
||||
BIN
resultshandling/printer/v2/pdf/logo.png
Normal file
BIN
resultshandling/printer/v2/pdf/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 53 KiB |
@@ -1,21 +1,3 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
"github.com/armosec/kubescape/resultshandling/printer"
|
||||
"github.com/armosec/kubescape/resultshandling/printer/v2/resourcemapping"
|
||||
)
|
||||
|
||||
var INDENT = " "
|
||||
|
||||
func GetPrinter(printFormat string, verboseMode bool) printer.IPrinter {
|
||||
switch printFormat {
|
||||
case printer.JsonFormat:
|
||||
return resourcemapping.NewJsonPrinter()
|
||||
case printer.JunitResultFormat:
|
||||
return NewJunitPrinter()
|
||||
// case printer.PrometheusFormat:
|
||||
// return NewPrometheusPrinter(verboseMode)
|
||||
default:
|
||||
return resourcemapping.NewPrettyPrinter(verboseMode)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
"github.com/armosec/kubescape/cautils/logger"
|
||||
"github.com/armosec/kubescape/cautils/logger/helpers"
|
||||
"github.com/armosec/opa-utils/reporthandling"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const MAX_REPORT_SIZE = 2097152 // 2 MB
|
||||
@@ -44,15 +44,14 @@ func (report *ReportEventReceiver) ActionSendReport(opaSessionObj *cautils.OPASe
|
||||
}
|
||||
|
||||
if report.customerGUID == "" {
|
||||
report.message = "WARNING: Failed to publish results. Reason: Unknown accout ID. Run kubescape with the '--account <account ID>' flag. Contact ARMO team for more details"
|
||||
report.message = "WARNING: Failed to publish results. Reason: Unknown accout ID. Run kubescape with the '--account <account ID>' flag. Please feel free to contact ARMO team for more details"
|
||||
return nil
|
||||
}
|
||||
if report.clusterName == "" {
|
||||
report.message = "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"
|
||||
report.message = "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.Please feel free to contact ARMO team for more details"
|
||||
return nil
|
||||
}
|
||||
|
||||
opaSessionObj.PostureReport.ReportID = uuid.NewV4().String()
|
||||
opaSessionObj.PostureReport.ReportID = uuid.NewString()
|
||||
opaSessionObj.PostureReport.CustomerGUID = report.customerGUID
|
||||
opaSessionObj.PostureReport.ClusterName = report.clusterName
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"github.com/armosec/k8s-interface/workloadinterface"
|
||||
"github.com/armosec/kubescape/cautils/getter"
|
||||
"github.com/armosec/opa-utils/reporthandling"
|
||||
"github.com/gofrs/uuid"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
func (report *ReportEventReceiver) initEventReceiverURL() {
|
||||
@@ -16,7 +16,7 @@ func (report *ReportEventReceiver) initEventReceiverURL() {
|
||||
urlObj.Host = getter.GetArmoAPIConnector().GetReportReceiverURL()
|
||||
urlObj.Path = "/k8s/postureReport"
|
||||
q := urlObj.Query()
|
||||
q.Add("customerGUID", uuid.FromStringOrNil(report.customerGUID).String())
|
||||
q.Add("customerGUID", uuid.MustParse(report.customerGUID).String())
|
||||
q.Add("clusterName", report.clusterName)
|
||||
|
||||
urlObj.RawQuery = q.Encode()
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"github.com/armosec/kubescape/cautils/getter"
|
||||
"github.com/armosec/kubescape/cautils/logger"
|
||||
"github.com/armosec/kubescape/cautils/logger/helpers"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/armosec/opa-utils/reporthandling"
|
||||
"github.com/armosec/opa-utils/reporthandling/results/v1/resourcesresults"
|
||||
@@ -44,19 +44,20 @@ func (report *ReportEventReceiver) ActionSendReport(opaSessionObj *cautils.OPASe
|
||||
finalizeReport(opaSessionObj)
|
||||
|
||||
if report.customerGUID == "" {
|
||||
report.message = "WARNING: Failed to publish results. Reason: Unknown accout ID. Run kubescape with the '--account <account ID>' flag. Contact ARMO team for more details"
|
||||
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 report.clusterName == "" {
|
||||
report.message = "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"
|
||||
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
|
||||
}
|
||||
opaSessionObj.Report.ReportID = uuid.NewV4().String()
|
||||
opaSessionObj.Report.ReportID = uuid.NewString()
|
||||
opaSessionObj.Report.CustomerGUID = report.customerGUID
|
||||
opaSessionObj.Report.ClusterName = report.clusterName
|
||||
|
||||
if err := report.prepareReport(opaSessionObj.Report); err != nil {
|
||||
report.message = err.Error()
|
||||
logger.L().Error("failed to publish results", helpers.Error(err))
|
||||
} else {
|
||||
report.generateMessage()
|
||||
}
|
||||
@@ -229,5 +230,7 @@ func (report *ReportEventReceiver) generateMessage() {
|
||||
}
|
||||
|
||||
func (report *ReportEventReceiver) DisplayReportURL() {
|
||||
cautils.InfoTextDisplay(os.Stderr, fmt.Sprintf("\n\n%s\n\n", report.message))
|
||||
if report.message != "" {
|
||||
cautils.InfoTextDisplay(os.Stderr, fmt.Sprintf("\n\n%s\n\n", report.message))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"github.com/armosec/kubescape/cautils/getter"
|
||||
"github.com/armosec/opa-utils/reporthandling"
|
||||
reporthandlingv2 "github.com/armosec/opa-utils/reporthandling/v2"
|
||||
"github.com/gofrs/uuid"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
func (report *ReportEventReceiver) initEventReceiverURL() {
|
||||
@@ -18,7 +18,7 @@ func (report *ReportEventReceiver) initEventReceiverURL() {
|
||||
urlObj.Path = "/k8s/v2/postureReport"
|
||||
|
||||
q := urlObj.Query()
|
||||
q.Add("customerGUID", uuid.FromStringOrNil(report.customerGUID).String())
|
||||
q.Add("customerGUID", uuid.MustParse(report.customerGUID).String())
|
||||
q.Add("clusterName", report.clusterName)
|
||||
|
||||
urlObj.RawQuery = q.Encode()
|
||||
|
||||
@@ -4,6 +4,10 @@ import (
|
||||
"github.com/armosec/kubescape/cautils"
|
||||
"github.com/armosec/kubescape/cautils/logger"
|
||||
"github.com/armosec/kubescape/resultshandling/printer"
|
||||
printerv1 "github.com/armosec/kubescape/resultshandling/printer/v1"
|
||||
printerv2 "github.com/armosec/kubescape/resultshandling/printer/v2"
|
||||
"github.com/armosec/kubescape/resultshandling/printer/v2/controlmapping"
|
||||
|
||||
"github.com/armosec/kubescape/resultshandling/reporter"
|
||||
"github.com/armosec/opa-utils/reporthandling"
|
||||
)
|
||||
@@ -49,3 +53,19 @@ func CalculatePostureScore(postureReport *reporthandling.PostureReport) float32
|
||||
|
||||
return (float32(len(allResources)) - float32(len(failedResources))) / float32(len(allResources))
|
||||
}
|
||||
|
||||
func NewPrinter(printFormat string, verboseMode bool) printer.IPrinter {
|
||||
|
||||
switch printFormat {
|
||||
case printer.JsonFormat:
|
||||
return printerv1.NewJsonPrinter()
|
||||
case printer.JunitResultFormat:
|
||||
return printerv1.NewJunitPrinter()
|
||||
case printer.PrometheusFormat:
|
||||
return printerv1.NewPrometheusPrinter(verboseMode)
|
||||
case printer.PdfFormat:
|
||||
return printerv2.NewPdfPrinter()
|
||||
default:
|
||||
return controlmapping.NewPrettyPrinter(verboseMode)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user