Compare commits

..

54 Commits

Author SHA1 Message Date
Ben Hirschberg
2fb2ab02c4 Merge pull request #558 from armosec/dev
Support helm chart scanning and reporting
2022-07-06 10:37:14 +03:00
David Wertenteil
1a94004de4 Merge pull request #557 from dwertent/master
Fixed windows support, update limit size
2022-07-05 16:27:18 +03:00
David Wertenteil
424f2cc403 update report size limit to 4mb 2022-07-05 15:13:02 +03:00
David Wertenteil
eab77a9e61 Merge pull request #556 from dwertent/master
Helm scanning support
2022-07-05 12:16:18 +03:00
David Wertenteil
fc78d9143b use filepath join in unitests 2022-07-05 11:44:07 +03:00
David Wertenteil
034dbca30c update go mod 2022-07-05 11:20:44 +03:00
David Wertenteil
a41adc6c9e update readme 2022-07-05 11:13:39 +03:00
David Wertenteil
bd170938c5 update readme 2022-07-05 11:12:58 +03:00
David Wertenteil
e91a73a32e validate no workloads found 2022-07-05 11:11:17 +03:00
David Wertenteil
099886e1bb mixed merge 2022-07-05 10:34:33 +03:00
David Wertenteil
c05dc8d7ae Merge pull request #548 from amirmalka/dev
helm chart scanning
2022-07-05 09:53:55 +03:00
David Wertenteil
3cebfb3065 Merge branch 'dev' into dev 2022-07-05 09:51:32 +03:00
David Wertenteil
f7445d1777 Merge pull request #554 from armosec/dev
Handling edge cases when scanning files
2022-06-30 20:36:54 +03:00
David Wertenteil
ed5abd5791 Merge pull request #553 from dwertent/master
Handling edge cases when scanning files
2022-06-30 19:49:43 +03:00
David Wertenteil
898b847211 fixed printer 2022-06-30 19:41:29 +03:00
David Wertenteil
889dd15772 handke invalide files 2022-06-30 19:33:43 +03:00
Bezbran
2ce6c1840b Merge pull request #543 from armosec/dev
Adding repository scanning support
2022-06-30 15:21:19 +03:00
David Wertenteil
d46d77411b Merge pull request #549 from armosec/fileutils-update
remove error when reading yaml
2022-06-29 09:09:27 +03:00
Amir Malka
ee4f4d8af1 remove error when reading yaml
Remove an error if we try to read YAML file which is not a map[string]interface{}
2022-06-28 11:31:11 +03:00
Amir Malka
ea1426a24b helm chart scanning 2022-06-27 17:28:25 +03:00
shm12
bd78e4c4de Merge pull request #546 from shm12/dev
New host sensor resources
2022-06-22 13:44:07 +03:00
shm12
e3f70b6cd6 Added host sensor new resources 2022-06-21 17:55:18 +03:00
David Wertenteil
a5007df1bc Merge pull request #544 from dwertent/master
fixed docker version
2022-06-19 14:43:49 +03:00
David Wertenteil
d6720b67ed fixed docker version 2022-06-19 14:40:48 +03:00
Amir Malka
2261fd6adb Merge pull request #541 from dwertent/master
Final fixes
2022-06-19 14:14:01 +03:00
David Wertenteil
9334ad6991 fixed typo 2022-06-19 14:11:04 +03:00
David Wertenteil
7b5e4143c3 fixed test for win 2022-06-19 12:47:42 +03:00
David Wertenteil
e63e5502cd fixed test 2022-06-19 11:55:47 +03:00
David Wertenteil
154794e774 fixed test 2022-06-19 11:46:43 +03:00
David Wertenteil
4aa71725dd ignore empty file 2022-06-19 11:19:29 +03:00
David Wertenteil
9bd2e7fea4 upgrade go version 2022-06-19 09:05:32 +03:00
David Wertenteil
e6d3e7d7da fixed test 2022-06-19 08:55:56 +03:00
David Wertenteil
35bb15b5df Merge pull request #540 from 06kellyjac/update_and_install_details
update deps and add nix/nixos install details
2022-06-19 08:55:04 +03:00
David Wertenteil
e54d61fd87 Merge pull request #532 from vladklokun/print-results-to-html
feat: Print results to html
2022-06-19 08:48:30 +03:00
06kellyjac
f28b2836c7 add nixos/nix and go install instructions 2022-06-17 18:44:58 +01:00
06kellyjac
d196f1f327 update dependencies 2022-06-17 18:41:53 +01:00
David Wertenteil
995f90ca53 update pkg 2022-06-16 16:41:25 +03:00
David Wertenteil
c1da380c9b fixed test 2022-06-16 12:13:55 +03:00
David Wertenteil
77f77b8c7d update opa pkg 2022-06-16 12:06:52 +03:00
David Wertenteil
b3c1aec461 fixed unitests 2022-06-15 13:43:45 +03:00
Vlad Klokun
af1d5694dc feat: add HTML as an output for scan results 2022-06-14 16:01:07 +03:00
David Wertenteil
a5ac47ff6d Merge pull request #536 from dwertent/master
fixed go mod
2022-06-13 16:13:18 +03:00
David Wertenteil
8385cd0bd7 Merge pull request #535 from dwertent/master
fixed build files
2022-06-12 17:40:25 +03:00
David Wertenteil
9b9ed514c8 Merge pull request #530 from dwertent/master
beta URL support
2022-06-12 17:34:59 +03:00
Rotem Refael
54020d317e Merge pull request #528 from armosec/rotemamsa-patch-1
Update README.md
2022-06-06 13:45:35 +03:00
Rotem Refael
91d1ec6c2f Update README.md 2022-06-06 13:30:22 +03:00
Rotem Refael
1d3fd0dc9d Merge pull request #527 from vladklokun/add-maintenance-message 2022-06-03 19:43:27 +03:00
Vlad Klokun
8a7511cecb chore: add maintenance message 2022-06-03 19:35:33 +03:00
David Wertenteil
0af0c01ec0 Merge pull request #524 from armosec/dev
Quick fix
2022-05-26 12:21:29 +03:00
David Wertenteil
4f1971a63d Merge pull request #520 from armosec/dev
Extend microservice support
2022-05-24 11:07:24 +03:00
Rotem Refael
afb6ea1d9c Merge pull request #507 from armosec/dev
- Adding Lens extension to readme
- Supporting --view flag
2022-05-12 10:26:14 +03:00
David Wertenteil
b3d16875d6 Merge pull request #493 from armosec/dev
Microservice support
2022-05-03 15:14:24 +03:00
Rotem Refael
cf086e6614 Merge pull request #487 from armosec/dev
Remove binary from repo
2022-04-11 17:20:18 +03:00
Rotem Refael
a27d2d41f2 Merge pull request #484 from armosec/dev
CLI improvement release
2022-04-11 15:48:10 +03:00
35 changed files with 2794 additions and 830 deletions

View File

@@ -28,11 +28,11 @@ jobs:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v2
uses: actions/setup-go@v3
with:
go-version: 1.17
go-version: 1.18
# - name: Test cmd pkg
# run: cd cmd && go test -v ./...
- name: Test core pkg

View File

@@ -11,12 +11,11 @@ jobs:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v2
uses: actions/setup-go@v3
with:
go-version: 1.17
go-version: 1.18
# - name: Test cmd pkg
# run: cd cmd && go test -v ./...

View File

@@ -12,12 +12,11 @@ jobs:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v2
uses: actions/setup-go@v3
with:
go-version: 1.17
go-version: 1.18
# - name: Test cmd pkg
# run: cd cmd && go test -v ./...

View File

