From 44803ab91561189d518223124417f8f95973054a Mon Sep 17 00:00:00 2001 From: David Wertenteil <64066841+dwertent@users.noreply.github.com> Date: Mon, 30 Aug 2021 11:06:13 +0300 Subject: [PATCH] Support glob file loading (#41) * recursive glob * adding helm support to readme * update glob function --- README.md | 14 +++++++++- policyhandler/filesloader.go | 46 +++++++++++++++++++++++++------ policyhandler/filesloader_test.go | 2 +- policyhandler/urlloader.go | 3 -- 4 files changed, 52 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index cf66bb23..4a414e09 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ logo [![build](https://github.com/armosec/kubescape/actions/workflows/build.yaml/badge.svg)](https://github.com/armosec/kubescape/actions/workflows/build.yaml) -[![Github All Releases](https://img.shields.io/github/downloads/armosec/kubescape/total.svg)]() +[![Github All Releases](https://img.shields.io/github/downloads/armosec/kubescape/total.svg)](https://github.com/armosec/kubescape) [![Go Report Card](https://goreportcard.com/badge/github.com/armosec/kubescape)](https://goreportcard.com/report/github.com/armosec/kubescape) Kubescape is the first tool for testing if Kubernetes is deployed securely as defined in [Kubernetes Hardening Guidance by NSA and CISA](https://www.nsa.gov/News-Features/Feature-Stories/Article-View/Article/2716980/nsa-cisa-release-kubernetes-hardening-guidance/) @@ -77,6 +77,18 @@ kubescape scan framework nsa --exclude-namespaces kube-system,kube-public --sile kubescape scan framework nsa --exclude-namespaces kube-system,kube-public --silence -o junit > results.xml ``` +### Helm Support + +1. Render the helm template to an output yaml +``` +helm template [CHART] [flags] --generate-name --dry-run --output-dir helm-output +``` + +2. Run `kubescape` with rended yaml files +``` +kubescape scan framework nsa helm-output/* +``` + # How to build Note: development (and the release process) is done with Go `1.16` diff --git a/policyhandler/filesloader.go b/policyhandler/filesloader.go index e65a608e..57969138 100644 --- a/policyhandler/filesloader.go +++ b/policyhandler/filesloader.go @@ -8,6 +8,7 @@ import ( "kubescape/cautils" "kubescape/cautils/k8sinterface" "kubescape/cautils/opapolicy" + "os" "path/filepath" "strings" @@ -38,7 +39,7 @@ func (policyHandler *PolicyHandler) loadResources(frameworks []opapolicy.Framewo workloads = append(workloads, w...) } - // load resource from url + // load resources from url w, err = loadResourcesFromUrl(scanInfo.InputPatterns) if err != nil { return nil, err @@ -47,11 +48,15 @@ func (policyHandler *PolicyHandler) loadResources(frameworks []opapolicy.Framewo workloads = append(workloads, w...) } + if len(workloads) == 0 { + return nil, fmt.Errorf("empty list of workloads - no workloads found") + } + // map all resources: map["/group/version/kind"][] allResources := mapResources(workloads) // build resources map - // map resources based on framework requrid resources: map["/group/version/kind"][] + // map resources based on framework required resources: map["/group/version/kind"][] k8sResources := setResourceMap(frameworks) // save only relevant resources @@ -78,9 +83,6 @@ func loadResourcesFromFiles(inputPatterns []string) ([]k8sinterface.IWorkload, e if len(errs) > 0 { cautils.ErrorDisplay(fmt.Sprintf("%v", errs)) // TODO - print error } - if len(workloads) == 0 { - return workloads, fmt.Errorf("empty list of workloads - no workloads found") - } return workloads, nil } @@ -138,10 +140,11 @@ func readFile(fileContent []byte, fileFromat FileFormat) ([]k8sinterface.IWorklo case JSON_FILE_FORMAT: return readJsonFile(fileContent) default: - return nil, []error{fmt.Errorf("file extension %s not supported", fileFromat)} + return nil, nil // []error{fmt.Errorf("file extension %s not supported", fileFromat)} } } + func listFiles(patterns []string) ([]string, []error) { files := []string{} errs := []error{} @@ -149,7 +152,11 @@ func listFiles(patterns []string) ([]string, []error) { if strings.HasPrefix(patterns[i], "http") { continue } - f, err := filepath.Glob(patterns[i]) + if !filepath.IsAbs(patterns[i]) { + o, _ := os.Getwd() + patterns[i] = filepath.Join(o, patterns[i]) + } + f, err := glob(filepath.Split(patterns[i])) //filepath.Glob(patterns[i]) if err != nil { errs = append(errs, err) } else { @@ -209,7 +216,9 @@ func convertYamlToJson(i interface{}) interface{} { case map[interface{}]interface{}: m2 := map[string]interface{}{} for k, v := range x { - m2[k.(string)] = convertYamlToJson(v) + if s, ok := k.(string); ok { + m2[s] = convertYamlToJson(v) + } } return m2 case []interface{}: @@ -220,6 +229,27 @@ func convertYamlToJson(i interface{}) interface{} { return i } +func glob(root, pattern string) ([]string, error) { + var matches []string + err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() { + return nil + } + if matched, err := filepath.Match(pattern, filepath.Base(path)); err != nil { + return err + } else if matched { + matches = append(matches, path) + } + return nil + }) + if err != nil { + return nil, err + } + return matches, nil +} func isYaml(filePath string) bool { return cautils.StringInSlice(YAML_PREFIX, filepath.Ext(filePath)) != cautils.ValueNotFound } diff --git a/policyhandler/filesloader_test.go b/policyhandler/filesloader_test.go index c41b6993..40107267 100644 --- a/policyhandler/filesloader_test.go +++ b/policyhandler/filesloader_test.go @@ -31,7 +31,7 @@ func TestListFiles(t *testing.T) { if len(errs) > 0 { t.Error(errs) } - expected := 14 + expected := 12 if len(files) != expected { t.Errorf("wrong number of files, expected: %d, found: %d", expected, len(files)) } diff --git a/policyhandler/urlloader.go b/policyhandler/urlloader.go index d1de20db..9d2e14bf 100644 --- a/policyhandler/urlloader.go +++ b/policyhandler/urlloader.go @@ -20,9 +20,6 @@ func loadResourcesFromUrl(inputPatterns []string) ([]k8sinterface.IWorkload, err if len(errs) > 0 { cautils.ErrorDisplay(fmt.Sprintf("%v", errs)) // TODO - print error } - if len(workloads) == 0 { - return workloads, fmt.Errorf("empty list of workloads - no workloads valid workloads found") - } return workloads, nil }