mirror of
https://github.com/kubescape/kubescape.git
synced 2026-02-14 18:09:55 +00:00
Merge branch 'Daniel-GrunbergerCA-master' into dev
This commit is contained in:
1
LICENSE
1
LICENSE
@@ -1,3 +1,4 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
@@ -148,3 +148,11 @@ type PolicyIdentifier struct {
|
||||
Kind NotificationPolicyKind `json:"kind"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type ScanInfo struct {
|
||||
PolicyIdentifier PolicyIdentifier `json:"policyIdentifier"`
|
||||
Output string `json:"output"`
|
||||
ExcludedNamespaces string `json:"excludedNamespaces"`
|
||||
Input []string `json:"input"`
|
||||
Silent bool `json:"silent"`
|
||||
}
|
||||
|
||||
131
cmd/framework.go
Normal file
131
cmd/framework.go
Normal file
@@ -0,0 +1,131 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"kube-escape/cautils"
|
||||
"kube-escape/cautils/armotypes"
|
||||
"kube-escape/cautils/k8sinterface"
|
||||
"kube-escape/cautils/opapolicy"
|
||||
"kube-escape/opaprocessor"
|
||||
"kube-escape/policyhandler"
|
||||
"kube-escape/printer"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var scanInfo opapolicy.ScanInfo
|
||||
|
||||
type CLIHandler struct {
|
||||
policyHandler *policyhandler.PolicyHandler
|
||||
scanInfo *opapolicy.ScanInfo
|
||||
}
|
||||
|
||||
var frameworkCmd = &cobra.Command{
|
||||
Use: "framework <framework name>",
|
||||
Short: "The framework you wish to use. Supported frameworks: nsa, mitre",
|
||||
Long: ``,
|
||||
ValidArgs: []string{"nsa", "mitre"},
|
||||
Args: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return errors.New("requires at least one argument")
|
||||
}
|
||||
if !isValidFramework(args[0]) {
|
||||
return errors.New("supported frameworks: nsa and mitre")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
scanInfo.PolicyIdentifier = opapolicy.PolicyIdentifier{}
|
||||
scanInfo.PolicyIdentifier.Kind = opapolicy.KindFramework
|
||||
scanInfo.PolicyIdentifier.Name = args[0]
|
||||
scanInfo.Input = args[1:]
|
||||
CliSetup()
|
||||
},
|
||||
}
|
||||
|
||||
func isValidFramework(framework string) bool {
|
||||
return framework == "nsa" || framework != "mitre"
|
||||
}
|
||||
|
||||
func init() {
|
||||
scanCmd.AddCommand(frameworkCmd)
|
||||
scanInfo = opapolicy.ScanInfo{}
|
||||
frameworkCmd.Flags().StringVarP(&scanInfo.ExcludedNamespaces, "excluded-namespaces", "e", "", "namespaces to exclude from check")
|
||||
frameworkCmd.Flags().StringVarP(&scanInfo.Output, "output", "o", "pretty-printer", "output format")
|
||||
frameworkCmd.Flags().BoolVarP(&scanInfo.Silent, "silent", "s", false, "silent output")
|
||||
|
||||
}
|
||||
|
||||
func processYamlInput(yamls string) {
|
||||
listOfYamls := strings.Split(yamls, ",")
|
||||
for _, yaml := range listOfYamls {
|
||||
dat, err := ioutil.ReadFile(yaml)
|
||||
if err != nil {
|
||||
fmt.Printf("Could not open file: %s.", yaml)
|
||||
}
|
||||
fmt.Print(string(dat))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func CliSetup() error {
|
||||
k8s := k8sinterface.NewKubernetesApi()
|
||||
|
||||
processNotification := make(chan *cautils.OPASessionObj)
|
||||
reportResults := make(chan *cautils.OPASessionObj)
|
||||
|
||||
// policy handler setup
|
||||
policyHandler := policyhandler.NewPolicyHandler(&processNotification, k8s)
|
||||
|
||||
// cli handler setup
|
||||
cli := NewCLIHandler(policyHandler)
|
||||
if err := cli.Scan(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// processor setup - rego run
|
||||
go func() {
|
||||
reporterObj := opaprocessor.NewOPAProcessor(&processNotification, &reportResults)
|
||||
reporterObj.ProcessRulesListenner()
|
||||
}()
|
||||
p := printer.NewPrinter(&reportResults, scanInfo.Output)
|
||||
p.ActionPrint()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewCLIHandler(policyHandler *policyhandler.PolicyHandler) *CLIHandler {
|
||||
return &CLIHandler{
|
||||
scanInfo: &scanInfo,
|
||||
policyHandler: policyHandler,
|
||||
}
|
||||
}
|
||||
|
||||
func (clihandler *CLIHandler) Scan() error {
|
||||
cautils.InfoDisplay(os.Stdout, "ARMO security scanner starting\n")
|
||||
|
||||
policyNotification := &opapolicy.PolicyNotification{
|
||||
NotificationType: opapolicy.TypeExecPostureScan,
|
||||
Rules: []opapolicy.PolicyIdentifier{
|
||||
*&clihandler.scanInfo.PolicyIdentifier,
|
||||
},
|
||||
Designators: armotypes.PortalDesignator{},
|
||||
}
|
||||
|
||||
switch policyNotification.NotificationType {
|
||||
case opapolicy.TypeExecPostureScan:
|
||||
go func() {
|
||||
if err := clihandler.policyHandler.HandleNotificationRequest(policyNotification, scanInfo.ExcludedNamespaces); err != nil {
|
||||
fmt.Printf("%v\n", err)
|
||||
os.Exit(0)
|
||||
}
|
||||
}()
|
||||
default:
|
||||
return fmt.Errorf("notification type '%s' Unknown", policyNotification.NotificationType)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
26
cmd/root.go
Normal file
26
cmd/root.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var cfgFile string
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "kubescape",
|
||||
Short: "A tool for running NSA recommended tests in your cluster ",
|
||||
Long: `Kubescape is the first tool for testing if Kubernetes is deployed securely as defined in Kubernetes Hardening Guidance
|
||||
by to NSA and CISA Tests are configured with YAML files, making this tool easy to update as test specifications evolve.`,
|
||||
}
|
||||
|
||||
func Execute() {
|
||||
rootCmd.Execute()
|
||||
}
|
||||
|
||||
func init() {
|
||||
cobra.OnInitialize(initConfig)
|
||||
}
|
||||
|
||||
// initConfig reads in config file and ENV variables if set.
|
||||
func initConfig() {
|
||||
}
|
||||
18
cmd/scan.go
Normal file
18
cmd/scan.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// scanCmd represents the scan command
|
||||
var scanCmd = &cobra.Command{
|
||||
Use: "scan",
|
||||
Short: "Scan command",
|
||||
Long: `The action you want to perform`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(scanCmd)
|
||||
}
|
||||
4
go.mod
4
go.mod
@@ -12,6 +12,7 @@ require (
|
||||
github.com/enescakir/emoji v1.0.0
|
||||
github.com/fatih/color v1.12.0
|
||||
github.com/francoispqt/gojay v1.2.13
|
||||
github.com/fsnotify/fsnotify v1.5.0 // indirect
|
||||
github.com/gofrs/uuid v4.0.0+incompatible
|
||||
github.com/golang/glog v0.0.0-20210429001901-424d2337a529
|
||||
github.com/mattn/go-isatty v0.0.13
|
||||
@@ -21,7 +22,10 @@ require (
|
||||
github.com/opencontainers/image-spec v1.0.1 // indirect
|
||||
github.com/pquerna/cachecontrol v0.1.0 // indirect
|
||||
github.com/satori/go.uuid v1.2.0
|
||||
github.com/spf13/cobra v1.2.1
|
||||
golang.org/x/oauth2 v0.0.0-20210810183815-faf39c7919d5
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
k8s.io/api v0.22.0
|
||||
k8s.io/apimachinery v0.22.0
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
package clihandler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"kube-escape/cautils"
|
||||
"kube-escape/policyhandler"
|
||||
"os"
|
||||
|
||||
"kube-escape/cautils/armotypes"
|
||||
"kube-escape/cautils/opapolicy"
|
||||
)
|
||||
|
||||
type CLIHandler struct {
|
||||
policyHandler *policyhandler.PolicyHandler
|
||||
flagHandler FlagHandler
|
||||
}
|
||||
|
||||
func NewCLIHandler(policyHandler *policyhandler.PolicyHandler) *CLIHandler {
|
||||
return &CLIHandler{
|
||||
flagHandler: *NewFlagHandler(),
|
||||
policyHandler: policyHandler,
|
||||
}
|
||||
}
|
||||
|
||||
func (clihandler *CLIHandler) Scan() error {
|
||||
clihandler.flagHandler.ParseFlag()
|
||||
if !clihandler.flagHandler.ExecuteScan() {
|
||||
os.Exit(0)
|
||||
}
|
||||
cautils.InfoDisplay(os.Stdout, "ARMO security scanner starting\n")
|
||||
|
||||
policyNotification := &opapolicy.PolicyNotification{
|
||||
NotificationType: opapolicy.TypeExecPostureScan,
|
||||
Rules: []opapolicy.PolicyIdentifier{
|
||||
*clihandler.flagHandler.policyIdentifier,
|
||||
},
|
||||
Designators: armotypes.PortalDesignator{},
|
||||
}
|
||||
|
||||
switch policyNotification.NotificationType {
|
||||
case opapolicy.TypeExecPostureScan:
|
||||
go func() {
|
||||
if err := clihandler.policyHandler.HandleNotificationRequest(policyNotification); err != nil {
|
||||
fmt.Printf("%v\n", err)
|
||||
os.Exit(0)
|
||||
}
|
||||
}()
|
||||
default:
|
||||
return fmt.Errorf("notification type '%s' Unknown", policyNotification.NotificationType)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
46
main.go
46
main.go
@@ -1,49 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"kube-escape/cautils"
|
||||
k8sinterface "kube-escape/cautils/k8sinterface"
|
||||
"kube-escape/inputhandler/clihandler"
|
||||
|
||||
"kube-escape/opaprocessor"
|
||||
"kube-escape/policyhandler"
|
||||
"kube-escape/printer"
|
||||
|
||||
"os"
|
||||
)
|
||||
import "kube-escape/cmd"
|
||||
|
||||
func main() {
|
||||
|
||||
if err := CliSetup(); err != nil {
|
||||
fmt.Println(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func CliSetup() error {
|
||||
k8s := k8sinterface.NewKubernetesApi()
|
||||
|
||||
processNotification := make(chan *cautils.OPASessionObj)
|
||||
reportResults := make(chan *cautils.OPASessionObj)
|
||||
|
||||
// policy handler setup
|
||||
policyHandler := policyhandler.NewPolicyHandler(&processNotification, k8s)
|
||||
|
||||
// cli handler setup
|
||||
cli := clihandler.NewCLIHandler(policyHandler)
|
||||
if err := cli.Scan(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// processor setup - rego run
|
||||
go func() {
|
||||
reporterObj := opaprocessor.NewOPAProcessor(&processNotification, &reportResults)
|
||||
reporterObj.ProcessRulesListenner()
|
||||
}()
|
||||
p := printer.NewPrinter(&reportResults, printer.PrettyPrinter)
|
||||
p.ActionPrint()
|
||||
|
||||
return nil
|
||||
cmd.Execute()
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -1,7 +1,6 @@
|
||||
package policyhandler
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"kube-escape/cautils"
|
||||
|
||||
@@ -27,7 +26,7 @@ func NewPolicyHandler(processPolicy *chan *cautils.OPASessionObj, k8s *k8sinterf
|
||||
}
|
||||
}
|
||||
|
||||
func (policyHandler *PolicyHandler) HandleNotificationRequest(notification *opapolicy.PolicyNotification) error {
|
||||
func (policyHandler *PolicyHandler) HandleNotificationRequest(notification *opapolicy.PolicyNotification, excludedNamespaces string) error {
|
||||
glog.Infof("Processing notification. reportID: %s", notification.ReportID)
|
||||
opaSessionObj := cautils.NewOPASessionObj(nil, nil)
|
||||
// validate notification
|
||||
@@ -53,10 +52,7 @@ func (policyHandler *PolicyHandler) HandleNotificationRequest(notification *opap
|
||||
// get k8s resources
|
||||
cautils.ProgressTextDisplay("Accessing Kubernetes objects")
|
||||
glog.Infof(fmt.Sprintf("Getting kubernetes objects. reportID: %s", notification.ReportID))
|
||||
excludedNamespaces := ""
|
||||
if flag.Arg(3) == "--exclude-namespaces" {
|
||||
excludedNamespaces = flag.Arg(4)
|
||||
}
|
||||
|
||||
k8sResources, err := policyHandler.getK8sResources(frameworks, ¬ification.Designators, excludedNamespaces)
|
||||
if err != nil || len(*k8sResources) == 0 {
|
||||
glog.Error(err)
|
||||
|
||||
@@ -61,7 +61,7 @@ func (db *ArmoAPI) GetHttpClient() *http.Client {
|
||||
func (db *ArmoAPI) OPAFRAMEWORKGet(name string) ([]opapolicy.Framework, error) {
|
||||
requestURI := "v1/armoFrameworks"
|
||||
requestURI += fmt.Sprintf("?customerGUID=%s", "11111111-1111-1111-1111-111111111111")
|
||||
requestURI += fmt.Sprintf("&frameworkName=%s", name)
|
||||
requestURI += fmt.Sprintf("&frameworkName=%s", strings.ToUpper(name))
|
||||
requestURI += "&getRules=true"
|
||||
|
||||
fullURL := URLEncoder(fmt.Sprintf("%s/%s", db.GetServerAddress(), requestURI))
|
||||
|
||||
@@ -19,8 +19,8 @@ var INDENT = " "
|
||||
|
||||
const (
|
||||
PrettyPrinter string = "pretty-printer"
|
||||
JsonPrinter string = "json-printer"
|
||||
JunitResultPrinter string = "junit-result-printer"
|
||||
JsonPrinter string = "json"
|
||||
JunitResultPrinter string = "junit"
|
||||
)
|
||||
|
||||
type Printer struct {
|
||||
@@ -91,6 +91,7 @@ func (printer *Printer) SummerySetup(postureReport *opapolicy.PostureReport) {
|
||||
TotalFailed: len(workloadsSummery),
|
||||
WorkloadSummery: mapResources,
|
||||
Description: cr.Description,
|
||||
Remediation: cr.Remediation,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,7 +116,12 @@ func (print *Printer) printSummery(controlName string, controlSummery *ControlSu
|
||||
cautils.SimpleDisplay(os.Stdout, "Summary - ")
|
||||
cautils.SuccessDisplay(os.Stdout, "Passed:%v ", controlSummery.TotalResources-controlSummery.TotalFailed)
|
||||
cautils.FailureDisplay(os.Stdout, "Failed:%v ", controlSummery.TotalFailed)
|
||||
cautils.InfoDisplay(os.Stdout, "Total:%v\n\n", controlSummery.TotalResources)
|
||||
cautils.InfoDisplay(os.Stdout, "Total:%v\n", controlSummery.TotalResources)
|
||||
if controlSummery.TotalFailed > 0 {
|
||||
cautils.DescriptionDisplay(os.Stdout, "Remediation: %v\n", controlSummery.Remediation)
|
||||
}
|
||||
cautils.DescriptionDisplay(os.Stdout, "\n")
|
||||
|
||||
}
|
||||
|
||||
func (printer *Printer) printTitle(controlName string, controlSummery *ControlSummery) {
|
||||
|
||||
@@ -14,6 +14,7 @@ type ControlSummery struct {
|
||||
TotalResources int
|
||||
TotalFailed int
|
||||
Description string
|
||||
Remediation string
|
||||
WorkloadSummery map[string][]WorkloadSummery // <namespace>:[<WorkloadSummery>]
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user