diff --git a/go.mod b/go.mod index ce3983ca..a0015e32 100644 --- a/go.mod +++ b/go.mod @@ -23,6 +23,7 @@ require ( github.com/satori/go.uuid v1.2.0 golang.org/x/oauth2 v0.0.0-20210810183815-faf39c7919d5 gopkg.in/square/go-jose.v2 v2.6.0 // indirect + gopkg.in/yaml.v2 v2.4.0 k8s.io/api v0.22.0 k8s.io/apimachinery v0.22.0 k8s.io/client-go v0.22.0 diff --git a/policyhandler/__debug_bin b/policyhandler/__debug_bin deleted file mode 100644 index 0cbfc5ed..00000000 Binary files a/policyhandler/__debug_bin and /dev/null differ diff --git a/policyhandler/filesloader.go b/policyhandler/filesloader.go new file mode 100644 index 00000000..e66cffa6 --- /dev/null +++ b/policyhandler/filesloader.go @@ -0,0 +1,114 @@ +package policyhandler + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "kube-escape/cautils" + "path/filepath" + + "gopkg.in/yaml.v2" +) + +var ( + YAML_PREFIX = []string{".yaml", ".yml"} + JSON_PREFIX = []string{".json"} +) + +// // build resources map +// k8sResourcesMap := setResourceMap(frameworks) +func loadFiles(filePaths []string) { + + for i := range filePaths { + loadFile(filePaths[i]) + } +} + +func loadFile(filePath string) (interface{}, error) { + var obj interface{} + var err error + if isYaml(filePath) { + obj, err = loadYamlFile(filePath) + } else if isJson(filePath) { + obj, err = loadJsonFile(filePath) + } else { + return nil, fmt.Errorf("Unknown file format") + } + if err != nil { + return obj, err + } + if _, ok := obj.([]interface{}); ok { + return obj, nil + } + return []interface{}{obj}, nil +} +func listFiles(patterns []string) ([]string, []error) { + files := []string{} + errs := []error{} + for i := range patterns { + f, err := filepath.Glob(patterns[i]) + if err != nil { + errs = append(errs, err) + } else { + files = append(files, f...) + } + } + return files, errs +} +func loadYamlFile(filePath string) (interface{}, error) { + yamlFile, err := ioutil.ReadFile(filePath) + if err != nil { + return nil, err + } + + r := bytes.NewReader(yamlFile) + dec := yaml.NewDecoder(r) + var t interface{} + yamlObjs := []interface{}{} + for dec.Decode(&t) == nil { + var yamlObj interface{} + if err := yaml.Unmarshal(yamlFile, &yamlObj); err != nil { + return yamlObj, err + } + yamlObjs = append(yamlObjs, t) + } + + return convertYamlToJson(yamlObjs), nil +} + +func loadJsonFile(filePath string) (interface{}, error) { + var jsonObj interface{} + jsonFile, err := ioutil.ReadFile(filePath) + if err != nil { + return jsonObj, err + } + if err = json.Unmarshal(jsonFile, &jsonObj); err != nil { + return jsonObj, err + } + return jsonObj, nil +} + +func convertYamlToJson(i interface{}) interface{} { + switch x := i.(type) { + case map[interface{}]interface{}: + m2 := map[string]interface{}{} + for k, v := range x { + m2[k.(string)] = convertYamlToJson(v) + } + return m2 + case []interface{}: + for i, v := range x { + x[i] = convertYamlToJson(v) + } + } + return i +} + +func isYaml(filePath string) bool { + return cautils.StringInSlice(YAML_PREFIX, filepath.Ext(filePath)) != cautils.ValueNotFound +} + +func isJson(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 new file mode 100644 index 00000000..6ee44b11 --- /dev/null +++ b/policyhandler/filesloader_test.go @@ -0,0 +1,8 @@ +package policyhandler + +import "testing" + +func TestLoadFiles(t *testing.T) { + + loadFiles([]string{}) +} diff --git a/policyhandler/handlenotification.go b/policyhandler/handlenotification.go index d577fe3b..1ec5e84d 100644 --- a/policyhandler/handlenotification.go +++ b/policyhandler/handlenotification.go @@ -1,15 +1,12 @@ package policyhandler import ( - "flag" "fmt" "kube-escape/cautils" "kube-escape/cautils/k8sinterface" "kube-escape/cautils/opapolicy" - - "github.com/golang/glog" ) // PolicyHandler - @@ -28,40 +25,26 @@ func NewPolicyHandler(processPolicy *chan *cautils.OPASessionObj, k8s *k8sinterf } func (policyHandler *PolicyHandler) HandleNotificationRequest(notification *opapolicy.PolicyNotification) error { - glog.Infof("Processing notification. reportID: %s", notification.ReportID) opaSessionObj := cautils.NewOPASessionObj(nil, nil) // validate notification // TODO // get policies - glog.Infof(fmt.Sprintf("Getting %d policies from backend. reportID: %s", len(notification.Rules), notification.ReportID)) - cautils.ProgressTextDisplay("Downloading framework definitions") - frameworks, err := policyHandler.GetPoliciesFromBackend(notification) + frameworks, err := policyHandler.getPolicies(notification) if err != nil { return err } - if len(frameworks) == 0 { - err := fmt.Errorf("Could not download any policies, please check previous logs") - return err + return fmt.Errorf("empty list of frameworks") } opaSessionObj.Frameworks = frameworks - cautils.SuccessTextDisplay("Downloaded framework") - // store policies as configmaps - // TODO - // 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.getResources(notification, opaSessionObj) + if err != nil { + return err } - k8sResources, err := policyHandler.getK8sResources(frameworks, ¬ification.Designators, excludedNamespaces) - if err != nil || len(*k8sResources) == 0 { - glog.Error(err) - } else { - cautils.SuccessTextDisplay("Accessed successfully to Kubernetes objects, let’s start!!!") + if k8sResources == nil || len(*k8sResources) == 0 { + return fmt.Errorf("empty list of resources") } opaSessionObj.K8SResources = k8sResources @@ -69,3 +52,37 @@ func (policyHandler *PolicyHandler) HandleNotificationRequest(notification *opap *policyHandler.processPolicy <- opaSessionObj return nil } + +func (policyHandler *PolicyHandler) getPolicies(notification *opapolicy.PolicyNotification) ([]opapolicy.Framework, error) { + + cautils.ProgressTextDisplay("Downloading framework definitions") + + // TODO - support load policies from local file + frameworks, err := policyHandler.GetPoliciesFromBackend(notification) + if err != nil { + return frameworks, err + } + + if len(frameworks) == 0 { + err := fmt.Errorf("could not download any policies, please check previous logs") + return frameworks, err + } + cautils.SuccessTextDisplay("Downloaded framework") + + return frameworks, nil +} + +func (policyHandler *PolicyHandler) getResources(notification *opapolicy.PolicyNotification, opaSessionObj *cautils.OPASessionObj) (*cautils.K8SResources, error) { + var k8sResources *cautils.K8SResources + var err error + paths := []string{} + if len(paths) > 0 { + // + } else { + excludedNamespaces := "" + k8sResources, err = policyHandler.getK8sResources(opaSessionObj.Frameworks, ¬ification.Designators, excludedNamespaces) + + } + + return k8sResources, err +} diff --git a/policyhandler/k8sresources.go b/policyhandler/k8sresources.go index 31de93ea..c87ca5b7 100644 --- a/policyhandler/k8sresources.go +++ b/policyhandler/k8sresources.go @@ -20,6 +20,9 @@ import ( const SelectAllResources = "*" func (policyHandler *PolicyHandler) getK8sResources(frameworks []opapolicy.Framework, designator *armotypes.PortalDesignator, excludedNamespaces string) (*cautils.K8SResources, error) { + // get k8s resources + cautils.ProgressTextDisplay("Accessing Kubernetes objects") + // build resources map k8sResourcesMap := setResourceMap(frameworks) @@ -31,6 +34,7 @@ func (policyHandler *PolicyHandler) getK8sResources(frameworks []opapolicy.Frame return k8sResourcesMap, err } + cautils.SuccessTextDisplay("Accessed successfully to Kubernetes objects, let’s start!!!") return k8sResourcesMap, nil } @@ -66,7 +70,7 @@ func (policyHandler *PolicyHandler) pullSingleResource(resource *schema.GroupVer listOptions.FieldSelector += "metadata.namespace!=" + excludedNamespace + "," } } - if labels != nil && len(labels) > 0 { + if len(labels) > 0 { set := k8slabels.Set(labels) listOptions.LabelSelector = set.AsSelector().String() }