add download json option

This commit is contained in:
Daniel-GrunbergerCA
2021-09-01 15:51:24 +03:00
parent 304017fc41
commit 05e108b47b
7 changed files with 190 additions and 9 deletions
+20
View File
@@ -0,0 +1,20 @@
package cautils
import (
"os"
"path/filepath"
"github.com/armosec/kubescape/cautils/getter"
)
type DownloadInfo struct {
Path string
FrameworkName string
}
func GetDefaultPath(frameworkName string) string {
if homeDir, err := os.UserHomeDir(); err == nil {
return filepath.Join(homeDir, getter.DefaultLocalStore, frameworkName+".json")
}
return filepath.Join(getter.DefaultLocalStore, frameworkName+".json")
}
+58 -3
View File
@@ -5,6 +5,7 @@ import (
"fmt"
"io/ioutil"
"net/http"
"os"
"strings"
"github.com/armosec/kubescape/cautils/opapolicy"
@@ -12,6 +13,8 @@ import (
const DefaultLocalStore = ".kubescape"
var path string
type IPolicyGetter interface {
GetFramework(name string) (*opapolicy.Framework, error)
}
@@ -33,6 +36,15 @@ func NewDownloadReleasedPolicy() *DownloadReleasedPolicy {
}
}
func SaveFrameworkInFile(framework *opapolicy.Framework, path string) error {
encodedData, _ := json.Marshal(framework)
err := os.WriteFile(path, []byte(fmt.Sprintf("%v", string(encodedData))), 0644)
if err != nil {
return err
}
return nil
}
func (drp *DownloadReleasedPolicy) GetFramework(name string) (*opapolicy.Framework, error) {
drp.setURL(name)
respStr, err := HttpGetter(drp.httpClient, drp.hostURL)
@@ -42,13 +54,56 @@ func (drp *DownloadReleasedPolicy) GetFramework(name string) (*opapolicy.Framewo
framework := &opapolicy.Framework{}
err = JSONDecoder(respStr).Decode(framework)
// SaveFrameworkInFile(framework)
// store in file
//
/*
1. Public save framework function (framework, path) error
2. Call the function from Download And GetFramework
3. export to function: os.Join($HOME, getter.DefaultLocalStore, <name>.json)
*/
return framework, err
}
func (drp *DownloadReleasedPolicy) setURL(frameworkName string) {
// requestURI := "v1/armoFrameworks"
func (drp *DownloadReleasedPolicy) setURL(frameworkName string) error {
resp, err := http.Get("https://api.github.com/repos/armosec/regolibrary/releases/latest")
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode < 200 || 301 < resp.StatusCode {
return fmt.Errorf("failed to download file, status code: %s", resp.Status)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
var data map[string]interface{}
err = json.Unmarshal(body, &data)
if err != nil {
return err
}
if assets, ok := data["assets"].([]interface{}); ok {
for i := range assets {
if asset, ok := assets[i].(map[string]interface{}); ok {
if name, ok := asset["name"].(string); ok {
if name == frameworkName {
if url, ok := asset["browser_download_url"].(string); ok {
drp.hostURL = url
}
}
}
}
}
}
return nil
// drp.hostURL = URLEncoder(fmt.Sprintf("%s/%s", drp.hostURL, requestURI))
}
// =======================================================================================================================
+25 -2
View File
@@ -10,6 +10,8 @@ import (
type ScanInfo struct {
PolicyGetter getter.IPolicyGetter
PolicyIdentifier opapolicy.PolicyIdentifier
UseFrom string
UseDefault bool
Format string
Output string
ExcludedNamespaces string
@@ -19,13 +21,34 @@ type ScanInfo struct {
func (scanInfo *ScanInfo) Init() {
// scanInfo.setSilentMode()
scanInfo.setUseFrom()
scanInfo.setOutputFile()
scanInfo.setGetter()
}
func (scanInfo *ScanInfo) setGetter() {
scanInfo.PolicyGetter = getter.NewArmoAPI()
func (scanInfo *ScanInfo) setUseFrom() {
if scanInfo.UseFrom != "" {
return
}
if scanInfo.UseDefault {
scanInfo.UseFrom = GetDefaultPath(scanInfo.PolicyIdentifier.Name)
}
}
func (scanInfo *ScanInfo) setGetter() {
// // get from armo backend
// scanInfo.PolicyGetter = getter.NewArmoAPI()
if scanInfo.UseFrom != "" {
// load from file
scanInfo.PolicyGetter = getter.NewLoadPolicy(scanInfo.UseFrom)
} else {
scanInfo.PolicyGetter = getter.NewDownloadReleasedPolicy()
}
}
func (scanInfo *ScanInfo) setSilentMode() {
if scanInfo.Format == "json" || scanInfo.Format == "junit" {
scanInfo.Silent = true
+55
View File
@@ -0,0 +1,55 @@
package cmd
import (
"fmt"
"os"
"path/filepath"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/cautils/getter"
"github.com/spf13/cobra"
)
var downloadInfo cautils.DownloadInfo
var downloadCmd = &cobra.Command{
Use: "download framework <framework-name>",
Short: "Download framework controls",
Long: ``,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) != 2 {
return fmt.Errorf("requires two arguments : framework <framework-name>")
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
downloadInfo.FrameworkName = args[1]
g := getter.NewDownloadReleasedPolicy()
if !(cmd.Flags().Lookup("output").Changed) {
downloadInfo.Path = cautils.GetDefaultPath(downloadInfo.FrameworkName)
} else {
currPath, err := os.Getwd()
if err != nil {
downloadInfo.Path = filepath.Join(downloadInfo.Path)
} else {
downloadInfo.Path = filepath.Join(currPath, downloadInfo.Path)
}
}
frameworks, err := g.GetFramework(downloadInfo.FrameworkName)
if err != nil {
return err
}
err = getter.SaveFrameworkInFile(frameworks, downloadInfo.Path)
if err != nil {
return err
}
return nil
},
}
func init() {
rootCmd.AddCommand(downloadCmd)
downloadInfo = cautils.DownloadInfo{}
downloadCmd.Flags().StringVarP(&downloadInfo.Path, "output", "o", "", "Output file.")
}
+6 -2
View File
@@ -33,7 +33,7 @@ var frameworkCmd = &cobra.Command{
Long: "Execute a scan on a running Kubernetes cluster or `yaml`/`json` files (use glob) or `-` for stdin",
ValidArgs: supportedFrameworks,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
if len(args) < 1 && !(cmd.Flags().Lookup("use-from").Changed) {
return fmt.Errorf("requires at least one argument")
}
if !isValidFramework(args[0]) {
@@ -44,8 +44,10 @@ var frameworkCmd = &cobra.Command{
RunE: func(cmd *cobra.Command, args []string) error {
scanInfo.PolicyIdentifier = opapolicy.PolicyIdentifier{}
scanInfo.PolicyIdentifier.Kind = opapolicy.KindFramework
scanInfo.PolicyIdentifier.Name = args[0]
if !(cmd.Flags().Lookup("use-from").Changed) {
scanInfo.PolicyIdentifier.Name = args[0]
}
if len(args[1:]) == 0 || args[1] != "-" {
scanInfo.InputPatterns = args[1:]
} else { // store stout to file
@@ -75,6 +77,8 @@ func isValidFramework(framework string) bool {
func init() {
scanCmd.AddCommand(frameworkCmd)
scanInfo = cautils.ScanInfo{}
frameworkCmd.Flags().StringVarP(&scanInfo.UseFrom, "use-from", "", "", "Path to load framework from")
frameworkCmd.Flags().BoolVarP(&scanInfo.UseDefault, "use-default", "", false, "Load framework from default path")
frameworkCmd.Flags().StringVarP(&scanInfo.ExcludedNamespaces, "exclude-namespaces", "e", "", "Namespaces to exclude from check")
frameworkCmd.Flags().StringVarP(&scanInfo.Format, "format", "f", "pretty-printer", `Output format. supported formats: "pretty-printer"/"json"/"junit"`)
frameworkCmd.Flags().StringVarP(&scanInfo.Output, "output", "o", "", "Output file. print output to file and not stdout")
+25 -1
View File
@@ -50,6 +50,18 @@ kubescape scan framework nsa https://raw.githubusercontent.com/GoogleCloudPlatfo
helm template [CHART] [flags] --generate-name --dry-run | kubescape scan framework nsa -
```
### Scan on-prem (offline)
* Scan using a framework from the local file system
```
kubescape scan framework --use-from <path>
```
* Scan using the framework from the default location in file system
```
kubescape scan framework --use-default
```
## Output formats
By default, the output is user friendly.
@@ -64,4 +76,16 @@ kubescape scan framework nsa --format json --output results.json
* Output in `junit xml` format <img src="new-feature.svg">
```
kubescape scan framework nsa --format junit --output results.xml
```
```
## Download
* Download and save in file <img src="new-feature.svg">
```
kubescape download framework nsa --output nsa.json
```
* Download and save in default file (`~/.kubescape/<framework name>.json`)
```
kubescape download framework nsa
```
+1 -1
View File
@@ -25,7 +25,7 @@ func (policyHandler *PolicyHandler) GetPoliciesFromBackend(notification *opapoli
}
default:
err := fmt.Errorf("Missing rule kind, expected: %s", opapolicy.KindFramework)
err := fmt.Errorf("missing rule kind, expected: %s", opapolicy.KindFramework)
errs = fmt.Errorf("%s", err.Error())
}