@@ -28,7 +28,7 @@ Kubescape integrates natively with other DevOps tools, including Jenkins, Circle
# TL;DR
## Install:
```
```sh
curl -s https://raw.githubusercontent.com/armosec/kubescape/master/install.sh | /bin/bash
```
@@ -36,8 +36,12 @@ curl -s https://raw.githubusercontent.com/armosec/kubescape/master/install.sh |
[Install on macOS](#install-on-macos)
[Install on NixOS or Linux/macOS via nix](#install-on-nixos-or-with-nix-community)
[Install using Go](#install-using-go)
## Run:
```
```sh
kubescape scan --submit --enable-host-scan --verbose
```
@@ -101,13 +105,49 @@ Set-ExecutionPolicy RemoteSigned -scope CurrentUser
## Install on macOS
1. ```
1. ```sh
brew tap armosec/kubescape
```
2. ```
2. ```sh
brew install kubescape
```
## Install on NixOS or with nix (Community)
Direct issues installing `kubescape` via `nix` through the channels mentioned [here](https://nixos.wiki/wiki/Support)
You can use `nix` on Linux or macOS and on other platforms unofficially.
Try it out in an ephemeral shell: `nix-shell -p kubescape`
Install declarative as usual
NixOS:
```nix
# your other config ...
environment.systemPackages = with pkgs; [
# your other packages ...
kubescape
];
```
home-manager:
```nix
# your other config ...
home.packages = with pkgs; [
# your other packages ...
kubescape
];
```
Or to your profile (not preferred): `nix-env --install -A nixpkgs.kubescape`
## Install using Go
With a sufficient version of `go` you can install and build with `go install github.com/armosec/kubescape/v2@latest`
## Usage & Examples
### Examples
@@ -147,14 +187,14 @@ kubescape scan --include-namespaces development,staging,production
kubescape scan --exclude-namespaces kube-system,kube-public
```
#### Scan local `yaml`/`json` files before deploying. [Take a look at the demonstration](https://youtu.be/Ox6DaR7_4ZI)
#### Scan local `yaml`/`json` files before deploying. [Take a look at the demonstration](https://youtu.be/Ox6DaR7_4ZI) Submit the results in case the directory is a git repo. [docs](https://hub.armo.cloud/docs/repository-scanning)
```
kubescape scan *.yaml
kubescape scan *.yaml --submit
```
#### Scan kubernetes manifest files from a public github repository
#### Scan kubernetes manifest files from a git repository [and submit the results](https://hub.armo.cloud/docs/repository-scanning)
```
kubescape scan https://github.com/armosec/kubescape
kubescape scan https://github.com/armosec/kubescape --submit
```
#### Display all scanned resources (including the resources who passed)
@@ -193,16 +233,11 @@ kubescape scan --format prometheus
kubescape scan --exceptions examples/exceptions/exclude-kube-namespaces.json
```
#### Scan Helm charts - Render the helm chart using [`helm template`](https://helm.sh/docs/helm/helm_template/) and pass to stdout
#### Scan Helm charts
```
helm template [NAME] [CHART] [flags] --dry-run | kubescape scan -
kubescape scan </path/to/directory> --submit
```
e.g.
```
helm template bitnami/mysql --generate-name --dry-run | kubescape scan -
```
> Kubescape will load the default values file
### Offline/Air-gaped Environment Support

View File

@@ -1,5 +1,4 @@
FROM golang:1.17-alpine as builder
#ENV GOPROXY=https://goproxy.io,direct
FROM golang:1.18-alpine as builder
ARG image_version
ARG client

View File

@@ -72,7 +72,7 @@ func GetScanCommand(ks meta.IKubescape) *cobra.Command {
scanCmd.PersistentFlags().StringVar(&scanInfo.UseArtifactsFrom, "use-artifacts-from", "", "Load artifacts from local directory. If not used will download them")
scanCmd.PersistentFlags().StringVarP(&scanInfo.ExcludedNamespaces, "exclude-namespaces", "e", "", "Namespaces to exclude from scanning. Recommended: kube-system,kube-public")
scanCmd.PersistentFlags().Float32VarP(&scanInfo.FailThreshold, "fail-threshold", "t", 100, "Failure threshold is the percent above which the command fails and returns exit code 1")
scanCmd.PersistentFlags().StringVarP(&scanInfo.Format, "format", "f", "pretty-printer", `Output format. Supported formats: "pretty-printer","json","junit","prometheus","pdf"`)
scanCmd.PersistentFlags().StringVarP(&scanInfo.Format, "format", "f", "pretty-printer", `Output format. Supported formats: "pretty-printer", "json", "junit", "prometheus", "pdf", "html"`)
scanCmd.PersistentFlags().StringVar(&scanInfo.IncludeNamespaces, "include-namespaces", "", "scan specific namespaces. e.g: --include-namespaces ns-a,ns-b")
scanCmd.PersistentFlags().BoolVarP(&scanInfo.Local, "keep-local", "", false, "If you do not want your Kubescape results reported to ARMO backend. Use this flag if you ran with the '--submit' flag in the past and you do not want to submit your current scan results")
scanCmd.PersistentFlags().StringVarP(&scanInfo.Output, "output", "o", "", "Output file. Print output to file and not stdout")

View File

@@ -11,6 +11,7 @@ import (
"github.com/armosec/k8s-interface/workloadinterface"
"github.com/armosec/kubescape/v2/core/cautils/logger"
"github.com/armosec/kubescape/v2/core/cautils/logger/helpers"
"github.com/armosec/opa-utils/objectsenvelopes"
"github.com/armosec/opa-utils/objectsenvelopes/localworkload"
"gopkg.in/yaml.v2"
@@ -28,24 +29,52 @@ const (
JSON_FILE_FORMAT FileFormat = "json"
)
func LoadResourcesFromFiles(input string) (map[string][]workloadinterface.IMetadata, error) {
// LoadResourcesFromHelmCharts scans a given path (recuresively) for helm charts, renders the templates and returns a list of workloads
func LoadResourcesFromHelmCharts(basePath string) map[string][]workloadinterface.IMetadata {
directories, _ := listDirs(basePath)
helmDirectories := make([]string, 0)
for _, dir := range directories {
if ok, _ := IsHelmDirectory(dir); ok {
helmDirectories = append(helmDirectories, dir)
}
}
result := map[string][]workloadinterface.IMetadata{}
for _, helmDir := range helmDirectories {
chart, err := NewHelmChart(helmDir)
if err == nil {
wls, errs := chart.GetWorkloadsWithDefaultValues()
if len(errs) > 0 {
logger.L().Error(fmt.Sprintf("Rendering of Helm chart template failed: %v", errs))
continue
}
for k, v := range wls {
result[k] = v
}
}
}
return result
}
func LoadResourcesFromFiles(input, rootPath string) map[string][]workloadinterface.IMetadata {
files, errs := listFiles(input)
if len(errs) > 0 {
logger.L().Error(fmt.Sprintf("%v", errs))
}
if len(files) == 0 {
return nil, nil
return nil
}
workloads, errs := loadFiles(files)
workloads, errs := loadFiles(rootPath, files)
if len(errs) > 0 {
logger.L().Error(fmt.Sprintf("%v", errs))
}
return workloads, nil
return workloads
}
func loadFiles(filePaths []string) (map[string][]workloadinterface.IMetadata, []error) {
func loadFiles(rootPath string, filePaths []string) (map[string][]workloadinterface.IMetadata, []error) {
workloads := make(map[string][]workloadinterface.IMetadata, 0)
errs := []error{}
for i := range filePaths {
@@ -54,9 +83,15 @@ func loadFiles(filePaths []string) (map[string][]workloadinterface.IMetadata, []
errs = append(errs, err)
continue
}
if len(f) == 0 {
continue // empty file
}
w, e := ReadFile(f, GetFileFormat(filePaths[i]))
errs = append(errs, e...)
if w != nil {
if e != nil {
logger.L().Debug("failed to read file", helpers.String("file", filePaths[i]), helpers.Error(e))
}
if len(w) != 0 {
path := filePaths[i]
if _, ok := workloads[path]; !ok {
workloads[path] = []workloadinterface.IMetadata{}
@@ -64,7 +99,11 @@ func loadFiles(filePaths []string) (map[string][]workloadinterface.IMetadata, []
wSlice := workloads[path]
for j := range w {
lw := localworkload.NewLocalWorkload(w[j].GetObject())
lw.SetPath(path)
if relPath, err := filepath.Rel(rootPath, path); err == nil {
lw.SetPath(relPath)
} else {
lw.SetPath(path)
}
wSlice = append(wSlice, lw)
}
workloads[path] = wSlice
@@ -76,22 +115,30 @@ func loadFiles(filePaths []string) (map[string][]workloadinterface.IMetadata, []
func loadFile(filePath string) ([]byte, error) {
return os.ReadFile(filePath)
}
func ReadFile(fileContent []byte, fileFromat FileFormat) ([]workloadinterface.IMetadata, []error) {
func ReadFile(fileContent []byte, fileFormat FileFormat) ([]workloadinterface.IMetadata, error) {
switch fileFromat {
switch fileFormat {
case YAML_FILE_FORMAT:
return readYamlFile(fileContent)
case JSON_FILE_FORMAT:
return readJsonFile(fileContent)
default:
return nil, nil // []error{fmt.Errorf("file extension %s not supported", fileFromat)}
return nil, nil
}
}
// listFiles returns the list of absolute paths, full file path and list of errors. The list of abs paths and full path have the same length
func listFiles(pattern string) ([]string, []error) {
return listFilesOrDirectories(pattern, false)
}
var files []string
// listDirs returns the list of absolute paths, full directories path and list of errors. The list of abs paths and full path have the same length
func listDirs(pattern string) ([]string, []error) {
return listFilesOrDirectories(pattern, true)
}
func listFilesOrDirectories(pattern string, onlyDirectories bool) ([]string, []error) {
var paths []string
errs := []error{}
if !filepath.IsAbs(pattern) {
@@ -99,9 +146,9 @@ func listFiles(pattern string) ([]string, []error) {
pattern = filepath.Join(o, pattern)
}
if IsFile(pattern) {
files = append(files, pattern)
return files, errs
if !onlyDirectories && IsFile(pattern) {
paths = append(paths, pattern)
return paths, errs
}
root, shouldMatch := filepath.Split(pattern)
@@ -114,18 +161,18 @@ func listFiles(pattern string) ([]string, []error) {
shouldMatch = "*"
}
f, err := glob(root, shouldMatch)
f, err := glob(root, shouldMatch, onlyDirectories)
if err != nil {
errs = append(errs, err)
} else {
files = append(files, f...)
paths = append(paths, f...)
}
return files, errs
return paths, errs
}
func readYamlFile(yamlFile []byte) ([]workloadinterface.IMetadata, []error) {
errs := []error{}
func readYamlFile(yamlFile []byte) ([]workloadinterface.IMetadata, error) {
defer recover()
r := bytes.NewReader(yamlFile)
dec := yaml.NewDecoder(r)
@@ -145,19 +192,17 @@ func readYamlFile(yamlFile []byte) ([]workloadinterface.IMetadata, []error) {
yamlObjs = append(yamlObjs, o)
}
}
} else {
errs = append(errs, fmt.Errorf("failed to convert yaml file to map[string]interface, file content: %v", j))
}
}
return yamlObjs, errs
return yamlObjs, nil
}
func readJsonFile(jsonFile []byte) ([]workloadinterface.IMetadata, []error) {
func readJsonFile(jsonFile []byte) ([]workloadinterface.IMetadata, error) {
workloads := []workloadinterface.IMetadata{}
var jsonObj interface{}
if err := json.Unmarshal(jsonFile, &jsonObj); err != nil {
return workloads, []error{err}
return workloads, err
}
convertJsonToWorkload(jsonObj, &workloads)
@@ -203,13 +248,27 @@ func IsJson(filePath string) bool {
return StringInSlice(JSON_PREFIX, strings.ReplaceAll(filepath.Ext(filePath), ".", "")) != ValueNotFound
}
func glob(root, pattern string) ([]string, error) {
func glob(root, pattern string, onlyDirectories bool) ([]string, error) {
var matches []string
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// listing only directotries
if onlyDirectories {
if info.IsDir() {
if matched, err := filepath.Match(pattern, filepath.Base(path)); err != nil {
return err
} else if matched {
matches = append(matches, path)
}
}
return nil
}
// listing only files
if info.IsDir() {
return nil
}
@@ -222,6 +281,7 @@ func glob(root, pattern string) ([]string, error) {
} else if matched {
matches = append(matches, path)
}
return nil
})
if err != nil {

View File

@@ -6,12 +6,18 @@ import (
"strings"
"testing"
"github.com/armosec/opa-utils/objectsenvelopes/localworkload"
"github.com/stretchr/testify/assert"
)
func onlineBoutiquePath() string {
o, _ := os.Getwd()
return filepath.Join(filepath.Dir(o), "../examples/online-boutique/*")
return filepath.Join(filepath.Dir(o), "..", "examples", "online-boutique")
}
func helmChartPath() string {
o, _ := os.Getwd()
return filepath.Join(filepath.Dir(o), "..", "examples", "helm_chart")
}
func TestListFiles(t *testing.T) {
@@ -24,41 +30,75 @@ func TestListFiles(t *testing.T) {
}
func TestLoadResourcesFromFiles(t *testing.T) {
workloads, err := LoadResourcesFromFiles(onlineBoutiquePath())
assert.NoError(t, err)
workloads := LoadResourcesFromFiles(onlineBoutiquePath(), "")
assert.Equal(t, 12, len(workloads))
for i, w := range workloads {
switch filepath.Base(i) {
case "adservice.yaml":
assert.Equal(t, 2, len(w))
assert.Equal(t, "apps/v1//Deployment/adservice", w[0].GetID())
assert.Equal(t, "/v1//Service/adservice", w[1].GetID())
assert.Equal(t, "apps/v1//Deployment/adservice", getRelativePath(w[0].GetID()))
assert.Equal(t, "/v1//Service/adservice", getRelativePath(w[1].GetID()))
}
}
}
func TestLoadResourcesFromHelmCharts(t *testing.T) {
sourceToWorkloads := LoadResourcesFromHelmCharts(helmChartPath())
assert.Equal(t, 6, len(sourceToWorkloads))
for file, workloads := range sourceToWorkloads {
assert.Equalf(t, 1, len(workloads), "expected 1 workload in file %s", file)
w := workloads[0]
assert.True(t, localworkload.IsTypeLocalWorkload(w.GetObject()), "Expected localworkload as object type")
switch filepath.Base(file) {
case "serviceaccount.yaml":
assert.Equal(t, "/v1//ServiceAccount/kubescape-discovery", getRelativePath(w.GetID()))
case "clusterrole.yaml":
assert.Equal(t, "rbac.authorization.k8s.io/v1//ClusterRole/-kubescape", getRelativePath(w.GetID()))
case "cronjob.yaml":
assert.Equal(t, "batch/v1//CronJob/-kubescape", getRelativePath(w.GetID()))
case "role.yaml":
assert.Equal(t, "rbac.authorization.k8s.io/v1//Role/-kubescape", getRelativePath(w.GetID()))
case "rolebinding.yaml":
assert.Equal(t, "rbac.authorization.k8s.io/v1//RoleBinding/-kubescape", getRelativePath(w.GetID()))
case "clusterrolebinding.yaml":
assert.Equal(t, "rbac.authorization.k8s.io/v1//ClusterRoleBinding/-kubescape", getRelativePath(w.GetID()))
default:
assert.Failf(t, "missing case for file: %s", filepath.Base(file))
}
}
}
func TestLoadFiles(t *testing.T) {
files, _ := listFiles(onlineBoutiquePath())
_, err := loadFiles(files)
_, err := loadFiles("", files)
assert.Equal(t, 0, len(err))
}
func TestListDirs(t *testing.T) {
dirs, _ := listDirs(filepath.Join(onlineBoutiquePath(), "adservice.yaml"))
assert.Equal(t, 0, len(dirs))
expectedDirs := []string{filepath.Join("examples", "helm_chart"), filepath.Join("examples", "helm_chart", "templates")}
dirs, _ = listDirs(helmChartPath())
assert.Equal(t, len(expectedDirs), len(dirs))
for i := range expectedDirs {
assert.Contains(t, dirs[i], expectedDirs[i])
}
}
func TestLoadFile(t *testing.T) {
files, _ := listFiles(strings.Replace(onlineBoutiquePath(), "*", "adservice.yaml", 1))
files, _ := listFiles(filepath.Join(onlineBoutiquePath(), "adservice.yaml"))
assert.Equal(t, 1, len(files))
_, err := loadFile(files[0])
assert.NoError(t, err)
}
func TestMapResources(t *testing.T) {
// policyHandler := &PolicyHandler{}
// k8sResources, err := policyHandler.loadResources(opaSessionObj.Frameworks, scanInfo)
// files, _ := listFiles([]string{onlineBoutiquePath()})
// bb, err := loadFile(files[0])
// if len(err) > 0 {
// t.Errorf("%v", err)
// }
// for i := range bb {
// t.Errorf("%s", bb[i].ToString())
// }
func getRelativePath(p string) string {
pp := strings.SplitAfter(p, "api=")
return pp[1]
}

View File

@@ -34,7 +34,7 @@ var (
armoDevERURL = "report.eudev3.cyberarmorsoft.com"
armoDevBEURL = "api-dev.armo.cloud"
armoDevFEURL = "armoui-dev.eudev3.cyberarmorsoft.com"
armoDevFEURL = "cloud-dev.armosec.io"
armoDevAUTHURL = "eggauth.eudev3.cyberarmorsoft.com"
)

91
core/cautils/helmchart.go Normal file
View File

@@ -0,0 +1,91 @@
package cautils
import (
"path/filepath"
"strings"
"github.com/armosec/k8s-interface/workloadinterface"
"github.com/armosec/kubescape/v2/core/cautils/logger"
"github.com/armosec/kubescape/v2/core/cautils/logger/helpers"
"github.com/armosec/opa-utils/objectsenvelopes/localworkload"
helmchart "helm.sh/helm/v3/pkg/chart"
helmloader "helm.sh/helm/v3/pkg/chart/loader"
helmchartutil "helm.sh/helm/v3/pkg/chartutil"
helmengine "helm.sh/helm/v3/pkg/engine"
)
type HelmChart struct {
chart *helmchart.Chart
path string
}
func IsHelmDirectory(path string) (bool, error) {
return helmchartutil.IsChartDir(path)
}
func NewHelmChart(path string) (*HelmChart, error) {
chart, err := helmloader.Load(path)
if err != nil {
return nil, err
}
return &HelmChart{
chart: chart,
path: path,
}, nil
}
func (hc *HelmChart) GetName() string {
return hc.chart.Name()
}
func (hc *HelmChart) GetDefaultValues() map[string]interface{} {
return hc.chart.Values
}
// GetWorkloads renders chart template using the default values and returns a map of source file to its workloads
func (hc *HelmChart) GetWorkloadsWithDefaultValues() (map[string][]workloadinterface.IMetadata, []error) {
return hc.GetWorkloads(hc.GetDefaultValues())
}
// GetWorkloads renders chart template using the provided values and returns a map of source (absolute) file path to its workloads
func (hc *HelmChart) GetWorkloads(values map[string]interface{}) (map[string][]workloadinterface.IMetadata, []error) {
vals, err := helmchartutil.ToRenderValues(hc.chart, values, helmchartutil.ReleaseOptions{}, nil)
if err != nil {
return nil, []error{err}
}
sourceToFile, err := helmengine.Render(hc.chart, vals)
if err != nil {
return nil, []error{err}
}
workloads := make(map[string][]workloadinterface.IMetadata, 0)
errs := []error{}
for path, renderedYaml := range sourceToFile {
if !IsYaml(strings.ToLower(path)) {
continue
}
wls, e := ReadFile([]byte(renderedYaml), YAML_FILE_FORMAT)
if e != nil {
logger.L().Debug("failed to read rendered yaml file", helpers.String("file", path), helpers.Error(e))
}
if len(wls) == 0 {
continue
}
// separate base path and file name. We do not use the os.Separator because the paths returned from the helm engine are not OS specific (e.g. mychart/templates/myfile.yaml)
if firstPathSeparatorIndex := strings.Index(path, string("/")); firstPathSeparatorIndex != -1 {
absPath := filepath.Join(hc.path, path[firstPathSeparatorIndex:])
workloads[absPath] = []workloadinterface.IMetadata{}
for i := range wls {
lw := localworkload.NewLocalWorkload(wls[i].GetObject())
lw.SetPath(absPath)
workloads[absPath] = append(workloads[absPath], lw)
}
}
}
return workloads, errs
}

View File

@@ -0,0 +1,133 @@
package cautils
import (
_ "embed"
"encoding/json"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"github.com/armosec/opa-utils/objectsenvelopes/localworkload"
"github.com/stretchr/testify/suite"
)
type HelmChartTestSuite struct {
suite.Suite
helmChartPath string
expectedFiles []string
expectedDefaultValues map[string]interface{}
}
func TestHelmChartTestSuite(t *testing.T) {
suite.Run(t, new(HelmChartTestSuite))
}
func (s *HelmChartTestSuite) SetupSuite() {
o, _ := os.Getwd()
s.helmChartPath = filepath.Join(filepath.Dir(o), "..", "examples", "helm_chart")
s.expectedFiles = []string{
filepath.Join(s.helmChartPath, "templates", "clusterrolebinding.yaml"),
filepath.Join(s.helmChartPath, "templates", "clusterrole.yaml"),
filepath.Join(s.helmChartPath, "templates", "serviceaccount.yaml"),
filepath.Join(s.helmChartPath, "templates", "rolebinding.yaml"),
filepath.Join(s.helmChartPath, "templates", "role.yaml"),
filepath.Join(s.helmChartPath, "templates", "cronjob.yaml"),
}
var obj interface{}
file, _ := ioutil.ReadFile(filepath.Join("testdata", "helm_expected_default_values.json"))
_ = json.Unmarshal([]byte(file), &obj)
s.expectedDefaultValues = obj.(map[string]interface{})
}
func (s *HelmChartTestSuite) TestInvalidHelmDirectory() {
_, err := NewHelmChart("/invalid_path")
s.Error(err)
}
func (s *HelmChartTestSuite) TestValidHelmDirectory() {
chart, err := NewHelmChart(s.helmChartPath)
s.NoError(err)
s.NotNil(chart)
}
func (s *HelmChartTestSuite) TestGetName() {
chart, _ := NewHelmChart(s.helmChartPath)
s.Equal("kubescape", chart.GetName())
}
func (s *HelmChartTestSuite) TestGetDefaultValues() {
chart, _ := NewHelmChart(s.helmChartPath)
values := chart.GetDefaultValues()
valuesJson, _ := json.Marshal(values)
expectedValuesJson, _ := json.Marshal(s.expectedDefaultValues)
s.JSONEq(string(valuesJson), string(expectedValuesJson))
}
func (s *HelmChartTestSuite) TestGetWorkloadsWithOverride() {
chart, err := NewHelmChart(s.helmChartPath)
s.NoError(err, "Expected a valid helm chart")
values := chart.GetDefaultValues()
// Default pullPolicy value = Always
pullPolicyValue := values["image"].(map[string]interface{})["pullPolicy"].(string)
s.Equal(pullPolicyValue, "Always")
// Override default value
values["image"].(map[string]interface{})["pullPolicy"] = "Never"
fileToWorkloads, errs := chart.GetWorkloads(values)
s.Len(errs, 0)
s.Lenf(fileToWorkloads, len(s.expectedFiles), "Expected %d files", len(s.expectedFiles))
for _, expectedFile := range s.expectedFiles {
s.Contains(fileToWorkloads, expectedFile)
s.FileExists(expectedFile)
s.GreaterOrEqualf(len(fileToWorkloads[expectedFile]), 1, "Expected at least one workload in %q", expectedFile)
for i := range fileToWorkloads[expectedFile] {
pathInWorkload := fileToWorkloads[expectedFile][i].(*localworkload.LocalWorkload).GetPath()
s.Equal(pathInWorkload, expectedFile, "Expected GetPath() to return a valid path on workload")
}
if strings.Contains(expectedFile, "cronjob.yaml") {
jsonBytes, _ := json.Marshal(fileToWorkloads[expectedFile][0].GetObject())
s.Contains(string(jsonBytes), "\"imagePullPolicy\":\"Never\"", "Expected to overriden value of imagePullPolicy to be 'Never'")
}
}
}
func (s *HelmChartTestSuite) TestGetWorkloadsMissingValue() {
chart, _ := NewHelmChart(s.helmChartPath)
values := chart.GetDefaultValues()
delete(values, "image")
fileToWorkloads, errs := chart.GetWorkloads(values)
s.Nil(fileToWorkloads)
s.Len(errs, 1, "Expected an error due to missing value")
expectedErrMsg := "<.Values.image.repository>: nil pointer"
s.Containsf(errs[0].Error(), expectedErrMsg, "expected error containing %q, got %q", expectedErrMsg, errs[0])
}
func (s *HelmChartTestSuite) TestIsHelmDirectory() {
ok, err := IsHelmDirectory(s.helmChartPath)
s.True(ok)
s.NoError(err)
o, _ := os.Getwd()
nonHelmDir := filepath.Join(filepath.Dir(o), "../examples/online-boutique")
ok, err = IsHelmDirectory(nonHelmDir)
s.False(ok)
s.Contains(err.Error(), "no Chart.yaml exists in directory")
}

View File

@@ -5,7 +5,6 @@ import (
"fmt"
"io"
"os"
"path"
"path/filepath"
"strings"
"testing"
@@ -62,9 +61,9 @@ func unzipFile(zipPath, destinationFolder string) (*zip.ReadCloser, error) {
}
func (s *LocalGitRepositoryTestSuite) SetupSuite() {
zippedFixturePath := path.Join(".", "testdata", "localrepo.git")
destinationPath := path.Join(".", "testdata", "temp")
gitRepositoryPath := path.Join(destinationPath, "localrepo")
zippedFixturePath := filepath.Join(".", "testdata", "localrepo.git")
destinationPath := filepath.Join(".", "testdata", "temp")
gitRepositoryPath := filepath.Join(destinationPath, "localrepo")
os.RemoveAll(destinationPath)
archive, err := unzipFile(zippedFixturePath, destinationPath)

View File

@@ -18,20 +18,6 @@ func TestSetContextMetadata(t *testing.T) {
assert.Nil(t, ctx.HelmContextMetadata)
assert.Nil(t, ctx.RepoContextMetadata)
}
{
ctx := reporthandlingv2.ContextMetadata{}
setContextMetadata(&ctx, "/file")
assert.Nil(t, ctx.ClusterContextMetadata)
assert.NotNil(t, ctx.DirectoryContextMetadata)
assert.Nil(t, ctx.FileContextMetadata)
assert.Nil(t, ctx.HelmContextMetadata)
assert.Nil(t, ctx.RepoContextMetadata)
hostName := getHostname()
assert.Contains(t, ctx.DirectoryContextMetadata.BasePath, "file")
assert.Equal(t, hostName, ctx.DirectoryContextMetadata.HostName)
}
{
ctx := reporthandlingv2.ContextMetadata{}
setContextMetadata(&ctx, "https://github.com/armosec/kubescape")
@@ -54,8 +40,8 @@ func TestGetHostname(t *testing.T) {
func TestGetScanningContext(t *testing.T) {
assert.Equal(t, ContextCluster, GetScanningContext(""))
assert.Equal(t, ContextDir, GetScanningContext("/"))
assert.Equal(t, ContextGitURL, GetScanningContext("https://github.com/armosec/kubescpae"))
// assert.Equal(t, ContextDir, GetScanningContext("/"))
assert.Equal(t, ContextGitURL, GetScanningContext("https://github.com/armosec/kubescape"))
// assert.Equal(t, ContextFile, GetScanningContext(path.Join(".", "testdata", "localrepo.git")))
// assert.Equal(t, ContextGitLocal, GetScanningContext(path.Join(".", "testdata")))
}

View File

@@ -0,0 +1,40 @@
{
"affinity": {},
"configMap": {
"create": false,
"params": {
"clusterName": "<MyK8sClusterName>",
"customerGUID": "<MyGUID>"
}
},
"fullnameOverride": "",
"image": {
"imageName": "kubescape",
"pullPolicy": "Always",
"repository": "quay.io/armosec",
"tag": "latest"
},
"imagePullSecrets": [],
"nameOverride": "",
"nodeSelector": {},
"podAnnotations": {},
"podSecurityContext": {},
"resources": {
"limits": {
"cpu": "500m",
"memory": "512Mi"
},
"requests": {
"cpu": "200m",
"memory": "256Mi"
}
},
"schedule": "* * 1 * *",
"securityContext": {},
"serviceAccount": {
"annotations": {},
"create": true,
"name": "kubescape-discovery"
},
"tolerations": []
}

View File

@@ -14,7 +14,10 @@ var (
"KernelVersion",
"LinuxSecurityHardeningStatus",
"OpenPortsList",
"LinuxKernelVariables"}
"LinuxKernelVariables",
"KubeletInfo",
"KubeProxyInfo",
}
CloudResources = []string{"ClusterDescribe"}
)

View File

@@ -89,7 +89,7 @@ func (hsh *HostSensorHandler) Init() error {
func (hsh *HostSensorHandler) applyYAML() error {
workloads, err := cautils.ReadFile([]byte(hostSensorYAML), cautils.YAML_FILE_FORMAT)
if len(err) != 0 {
if err != nil {
return fmt.Errorf("failed to read YAML files, reason: %v", err)
}

View File

@@ -109,6 +109,18 @@ func (hsh *HostSensorHandler) GetLinuxSecurityHardeningStatus() ([]hostsensor.Ho
return hsh.sendAllPodsHTTPGETRequest("/linuxSecurityHardening", "LinuxSecurityHardeningStatus")
}
// return list of KubeletInfo
func (hsh *HostSensorHandler) GetKubeletInfo() ([]hostsensor.HostSensorDataEnvelope, error) {
// loop over pods and port-forward it to each of them
return hsh.sendAllPodsHTTPGETRequest("/kubeletInfo", "KubeletInfo")
}
// return list of KubeProxyInfo
func (hsh *HostSensorHandler) GetKubeProxyInfo() ([]hostsensor.HostSensorDataEnvelope, error) {
// loop over pods and port-forward it to each of them
return hsh.sendAllPodsHTTPGETRequest("/kubeProxyInfo", "KubeProxyInfo")
}
// return list of KubeletCommandLine
func (hsh *HostSensorHandler) GetKubeletCommandLine() ([]hostsensor.HostSensorDataEnvelope, error) {
// loop over pods and port-forward it to each of them
@@ -228,6 +240,27 @@ func (hsh *HostSensorHandler) CollectResources() ([]hostsensor.HostSensorDataEnv
if len(kcData) > 0 {
res = append(res, kcData...)
}
// GetKubeletInfo
kcData, err = hsh.GetKubeletInfo()
if err != nil {
addInfoToMap(KubeletInfo, infoMap, err)
logger.L().Warning(err.Error())
}
if len(kcData) > 0 {
res = append(res, kcData...)
}
// GetKubeProxyInfo
kcData, err = hsh.GetKubeProxyInfo()
if err != nil {
addInfoToMap(KubeProxyInfo, infoMap, err)
logger.L().Warning(err.Error())
}
if len(kcData) > 0 {
res = append(res, kcData...)
}
logger.L().Debug("Done reading information from host scanner")
return res, infoMap, nil
}

View File

@@ -13,6 +13,8 @@ var (
OpenPortsList = "OpenPortsList"
LinuxKernelVariables = "LinuxKernelVariables"
KubeletCommandLine = "KubeletCommandLine"
KubeletInfo = "KubeletInfo"
KubeProxyInfo = "KubeProxyInfo"
MapHostSensorResourceToApiGroup = map[string]string{
KubeletConfiguration: "hostdata.kubescape.cloud/v1beta0",
@@ -22,6 +24,8 @@ var (
LinuxSecurityHardeningStatus: "hostdata.kubescape.cloud/v1beta0",
OpenPortsList: "hostdata.kubescape.cloud/v1beta0",
LinuxKernelVariables: "hostdata.kubescape.cloud/v1beta0",
KubeletInfo: "hostdata.kubescape.cloud/v1beta0",
KubeProxyInfo: "hostdata.kubescape.cloud/v1beta0",
}
)

View File

@@ -6,7 +6,6 @@ import (
"path/filepath"
"github.com/armosec/armoapi-go/armotypes"
giturl "github.com/armosec/go-git-url"
"github.com/armosec/k8s-interface/workloadinterface"
"github.com/armosec/opa-utils/reporthandling"
"k8s.io/apimachinery/pkg/version"
@@ -33,6 +32,7 @@ func NewFileResourceHandler(inputPatterns []string, registryAdaptors *RegistryAd
func (fileHandler *FileResourceHandler) GetResources(sessionObj *cautils.OPASessionObj, designator *armotypes.PortalDesignator) (*cautils.K8SResources, map[string]workloadinterface.IMetadata, *cautils.ArmoResources, error) {
//
// build resources map
// map resources based on framework required resources: map["/group/version/kind"][]<k8s workloads ids>
k8sResources := setK8sResourceMap(sessionObj.Policies)
@@ -47,27 +47,13 @@ func (fileHandler *FileResourceHandler) GetResources(sessionObj *cautils.OPASess
}
path := fileHandler.inputPatterns[0]
// Clone git repository if needed
gitURL, err := giturl.NewGitURL(path)
if err == nil {
logger.L().Info("cloning", helpers.String("repository url", gitURL.GetURL().String()))
cautils.StartSpinner()
cloneDir, err := cloneRepo(gitURL)
cautils.StopSpinner()
if err != nil {
return nil, allResources, nil, fmt.Errorf("failed to clone git repo '%s', %w", gitURL.GetURL().String(), err)
}
defer os.RemoveAll(cloneDir)
path = filepath.Join(cloneDir, gitURL.GetPath())
}
// load resource from local file system
logger.L().Info("Accessing local objects")
sourceToWorkloads, err := cautils.LoadResourcesFromFiles(path)
clonedRepo, err := cloneGitRepo(&path)
if err != nil {
return nil, allResources, nil, err
}
if clonedRepo != "" {
defer os.RemoveAll(clonedRepo)
}
// Get repo root
repoRoot := ""
@@ -76,6 +62,12 @@ func (fileHandler *FileResourceHandler) GetResources(sessionObj *cautils.OPASess
repoRoot, _ = giRepo.GetRootDir()
}
// load resource from local file system
logger.L().Info("Accessing local objects")
sourceToWorkloads := cautils.LoadResourcesFromFiles(path, repoRoot)
// update workloads and workloadIDToSource
for source, ws := range sourceToWorkloads {
workloads = append(workloads, ws...)
@@ -84,17 +76,51 @@ func (fileHandler *FileResourceHandler) GetResources(sessionObj *cautils.OPASess
source = relSource
}
for i := range ws {
workloadIDToSource[ws[i].GetID()] = reporthandling.Source{RelativePath: source}
var filetype string
if cautils.IsYaml(source) {
filetype = reporthandling.SourceTypeYaml
} else if cautils.IsJson(source) {
filetype = reporthandling.SourceTypeJson
} else {
continue
}
workloadIDToSource[ws[i].GetID()] = reporthandling.Source{
RelativePath: source,
FileType: filetype,
}
}
}
logger.L().Debug("files found in local storage", helpers.Int("files", len(sourceToWorkloads)), helpers.Int("workloads", len(workloads)))
if len(workloads) == 0 {
logger.L().Debug("files found in local storage", helpers.Int("files", len(sourceToWorkloads)), helpers.Int("workloads", len(workloads)))
}
// load resources from helm charts
helmSourceToWorkloads := cautils.LoadResourcesFromHelmCharts(path)
for source, ws := range helmSourceToWorkloads {
workloads = append(workloads, ws...)
relSource, err := filepath.Rel(repoRoot, source)
if err == nil {
source = relSource
}
for i := range ws {
workloadIDToSource[ws[i].GetID()] = reporthandling.Source{
RelativePath: source,
FileType: reporthandling.SourceTypeHelmChart,
}
}
}
if len(helmSourceToWorkloads) > 0 {
logger.L().Debug("helm templates found in local storage", helpers.Int("helmTemplates", len(helmSourceToWorkloads)), helpers.Int("workloads", len(workloads)))
}
// addCommitData(fileHandler.inputPatterns[0], workloadIDToSource)
if len(workloads) == 0 {
return nil, allResources, nil, fmt.Errorf("empty list of workloads - no workloads found")
}
logger.L().Debug("files found in git repo", helpers.Int("files", len(sourceToWorkloads)), helpers.Int("workloads", len(workloads)))
sessionObj.ResourceSource = workloadIDToSource
@@ -125,54 +151,3 @@ func (fileHandler *FileResourceHandler) GetResources(sessionObj *cautils.OPASess
func (fileHandler *FileResourceHandler) GetClusterAPIServerInfo() *version.Info {
return nil
}
// build resources map
func mapResources(workloads []workloadinterface.IMetadata) map[string][]workloadinterface.IMetadata {
allResources := map[string][]workloadinterface.IMetadata{}
for i := range workloads {
groupVersionResource, err := k8sinterface.GetGroupVersionResource(workloads[i].GetKind())
if err != nil {
// TODO - print warning
continue
}
if k8sinterface.IsTypeWorkload(workloads[i].GetObject()) {
w := workloadinterface.NewWorkloadObj(workloads[i].GetObject())
if groupVersionResource.Group != w.GetGroup() || groupVersionResource.Version != w.GetVersion() {
// TODO - print warning
continue
}
}
resourceTriplets := k8sinterface.JoinResourceTriplets(groupVersionResource.Group, groupVersionResource.Version, groupVersionResource.Resource)
if r, ok := allResources[resourceTriplets]; ok {
allResources[resourceTriplets] = append(r, workloads[i])
} else {
allResources[resourceTriplets] = []workloadinterface.IMetadata{workloads[i]}
}
}
return allResources
}
func addCommitData(input string, workloadIDToSource map[string]reporthandling.Source) {
giRepo, err := cautils.NewLocalGitRepository(input)
if err != nil {
return
}
for k := range workloadIDToSource {
sourceObj := workloadIDToSource[k]
lastCommit, err := giRepo.GetFileLastCommit(sourceObj.RelativePath)
if err != nil {
continue
}
sourceObj.LastCommit = reporthandling.LastCommit{
Hash: lastCommit.SHA,
Date: lastCommit.Author.Date,
CommitterName: lastCommit.Author.Name,
CommitterEmail: lastCommit.Author.Email,
Message: lastCommit.Message,
}
workloadIDToSource[k] = sourceObj
}
}

View File

@@ -0,0 +1,86 @@
package resourcehandler
import (
"fmt"
"path/filepath"
giturl "github.com/armosec/go-git-url"
"github.com/armosec/k8s-interface/k8sinterface"
"github.com/armosec/k8s-interface/workloadinterface"
"github.com/armosec/kubescape/v2/core/cautils"
"github.com/armosec/kubescape/v2/core/cautils/logger"
"github.com/armosec/kubescape/v2/core/cautils/logger/helpers"
"github.com/armosec/opa-utils/reporthandling"
)
// Clone git repository
func cloneGitRepo(path *string) (string, error) {
var clonedDir string
// Clone git repository if needed
gitURL, err := giturl.NewGitURL(*path)
if err == nil {
logger.L().Info("cloning", helpers.String("repository url", gitURL.GetURL().String()))
cautils.StartSpinner()
clonedDir, err = cloneRepo(gitURL)
cautils.StopSpinner()
if err != nil {
return "", fmt.Errorf("failed to clone git repo '%s', %w", gitURL.GetURL().String(), err)
}
*path = filepath.Join(clonedDir, gitURL.GetPath())
}
return clonedDir, nil
}
// build resources map
func mapResources(workloads []workloadinterface.IMetadata) map[string][]workloadinterface.IMetadata {
allResources := map[string][]workloadinterface.IMetadata{}
for i := range workloads {
groupVersionResource, err := k8sinterface.GetGroupVersionResource(workloads[i].GetKind())
if err != nil {
// TODO - print warning
continue
}
if k8sinterface.IsTypeWorkload(workloads[i].GetObject()) {
w := workloadinterface.NewWorkloadObj(workloads[i].GetObject())
if groupVersionResource.Group != w.GetGroup() || groupVersionResource.Version != w.GetVersion() {
// TODO - print warning
continue
}
}
resourceTriplets := k8sinterface.JoinResourceTriplets(groupVersionResource.Group, groupVersionResource.Version, groupVersionResource.Resource)
if r, ok := allResources[resourceTriplets]; ok {
allResources[resourceTriplets] = append(r, workloads[i])
} else {
allResources[resourceTriplets] = []workloadinterface.IMetadata{workloads[i]}
}
}
return allResources
}
func addCommitData(input string, workloadIDToSource map[string]reporthandling.Source) {
giRepo, err := cautils.NewLocalGitRepository(input)
if err != nil {
return
}
for k := range workloadIDToSource {
sourceObj := workloadIDToSource[k]
lastCommit, err := giRepo.GetFileLastCommit(sourceObj.RelativePath)
if err != nil {
continue
}
sourceObj.LastCommit = reporthandling.LastCommit{
Hash: lastCommit.SHA,
Date: lastCommit.Author.Date,
CommitterName: lastCommit.Author.Name,
CommitterEmail: lastCommit.Author.Email,
Message: lastCommit.Message,
}
workloadIDToSource[k] = sourceObj
}
}

View File

@@ -20,6 +20,8 @@ var (
LinuxKernelVariables = "LinuxKernelVariables"
KubeletCommandLine = "KubeletCommandLine"
ImageVulnerabilities = "ImageVulnerabilities"
KubeletInfo = "KubeletInfo"
KubeProxyInfo = "KubeProxyInfo"
MapResourceToApiGroup = map[string]string{
KubeletConfiguration: "hostdata.kubescape.cloud/v1beta0",
@@ -29,6 +31,8 @@ var (
LinuxSecurityHardeningStatus: "hostdata.kubescape.cloud/v1beta0",
OpenPortsList: "hostdata.kubescape.cloud/v1beta0",
LinuxKernelVariables: "hostdata.kubescape.cloud/v1beta0",
KubeletInfo: "hostdata.kubescape.cloud/v1beta0",
KubeProxyInfo: "hostdata.kubescape.cloud/v1beta0",
}
MapResourceToApiGroupVuln = map[string][]string{
ImageVulnerabilities: {"armo.vuln.images/v1", "image.vulnscan.com/v1"}}

View File

@@ -33,7 +33,7 @@ func loadResourcesFromUrl(inputPatterns []string) (map[string][]workloadinterfac
for i, j := range files {
w, e := cautils.ReadFile(j, cautils.GetFileFormat(i))
if len(e) != 0 || len(w) == 0 {
if e != nil || len(w) == 0 {
continue
}
if _, ok := workloads[i]; !ok {

View File

@@ -17,6 +17,7 @@ const (
JunitResultFormat string = "junit"
PrometheusFormat string = "prometheus"
PdfFormat string = "pdf"
HtmlFormat string = "html"
)
type IPrinter interface {

View File

@@ -0,0 +1,154 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<title>Kubescape Scan Report</title>
</head>
<style>
:root {
--cell-padding-vertical: 0.25em;
--cell-padding-horizontal: 0.25em;
--font-family-sans: system-ui, -apple-system, sans-serif;
}
body {
max-width: 60em;
margin: auto;
font-family: var(--font-family-sans);
}
table {
width: 100%;
border-top: 0.1em solid black;
border-bottom: 0.1em solid black;
border-collapse: collapse;
table-layout: fixed;
}
th {
text-align: left;
}
td, th {
padding-top: var(--cell-padding-vertical);
padding-bottom: var(--cell-padding-vertical);
padding-right: var(--cell-padding-horizontal);
vertical-align: top;
}
td > p {
margin: 0;
word-break: break-all;
hyphens: auto;
}
thead {
border-bottom: 0.01em solid black;
}
.numericCell {
text-align: right;
}
.controlSeverityCell {
width: 10%;
}
.controlNameCell {
width: 50%;
}
.controlRiskCell {
width: 10%;
}
.resourceSeverityCell {
width: 10%;
}
.resourceNameCell {
width: 30%;
}
.resourceURLCell {
width: 10%;
}
.resourceRemediationCell {
width: 50%;
}
.logo {
width: 25%;
float: right;
}
</style>
<body>
<img class="logo" src="https://raw.githubusercontent.com/armosec/kubescape/master/core/pkg/resultshandling/printer/v2/pdf/logo.png">
<h1>Kubescape Scan Report</h1>
{{ with .OPASessionObj.Report.SummaryDetails }}
<h2>By Controls</h2>
<h3>Summary</h3>
<table>
<thead>
<tr>
<th>All</th>
<th>Failed</th>
<th>Excluded</th>
<th>Skipped</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ .NumberOfControls.All }}</td>
<td>{{ .NumberOfControls.Failed }}</td>
<td>{{ .NumberOfControls.Excluded }}</td>
<td>{{ .NumberOfControls.Skipped }}</td>
</tr>
</tbody>
</table>
<h3>Details</h3>
<table>
<thead>
<tr>
<th class="controlSeverityCell">Severity</th>
<th class="controlNameCell">Control Name</th>
<th class="controlRiskCell">Failed Resources</th>
<th class="controlRiskCell">Excluded Resources</th>
<th class="controlRiskCell">All Resources</th>
<th class="controlRiskCell">Risk Score, %</th>
</tr>
</thead>
<tbody>
{{ $sorted := sortBySeverityName .Controls }}
{{ range $control := $sorted }}
<tr>
<td class="controlSeverityCell">{{ controlSeverityToString $control.ScoreFactor }}</td>
<td class="controlNameCell">{{ $control.Name }}</td>
<td class="controlRiskCell numericCell">{{ $control.ResourceCounters.FailedResources }}</td>
<td class="controlRiskCell numericCell">{{ $control.ResourceCounters.ExcludedResources }}</td>
<td class="controlRiskCell numericCell">{{ sum $control.ResourceCounters.ExcludedResources $control.ResourceCounters.FailedResources $control.ResourceCounters.PassedResources }}</td>
<td class="controlRiskCell numericCell">{{ float32ToInt $control.Score }}</td>
</tr>
</tr>
{{ end }}
<tbody>
</table>
{{ end }}
<h2>By Resource</h2>
{{ $sortedResourceTableView := sortByNamespace .ResourceTableView }}
{{ range $sortedResourceTableView }}
<h3>Name: {{ .Resource.GetName }}</h3>
<p>ApiVersion: {{ .Resource.GetApiVersion }}</p>
<p>Kind: {{ .Resource.GetKind }}</p>
<p>Name: {{ .Resource.GetName }}</p>
<p>Namespace: {{ .Resource.GetNamespace }}</p>
<table>
<thead>
<tr>
<th class="resourceSeverityCell">Severity</th>
<th class="resourceNameCell">Name</th>
<th class="resourceURLCell">Docs</th>
<th class="resourceRemediationCell">Assistant Remediation</th>
</tr>
</thead>
<tbody>
{{ range .ControlsResult }}
<tr>
<td class="resourceSeverityCell">{{ .Severity }}</td>
<td class="resourceNameCell">{{ .Name }}</td>
<td class="resourceURLCell"><a href="https://hub.armo.cloud/docs/{{ lower .URL }}">{{ .URL }}</a></td>
<td class="resourceRemediationCell">{{ range .FailedPaths }} <p>{{ . }}</p> {{ end }}</td>
</tr>
{{ end }}
</tbody>
</table>
</div>
{{ end }}
</body>
</html>

View File

@@ -0,0 +1,151 @@
package v2
import (
_ "embed"
"html/template"
"os"
"path/filepath"
"sort"
"strings"
"github.com/armosec/kubescape/v2/core/cautils"
"github.com/armosec/kubescape/v2/core/cautils/logger"
"github.com/armosec/kubescape/v2/core/cautils/logger/helpers"
"github.com/armosec/kubescape/v2/core/pkg/resultshandling/printer"
"github.com/armosec/opa-utils/reporthandling/apis"
"github.com/armosec/opa-utils/reporthandling/results/v1/reportsummary"
"github.com/armosec/opa-utils/reporthandling/results/v1/resourcesresults"
)
const (
htmlOutputFile = "report"
htmlOutputExt = ".html"
)
//go:embed html/report.gohtml
var reportTemplate string
type HTMLReportingCtx struct {
OPASessionObj *cautils.OPASessionObj
ResourceTableView ResourceTableView
}
type HtmlPrinter struct {
writer *os.File
}
func NewHtmlPrinter() *HtmlPrinter {
return &HtmlPrinter{}
}
func (htmlPrinter *HtmlPrinter) SetWriter(outputFile string) {
if outputFile == "" {
outputFile = htmlOutputFile
}
if filepath.Ext(strings.TrimSpace(outputFile)) != htmlOutputExt {
outputFile = outputFile + htmlOutputExt
}
htmlPrinter.writer = printer.GetWriter(outputFile)
}
func (htmlPrinter *HtmlPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
tplFuncMap := template.FuncMap{
"sum": func(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
},
"float32ToInt": cautils.Float32ToInt,
"lower": strings.ToLower,
"sortByNamespace": func(resourceTableView ResourceTableView) ResourceTableView {
sortedResourceTableView := make(ResourceTableView, len(resourceTableView))
copy(sortedResourceTableView, resourceTableView)
sort.SliceStable(
sortedResourceTableView,
func(i, j int) bool {
return sortedResourceTableView[i].Resource.GetNamespace() < sortedResourceTableView[j].Resource.GetNamespace()
},
)
return sortedResourceTableView
},
"controlSeverityToString": apis.ControlSeverityToString,
"sortBySeverityName": func(controlSummaries map[string]reportsummary.ControlSummary) []reportsummary.ControlSummary {
sortedSlice := make([]reportsummary.ControlSummary, 0, len(controlSummaries))
for _, val := range controlSummaries {
sortedSlice = append(sortedSlice, val)
}
sort.SliceStable(
sortedSlice,
func(i, j int) bool {
//First sort by Severity descending
iSeverity := apis.ControlSeverityToInt(sortedSlice[i].GetScoreFactor())
jSeverity := apis.ControlSeverityToInt(sortedSlice[j].GetScoreFactor())
if iSeverity > jSeverity {
return true
}
if iSeverity < jSeverity {
return false
}
//And then by Name ascending
return sortedSlice[i].GetName() < sortedSlice[j].GetName()
},
)
return sortedSlice
},
}
tpl := template.Must(
template.New("htmlReport").Funcs(tplFuncMap).Parse(reportTemplate),
)
resourceTableView := buildResourceTableView(opaSessionObj)
reportingCtx := HTMLReportingCtx{opaSessionObj, resourceTableView}
err := tpl.Execute(htmlPrinter.writer, reportingCtx)
if err != nil {
logger.L().Error("failed to render template", helpers.Error(err))
}
}
func (htmlPrinter *HtmlPrinter) Score(score float32) {
return
}
func buildResourceTableView(opaSessionObj *cautils.OPASessionObj) ResourceTableView {
resourceTableView := make(ResourceTableView, 0)
for resourceID, result := range opaSessionObj.ResourcesResult {
if result.GetStatus(nil).IsFailed() {
resource := opaSessionObj.AllResources[resourceID]
ctlResults := buildResourceControlResultTable(result.AssociatedControls, &opaSessionObj.Report.SummaryDetails)
resourceTableView = append(resourceTableView, ResourceResult{resource, ctlResults})
}
}
return resourceTableView
}
func buildResourceControlResult(resourceControl resourcesresults.ResourceAssociatedControl, control reportsummary.IControlSummary) ResourceControlResult {
ctlSeverity := apis.ControlSeverityToString(control.GetScoreFactor())
ctlName := resourceControl.GetName()
ctlURL := resourceControl.GetID()
failedPaths := failedPathsToString(&resourceControl)
return ResourceControlResult{ctlSeverity, ctlName, ctlURL, failedPaths}
}
func buildResourceControlResultTable(resourceControls []resourcesresults.ResourceAssociatedControl, summaryDetails *reportsummary.SummaryDetails) []ResourceControlResult {
var ctlResults []ResourceControlResult
for _, resourceControl := range resourceControls {
if resourceControl.GetStatus(nil).IsFailed() {
control := summaryDetails.Controls.GetControl(reportsummary.EControlCriteriaName, resourceControl.GetName())
ctlResult := buildResourceControlResult(resourceControl, control)
ctlResults = append(ctlResults, ctlResult)
}
}
return ctlResults
}

View File

@@ -49,7 +49,7 @@ type JUnitTestSuite struct {
XMLName xml.Name `xml:"testsuite"`
Name string `xml:"name,attr"` // Full (class) name of the test for non-aggregated testsuite documents. Class name without the package for aggregated testsuites documents. Required
Disabled int `xml:"disabled,attr"` // The total number of disabled tests in the suite. optional. not supported by maven surefire.
Errors int `xml:"errors,attr"` // The total number of tests in the suite that errored
Errors int `xml:"errors,attr"` // The total number of tests in the suite that errors
Failures int `xml:"failures,attr"` // The total number of tests in the suite that failed
Hostname string `xml:"hostname,attr"` // Host on which the tests were executed ? cluster name ?
ID int `xml:"id,attr"` // Starts at 0 for the first testsuite and is incremented by 1 for each following testsuite
@@ -181,7 +181,7 @@ func testsCases(results *cautils.OPASessionObj, controls reportsummary.IControls
testCase.Failure = &testCaseFailure
} else if control.GetStatus().IsSkipped() {
testCase.SkipMessage = &JUnitSkipMessage{
Message: "", // TODO - fill after statusInfo is supportred
Message: "", // TODO - fill after statusInfo is supported
}
}

View File

@@ -188,6 +188,10 @@ func generateFooter(summaryDetails *reportsummary.SummaryDetails) []string {
}
func (prettyPrinter *PrettyPrinter) printSummaryTable(summaryDetails *reportsummary.SummaryDetails, sortedControlNames [][]string) {
if summaryDetails.NumberOfControls().All() == 0 {
fmt.Fprintf(prettyPrinter.writer, "\nKubescape did not scan any of the resources, make sure you are scanning valid kubernetes manifests (Deployments, Pods, etc.)\n")
return
}
cautils.InfoTextDisplay(prettyPrinter.writer, "\n"+controlCountersForSummary(summaryDetails.NumberOfControls())+"\n\n")
summaryTable := tablewriter.NewWriter(prettyPrinter.writer)
@@ -196,10 +200,16 @@ func (prettyPrinter *PrettyPrinter) printSummaryTable(summaryDetails *reportsumm
summaryTable.SetHeaderLine(true)
summaryTable.SetColumnAlignment(getColumnsAlignments())
printAll := prettyPrinter.verboseMode
if summaryDetails.NumberOfResources().Failed() == 0 {
// if there are no failed controls, print the resource table and detailed information
printAll = true
}
infoToPrintInfo := mapInfoToPrintInfo(summaryDetails.Controls)
for i := len(sortedControlNames) - 1; i >= 0; i-- {
for _, c := range sortedControlNames[i] {
row := generateRow(summaryDetails.Controls.GetControl(reportsummary.EControlCriteriaName, c), infoToPrintInfo, prettyPrinter.verboseMode)
row := generateRow(summaryDetails.Controls.GetControl(reportsummary.EControlCriteriaName, c), infoToPrintInfo, printAll)
if len(row) > 0 {
summaryTable.Append(row)
}

View File

@@ -0,0 +1,19 @@
package v2
import (
"github.com/armosec/k8s-interface/workloadinterface"
)
type ResourceTableView []ResourceResult
type ResourceResult struct {
Resource workloadinterface.IMetadata
ControlsResult []ResourceControlResult
}
type ResourceControlResult struct {
Severity string
Name string
URL string
FailedPaths []string
}

View File

@@ -29,7 +29,7 @@ func (prettyPrinter *PrettyPrinter) resourceTable(opaSessionObj *cautils.OPASess
if !ok {
continue
}
fmt.Fprintf(prettyPrinter.writer, fmt.Sprintf("\n%s\n\n", getSeparator("#")))
fmt.Fprintf(prettyPrinter.writer, "\n%s\n", getSeparator("#"))
if source, ok := opaSessionObj.ResourceSource[resourceID]; ok {
fmt.Fprintf(prettyPrinter.writer, "Source: %s\n", source.RelativePath)

View File

@@ -7,18 +7,18 @@ import (
"net/url"
"os"
"github.com/armosec/armoapi-go/apis"
"github.com/armosec/k8s-interface/workloadinterface"
"github.com/armosec/kubescape/v2/core/cautils"
"github.com/armosec/kubescape/v2/core/cautils/getter"
"github.com/armosec/kubescape/v2/core/cautils/logger"
"github.com/armosec/kubescape/v2/core/cautils/logger/helpers"
"github.com/armosec/opa-utils/reporthandling"
"github.com/armosec/opa-utils/reporthandling/results/v1/resourcesresults"
reporthandlingv2 "github.com/armosec/opa-utils/reporthandling/v2"
)
const MAX_REPORT_SIZE = 2097152 // 2 MB
const MAX_REPORT_SIZE = 4000000 // 4 MB
type ReportEventReceiver struct {
httpClient *http.Client
@@ -124,6 +124,7 @@ func (report *ReportEventReceiver) sendResources(host string, opaSessionObj *cau
if err := report.setResults(splittedPostureReport, opaSessionObj.ResourcesResult, &counter, &reportCounter, host); err != nil {
return err
}
return report.sendReport(host, splittedPostureReport, reportCounter, true)
}
func (report *ReportEventReceiver) setResults(reportObj *reporthandlingv2.PostureReport, results map[string]resourcesresults.Result, counter, reportCounter *int, host string) error {
@@ -188,7 +189,7 @@ func (report *ReportEventReceiver) setResources(reportObj *reporthandlingv2.Post
return nil
}
func (report *ReportEventReceiver) sendReport(host string, postureReport *reporthandlingv2.PostureReport, counter int, isLastReport bool) error {
postureReport.PaginationInfo = reporthandlingv2.PaginationMarks{
postureReport.PaginationInfo = apis.PaginationMarks{
ReportNumber: counter,
IsLastReport: isLastReport,
}

View File

@@ -95,6 +95,8 @@ func NewPrinter(printFormat, formatVersion string, verboseMode bool, viewType ca
return printerv2.NewPrometheusPrinter(verboseMode)
case printer.PdfFormat:
return printerv2.NewPdfPrinter()
case printer.HtmlFormat:
return printerv2.NewHtmlPrinter()
default:
return printerv2.NewPrettyPrinter(verboseMode, formatVersion, viewType)
}

156
go.mod
View File

@@ -1,45 +1,46 @@
module github.com/armosec/kubescape/v2
go 1.17
go 1.18
require (
github.com/armosec/armoapi-go v0.0.73
github.com/armosec/armoapi-go v0.0.97
github.com/armosec/go-git-url v0.0.13
github.com/armosec/k8s-interface v0.0.78
github.com/armosec/opa-utils v0.0.148
github.com/armosec/opa-utils v0.0.159
github.com/armosec/rbac-utils v0.0.14
github.com/armosec/utils-go v0.0.5
github.com/armosec/utils-k8s-go v0.0.6
github.com/armosec/utils-go v0.0.7
github.com/armosec/utils-k8s-go v0.0.7
github.com/briandowns/spinner v1.18.1
github.com/enescakir/emoji v1.0.0
github.com/fatih/color v1.13.0
github.com/francoispqt/gojay v1.2.13
github.com/go-git/go-git/v5 v5.4.2
github.com/google/uuid v1.3.0
github.com/johnfercher/maroto v0.36.1
github.com/johnfercher/maroto v0.37.0
github.com/mattn/go-isatty v0.0.14
github.com/olekukonko/tablewriter v0.0.5
github.com/open-policy-agent/opa v0.39.0
github.com/open-policy-agent/opa v0.41.0
github.com/spf13/cobra v1.4.0
github.com/stretchr/testify v1.7.1
github.com/whilp/git-urls v1.0.0
go.uber.org/zap v1.21.0
golang.org/x/mod v0.5.1
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3
gopkg.in/yaml.v2 v2.4.0
k8s.io/api v0.23.5
k8s.io/apimachinery v0.23.5
k8s.io/client-go v0.23.5
helm.sh/helm/v3 v3.9.0
k8s.io/api v0.24.2
k8s.io/apimachinery v0.24.2
k8s.io/client-go v0.24.2
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9
sigs.k8s.io/yaml v1.3.0
)
require (
cloud.google.com/go v0.99.0 // indirect
cloud.google.com/go/container v1.0.0 // indirect
github.com/Azure/azure-sdk-for-go v63.0.0+incompatible // indirect
cloud.google.com/go/compute v1.7.0 // indirect
cloud.google.com/go/container v1.2.0 // indirect
github.com/Azure/azure-sdk-for-go v65.0.0+incompatible // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest v0.11.24 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.18 // indirect
github.com/Azure/go-autorest/autorest v0.11.27 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.20 // indirect
github.com/Azure/go-autorest/autorest/azure/auth v0.5.11 // indirect
github.com/Azure/go-autorest/autorest/azure/cli v0.4.5 // indirect
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
@@ -47,100 +48,117 @@ require (
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/Microsoft/go-winio v0.4.16 // indirect
github.com/BurntSushi/toml v1.0.0 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.1.1 // indirect
github.com/Masterminds/sprig/v3 v3.2.2 // indirect
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/OneOfOne/xxhash v1.2.8 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20220517143526-88bb52951d5b // indirect
github.com/acomagu/bufpipe v1.0.3 // indirect
github.com/aws/aws-sdk-go v1.41.11 // indirect
github.com/aws/aws-sdk-go-v2 v1.12.0 // indirect
github.com/aws/aws-sdk-go-v2/config v1.12.0 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.7.0 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.9.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.1.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.3 // indirect
github.com/aws/aws-sdk-go-v2/service/eks v1.17.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.6.0 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.8.0 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.13.0 // indirect
github.com/aws/smithy-go v1.9.1 // indirect
github.com/agnivade/levenshtein v1.1.1 // indirect
github.com/aws/aws-sdk-go v1.44.36 // indirect
github.com/aws/aws-sdk-go-v2 v1.16.5 // indirect
github.com/aws/aws-sdk-go-v2/config v1.15.11 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.12.6 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.6 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.12 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.6 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.13 // indirect
github.com/aws/aws-sdk-go-v2/service/eks v1.21.2 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.6 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.11.9 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.16.7 // indirect
github.com/aws/smithy-go v1.11.3 // indirect
github.com/boombuler/barcode v1.0.1 // indirect
github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 // indirect
github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490 // indirect
github.com/coreos/go-oidc v2.2.1+incompatible // indirect
github.com/cyphar/filepath-securejoin v0.2.3 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dimchansky/utfbom v1.1.1 // indirect
github.com/docker/docker v20.10.9+incompatible // indirect
github.com/docker/docker v20.10.17+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.4.0 // indirect
github.com/emirpasic/gods v1.12.0 // indirect
github.com/envoyproxy/go-control-plane v0.10.1 // indirect
github.com/envoyproxy/protoc-gen-validate v0.6.2 // indirect
github.com/emicklei/go-restful/v3 v3.8.0 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-git/gcfg v1.5.0 // indirect
github.com/go-git/go-billy/v5 v5.3.1 // indirect
github.com/go-gota/gota v0.12.0 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.20.0 // indirect
github.com/go-openapi/swag v0.21.1 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.2.0 // indirect
github.com/golang-jwt/jwt/v4 v4.4.1 // indirect
github.com/golang/glog v1.0.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-cmp v0.5.7 // indirect
github.com/google/gofuzz v1.1.0 // indirect
github.com/googleapis/gax-go/v2 v2.1.1 // indirect
github.com/googleapis/gnostic v0.5.5 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/google/gnostic v0.6.9 // indirect
github.com/google/go-cmp v0.5.8 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.1.0 // indirect
github.com/googleapis/gax-go/v2 v2.4.0 // indirect
github.com/huandu/xstrings v1.3.2 // indirect
github.com/imdario/mergo v0.3.13 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/jung-kurt/gofpdf v1.16.2 // indirect
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.2 // indirect
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/pquerna/cachecontrol v0.1.0 // indirect
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58 // indirect
github.com/sergi/go-diff v1.1.0 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245 // indirect
github.com/sergi/go-diff v1.2.0 // indirect
github.com/shopspring/decimal v1.2.0 // indirect
github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/xanzy/ssh-agent v0.3.0 // indirect
github.com/vektah/gqlparser/v2 v2.4.5 // indirect
github.com/xanzy/ssh-agent v0.3.1 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
github.com/yashtewari/glob-intersection v0.1.0 // indirect
go.opencensus.io v0.23.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect
golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect
golang.org/x/net v0.0.0-20220615171555-694bf12d69de // indirect
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb // indirect
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c // indirect
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
gonum.org/v1/gonum v0.9.1 // indirect
google.golang.org/api v0.62.0 // indirect
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect
gonum.org/v1/gonum v0.11.0 // indirect
google.golang.org/api v0.84.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
google.golang.org/grpc v1.45.0 // indirect
google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad // indirect
google.golang.org/grpc v1.47.0 // indirect
google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
k8s.io/klog/v2 v2.30.0 // indirect
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect
sigs.k8s.io/controller-runtime v0.11.1 // indirect
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiextensions-apiserver v0.24.0 // indirect
k8s.io/klog/v2 v2.60.1 // indirect
k8s.io/kube-openapi v0.0.0-20220614142933-1062c7ade5f8 // indirect
sigs.k8s.io/controller-runtime v0.12.1 // indirect
sigs.k8s.io/json v0.0.0-20220525155127-227cbc7cc124 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
)

1066
go.sum

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +1,13 @@
module github.com/armosec/kubescape/v2/httphandler
go 1.17
go 1.18
replace github.com/armosec/kubescape/v2 => ../
require (
github.com/armosec/kubescape/v2 v2.0.0-00010101000000-000000000000
github.com/armosec/opa-utils v0.0.148
github.com/armosec/utils-go v0.0.5
github.com/armosec/opa-utils v0.0.159
github.com/armosec/utils-go v0.0.7
github.com/google/uuid v1.3.0
github.com/gorilla/mux v1.8.0
github.com/gorilla/schema v1.2.0
@@ -16,12 +16,12 @@ require (
)
require (
cloud.google.com/go v0.99.0 // indirect
cloud.google.com/go/container v1.0.0 // indirect
github.com/Azure/azure-sdk-for-go v63.0.0+incompatible // indirect
cloud.google.com/go/compute v1.7.0 // indirect
cloud.google.com/go/container v1.2.0 // indirect
github.com/Azure/azure-sdk-for-go v65.0.0+incompatible // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest v0.11.24 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.18 // indirect
github.com/Azure/go-autorest/autorest v0.11.27 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.20 // indirect
github.com/Azure/go-autorest/autorest/azure/auth v0.5.11 // indirect
github.com/Azure/go-autorest/autorest/azure/cli v0.4.5 // indirect
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
@@ -29,44 +29,45 @@ require (
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/Microsoft/go-winio v0.4.16 // indirect
github.com/BurntSushi/toml v1.0.0 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.1.1 // indirect
github.com/Masterminds/sprig/v3 v3.2.2 // indirect
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/OneOfOne/xxhash v1.2.8 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20220517143526-88bb52951d5b // indirect
github.com/acomagu/bufpipe v1.0.3 // indirect
github.com/armosec/armoapi-go v0.0.73 // indirect
github.com/agnivade/levenshtein v1.1.1 // indirect
github.com/armosec/armoapi-go v0.0.97 // indirect
github.com/armosec/go-git-url v0.0.13 // indirect
github.com/armosec/k8s-interface v0.0.78 // indirect
github.com/armosec/rbac-utils v0.0.14 // indirect
github.com/armosec/utils-k8s-go v0.0.6 // indirect
github.com/aws/aws-sdk-go v1.41.11 // indirect
github.com/aws/aws-sdk-go-v2 v1.12.0 // indirect
github.com/aws/aws-sdk-go-v2/config v1.12.0 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.7.0 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.9.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.1.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.3 // indirect
github.com/aws/aws-sdk-go-v2/service/eks v1.17.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.6.0 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.8.0 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.13.0 // indirect
github.com/aws/smithy-go v1.9.1 // indirect
github.com/armosec/utils-k8s-go v0.0.7 // indirect
github.com/aws/aws-sdk-go v1.44.36 // indirect
github.com/aws/aws-sdk-go-v2 v1.16.5 // indirect
github.com/aws/aws-sdk-go-v2/config v1.15.11 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.12.6 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.6 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.12 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.6 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.13 // indirect
github.com/aws/aws-sdk-go-v2/service/eks v1.21.2 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.6 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.11.9 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.16.7 // indirect
github.com/aws/smithy-go v1.11.3 // indirect
github.com/boombuler/barcode v1.0.1 // indirect
github.com/briandowns/spinner v1.18.1 // indirect
github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 // indirect
github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490 // indirect
github.com/coreos/go-oidc v2.2.1+incompatible // indirect
github.com/cyphar/filepath-securejoin v0.2.3 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dimchansky/utfbom v1.1.1 // indirect
github.com/docker/docker v20.10.9+incompatible // indirect
github.com/docker/docker v20.10.17+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.4.0 // indirect
github.com/emirpasic/gods v1.12.0 // indirect
github.com/emicklei/go-restful/v3 v3.8.0 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/enescakir/emoji v1.0.0 // indirect
github.com/envoyproxy/go-control-plane v0.10.1 // indirect
github.com/envoyproxy/protoc-gen-validate v0.6.2 // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
@@ -75,75 +76,92 @@ require (
github.com/go-git/go-git/v5 v5.4.2 // indirect
github.com/go-gota/gota v0.12.0 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.20.0 // indirect
github.com/go-openapi/swag v0.21.1 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.2.0 // indirect
github.com/golang-jwt/jwt/v4 v4.4.1 // indirect
github.com/golang/glog v1.0.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-cmp v0.5.7 // indirect
github.com/google/gofuzz v1.1.0 // indirect
github.com/googleapis/gax-go/v2 v2.1.1 // indirect
github.com/googleapis/gnostic v0.5.5 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/google/gnostic v0.6.9 // indirect
github.com/google/go-cmp v0.5.8 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.1.0 // indirect
github.com/googleapis/gax-go/v2 v2.4.0 // indirect
github.com/huandu/xstrings v1.3.2 // indirect
github.com/imdario/mergo v0.3.13 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/johnfercher/maroto v0.36.1 // indirect
github.com/johnfercher/maroto v0.37.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/jung-kurt/gofpdf v1.16.2 // indirect
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/open-policy-agent/opa v0.39.0 // indirect
github.com/open-policy-agent/opa v0.41.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.2 // indirect
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/pquerna/cachecontrol v0.1.0 // indirect
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58 // indirect
github.com/sergi/go-diff v1.1.0 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245 // indirect
github.com/sergi/go-diff v1.2.0 // indirect
github.com/shopspring/decimal v1.2.0 // indirect
github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/vektah/gqlparser/v2 v2.4.5 // indirect
github.com/whilp/git-urls v1.0.0 // indirect
github.com/xanzy/ssh-agent v0.3.0 // indirect
github.com/xanzy/ssh-agent v0.3.1 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
github.com/yashtewari/glob-intersection v0.1.0 // indirect
go.opencensus.io v0.23.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.21.0 // indirect
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect
golang.org/x/mod v0.5.1 // indirect
golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
golang.org/x/net v0.0.0-20220615171555-694bf12d69de // indirect
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb // indirect
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c // indirect
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
gonum.org/v1/gonum v0.9.1 // indirect
google.golang.org/api v0.62.0 // indirect
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect
gonum.org/v1/gonum v0.11.0 // indirect
google.golang.org/api v0.84.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
google.golang.org/grpc v1.45.0 // indirect
google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad // indirect
google.golang.org/grpc v1.47.0 // indirect
google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
k8s.io/api v0.23.5 // indirect
k8s.io/apimachinery v0.23.5 // indirect
k8s.io/client-go v0.23.5 // indirect
k8s.io/klog/v2 v2.30.0 // indirect
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect
sigs.k8s.io/controller-runtime v0.11.1 // indirect
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
helm.sh/helm/v3 v3.9.0 // indirect
k8s.io/api v0.24.2 // indirect
k8s.io/apiextensions-apiserver v0.24.0 // indirect
k8s.io/apimachinery v0.24.2 // indirect
k8s.io/client-go v0.24.2 // indirect
k8s.io/klog/v2 v2.60.1 // indirect
k8s.io/kube-openapi v0.0.0-20220614142933-1062c7ade5f8 // indirect
sigs.k8s.io/controller-runtime v0.12.1 // indirect
sigs.k8s.io/json v0.0.0-20220525155127-227cbc7cc124 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)

File diff suppressed because it is too large Load Diff