Merge branch 'Daniel-GrunbergerCA-master' into dev

This commit is contained in:
dwertent
2021-08-26 12:22:34 +03:00
13 changed files with 203 additions and 106 deletions

View File

@@ -1,3 +1,4 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/

View File

@@ -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
View 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
View 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
View 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
View File

@@ -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

View File

@@ -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
View File

@@ -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.

View File

@@ -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, &notification.Designators, excludedNamespaces)
if err != nil || len(*k8sResources) == 0 {
glog.Error(err)

View File

@@ -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))

View File

@@ -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) {

View File

@@ -14,6 +14,7 @@ type ControlSummery struct {
TotalResources int
TotalFailed int
Description string
Remediation string
WorkloadSummery map[string][]WorkloadSummery // <namespace>:[<WorkloadSummery>]
}