Compare commits

..

94 Commits

Author SHA1 Message Date
David Wertenteil
0cfdabd25a remove v1 format 2022-04-10 16:26:59 +03:00
David Wertenteil
8b6cb6c5d8 adding logs 2022-04-10 11:55:35 +03:00
David Wertenteil
3df3b7766c save policy in file 2022-04-10 09:33:44 +03:00
David Wertenteil
0d83654197 update resource table 2022-04-07 16:44:56 +03:00
David Wertenteil
bd9e44382e format v2 2022-04-07 13:54:49 +03:00
David Wertenteil
2a7c20ea94 report format version 2022-04-07 11:59:19 +03:00
David Wertenteil
bde0dc9a17 convert score to int 2022-04-07 11:00:39 +03:00
David Wertenteil
7d7336ae01 support only one input 2022-04-07 09:53:44 +03:00
David Wertenteil
e5e608324d send file meta 2022-04-06 16:11:57 +03:00
David Wertenteil
569c1444f7 Merge remote-tracking branch 'armosec/dev' 2022-04-06 09:45:32 +03:00
dwertent
dc5ef28324 update output 2022-04-06 09:29:28 +03:00
David Wertenteil
aea6c0eab8 Merge pull request #477 from Daniel-GrunbergerCA/master
Fix error msg for cloud
2022-04-06 09:23:12 +03:00
DanielGrunbergerCA
c80a15d0cf Merge remote-tracking branch 'upstream/dev' 2022-04-05 17:19:11 +03:00
DanielGrunbergerCA
1ddd57aa1d fix error msg for cloud 2022-04-05 17:18:50 +03:00
David Wertenteil
55adb0da6b Merge pull request #474 from Daniel-GrunbergerCA/master
Fix posture control inputs for yaml scan
2022-04-05 16:28:39 +03:00
DanielGrunbergerCA
a716289cc8 go mod 2022-04-05 14:10:11 +03:00
DanielGrunbergerCA
093d71fff4 exit status 1 2022-04-05 14:05:31 +03:00
DanielGrunbergerCA
4fe40e348d Merge branch 'master' of github.com:Daniel-GrunbergerCA/kubescape 2022-04-05 13:40:41 +03:00
DanielGrunbergerCA
29a67b806d Merge remote-tracking branch 'upstream/dev' 2022-04-05 13:39:39 +03:00
DanielGrunbergerCA
0169f42747 Merge remote-tracking branch 'upstream/master' 2022-04-05 13:39:28 +03:00
David Wertenteil
92e100c497 Merge branch 'dev' into master 2022-04-04 13:39:17 +03:00
DanielGrunbergerCA
536fe970f7 fix go mod 2022-04-04 12:31:45 +03:00
DanielGrunbergerCA
85526b06b6 fix control input for yaml scan 2022-04-04 12:27:30 +03:00
dwertent
d9b6c048d5 Merge remote-tracking branch 'armosec/dev' 2022-04-04 12:14:45 +03:00
David Wertenteil
7e46a6529a Merge pull request #473 from Lucifergene/dev
Added Severity Column with colored text
2022-04-04 12:14:35 +03:00
dwertent
2dc5fd80da Merge remote-tracking branch 'armosec/dev' 2022-04-04 12:14:13 +03:00
dwertent
e89cc8ca24 register usesrs download from BE 2022-04-04 12:13:35 +03:00
dwertent
d39aeb0691 update metrics 2022-04-04 11:32:56 +03:00
Lucifergene
da9d98134a Added Severity Column with colored text 2022-04-04 03:46:05 +05:30
David Wertenteil
9992a9a0e4 Merge pull request #472 from falconcode16/master
Improved grammatical mistakes and typos
2022-04-03 10:03:15 +03:00
Rohit Patil
adc8a16e85 Improved grammatical mistakes and typos 2022-04-03 10:40:56 +05:30
dwertent
58b833c18a support yaml scan submit 2022-03-28 09:40:11 +03:00
Rotem Refael
cb424eab00 Merge pull request #461 from armosec/dev
Microservice support
2022-03-27 17:20:35 +03:00
Rotem Refael
9f2e18c3ee Merge pull request #466 from dwertent/master
udpate armo api types
2022-03-27 17:09:52 +03:00
dwertent
b44a73aea5 udpate armo api types 2022-03-27 17:07:17 +03:00
Rotem Refael
9c5759286f Merge pull request #465 from dwertent/master
Update url support
2022-03-27 16:29:01 +03:00
dwertent
74dc714736 use scan ID 2022-03-27 15:51:29 +03:00
dwertent
83751e22cc fixed report sending 2022-03-27 15:37:11 +03:00
dwertent
db5fdd75c4 inserting scan source 2022-03-25 16:08:07 +03:00
dwertent
4be2104d4b adding githubusercontent tests 2022-03-24 12:37:00 +02:00
dwertent
b6bab7618f loading github token from env 2022-03-24 12:15:54 +02:00
dwertent
3e1fda6f3b fixed test 2022-03-24 11:12:28 +02:00
dwertent
8487a031ee fixed url scanning 2022-03-24 09:45:35 +02:00
David Wertenteil
efbb123fce Merge pull request #464 from dwertent/master
update error display
2022-03-23 09:27:58 +02:00
dwertent
5a335d4f1c update error display 2022-03-23 09:05:36 +02:00
dwertent
5770a823d6 update readme 2022-03-23 08:47:24 +02:00
Rotem Refael
52d7be9108 Add kubescape covarage 2022-03-22 17:42:20 +02:00
David Wertenteil
9512b9c6c4 Merge pull request #463 from Daniel-GrunbergerCA/dev
fix json printer
2022-03-22 09:14:59 +02:00
DanielGrunbergerCA
da9ab642ec rm list initializtion 2022-03-22 09:07:55 +02:00
DanielGrunbergerCA
718ca1c7ab fix json printer 2022-03-22 08:55:36 +02:00
DanielGrunbergerCA
ee3742c5a0 update opa-utils version 2022-03-21 15:36:17 +02:00
DanielGrunbergerCA
7eef843a7a fix resources in report 2022-03-21 15:11:26 +02:00
David Wertenteil
b4a8b06f07 Merge pull request #462 from dwertent/master
update get context
2022-03-21 09:09:12 +02:00
dwertent
4e13609985 update get context 2022-03-21 09:08:01 +02:00
David Wertenteil
2e5e4328f6 Merge pull request #460 from dwertent/master
update readme
2022-03-20 11:30:37 +02:00
dwertent
d98a11a8fa udpate badges 2022-03-20 11:28:56 +02:00
dwertent
bdb25cbb66 adding vs code to readme 2022-03-20 11:08:48 +02:00
David Wertenteil
369804cb6e Merge pull request #459 from shm12/dev
send scan metadata
2022-03-20 10:45:19 +02:00
shm12
1b08a92095 send scan metadata 2022-03-20 10:05:40 +02:00
David Wertenteil
e787454d53 Merge pull request #458 from dwertent/master
fixed json output
2022-03-16 16:58:54 +02:00
dwertent
31d1ba663a json output 2022-03-16 16:58:05 +02:00
David Wertenteil
c3731d8ff6 Merge pull request #457 from dwertent/master
support frameworks from http request
2022-03-16 16:37:40 +02:00
dwertent
c5b46beb1a support frameworks from http request 2022-03-16 16:33:03 +02:00
dwertent
c5ca576c98 Merge remote-tracking branch 'armosec/dev' 2022-03-16 15:27:10 +02:00
dwertent
eae6458b42 fixed cmd init 2022-03-16 15:26:59 +02:00
David Wertenteil
aa1aa913b6 Merge pull request #456 from Daniel-GrunbergerCA/dev
Support status information
2022-03-16 15:17:49 +02:00
DanielGrunbergerCA
44084592cb fixes 2022-03-16 14:16:48 +02:00
DanielGrunbergerCA
6cacfb7b16 refactor 2022-03-16 12:22:21 +02:00
DanielGrunbergerCA
6372ce5647 Merge branch 'dev' 2022-03-16 12:13:16 +02:00
DanielGrunbergerCA
306d3a7081 fix table display 2022-03-16 12:12:39 +02:00
DanielGrunbergerCA
442530061f rm space 2022-03-16 12:09:53 +02:00
DanielGrunbergerCA
961a6f6ebc Merge remote-tracking branch 'upstream/dev' into dev 2022-03-16 12:08:38 +02:00
DanielGrunbergerCA
0d0c8e1b97 support status info 2022-03-16 12:08:04 +02:00
David Wertenteil
5b843ba2c4 Merge pull request #455 from dwertent/master
update prometheus format
2022-03-16 09:32:23 +02:00
dwertent
8f9b46cdbe update prometheus format 2022-03-16 09:25:45 +02:00
David Wertenteil
e16885a044 Merge pull request #452 from dwertent/master
update dockerfile and scan triggering
2022-03-15 22:12:31 +02:00
dwertent
06a2fa05be add ks user to dockerfile 2022-03-15 22:10:27 +02:00
dwertent
d26f90b98e update Prometheus yaml 2022-03-15 18:40:42 +02:00
David Wertenteil
b47c128eb3 Merge pull request #451 from dwertent/master
update prometheus format
2022-03-15 17:12:07 +02:00
dwertent
9d957b3c77 update output 2022-03-15 17:04:59 +02:00
dwertent
8ec5615569 junit format 2022-03-15 16:50:39 +02:00
David Wertenteil
fae73b827a Merge pull request #450 from dwertent/master
build each pkg
2022-03-14 19:27:47 +02:00
dwertent
6477437872 update readme 2022-03-14 19:14:31 +02:00
dwertent
6099f46dea adding docker build 2022-03-14 18:34:34 +02:00
Rotem Refael
5009e6ef47 change gif 2022-03-14 11:33:56 +02:00
Rotem Refael
c4450d3259 add web & CLI Interfaces 2022-03-14 11:27:57 +02:00
Rotem Refael
0c3339f1c9 update gif 2022-03-14 10:28:32 +02:00
Rotem Refael
faee3d5ad6 Add new video to readme 2022-03-14 10:14:55 +02:00
David Wertenteil
a279963b28 Merge pull request #449 from dwertent/master
split to packages
2022-03-13 19:37:02 +02:00
dwertent
f7c0c95d3b adding tests to build 2022-03-13 19:05:06 +02:00
dwertent
b8df07b547 fixed unitest 2022-03-13 18:59:39 +02:00
dwertent
d0e2730518 add cautils to core 2022-03-13 18:14:48 +02:00
David Wertenteil
353a39d66a Merge pull request #448 from dwertent/master
microservice support
2022-03-10 17:17:35 +02:00
Rotem Refael
9733178228 Merge pull request #428 from armosec/dev
Release
2022-03-06 11:51:59 +02:00
146 changed files with 6331 additions and 1061 deletions

View File

@@ -33,9 +33,17 @@ jobs:
uses: actions/setup-go@v2
with:
go-version: 1.17
- name: Test cmd pkg
run: cd cmd && go test -v ./...
- name: Test core pkg
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: cd core && go test -v ./...
- name: Test
run: go test -v ./...
- name: Test httphandler pkg
run: cd httphandler && go test -v ./...
- name: Build
env:
@@ -45,7 +53,7 @@ jobs:
ArmoERServer: report.armo.cloud
ArmoWebsite: portal.armo.cloud
CGO_ENABLED: 0
run: python3 --version && python3 build.py
run: cd cmd && python3 --version && python3 build.py
- name: Smoke Testing
env:

View File

@@ -18,8 +18,16 @@ jobs:
with:
go-version: 1.17
- name: Test
run: go test -v ./...
- name: Test cmd pkg
run: cd cmd && go test -v ./...
- name: Test core pkg
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: cd core && go test -v ./...
- name: Test httphandler pkg
run: cd httphandler && go test -v ./...
- name: Build
env:
@@ -29,7 +37,7 @@ jobs:
ArmoERServer: report.armo.cloud
ArmoWebsite: portal.armo.cloud
CGO_ENABLED: 0
run: python3 --version && python3 build.py
run: cd cmd && python3 --version && python3 build.py
- name: Smoke Testing
env:

View File

@@ -19,8 +19,16 @@ jobs:
with:
go-version: 1.17
- name: Test
run: go test -v ./...
- name: Test cmd pkg
run: cd cmd && go test -v ./...
- name: Test core pkg
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: cd core && go test -v ./...
- name: Test httphandler pkg
run: cd httphandler && go test -v ./...
- name: Build
env:
@@ -30,7 +38,7 @@ jobs:
ArmoERServer: report.armo.cloud
ArmoWebsite: portal.armo.cloud
CGO_ENABLED: 0
run: python3 --version && python3 build.py
run: cd cmd && python3 --version && python3 build.py
- name: Smoke Testing
env:

View File

@@ -12,8 +12,20 @@ Kubescape integrates natively with other DevOps tools, including Jenkins, Circle
</br>
<!-- # Kubescape Coverage
<img src="docs/ksfromcodetodeploy.png">
</br> -->
# Kubescape CLI:
<img src="docs/demo.gif">
</br>
<!-- # Kubescape overview:
<img src="docs/ARMO-header-2022.gif"> -->
# TL;DR
## Install:
```
@@ -26,7 +38,7 @@ curl -s https://raw.githubusercontent.com/armosec/kubescape/master/install.sh |
## Run:
```
kubescape scan --submit --enable-host-scan
kubescape scan --submit --enable-host-scan --format-version v2 --verbose
```
<img src="docs/summary.png">
@@ -103,7 +115,7 @@ Set-ExecutionPolicy RemoteSigned -scope CurrentUser
#### Scan a running Kubernetes cluster and submit results to the [Kubescape SaaS version](https://portal.armo.cloud/)
```
kubescape scan --submit --enable-host-scan
kubescape scan --submit --enable-host-scan --verbose
```
> Read [here](https://hub.armo.cloud/docs/host-sensor) more about the `enable-host-scan` flag
@@ -255,6 +267,16 @@ Now you can submit the results to the Kubescape SaaS version -
kubescape submit results path/to/results.json
```
# Integrations
## VS Code Extension
![Visual Studio Marketplace Downloads](https://img.shields.io/visual-studio-marketplace/d/kubescape.kubescape?label=VScode) ![Open VSX](https://img.shields.io/open-vsx/dt/kubescape/kubescape?label=openVSX&color=yellowgreen)
Scan the YAML files while writing them using the [vs code extension](https://github.com/armosec/vscode-kubescape/blob/master/README.md)
# Under the hood
## Technology

View File

@@ -18,14 +18,27 @@ RUN pip3 install --no-cache --upgrade pip setuptools
WORKDIR /work
ADD . .
# build kubescape server
WORKDIR /work/httphandler
RUN python build.py
RUN ls -ltr build/ubuntu-latest
# build kubescape cmd
WORKDIR /work/cmd
RUN python build.py
RUN /work/build/ubuntu-latest/kubescape download artifacts -o /work/artifacts
FROM alpine
RUN addgroup -S ks && adduser -S ks -G ks
USER ks
WORKDIR /home/ks/
COPY --from=builder /work/httphandler/build/ubuntu-latest/kubescape /usr/bin/ksserver
COPY --from=builder /work/build/ubuntu-latest/kubescape /usr/bin/kubescape
# # Download the frameworks. Use the "--use-default" flag when running kubescape
# RUN kubescape download framework nsa && kubescape download framework mitre
RUN mkdir /home/ks/.kubescape && chmod 777 -R /home/ks/.kubescape
COPY --from=builder /work/artifacts/ /home/ks/.kubescape
ENTRYPOINT ["kubescape"]
ENTRYPOINT ["ksserver"]

View File

@@ -1,75 +0,0 @@
package cautils
import (
"github.com/armosec/armoapi-go/armotypes"
"github.com/armosec/k8s-interface/workloadinterface"
"github.com/armosec/opa-utils/reporthandling"
"github.com/armosec/opa-utils/reporthandling/results/v1/resourcesresults"
reporthandlingv2 "github.com/armosec/opa-utils/reporthandling/v2"
)
// K8SResources map[<api group>/<api version>/<resource>][]<resourceID>
type K8SResources map[string][]string
type OPASessionObj struct {
K8SResources *K8SResources // input k8s objects
Policies []reporthandling.Framework // list of frameworks to scan
AllResources map[string]workloadinterface.IMetadata // all scanned resources, map[<rtesource ID>]<resource>
ResourcesResult map[string]resourcesresults.Result // resources scan results, map[<rtesource ID>]<resource result>
PostureReport *reporthandling.PostureReport // scan results v1 - Remove
Report *reporthandlingv2.PostureReport // scan results v2 - Remove
Exceptions []armotypes.PostureExceptionPolicy // list of exceptions to apply on scan results
RegoInputData RegoInputData // input passed to rgo for scanning. map[<control name>][<input arguments>]
}
func NewOPASessionObj(frameworks []reporthandling.Framework, k8sResources *K8SResources) *OPASessionObj {
return &OPASessionObj{
Report: &reporthandlingv2.PostureReport{},
Policies: frameworks,
K8SResources: k8sResources,
AllResources: make(map[string]workloadinterface.IMetadata),
ResourcesResult: make(map[string]resourcesresults.Result),
PostureReport: &reporthandling.PostureReport{
ClusterName: ClusterName,
CustomerGUID: CustomerGUID,
},
}
}
func NewOPASessionObjMock() *OPASessionObj {
return &OPASessionObj{
Policies: nil,
K8SResources: nil,
AllResources: make(map[string]workloadinterface.IMetadata),
ResourcesResult: make(map[string]resourcesresults.Result),
Report: &reporthandlingv2.PostureReport{},
PostureReport: &reporthandling.PostureReport{
ClusterName: "",
CustomerGUID: "",
ReportID: "",
JobID: "",
},
}
}
type ComponentConfig struct {
Exceptions Exception `json:"exceptions"`
}
type Exception struct {
Ignore *bool `json:"ignore"` // ignore test results
MultipleScore *reporthandling.AlertScore `json:"multipleScore"` // MultipleScore number - float32
Namespaces []string `json:"namespaces"`
Regex string `json:"regex"` // not supported
}
type RegoInputData struct {
PostureControlInputs map[string][]string `json:"postureControlInputs"`
// ClusterName string `json:"clusterName"`
// K8sConfig RegoK8sConfig `json:"k8sconfig"`
}
type Policies struct {
Frameworks []string
Controls map[string]reporthandling.Control // map[<control ID>]<control>
}

View File

@@ -1,11 +0,0 @@
package cautils
// CA environment vars
var (
CustomerGUID = ""
ClusterName = ""
EventReceiverURL = ""
NotificationServerURL = ""
DashboardBackendURL = ""
RestAPIPort = "4001"
)

View File

@@ -4,7 +4,7 @@ import hashlib
import platform
import subprocess
BASE_GETTER_CONST = "github.com/armosec/kubescape/cautils/getter"
BASE_GETTER_CONST = "github.com/armosec/kubescape/core/cautils/getter"
BE_SERVER_CONST = BASE_GETTER_CONST + ".ArmoBEURL"
ER_SERVER_CONST = BASE_GETTER_CONST + ".ArmoERURL"
WEBSITE_CONST = BASE_GETTER_CONST + ".ArmoFEURL"
@@ -18,7 +18,7 @@ def checkStatus(status, msg):
def getBuildDir():
currentPlatform = platform.system()
buildDir = "build/"
buildDir = "../build/"
if currentPlatform == "Windows": buildDir += "windows-latest"
elif currentPlatform == "Linux": buildDir += "ubuntu-latest"
@@ -42,7 +42,7 @@ def main():
# Set some variables
packageName = getPackageName()
buildUrl = "github.com/armosec/kubescape/cautils.BuildNumber"
buildUrl = "github.com/armosec/kubescape/core/cautils.BuildNumber"
releaseVersion = os.getenv("RELEASE")
ArmoBEServer = os.getenv("ArmoBEServer")
ArmoERServer = os.getenv("ArmoERServer")
@@ -70,7 +70,7 @@ def main():
ldflags += " -X {}={}".format(WEBSITE_CONST, ArmoWebsite)
if ArmoAuthServer:
ldflags += " -X {}={}".format(AUTH_SERVER_CONST, ArmoAuthServer)
build_command = ["go", "build", "-o", ks_file, "-ldflags" ,ldflags]
print("Building kubescape and saving here: {}".format(ks_file))

View File

@@ -1,7 +1,7 @@
package config
import (
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/meta"
v1 "github.com/armosec/kubescape/core/meta/datastructures/v1"
"github.com/spf13/cobra"

View File

@@ -4,7 +4,7 @@ import (
"fmt"
"strings"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/meta"
metav1 "github.com/armosec/kubescape/core/meta/datastructures/v1"
"github.com/spf13/cobra"

View File

@@ -3,7 +3,7 @@ package config
import (
"os"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/meta"
v1 "github.com/armosec/kubescape/core/meta/datastructures/v1"
"github.com/spf13/cobra"

View File

@@ -4,7 +4,7 @@ import (
"fmt"
"strings"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/meta"
v1 "github.com/armosec/kubescape/core/meta/datastructures/v1"
"github.com/spf13/cobra"

View File

@@ -5,8 +5,8 @@ import (
"path/filepath"
"strings"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/core/cautils"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/core"
"github.com/armosec/kubescape/core/meta"
v1 "github.com/armosec/kubescape/core/meta/datastructures/v1"

127
cmd/go.mod Normal file
View File

@@ -0,0 +1,127 @@
module github.com/armosec/kubescape/cmd
go 1.17
replace github.com/armosec/kubescape/core => ../core
require (
github.com/armosec/k8s-interface v0.0.68
github.com/armosec/kubescape/core v0.0.0-00010101000000-000000000000
github.com/armosec/opa-utils v0.0.130
github.com/armosec/rbac-utils v0.0.14
github.com/enescakir/emoji v1.0.0
github.com/google/uuid v1.3.0
github.com/mattn/go-isatty v0.0.14
github.com/spf13/cobra v1.4.0
)
require (
cloud.google.com/go v0.99.0 // indirect
cloud.google.com/go/container v1.0.0 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest v0.11.18 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/OneOfOne/xxhash v1.2.8 // indirect
github.com/armosec/armoapi-go v0.0.58 // indirect
github.com/armosec/utils-go v0.0.3 // indirect
github.com/armosec/utils-k8s-go v0.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/boombuler/barcode v1.0.0 // 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/davecgh/go-spew v1.1.1 // indirect
github.com/docker/docker v20.10.9+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.4.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/form3tech-oss/jwt-go v3.2.3+incompatible // indirect
github.com/francoispqt/gojay v1.2.13 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-gota/gota v0.12.0 // indirect
github.com/go-logr/logr v1.2.2 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/gogo/protobuf v1.3.2 // 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/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/johnfercher/maroto v0.34.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/jung-kurt/gofpdf v1.4.2 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/open-policy-agent/opa v0.38.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.2 // indirect
github.com/pkg/errors v0.9.1 // 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/spf13/pflag v1.0.5 // indirect
github.com/whilp/git-urls v1.0.0 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/yashtewari/glob-intersection v0.0.0-20180916065949-5c77d914dd0b // 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/zap v1.21.0 // indirect
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // 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/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
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
google.golang.org/grpc v1.44.0 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
k8s.io/api v0.23.4 // indirect
k8s.io/apimachinery v0.23.4 // indirect
k8s.io/client-go v0.23.4 // indirect
k8s.io/klog/v2 v2.30.0 // indirect
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect
k8s.io/utils v0.0.0-20211116205334-6203023598ed // indirect
sigs.k8s.io/controller-runtime v0.11.1 // indirect
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)

1484
cmd/go.sum Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -4,8 +4,8 @@ import (
"fmt"
"strings"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/core/cautils"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/core"
"github.com/armosec/kubescape/core/meta"
v1 "github.com/armosec/kubescape/core/meta/datastructures/v1"

View File

@@ -1,14 +1,9 @@
package cmd
package main
import (
"fmt"
"os"
"strings"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/cautils/getter"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/cautils/logger/helpers"
"github.com/armosec/kubescape/cmd/completion"
"github.com/armosec/kubescape/cmd/config"
"github.com/armosec/kubescape/cmd/delete"
@@ -17,17 +12,17 @@ import (
"github.com/armosec/kubescape/cmd/scan"
"github.com/armosec/kubescape/cmd/submit"
"github.com/armosec/kubescape/cmd/version"
"github.com/armosec/kubescape/core/cautils"
"github.com/armosec/kubescape/core/cautils/getter"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
"github.com/armosec/kubescape/core/core"
"github.com/armosec/kubescape/core/meta"
"github.com/mattn/go-isatty"
"github.com/spf13/cobra"
)
var armoBEURLs = ""
var armoBEURLsDep = ""
const envFlagUsage = "Send report results to specific URL. Format:<ReportReceiver>,<Backend>,<Frontend>.\n\t\tExample:report.armo.cloud,api.armo.cloud,portal.armo.cloud"
var rootInfo cautils.RootInfo
var ksExamples = `
# Scan command
@@ -50,7 +45,6 @@ func NewDefaultKubescapeCommand() *cobra.Command {
}
func getRootCmd(ks meta.IKubescape) *cobra.Command {
var rootInfo cautils.RootInfo
rootCmd := &cobra.Command{
Use: "kubescape",
@@ -60,8 +54,8 @@ func getRootCmd(ks meta.IKubescape) *cobra.Command {
Example: ksExamples,
}
rootCmd.PersistentFlags().StringVar(&armoBEURLsDep, "environment", "", envFlagUsage)
rootCmd.PersistentFlags().StringVar(&armoBEURLs, "env", "", envFlagUsage)
rootCmd.PersistentFlags().StringVar(&rootInfo.ArmoBEURLsDep, "environment", "", envFlagUsage)
rootCmd.PersistentFlags().StringVar(&rootInfo.ArmoBEURLs, "env", "", envFlagUsage)
rootCmd.PersistentFlags().MarkDeprecated("environment", "use 'env' instead")
rootCmd.PersistentFlags().MarkHidden("environment")
rootCmd.PersistentFlags().MarkHidden("env")
@@ -73,11 +67,7 @@ func getRootCmd(ks meta.IKubescape) *cobra.Command {
rootCmd.PersistentFlags().StringVar(&rootInfo.CacheDir, "cache-dir", getter.DefaultLocalStore, "Cache directory [$KS_CACHE_DIR]")
rootCmd.PersistentFlags().BoolVarP(&rootInfo.DisableColor, "disable-color", "", false, "Disable Color output for logging")
// Initialize
initLogger(&rootInfo)
initLoggerLevel(&rootInfo)
initEnvironment(&rootInfo)
initCacheDir(&rootInfo)
cobra.OnInitialize(initLogger, initLoggerLevel, initEnvironment, initCacheDir)
// Supported commands
rootCmd.AddCommand(scan.GetScanCommand(ks))
@@ -92,97 +82,10 @@ func getRootCmd(ks meta.IKubescape) *cobra.Command {
return rootCmd
}
// func main() {
// ks := NewDefaultKubescapeCommand()
// ks.Execute()
// // // cmd.Execute()
// // listener.SetupHTTPListener()
// }
func Execute() {
func main() {
ks := NewDefaultKubescapeCommand()
// ks.DisableAutoGenTag = true
// identity := func(s string) string { return s }
// emptyStr := func(s string) string { return "" }
// fileLocation := doc.GenFileLocationHierarchy
// err := doc.GenMarkdownTreeCustom(ks, "/home/david/go/src/playground", emptyStr, identity, fileLocation)
// if err != nil {
// log.Fatal(err)
// }
ks.Execute()
}
func initLogger(rootInfo *cautils.RootInfo) {
logger.DisableColor(rootInfo.DisableColor)
if rootInfo.LoggerName == "" {
if l := os.Getenv("KS_LOGGER_NAME"); l != "" {
rootInfo.LoggerName = l
} else {
if isatty.IsTerminal(os.Stdout.Fd()) {
rootInfo.LoggerName = "pretty"
} else {
rootInfo.LoggerName = "zap"
}
}
}
logger.InitLogger(rootInfo.LoggerName)
}
func initLoggerLevel(rootInfo *cautils.RootInfo) {
if rootInfo.Logger != helpers.InfoLevel.String() {
} else if l := os.Getenv("KS_LOGGER"); l != "" {
rootInfo.Logger = l
}
if err := logger.L().SetLevel(rootInfo.Logger); err != nil {
logger.L().Fatal(fmt.Sprintf("supported levels: %s", strings.Join(helpers.SupportedLevels(), "/")), helpers.Error(err))
}
}
func initCacheDir(rootInfo *cautils.RootInfo) {
if rootInfo.CacheDir == getter.DefaultLocalStore {
getter.DefaultLocalStore = rootInfo.CacheDir
} else if cacheDir := os.Getenv("KS_CACHE_DIR"); cacheDir != "" {
getter.DefaultLocalStore = cacheDir
} else {
return // using default cache dir location
}
logger.L().Debug("cache dir updated", helpers.String("path", getter.DefaultLocalStore))
}
func initEnvironment(rootInfo *cautils.RootInfo) {
if armoBEURLsDep != "" {
armoBEURLs = armoBEURLsDep
}
urlSlices := strings.Split(armoBEURLs, ",")
if len(urlSlices) != 1 && len(urlSlices) < 3 {
logger.L().Fatal("expected at least 3 URLs (report, api, frontend, auth)")
}
switch len(urlSlices) {
case 1:
switch urlSlices[0] {
case "dev", "development":
getter.SetARMOAPIConnector(getter.NewARMOAPIDev())
case "stage", "staging":
getter.SetARMOAPIConnector(getter.NewARMOAPIStaging())
case "":
getter.SetARMOAPIConnector(getter.NewARMOAPIProd())
default:
logger.L().Fatal("--environment flag usage: " + envFlagUsage)
}
case 2:
logger.L().Fatal("--environment flag usage: " + envFlagUsage)
case 3, 4:
var armoAUTHURL string
armoERURL := urlSlices[0] // mandatory
armoBEURL := urlSlices[1] // mandatory
armoFEURL := urlSlices[2] // mandatory
if len(urlSlices) <= 4 {
armoAUTHURL = urlSlices[3]
}
getter.SetARMOAPIConnector(getter.NewARMOAPICustomized(armoERURL, armoBEURL, armoFEURL, armoAUTHURL))
err := ks.Execute()
if err != nil {
logger.L().Fatal(err.Error())
}
}

89
cmd/rootutils.go Normal file
View File

@@ -0,0 +1,89 @@
package main
import (
"fmt"
"os"
"strings"
"github.com/armosec/kubescape/core/cautils/getter"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
"github.com/mattn/go-isatty"
)
const envFlagUsage = "Send report results to specific URL. Format:<ReportReceiver>,<Backend>,<Frontend>.\n\t\tExample:report.armo.cloud,api.armo.cloud,portal.armo.cloud"
func initLogger() {
logger.DisableColor(rootInfo.DisableColor)
if rootInfo.LoggerName == "" {
if l := os.Getenv("KS_LOGGER_NAME"); l != "" {
rootInfo.LoggerName = l
} else {
if isatty.IsTerminal(os.Stdout.Fd()) {
rootInfo.LoggerName = "pretty"
} else {
rootInfo.LoggerName = "zap"
}
}
}
logger.InitLogger(rootInfo.LoggerName)
}
func initLoggerLevel() {
if rootInfo.Logger == helpers.InfoLevel.String() {
} else if l := os.Getenv("KS_LOGGER"); l != "" {
rootInfo.Logger = l
}
if err := logger.L().SetLevel(rootInfo.Logger); err != nil {
logger.L().Fatal(fmt.Sprintf("supported levels: %s", strings.Join(helpers.SupportedLevels(), "/")), helpers.Error(err))
}
}
func initCacheDir() {
if rootInfo.CacheDir != getter.DefaultLocalStore {
getter.DefaultLocalStore = rootInfo.CacheDir
} else if cacheDir := os.Getenv("KS_CACHE_DIR"); cacheDir != "" {
getter.DefaultLocalStore = cacheDir
} else {
return // using default cache dir location
}
logger.L().Debug("cache dir updated", helpers.String("path", getter.DefaultLocalStore))
}
func initEnvironment() {
if rootInfo.ArmoBEURLs == "" {
rootInfo.ArmoBEURLs = rootInfo.ArmoBEURLsDep
}
urlSlices := strings.Split(rootInfo.ArmoBEURLs, ",")
if len(urlSlices) != 1 && len(urlSlices) < 3 {
logger.L().Fatal("expected at least 3 URLs (report, api, frontend, auth)")
}
switch len(urlSlices) {
case 1:
switch urlSlices[0] {
case "dev", "development":
getter.SetARMOAPIConnector(getter.NewARMOAPIDev())
case "stage", "staging":
getter.SetARMOAPIConnector(getter.NewARMOAPIStaging())
case "":
getter.SetARMOAPIConnector(getter.NewARMOAPIProd())
default:
logger.L().Fatal("--environment flag usage: " + envFlagUsage)
}
case 2:
logger.L().Fatal("--environment flag usage: " + envFlagUsage)
case 3, 4:
var armoAUTHURL string
armoERURL := urlSlices[0] // mandatory
armoBEURL := urlSlices[1] // mandatory
armoFEURL := urlSlices[2] // mandatory
if len(urlSlices) >= 4 {
armoAUTHURL = urlSlices[3]
}
getter.SetARMOAPIConnector(getter.NewARMOAPICustomized(armoERURL, armoBEURL, armoFEURL, armoAUTHURL))
}
}

View File

@@ -6,10 +6,12 @@ import (
"os"
"strings"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/core/cautils"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
"github.com/armosec/kubescape/core/meta"
"github.com/armosec/opa-utils/reporthandling"
"github.com/enescakir/emoji"
"github.com/spf13/cobra"
)
@@ -66,7 +68,7 @@ func getControlCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comman
if len(args) > 1 {
if len(args[1:]) == 0 || args[1] != "-" {
scanInfo.InputPatterns = args[1:]
scanInfo.InputPatterns = []string{args[1]}
} else { // store stdin to file - do NOT move to separate function !!
tempFile, err := os.CreateTemp(".", "tmp-kubescape*.yaml")
if err != nil {
@@ -88,36 +90,16 @@ func getControlCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comman
if err != nil {
logger.L().Fatal(err.Error())
}
results.HandleResults()
if err := results.HandleResults(); err != nil {
logger.L().Fatal(err.Error())
}
if !scanInfo.VerboseMode {
cautils.SimpleDisplay(os.Stderr, "%s Run with '--verbose'/'-v' flag for detailed resources view\n\n", emoji.Detective)
}
if results.GetRiskScore() > float32(scanInfo.FailThreshold) {
return fmt.Errorf("scan risk-score %.2f is above permitted threshold %.2f", results.GetRiskScore(), scanInfo.FailThreshold)
logger.L().Fatal("scan risk-score is above permitted threshold", helpers.String("risk-score", fmt.Sprintf("%.2f", results.GetRiskScore())), helpers.String("fail-threshold", fmt.Sprintf("%.2f", scanInfo.FailThreshold)))
}
return nil
},
}
}
// func flagValidationControl() {
// if 100 < scanInfo.FailThreshold {
// logger.L().Fatal("bad argument: out of range threshold")
// }
// }
// func setScanForFirstControl(scanInfo, controls []string) []reporthandling.PolicyIdentifier {
// newPolicy := reporthandling.PolicyIdentifier{}
// newPolicy.Kind = reporthandling.KindControl
// newPolicy.Name = controls[0]
// scanInfo.PolicyIdentifier = append(scanInfo.PolicyIdentifier, newPolicy)
// return scanInfo.PolicyIdentifier
// }
// func SetScanForGivenControls(scanInfo, controls []string) []reporthandling.PolicyIdentifier {
// for _, control := range controls {
// control := strings.TrimLeft(control, " ")
// newPolicy := reporthandling.PolicyIdentifier{}
// newPolicy.Kind = reporthandling.KindControl
// newPolicy.Name = control
// scanInfo.PolicyIdentifier = append(scanInfo.PolicyIdentifier, newPolicy)
// }
// return scanInfo.PolicyIdentifier
// }

View File

@@ -6,10 +6,12 @@ import (
"os"
"strings"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/core/cautils"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
"github.com/armosec/kubescape/core/meta"
"github.com/armosec/opa-utils/reporthandling"
"github.com/enescakir/emoji"
"github.com/spf13/cobra"
)
@@ -27,7 +29,7 @@ var (
# Scan all frameworks
kubescape scan framework all
# Scan kubernetes YAML manifest files
# Scan kubernetes YAML manifest files (single file or glob)
kubescape scan framework nsa *.yaml
Run 'kubescape list frameworks' for the list of supported frameworks
@@ -58,7 +60,9 @@ func getFrameworkCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comm
},
RunE: func(cmd *cobra.Command, args []string) error {
flagValidationFramework(scanInfo)
if err := flagValidationFramework(scanInfo); err != nil {
return err
}
scanInfo.FrameworkScan = true
var frameworks []string
@@ -74,7 +78,7 @@ func getFrameworkCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comm
}
if len(args) > 1 {
if len(args[1:]) == 0 || args[1] != "-" {
scanInfo.InputPatterns = args[1:]
scanInfo.InputPatterns = []string{args[1]}
} else { // store stdin to file - do NOT move to separate function !!
tempFile, err := os.CreateTemp(".", "tmp-kubescape*.yaml")
if err != nil {
@@ -97,34 +101,27 @@ func getFrameworkCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comm
if err != nil {
logger.L().Fatal(err.Error())
}
results.HandleResults()
if err = results.HandleResults(); err != nil {
logger.L().Fatal(err.Error())
}
if !scanInfo.VerboseMode {
cautils.SimpleDisplay(os.Stderr, "%s Run with '--verbose'/'-v' flag for detailed resources view\n\n", emoji.Detective)
}
if results.GetRiskScore() > float32(scanInfo.FailThreshold) {
return fmt.Errorf("scan risk-score %.2f is above permitted threshold %.2f", results.GetRiskScore(), scanInfo.FailThreshold)
logger.L().Fatal("scan risk-score is above permitted threshold", helpers.String("risk-score", fmt.Sprintf("%.2f", results.GetRiskScore())), helpers.String("fail-threshold", fmt.Sprintf("%.2f", scanInfo.FailThreshold)))
}
return nil
},
}
}
// func init() {
// scanCmd.AddCommand(frameworkCmd)
// scanInfo = cautils.ScanInfo{}
// }
// func SetScanForFirstFramework(frameworks []string) []reporthandling.PolicyIdentifier {
// newPolicy := reporthandling.PolicyIdentifier{}
// newPolicy.Kind = reporthandling.KindFramework
// newPolicy.Name = frameworks[0]
// scanInfo.PolicyIdentifier = append(scanInfo.PolicyIdentifier, newPolicy)
// return scanInfo.PolicyIdentifier
// }
func flagValidationFramework(scanInfo *cautils.ScanInfo) {
func flagValidationFramework(scanInfo *cautils.ScanInfo) error {
if scanInfo.Submit && scanInfo.Local {
logger.L().Fatal("you can use `keep-local` or `submit`, but not both")
return fmt.Errorf("you can use `keep-local` or `submit`, but not both")
}
if 100 < scanInfo.FailThreshold {
logger.L().Fatal("bad argument: out of range threshold")
if 100 < scanInfo.FailThreshold || 0 > scanInfo.FailThreshold {
return fmt.Errorf("bad argument: out of range threshold")
}
return nil
}

View File

@@ -2,7 +2,7 @@ package scan
import (
"github.com/armosec/k8s-interface/k8sinterface"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/core/cautils"
"github.com/armosec/kubescape/core/meta"
"github.com/spf13/cobra"
)
@@ -11,7 +11,7 @@ var scanCmdExamples = `
Scan command is for scanning an existing cluster or kubernetes manifest files based on pre-defind frameworks
# Scan current cluster with all frameworks
kubescape scan --submit --enable-host-scan
kubescape scan --submit --enable-host-scan --verbose
# Scan kubernetes YAML manifest files
kubescape scan *.yaml
@@ -72,11 +72,11 @@ func GetScanCommand(ks meta.IKubescape) *cobra.Command {
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")
scanCmd.PersistentFlags().BoolVar(&scanInfo.VerboseMode, "verbose", false, "Display all of the input resources and not only failed resources")
scanCmd.PersistentFlags().BoolVarP(&scanInfo.VerboseMode, "verbose", "v", false, "Display all of the input resources and not only failed resources")
scanCmd.PersistentFlags().BoolVar(&scanInfo.UseDefault, "use-default", false, "Load local policy object from default path. If not used will download latest")
scanCmd.PersistentFlags().StringSliceVar(&scanInfo.UseFrom, "use-from", nil, "Load local policy object from specified path. If not used will download latest")
scanCmd.PersistentFlags().BoolVarP(&scanInfo.Submit, "submit", "", false, "Send the scan results to ARMO management portal where you can see the results in a user-friendly UI, choose your preferred compliance framework, check risk results history and trends, manage exceptions, get remediation recommendations and much more. By default the results are not submitted")
scanCmd.PersistentFlags().StringVar(&scanInfo.HostSensorYamlPath, "host-scan-yaml", "", "Override default host sensor DaemonSet. Use this flag cautiously")
scanCmd.PersistentFlags().StringVar(&scanInfo.HostSensorYamlPath, "host-scan-yaml", "", "Override default host scanner DaemonSet. Use this flag cautiously")
scanCmd.PersistentFlags().StringVar(&scanInfo.FormatVersion, "format-version", "v1", "Output object can be differnet between versions, this is for maintaining backward and forward compatibility. Supported:'v1'/'v2'")
// Deprecated flags - remove 1.May.2022

View File

@@ -3,7 +3,7 @@ package submit
import (
"fmt"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/meta"
metav1 "github.com/armosec/kubescape/core/meta/datastructures/v1"

View File

@@ -2,10 +2,10 @@ package submit
import (
"github.com/armosec/k8s-interface/k8sinterface"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/cautils/getter"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/cautils/logger/helpers"
"github.com/armosec/kubescape/core/cautils"
"github.com/armosec/kubescape/core/cautils/getter"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
"github.com/armosec/kubescape/core/meta"
"github.com/armosec/kubescape/core/meta/cliinterfaces"
v1 "github.com/armosec/kubescape/core/meta/datastructures/v1"

View File

@@ -7,8 +7,8 @@ import (
"time"
"github.com/armosec/k8s-interface/workloadinterface"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/cautils/logger/helpers"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
"github.com/armosec/kubescape/core/meta"
"github.com/armosec/kubescape/core/meta/cliinterfaces"
v1 "github.com/armosec/kubescape/core/meta/datastructures/v1"

View File

@@ -4,7 +4,7 @@ import (
"fmt"
"os"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/core/cautils"
"github.com/spf13/cobra"
)

View File

@@ -3,12 +3,12 @@
```go
// initialize kubescape
ks := core.NewKubescape()
ks := core.NewKubescape()
// scan cluster
results, err := ks.Scan()
results, err := ks.Scan(&cautils.ScanInfo{})
// convert scan results to json
jsonRes, err := results.ToJson()
// convert scan results to json
jsonRes, err := results.ToJson()
```

View File

@@ -10,7 +10,8 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/armosec/k8s-interface/k8sinterface"
"github.com/armosec/kubescape/cautils/getter"
"github.com/armosec/kubescape/core/cautils/getter"
"github.com/armosec/kubescape/core/cautils/logger"
corev1 "k8s.io/api/core/v1"
)
@@ -68,6 +69,7 @@ type ITenantConfig interface {
// getters
GetClusterName() string
GetAccountID() string
GetTennatEmail() string
GetConfigObj() *ConfigObj
// GetBackendAPI() getter.IBackend
// GenerateURL()
@@ -117,6 +119,7 @@ func NewLocalConfig(
}
func (lc *LocalConfig) GetConfigObj() *ConfigObj { return lc.configObj }
func (lc *LocalConfig) GetTennatEmail() string { return lc.configObj.CustomerAdminEMail }
func (lc *LocalConfig) GetAccountID() string { return lc.configObj.AccountID }
func (lc *LocalConfig) GetClusterName() string { return lc.configObj.ClusterName }
func (lc *LocalConfig) IsConfigFound() bool { return existsConfigFile() }
@@ -135,7 +138,10 @@ func (lc *LocalConfig) UpdateCachedConfig() error {
}
func (lc *LocalConfig) DeleteCachedConfig() error {
return DeleteConfigFile()
if err := DeleteConfigFile(); err != nil {
logger.L().Warning(err.Error())
}
return nil
}
func getTenantConfigFromBE(backendAPI getter.IBackend, configObj *ConfigObj) error {
@@ -228,6 +234,7 @@ func NewClusterConfig(k8s *k8sinterface.KubernetesApi, backendAPI getter.IBacken
func (c *ClusterConfig) GetConfigObj() *ConfigObj { return c.configObj }
func (c *ClusterConfig) GetDefaultNS() string { return c.configMapNamespace }
func (c *ClusterConfig) GetAccountID() string { return c.configObj.AccountID }
func (c *ClusterConfig) GetTennatEmail() string { return c.configObj.CustomerAdminEMail }
func (c *ClusterConfig) IsConfigFound() bool { return existsConfigFile() || c.existsConfigMap() }
func (c *ClusterConfig) SetTenant() error {
@@ -257,10 +264,10 @@ func (c *ClusterConfig) UpdateCachedConfig() error {
func (c *ClusterConfig) DeleteCachedConfig() error {
if err := c.deleteConfigMap(); err != nil {
return err
logger.L().Warning(err.Error())
}
if err := DeleteConfigFile(); err != nil {
return err
logger.L().Warning(err.Error())
}
return nil
}

View File

@@ -0,0 +1,88 @@
package cautils
import (
"github.com/armosec/armoapi-go/armotypes"
"github.com/armosec/k8s-interface/workloadinterface"
"github.com/armosec/opa-utils/reporthandling"
apis "github.com/armosec/opa-utils/reporthandling/apis"
"github.com/armosec/opa-utils/reporthandling/results/v1/resourcesresults"
reporthandlingv2 "github.com/armosec/opa-utils/reporthandling/v2"
)
// K8SResources map[<api group>/<api version>/<resource>][]<resourceID>
type K8SResources map[string][]string
type ArmoResources map[string][]string
type OPASessionObj struct {
K8SResources *K8SResources // input k8s objects
ArmoResource *ArmoResources // input ARMO objects
Policies []reporthandling.Framework // list of frameworks to scan
AllResources map[string]workloadinterface.IMetadata // all scanned resources, map[<rtesource ID>]<resource>
ResourcesResult map[string]resourcesresults.Result // resources scan results, map[<rtesource ID>]<resource result>
ResourceSource map[string]string // resources sources, map[<rtesource ID>]<resource result>
PostureReport *reporthandling.PostureReport // scan results v1 - Remove
Report *reporthandlingv2.PostureReport // scan results v2 - Remove
Exceptions []armotypes.PostureExceptionPolicy // list of exceptions to apply on scan results
RegoInputData RegoInputData // input passed to rgo for scanning. map[<control name>][<input arguments>]
Metadata *reporthandlingv2.Metadata
InfoMap map[string]apis.StatusInfo // Map errors of resources to StatusInfo
ResourceToControlsMap map[string][]string // map[<apigroup/apiversion/resource>] = [<control_IDs>]
SessionID string // SessionID
}
func NewOPASessionObj(frameworks []reporthandling.Framework, k8sResources *K8SResources, scanInfo *ScanInfo) *OPASessionObj {
return &OPASessionObj{
Report: &reporthandlingv2.PostureReport{},
Policies: frameworks,
K8SResources: k8sResources,
AllResources: make(map[string]workloadinterface.IMetadata),
ResourcesResult: make(map[string]resourcesresults.Result),
InfoMap: make(map[string]apis.StatusInfo),
ResourceToControlsMap: make(map[string][]string),
ResourceSource: make(map[string]string),
SessionID: scanInfo.ScanID,
PostureReport: &reporthandling.PostureReport{
ClusterName: ClusterName,
CustomerGUID: CustomerGUID,
},
Metadata: scanInfoToScanMetadata(scanInfo),
}
}
func NewOPASessionObjMock() *OPASessionObj {
return &OPASessionObj{
Policies: nil,
K8SResources: nil,
AllResources: make(map[string]workloadinterface.IMetadata),
ResourcesResult: make(map[string]resourcesresults.Result),
Report: &reporthandlingv2.PostureReport{},
PostureReport: &reporthandling.PostureReport{
ClusterName: "",
CustomerGUID: "",
ReportID: "",
JobID: "",
},
}
}
type ComponentConfig struct {
Exceptions Exception `json:"exceptions"`
}
type Exception struct {
Ignore *bool `json:"ignore"` // ignore test results
MultipleScore *reporthandling.AlertScore `json:"multipleScore"` // MultipleScore number - float32
Namespaces []string `json:"namespaces"`
Regex string `json:"regex"` // not supported
}
type RegoInputData struct {
PostureControlInputs map[string][]string `json:"postureControlInputs"`
// ClusterName string `json:"clusterName"`
// K8sConfig RegoK8sConfig `json:"k8sconfig"`
}
type Policies struct {
Frameworks []string
Controls map[string]reporthandling.Control // map[<control ID>]<control>
}

View File

@@ -4,7 +4,7 @@ import (
"os"
"time"
"github.com/briandowns/spinner"
spinnerpkg "github.com/briandowns/spinner"
"github.com/fatih/color"
"github.com/mattn/go-isatty"
)
@@ -18,18 +18,24 @@ var SimpleDisplay = color.New().FprintfFunc()
var SuccessDisplay = color.New(color.Bold, color.FgHiGreen).FprintfFunc()
var DescriptionDisplay = color.New(color.Faint, color.FgWhite).FprintfFunc()
var Spinner *spinner.Spinner
var spinner *spinnerpkg.Spinner
func StartSpinner() {
if spinner != nil {
if !spinner.Active() {
spinner.Start()
}
return
}
if isatty.IsTerminal(os.Stdout.Fd()) {
Spinner = spinner.New(spinner.CharSets[7], 100*time.Millisecond) // Build our new spinner
Spinner.Start()
spinner = spinnerpkg.New(spinnerpkg.CharSets[7], 100*time.Millisecond) // Build our new spinner
spinner.Start()
}
}
func StopSpinner() {
if Spinner == nil {
if spinner == nil || !spinner.Active() {
return
}
Spinner.Stop()
spinner.Stop()
}

View File

@@ -0,0 +1,7 @@
package cautils
// CA environment vars
var (
CustomerGUID = ""
ClusterName = ""
)

View File

@@ -9,7 +9,7 @@ import (
"strings"
"github.com/armosec/k8s-interface/workloadinterface"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/opa-utils/objectsenvelopes"
"gopkg.in/yaml.v2"
)
@@ -26,7 +26,7 @@ const (
JSON_FILE_FORMAT FileFormat = "json"
)
func LoadResourcesFromFiles(inputPatterns []string) ([]workloadinterface.IMetadata, error) {
func LoadResourcesFromFiles(inputPatterns []string) (map[string][]workloadinterface.IMetadata, error) {
files, errs := listFiles(inputPatterns)
if len(errs) > 0 {
logger.L().Error(fmt.Sprintf("%v", errs))
@@ -42,8 +42,8 @@ func LoadResourcesFromFiles(inputPatterns []string) ([]workloadinterface.IMetada
return workloads, nil
}
func loadFiles(filePaths []string) ([]workloadinterface.IMetadata, []error) {
workloads := []workloadinterface.IMetadata{}
func loadFiles(filePaths []string) (map[string][]workloadinterface.IMetadata, []error) {
workloads := make(map[string][]workloadinterface.IMetadata, 0)
errs := []error{}
for i := range filePaths {
f, err := loadFile(filePaths[i])
@@ -54,7 +54,12 @@ func loadFiles(filePaths []string) ([]workloadinterface.IMetadata, []error) {
w, e := ReadFile(f, GetFileFormat(filePaths[i]))
errs = append(errs, e...)
if w != nil {
workloads = append(workloads, w...)
if _, ok := workloads[filePaths[i]]; !ok {
workloads[filePaths[i]] = []workloadinterface.IMetadata{}
}
wSlice := workloads[filePaths[i]]
wSlice = append(wSlice, w...)
workloads[filePaths[i]] = wSlice
}
}
return workloads, errs

View File

@@ -11,7 +11,7 @@ import (
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 TestListFiles(t *testing.T) {
@@ -23,6 +23,20 @@ func TestListFiles(t *testing.T) {
assert.Equal(t, 12, len(files))
}
func TestLoadResourcesFromFiles(t *testing.T) {
workloads, err := LoadResourcesFromFiles([]string{onlineBoutiquePath()})
assert.NoError(t, err)
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())
}
}
}
func TestLoadFiles(t *testing.T) {
files, _ := listFiles([]string{onlineBoutiquePath()})
_, err := loadFiles(files)

View File

@@ -0,0 +1,18 @@
package cautils
import "math"
// Float64ToInt convert float64 to int
func Float64ToInt(x float64) int {
return int(math.Round(x))
}
// Float32ToInt convert float32 to int
func Float32ToInt(x float32) int {
return Float64ToInt(float64(x))
}
// Float16ToInt convert float16 to int
func Float16ToInt(x float32) int {
return Float64ToInt(float64(x))
}

View File

@@ -0,0 +1,24 @@
package cautils
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestFloat64ToInt(t *testing.T) {
assert.Equal(t, 3, Float64ToInt(3.49))
assert.Equal(t, 4, Float64ToInt(3.5))
assert.Equal(t, 4, Float64ToInt(3.51))
}
func TestFloat32ToInt(t *testing.T) {
assert.Equal(t, 3, Float32ToInt(3.49))
assert.Equal(t, 4, Float32ToInt(3.5))
assert.Equal(t, 4, Float32ToInt(3.51))
}
func TestFloat16ToInt(t *testing.T) {
assert.Equal(t, 3, Float16ToInt(3.49))
assert.Equal(t, 4, Float16ToInt(3.5))
assert.Equal(t, 4, Float16ToInt(3.51))
}

View File

@@ -10,8 +10,8 @@ import (
"time"
"github.com/armosec/armoapi-go/armotypes"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/cautils/logger/helpers"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
"github.com/armosec/opa-utils/reporthandling"
)
@@ -163,7 +163,6 @@ func (armoAPI *ArmoAPI) GetFramework(name string) (*reporthandling.Framework, er
if err = JSONDecoder(respStr).Decode(framework); err != nil {
return nil, err
}
SaveInFile(framework, GetDefaultPath(name+".json"))
return framework, err
}
@@ -233,7 +232,14 @@ func (armoAPI *ArmoAPI) GetAccountConfig(clusterName string) (*armotypes.Custome
}
if err = JSONDecoder(respStr).Decode(&accountConfig); err != nil {
return nil, err
// try with default scope
respStr, err = armoAPI.Get(armoAPI.getAccountConfigDefault(clusterName), nil)
if err != nil {
return nil, err
}
if err = JSONDecoder(respStr).Decode(&accountConfig); err != nil {
return nil, err
}
}
return accountConfig, nil

View File

@@ -73,6 +73,12 @@ func (armoAPI *ArmoAPI) exceptionsURL(exceptionsPolicyName string) string {
return u.String()
}
func (armoAPI *ArmoAPI) getAccountConfigDefault(clusterName string) string {
config := armoAPI.getAccountConfig(clusterName)
url := config + "&scope=default"
return url
}
func (armoAPI *ArmoAPI) getAccountConfig(clusterName string) string {
u := url.URL{}
u.Scheme = "https"

View File

@@ -4,10 +4,10 @@ import (
"os"
"strings"
"github.com/armosec/kubescape/cautils/logger/helpers"
"github.com/armosec/kubescape/cautils/logger/nonelogger"
"github.com/armosec/kubescape/cautils/logger/prettylogger"
"github.com/armosec/kubescape/cautils/logger/zaplogger"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
"github.com/armosec/kubescape/core/cautils/logger/nonelogger"
"github.com/armosec/kubescape/core/cautils/logger/prettylogger"
"github.com/armosec/kubescape/core/cautils/logger/zaplogger"
)
type ILogger interface {

View File

@@ -3,7 +3,7 @@ package nonelogger
import (
"os"
"github.com/armosec/kubescape/cautils/logger/helpers"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
)
const LoggerName string = "none"

View File

@@ -3,7 +3,7 @@ package prettylogger
import (
"io"
"github.com/armosec/kubescape/cautils/logger/helpers"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
"github.com/fatih/color"
)

View File

@@ -5,7 +5,7 @@ import (
"os"
"sync"
"github.com/armosec/kubescape/cautils/logger/helpers"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
)
const LoggerName string = "pretty"

View File

@@ -3,7 +3,7 @@ package zaplogger
import (
"os"
"github.com/armosec/kubescape/cautils/logger/helpers"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)

View File

@@ -11,8 +11,7 @@ func ReportV2ToV1(opaSessionObj *OPASessionObj) {
if len(opaSessionObj.PostureReport.FrameworkReports) > 0 {
return // report already converted
}
opaSessionObj.PostureReport.ClusterCloudProvider = opaSessionObj.Report.ClusterCloudProvider
// opaSessionObj.PostureReport.ClusterCloudProvider = opaSessionObj.Report.ClusterCloudProvider
frameworks := []reporthandling.FrameworkReport{}

89
core/cautils/rootinfo.go Normal file
View File

@@ -0,0 +1,89 @@
package cautils
type RootInfo struct {
Logger string // logger level
LoggerName string // logger name ("pretty"/"zap"/"none")
CacheDir string // cached dir
DisableColor bool // Disable Color
ArmoBEURLs string // armo url
ArmoBEURLsDep string // armo url
}
// func (rootInfo *RootInfo) InitLogger() {
// logger.DisableColor(rootInfo.DisableColor)
// if rootInfo.LoggerName == "" {
// if l := os.Getenv("KS_LOGGER_NAME"); l != "" {
// rootInfo.LoggerName = l
// } else {
// if isatty.IsTerminal(os.Stdout.Fd()) {
// rootInfo.LoggerName = "pretty"
// } else {
// rootInfo.LoggerName = "zap"
// }
// }
// }
// logger.InitLogger(rootInfo.LoggerName)
// }
// func (rootInfo *RootInfo) InitLoggerLevel() error {
// if rootInfo.Logger == helpers.InfoLevel.String() {
// } else if l := os.Getenv("KS_LOGGER"); l != "" {
// rootInfo.Logger = l
// }
// if err := logger.L().SetLevel(rootInfo.Logger); err != nil {
// return fmt.Errorf("supported levels: %s", strings.Join(helpers.SupportedLevels(), "/"))
// }
// return nil
// }
// func (rootInfo *RootInfo) InitCacheDir() error {
// if rootInfo.CacheDir == getter.DefaultLocalStore {
// getter.DefaultLocalStore = rootInfo.CacheDir
// } else if cacheDir := os.Getenv("KS_CACHE_DIR"); cacheDir != "" {
// getter.DefaultLocalStore = cacheDir
// } else {
// return nil // using default cache dir location
// }
// // TODO create dir if not found exist
// // logger.L().Debug("cache dir updated", helpers.String("path", getter.DefaultLocalStore))
// return nil
// }
// func (rootInfo *RootInfo) InitEnvironment() error {
// urlSlices := strings.Split(rootInfo.ArmoBEURLs, ",")
// if len(urlSlices) != 1 && len(urlSlices) < 3 {
// return fmt.Errorf("expected at least 2 URLs (report,api,frontend,auth)")
// }
// switch len(urlSlices) {
// case 1:
// switch urlSlices[0] {
// case "dev", "development":
// getter.SetARMOAPIConnector(getter.NewARMOAPIDev())
// case "stage", "staging":
// getter.SetARMOAPIConnector(getter.NewARMOAPIStaging())
// case "":
// getter.SetARMOAPIConnector(getter.NewARMOAPIProd())
// default:
// return fmt.Errorf("unknown environment")
// }
// case 2:
// armoERURL := urlSlices[0] // mandatory
// armoBEURL := urlSlices[1] // mandatory
// getter.SetARMOAPIConnector(getter.NewARMOAPICustomized(armoERURL, armoBEURL, "", ""))
// case 3, 4:
// var armoAUTHURL string
// armoERURL := urlSlices[0] // mandatory
// armoBEURL := urlSlices[1] // mandatory
// armoFEURL := urlSlices[2] // mandatory
// if len(urlSlices) <= 4 {
// armoAUTHURL = urlSlices[3]
// }
// getter.SetARMOAPIConnector(getter.NewARMOAPICustomized(armoERURL, armoBEURL, armoFEURL, armoAUTHURL))
// }
// return nil
// }

View File

@@ -8,10 +8,13 @@ import (
"path/filepath"
"strings"
"github.com/armosec/kubescape/cautils/getter"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/cautils/logger/helpers"
"github.com/armosec/k8s-interface/k8sinterface"
"github.com/armosec/kubescape/core/cautils/getter"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
"github.com/armosec/opa-utils/reporthandling"
reporthandlingv2 "github.com/armosec/opa-utils/reporthandling/v2"
"github.com/google/uuid"
)
const (
@@ -38,6 +41,12 @@ func (bpf *BoolPtrFlag) String() string {
func (bpf *BoolPtrFlag) Get() *bool {
return bpf.valPtr
}
func (bpf *BoolPtrFlag) GetBool() bool {
if bpf.valPtr == nil {
return false
}
return *bpf.valPtr
}
func (bpf *BoolPtrFlag) SetBool(val bool) {
bpf.valPtr = &val
@@ -53,13 +62,6 @@ func (bpf *BoolPtrFlag) Set(val string) error {
return nil
}
type RootInfo struct {
Logger string // logger level
LoggerName string // logger name ("pretty"/"zap"/"none")
CacheDir string // cached dir
DisableColor bool // Disable Color
}
// TODO - UPDATE
type ScanInfo struct {
Getters // TODO - remove from object
@@ -73,14 +75,14 @@ type ScanInfo struct {
Format string // Format results (table, json, junit ...)
Output string // Store results in an output file, Output file name
FormatVersion string // Output object can be differnet between versions, this is for testing and backward compatibility
ExcludedNamespaces string // used for host sensor namespace
ExcludedNamespaces string // used for host scanner namespace
IncludeNamespaces string // DEPRECATED?
InputPatterns []string // Yaml files input patterns
Silent bool // Silent mode - Do not print progress logs
FailThreshold float32 // Failure score threshold
Submit bool // Submit results to Armo BE
ReportID string // Report id of the current scan
HostSensorEnabled BoolPtrFlag // Deploy ARMO K8s host sensor to collect data from certain controls
ScanID string // Report id of the current scan
HostSensorEnabled BoolPtrFlag // Deploy ARMO K8s host scanner to collect data from certain controls
HostSensorYamlPath string // Path to hostsensor file
Local bool // Do not submit results
Account string // account ID
@@ -99,6 +101,10 @@ func (scanInfo *ScanInfo) Init() {
scanInfo.setUseFrom()
scanInfo.setOutputFile()
scanInfo.setUseArtifactsFrom()
if scanInfo.ScanID == "" {
scanInfo.ScanID = uuid.NewString()
}
}
func (scanInfo *ScanInfo) setUseArtifactsFrom() {
@@ -133,15 +139,6 @@ func (scanInfo *ScanInfo) setUseArtifactsFrom() {
scanInfo.UseExceptions = filepath.Join(scanInfo.UseArtifactsFrom, localExceptionsFilename)
}
func (scanInfo *ScanInfo) setUseExceptions() {
if scanInfo.UseExceptions != "" {
// load exceptions from file
scanInfo.ExceptionsGetter = getter.NewLoadPolicy([]string{scanInfo.UseExceptions})
} else {
scanInfo.ExceptionsGetter = getter.GetArmoAPIConnector()
}
}
func (scanInfo *ScanInfo) setUseFrom() {
if scanInfo.UseDefault {
for _, policy := range scanInfo.PolicyIdentifier {
@@ -197,3 +194,94 @@ func (scanInfo *ScanInfo) contains(policyName string) bool {
}
return false
}
func scanInfoToScanMetadata(scanInfo *ScanInfo) *reporthandlingv2.Metadata {
metadata := &reporthandlingv2.Metadata{}
metadata.ScanMetadata.Format = scanInfo.Format
metadata.ScanMetadata.FormatVersion = scanInfo.FormatVersion
metadata.ScanMetadata.Submit = scanInfo.Submit
// TODO - Add excluded and included namespaces
// if len(scanInfo.ExcludedNamespaces) > 1 {
// opaSessionObj.Metadata.ScanMetadata.ExcludedNamespaces = strings.Split(scanInfo.ExcludedNamespaces[1:], ",")
// }
// if len(scanInfo.IncludeNamespaces) > 1 {
// opaSessionObj.Metadata.ScanMetadata.IncludeNamespaces = strings.Split(scanInfo.IncludeNamespaces[1:], ",")
// }
// scan type
if len(scanInfo.PolicyIdentifier) > 0 {
metadata.ScanMetadata.TargetType = string(scanInfo.PolicyIdentifier[0].Kind)
}
// append frameworks
for _, policy := range scanInfo.PolicyIdentifier {
metadata.ScanMetadata.TargetNames = append(metadata.ScanMetadata.TargetNames, policy.Name)
}
metadata.ScanMetadata.VerboseMode = scanInfo.VerboseMode
metadata.ScanMetadata.FailThreshold = scanInfo.FailThreshold
metadata.ScanMetadata.HostScanner = scanInfo.HostSensorEnabled.GetBool()
metadata.ScanMetadata.VerboseMode = scanInfo.VerboseMode
metadata.ScanMetadata.ControlsInputs = scanInfo.ControlsInputs
metadata.ScanMetadata.ScanningTarget = reporthandlingv2.Cluster
if scanInfo.GetScanningEnvironment() == ScanLocalFiles {
metadata.ScanMetadata.ScanningTarget = reporthandlingv2.File
}
inputFiles := ""
if len(scanInfo.InputPatterns) > 0 {
inputFiles = scanInfo.InputPatterns[0]
}
setContextMetadata(&metadata.ContextMetadata, inputFiles)
return metadata
}
func setContextMetadata(contextMetadata *reporthandlingv2.ContextMetadata, input string) {
// if cluster
if input == "" {
contextMetadata.ClusterContextMetadata = &reporthandlingv2.ClusterMetadata{
ContextName: k8sinterface.GetClusterName(),
}
return
}
// if url
if strings.HasPrefix(input, "http") { // TODO - check if can parse
return
}
if !filepath.IsAbs(input) {
if o, err := os.Getwd(); err == nil {
input = filepath.Join(o, input)
}
}
// if single file
if IsFile(input) {
contextMetadata.FileContextMetadata = &reporthandlingv2.FileContextMetadata{
FilePath: input,
HostName: getHostname(),
}
return
}
// if dir/glob
if !IsFile(input) {
contextMetadata.DirectoryContextMetadata = &reporthandlingv2.DirectoryContextMetadata{
BasePath: input,
HostName: getHostname(),
}
return
}
}
func getHostname() string {
if h, e := os.Hostname(); e == nil {
return h
}
return ""
}

View File

@@ -0,0 +1,65 @@
package cautils
import (
"testing"
reporthandlingv2 "github.com/armosec/opa-utils/reporthandling/v2"
"github.com/stretchr/testify/assert"
)
// func TestSetInputPatterns(t *testing.T) { //Unitest
// {
// scanInfo := ScanInfo{
// InputPatterns: []string{"file"},
// }
// scanInfo.setInputPatterns()
// assert.Equal(t, "file", scanInfo.InputPatterns[0])
// }
// }
func TestSetContextMetadata(t *testing.T) {
{
ctx := reporthandlingv2.ContextMetadata{}
setContextMetadata(&ctx, "")
assert.NotNil(t, ctx.ClusterContextMetadata)
assert.Nil(t, ctx.DirectoryContextMetadata)
assert.Nil(t, ctx.FileContextMetadata)
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)
}
{
ctx := reporthandlingv2.ContextMetadata{}
setContextMetadata(&ctx, "scaninfo_test.go")
assert.Nil(t, ctx.ClusterContextMetadata)
assert.Nil(t, ctx.DirectoryContextMetadata)
assert.NotNil(t, ctx.FileContextMetadata)
assert.Nil(t, ctx.HelmContextMetadata)
assert.Nil(t, ctx.RepoContextMetadata)
}
{
ctx := reporthandlingv2.ContextMetadata{}
setContextMetadata(&ctx, "https://github.com/armosec/kubescape")
assert.Nil(t, ctx.ClusterContextMetadata)
assert.Nil(t, ctx.DirectoryContextMetadata)
assert.Nil(t, ctx.FileContextMetadata)
assert.Nil(t, ctx.HelmContextMetadata)
assert.Nil(t, ctx.RepoContextMetadata) // TODO
}
}
func TestGetHostname(t *testing.T) {
assert.NotEqual(t, "", getHostname())
}

View File

@@ -6,14 +6,15 @@ import (
"net/http"
"os"
"github.com/armosec/kubescape/cautils/getter"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/cautils/logger/helpers"
"github.com/armosec/kubescape/core/cautils/getter"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
pkgutils "github.com/armosec/utils-go/utils"
"golang.org/x/mod/semver"
)
const SKIP_VERSION_CHECK = "KUBESCAPE_SKIP_UPDATE_CHECK"
const SKIP_VERSION_CHECK_DEPRECATED = "KUBESCAPE_SKIP_UPDATE_CHECK"
const SKIP_VERSION_CHECK = "KS_SKIP_UPDATE_CHECK"
var BuildNumber string
@@ -29,6 +30,8 @@ func NewIVersionCheckHandler() IVersionCheckHandler {
}
if v, ok := os.LookupEnv(SKIP_VERSION_CHECK); ok && pkgutils.StringToBool(v) {
return NewVersionCheckHandlerMock()
} else if v, ok := os.LookupEnv(SKIP_VERSION_CHECK_DEPRECATED); ok && pkgutils.StringToBool(v) {
return NewVersionCheckHandlerMock()
}
return NewVersionCheckHandler()
}

View File

@@ -0,0 +1,52 @@
package cautils
import (
"strings"
"github.com/armosec/opa-utils/reporthandling/apis"
)
var (
ImageVulnResources = []string{"ImageVulnerabilities"}
HostSensorResources = []string{"KubeletConfiguration",
"KubeletCommandLine",
"OsReleaseFile",
"KernelVersion",
"LinuxSecurityHardeningStatus",
"OpenPortsList",
"LinuxKernelVariables"}
CloudResources = []string{"ClusterDescribe"}
)
func MapArmoResource(armoResourceMap *ArmoResources, resources []string) []string {
var hostResources []string
for k := range *armoResourceMap {
for _, resource := range resources {
if strings.Contains(k, resource) {
hostResources = append(hostResources, k)
}
}
}
return hostResources
}
func MapHostResources(armoResourceMap *ArmoResources) []string {
return MapArmoResource(armoResourceMap, HostSensorResources)
}
func MapImageVulnResources(armoResourceMap *ArmoResources) []string {
return MapArmoResource(armoResourceMap, ImageVulnResources)
}
func MapCloudResources(armoResourceMap *ArmoResources) []string {
return MapArmoResource(armoResourceMap, CloudResources)
}
func SetInfoMapForResources(info string, resources []string, errorMap map[string]apis.StatusInfo) {
for _, resource := range resources {
errorMap[resource] = apis.StatusInfo{
InnerInfo: info,
InnerStatus: apis.StatusSkipped,
}
}
}

View File

@@ -3,9 +3,9 @@ package core
import (
"fmt"
"github.com/armosec/kubescape/cautils/getter"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/cautils/logger/helpers"
"github.com/armosec/kubescape/core/cautils/getter"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
v1 "github.com/armosec/kubescape/core/meta/datastructures/v1"
)

View File

@@ -2,13 +2,14 @@ package core
import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/armosec/armoapi-go/armotypes"
"github.com/armosec/kubescape/cautils/getter"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/cautils/logger/helpers"
"github.com/armosec/kubescape/core/cautils/getter"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
metav1 "github.com/armosec/kubescape/core/meta/datastructures/v1"
)
@@ -30,6 +31,9 @@ func DownloadSupportCommands() []string {
func (ks *Kubescape) Download(downloadInfo *metav1.DownloadInfo) error {
setPathandFilename(downloadInfo)
if err := os.MkdirAll(downloadInfo.Path, os.ModePerm); err != nil {
return err
}
if err := downloadArtifact(downloadInfo, downloadFunc); err != nil {
return err
}
@@ -86,6 +90,9 @@ func downloadConfigInputs(downloadInfo *metav1.DownloadInfo) error {
if downloadInfo.FileName == "" {
downloadInfo.FileName = fmt.Sprintf("%s.json", downloadInfo.Target)
}
if controlInputs == nil {
return fmt.Errorf("failed to download controlInputs - received an empty objects")
}
// save in file
err = getter.SaveInFile(controlInputs, filepath.Join(downloadInfo.Path, downloadInfo.FileName))
if err != nil {
@@ -123,7 +130,7 @@ func downloadFramework(downloadInfo *metav1.DownloadInfo) error {
tenant := getTenantConfig(downloadInfo.Account, "", getKubernetesApi())
g := getPolicyGetter(nil, tenant.GetAccountID(), true, nil)
g := getPolicyGetter(nil, tenant.GetTennatEmail(), true, nil)
if downloadInfo.Name == "" {
// if framework name not specified - download all frameworks
@@ -148,6 +155,9 @@ func downloadFramework(downloadInfo *metav1.DownloadInfo) error {
if err != nil {
return err
}
if framework == nil {
return fmt.Errorf("failed to download framework - received an empty objects")
}
downloadTo := filepath.Join(downloadInfo.Path, downloadInfo.FileName)
err = getter.SaveInFile(framework, downloadTo)
if err != nil {
@@ -162,7 +172,7 @@ func downloadControl(downloadInfo *metav1.DownloadInfo) error {
tenant := getTenantConfig(downloadInfo.Account, "", getKubernetesApi())
g := getPolicyGetter(nil, tenant.GetAccountID(), false, nil)
g := getPolicyGetter(nil, tenant.GetTennatEmail(), false, nil)
if downloadInfo.Name == "" {
// TODO - support
@@ -175,6 +185,9 @@ func downloadControl(downloadInfo *metav1.DownloadInfo) error {
if err != nil {
return err
}
if controls == nil {
return fmt.Errorf("failed to download control - received an empty objects")
}
downloadTo := filepath.Join(downloadInfo.Path, downloadInfo.FileName)
err = getter.SaveInFile(controls, downloadTo)
if err != nil {

View File

@@ -2,13 +2,12 @@ package core
import (
"fmt"
"os"
"github.com/armosec/k8s-interface/k8sinterface"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/cautils/getter"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/cautils/logger/helpers"
"github.com/armosec/kubescape/core/cautils"
"github.com/armosec/kubescape/core/cautils/getter"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
"github.com/armosec/kubescape/core/pkg/hostsensorutils"
"github.com/armosec/kubescape/core/pkg/resourcehandler"
"github.com/armosec/kubescape/core/pkg/resultshandling/reporter"
@@ -48,11 +47,11 @@ func getRBACHandler(tenantConfig cautils.ITenantConfig, k8s *k8sinterface.Kubern
return nil
}
func getReporter(tenantConfig cautils.ITenantConfig, reportID string, submit, fwScan, clusterScan bool) reporter.IReport {
if submit && clusterScan {
func getReporter(tenantConfig cautils.ITenantConfig, reportID string, submit, fwScan bool) reporter.IReport {
if submit {
return reporterv2.NewReportEventReceiver(tenantConfig.GetConfigObj(), reportID)
}
if tenantConfig.GetAccountID() == "" && fwScan && clusterScan {
if tenantConfig.GetAccountID() == "" {
// Add link only when scanning a cluster using a framework
return reporterv2.NewReportMock(reporterv2.NO_SUBMIT_QUERY, "run kubescape with the '--submit' flag")
}
@@ -60,9 +59,7 @@ func getReporter(tenantConfig cautils.ITenantConfig, reportID string, submit, fw
if !fwScan {
message = "Kubescape does not submit scan results when scanning controls"
}
if !clusterScan {
message = "Kubescape will submit scan results only when scanning a cluster (not YAML files)"
}
return reporterv2.NewReportMock("", message)
}
@@ -82,7 +79,7 @@ func getHostSensorHandler(scanInfo *cautils.ScanInfo, k8s *k8sinterface.Kubernet
}
hasHostSensorControls := true
// we need to determined which controls needs host sensor
// we need to determined which controls needs host scanner
if scanInfo.HostSensorEnabled.Get() == nil && hasHostSensorControls {
scanInfo.HostSensorEnabled.SetBool(false) // default - do not run host scanner
logger.L().Warning("Kubernetes cluster nodes scanning is disabled. This is required to collect valuable data for certain controls. You can enable it using the --enable-host-scan flag")
@@ -90,7 +87,7 @@ func getHostSensorHandler(scanInfo *cautils.ScanInfo, k8s *k8sinterface.Kubernet
if hostSensorVal := scanInfo.HostSensorEnabled.Get(); hostSensorVal != nil && *hostSensorVal {
hostSensorHandler, err := hostsensorutils.NewHostSensorHandler(k8s, scanInfo.HostSensorYamlPath)
if err != nil {
logger.L().Warning(fmt.Sprintf("failed to create host sensor: %s", err.Error()))
logger.L().Warning(fmt.Sprintf("failed to create host scanner: %s", err.Error()))
return &hostsensorutils.HostSensorHandlerMock{}
}
return hostSensorHandler
@@ -153,11 +150,11 @@ func setSubmitBehavior(scanInfo *cautils.ScanInfo, tenantConfig cautils.ITenantC
}
// setPolicyGetter set the policy getter - local file/github release/ArmoAPI
func getPolicyGetter(loadPoliciesFromFile []string, accountID string, frameworkScope bool, downloadReleasedPolicy *getter.DownloadReleasedPolicy) getter.IPolicyGetter {
func getPolicyGetter(loadPoliciesFromFile []string, tennatEmail string, frameworkScope bool, downloadReleasedPolicy *getter.DownloadReleasedPolicy) getter.IPolicyGetter {
if len(loadPoliciesFromFile) > 0 {
return getter.NewLoadPolicy(loadPoliciesFromFile)
}
if accountID != "" && frameworkScope {
if tennatEmail != "" && frameworkScope {
g := getter.GetArmoAPIConnector() // download policy from ARMO backend
return g
}
@@ -195,7 +192,7 @@ func getConfigInputsGetter(ControlsInputs string, accountID string, downloadRele
downloadReleasedPolicy = getter.NewDownloadReleasedPolicy()
}
if err := downloadReleasedPolicy.SetRegoObjects(); err != nil { // if failed to pull config inputs, fallback to BE
cautils.WarningDisplay(os.Stderr, "Warning: failed to get config inputs from github release, this may affect the scanning results\n")
logger.L().Warning("failed to get config inputs from github release, this may affect the scanning results", helpers.Error(err))
}
return downloadReleasedPolicy
}

View File

@@ -6,7 +6,7 @@ import (
"sort"
"strings"
"github.com/armosec/kubescape/cautils/getter"
"github.com/armosec/kubescape/core/cautils/getter"
metav1 "github.com/armosec/kubescape/core/meta/datastructures/v1"
)
@@ -45,7 +45,7 @@ func (ks *Kubescape) List(listPolicies *metav1.ListPolicies) error {
func listFrameworks(listPolicies *metav1.ListPolicies) ([]string, error) {
tenant := getTenantConfig(listPolicies.Account, "", getKubernetesApi()) // change k8sinterface
g := getPolicyGetter(nil, tenant.GetAccountID(), true, nil)
g := getPolicyGetter(nil, tenant.GetTennatEmail(), true, nil)
return listFrameworksNames(g), nil
}
@@ -53,7 +53,7 @@ func listFrameworks(listPolicies *metav1.ListPolicies) ([]string, error) {
func listControls(listPolicies *metav1.ListPolicies) ([]string, error) {
tenant := getTenantConfig(listPolicies.Account, "", getKubernetesApi()) // change k8sinterface
g := getPolicyGetter(nil, tenant.GetAccountID(), false, nil)
g := getPolicyGetter(nil, tenant.GetTennatEmail(), false, nil)
l := getter.ListName
if listPolicies.ListIDs {
l = getter.ListID

View File

@@ -6,10 +6,10 @@ import (
"github.com/armosec/armoapi-go/armotypes"
"github.com/armosec/k8s-interface/k8sinterface"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/cautils/getter"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/cautils/logger/helpers"
"github.com/armosec/kubescape/core/cautils"
"github.com/armosec/kubescape/core/cautils/getter"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
"github.com/armosec/kubescape/core/pkg/hostsensorutils"
"github.com/armosec/kubescape/core/pkg/opaprocessor"
"github.com/armosec/kubescape/core/pkg/policyhandler"
@@ -48,6 +48,11 @@ func getInterfaces(scanInfo *cautils.ScanInfo) componentInterfaces {
// Set submit behavior AFTER loading tenant config
setSubmitBehavior(scanInfo, tenantConfig)
// Do not submit yaml scanning
if len(scanInfo.InputPatterns) > 0 {
scanInfo.Submit = false
}
if scanInfo.Submit {
// submit - Create tenant & Submit report
if err := tenantConfig.SetTenant(); err != nil {
@@ -60,11 +65,11 @@ func getInterfaces(scanInfo *cautils.ScanInfo) componentInterfaces {
v := cautils.NewIVersionCheckHandler()
v.CheckLatestVersion(cautils.NewVersionCheckRequest(cautils.BuildNumber, policyIdentifierNames(scanInfo.PolicyIdentifier), "", scanInfo.GetScanningEnvironment()))
// ================== setup host sensor object ======================================
// ================== setup host scanner object ======================================
hostSensorHandler := getHostSensorHandler(scanInfo, k8s)
if err := hostSensorHandler.Init(); err != nil {
logger.L().Error("failed to init host sensor", helpers.Error(err))
logger.L().Error("failed to init host scanner", helpers.Error(err))
hostSensorHandler = &hostsensorutils.HostSensorHandlerMock{}
}
// excluding hostsensor namespace
@@ -86,7 +91,7 @@ func getInterfaces(scanInfo *cautils.ScanInfo) componentInterfaces {
// ================== setup reporter & printer objects ======================================
// reporting behavior - setup reporter
reportHandler := getReporter(tenantConfig, scanInfo.ReportID, scanInfo.Submit, scanInfo.FrameworkScan, len(scanInfo.InputPatterns) == 0)
reportHandler := getReporter(tenantConfig, scanInfo.ScanID, scanInfo.Submit, scanInfo.FrameworkScan)
// setup printer
printerHandler := resultshandling.NewPrinter(scanInfo.Format, scanInfo.FormatVersion, scanInfo.VerboseMode)
@@ -119,7 +124,7 @@ func (ks *Kubescape) Scan(scanInfo *cautils.ScanInfo) (*resultshandling.ResultsH
downloadReleasedPolicy := getter.NewDownloadReleasedPolicy() // download config inputs from github release
// set policy getter only after setting the customerGUID
scanInfo.Getters.PolicyGetter = getPolicyGetter(scanInfo.UseFrom, interfaces.tenantConfig.GetAccountID(), scanInfo.FrameworkScan, downloadReleasedPolicy)
scanInfo.Getters.PolicyGetter = getPolicyGetter(scanInfo.UseFrom, interfaces.tenantConfig.GetTennatEmail(), scanInfo.FrameworkScan, downloadReleasedPolicy)
scanInfo.Getters.ControlsInputsGetter = getConfigInputsGetter(scanInfo.ControlsInputs, interfaces.tenantConfig.GetAccountID(), downloadReleasedPolicy)
scanInfo.Getters.ExceptionsGetter = getExceptionsGetter(scanInfo.UseExceptions)
@@ -131,7 +136,7 @@ func (ks *Kubescape) Scan(scanInfo *cautils.ScanInfo) (*resultshandling.ResultsH
// remove host scanner components
defer func() {
if err := interfaces.hostSensorHandler.TearDown(); err != nil {
logger.L().Error("failed to tear down host sensor", helpers.Error(err))
logger.L().Error("failed to tear down host scanner", helpers.Error(err))
}
}()

View File

@@ -1,10 +1,10 @@
package core
import (
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/cautils/getter"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/cautils/logger/helpers"
"github.com/armosec/kubescape/core/cautils"
"github.com/armosec/kubescape/core/cautils/getter"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
"github.com/armosec/kubescape/core/meta/cliinterfaces"
)
@@ -20,7 +20,7 @@ func (ks *Kubescape) Submit(submitInterfaces cliinterfaces.SubmitInterfaces) err
return err
}
// report
if err := submitInterfaces.Reporter.ActionSendReport(&cautils.OPASessionObj{PostureReport: postureReport, AllResources: allresources}); err != nil {
if err := submitInterfaces.Reporter.Submit(&cautils.OPASessionObj{PostureReport: postureReport, AllResources: allresources}); err != nil {
return err
}
logger.L().Success("Data has been submitted successfully")

View File

@@ -1,32 +1,32 @@
module github.com/armosec/kubescape
module github.com/armosec/kubescape/core
go 1.17
require (
github.com/armosec/armoapi-go v0.0.58
github.com/armosec/k8s-interface v0.0.68
github.com/armosec/opa-utils v0.0.116
github.com/armosec/opa-utils v0.0.130
github.com/armosec/rbac-utils v0.0.14
github.com/armosec/utils-go v0.0.3
github.com/armosec/utils-k8s-go v0.0.1
github.com/briandowns/spinner v1.18.0
github.com/armosec/utils-k8s-go v0.0.3
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/google/uuid v1.3.0
github.com/gorilla/mux v1.8.0
github.com/johnfercher/maroto v0.34.0
github.com/mattn/go-isatty v0.0.14
github.com/olekukonko/tablewriter v0.0.5
github.com/open-policy-agent/opa v0.38.0
github.com/spf13/cobra v1.3.0
github.com/stretchr/testify v1.7.0
github.com/whilp/git-urls v1.0.0
go.uber.org/zap v1.21.0
golang.org/x/mod v0.5.0
golang.org/x/mod v0.5.1
gopkg.in/yaml.v2 v2.4.0
k8s.io/api v0.23.4
k8s.io/apimachinery v0.23.4
k8s.io/client-go v0.23.4
k8s.io/utils v0.0.0-20211116205334-6203023598ed
sigs.k8s.io/yaml v1.3.0
)
@@ -79,7 +79,6 @@ require (
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/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/jung-kurt/gofpdf v1.4.2 // indirect
@@ -119,7 +118,6 @@ require (
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
k8s.io/utils v0.0.0-20211116205334-6203023598ed // indirect
sigs.k8s.io/controller-runtime v0.11.1 // indirect
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect

View File

@@ -109,16 +109,17 @@ github.com/armosec/k8s-interface v0.0.66/go.mod h1:vwprS8qn/iowd5yf0JHpqDsLA5I8W
github.com/armosec/k8s-interface v0.0.68 h1:6CtSakISiI47YHkxh+Va9FzZQIBkWa6g9sbiNxq1Zkk=
github.com/armosec/k8s-interface v0.0.68/go.mod h1:PeWn41C2uenZi+xfZdyFF/zG5wXACA00htQyknDUWDE=
github.com/armosec/opa-utils v0.0.64/go.mod h1:6tQP8UDq2EvEfSqh8vrUdr/9QVSCG4sJfju1SXQOn4c=
github.com/armosec/opa-utils v0.0.116 h1:3oWuhcpI+MJD/CktEStU1BA0feGNwsCbQrI3ifVfzMs=
github.com/armosec/opa-utils v0.0.116/go.mod h1:gap+EaLG5rnyqvIRGxtdNDC9y7VvoGNm90zK8Ls7avQ=
github.com/armosec/opa-utils v0.0.130 h1:uP60M0PzmDtLqvsA/jX8BED9/Ava4n2QG7VCkuI+hwI=
github.com/armosec/opa-utils v0.0.130/go.mod h1:gap+EaLG5rnyqvIRGxtdNDC9y7VvoGNm90zK8Ls7avQ=
github.com/armosec/rbac-utils v0.0.1/go.mod h1:pQ8CBiij8kSKV7aeZm9FMvtZN28VgA7LZcYyTWimq40=
github.com/armosec/rbac-utils v0.0.14 h1:CKYKcgqJEXWF2Hen/B1pVGtS3nDAG1wp9dDv6oNtq90=
github.com/armosec/rbac-utils v0.0.14/go.mod h1:Ex/IdGWhGv9HZq6Hs8N/ApzCKSIvpNe/ETqDfnuyah0=
github.com/armosec/utils-go v0.0.2/go.mod h1:itWmRLzRdsnwjpEOomL0mBWGnVNNIxSjDAdyc+b0iUo=
github.com/armosec/utils-go v0.0.3 h1:uyQI676yRciQM0sSN9uPoqHkbspTxHO0kmzXhBeE/xU=
github.com/armosec/utils-go v0.0.3/go.mod h1:itWmRLzRdsnwjpEOomL0mBWGnVNNIxSjDAdyc+b0iUo=
github.com/armosec/utils-k8s-go v0.0.1 h1:Ay3y7fW+4+FjVc0+obOWm8YsnEvM31vPAVoKTyTAFRk=
github.com/armosec/utils-k8s-go v0.0.1/go.mod h1:qrU4pmY2iZsOb39Eltpm0sTTNM3E4pmeyWx4dgDUC2U=
github.com/armosec/utils-k8s-go v0.0.3 h1:DDQ1U5ltevNAqOyObGsdw1w5/toxCut1C65AV9QGpr4=
github.com/armosec/utils-k8s-go v0.0.3/go.mod h1:qrU4pmY2iZsOb39Eltpm0sTTNM3E4pmeyWx4dgDUC2U=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/aws/aws-sdk-go v1.41.1/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
github.com/aws/aws-sdk-go v1.41.11 h1:QLouWsiYQ8i22kD8k58Dpdhio1A0MpT7bg9ZNXqEjuI=
@@ -160,8 +161,8 @@ github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnweb
github.com/boombuler/barcode v1.0.0 h1:s1TvRnXwL2xJRaccrdcBQMZxq6X7DvsMogtmJeHDdrc=
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
github.com/briandowns/spinner v1.18.0 h1:SJs0maNOs4FqhBwiJ3Gr7Z1D39/rukIVGQvpNZVHVcM=
github.com/briandowns/spinner v1.18.0/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ=
github.com/briandowns/spinner v1.18.1 h1:yhQmQtM1zsqFsouh09Bk/jCjd50pC3EOGsh28gLVvwY=
github.com/briandowns/spinner v1.18.1/go.mod h1:mQak9GHqbspjC/5iUx3qMlIho8xBS/ppAL/hX5SmPJU=
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/bytecodealliance/wasmtime-go v0.30.0/go.mod h1:q320gUxqyI8yB+ZqRuaJOEnGkAnHh6WtJjMaT2CW4wI=
github.com/bytecodealliance/wasmtime-go v0.34.0 h1:PaWS0DUusaXaU3aNoSYjag6WmuxjyPYBHgkrC4EXips=
@@ -435,7 +436,6 @@ github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2c
github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw=
github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
@@ -489,7 +489,6 @@ github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
@@ -741,7 +740,6 @@ github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
github.com/spf13/cobra v1.3.0 h1:R7cSvGu+Vv+qX0gW5R/85dx2kmmJT5z5NM8ifdYjdn0=
github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
@@ -773,6 +771,8 @@ github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqri
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
github.com/whilp/git-urls v1.0.0 h1:95f6UMWN5FKW71ECsXRUd3FVYiXdrE7aX4NZKcPmIjU=
github.com/whilp/git-urls v1.0.0/go.mod h1:J16SAmobsqc3Qcy98brfl5f5+e0clUvg1krgwk/qCfE=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
@@ -917,8 +917,9 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.0 h1:UG21uOlmZabA4fW5i7ZX6bjw1xELEGg/ZLgZq9auk/Q=
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=

View File

@@ -2,7 +2,7 @@ package cliinterfaces
import (
"github.com/armosec/k8s-interface/workloadinterface"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/core/cautils"
"github.com/armosec/kubescape/core/pkg/resultshandling/reporter"
"github.com/armosec/opa-utils/reporthandling"
)

View File

@@ -1,7 +1,7 @@
package meta
import (
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/core/cautils"
"github.com/armosec/kubescape/core/meta/cliinterfaces"
metav1 "github.com/armosec/kubescape/core/meta/datastructures/v1"
"github.com/armosec/kubescape/core/pkg/resultshandling"

View File

@@ -10,9 +10,9 @@ import (
"github.com/armosec/k8s-interface/k8sinterface"
"github.com/armosec/k8s-interface/workloadinterface"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/cautils/logger/helpers"
"github.com/armosec/kubescape/core/cautils"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -71,18 +71,19 @@ func (hsh *HostSensorHandler) Init() error {
// store namespace + port
// store pod names
// make sure all pods are running, after X seconds treat has running anyway, and log an error on the pods not running yet
logger.L().Info("Installing host sensor")
logger.L().Info("Installing host scanner")
cautils.StartSpinner()
defer cautils.StopSpinner()
if err := hsh.applyYAML(); err != nil {
return fmt.Errorf("failed to apply host sensor YAML, reason: %v", err)
cautils.StopSpinner()
return fmt.Errorf("failed to apply host scanner YAML, reason: %v", err)
}
hsh.populatePodNamesToNodeNames()
if err := hsh.checkPodForEachNode(); err != nil {
logger.L().Error("failed to validate host-sensor pods status", helpers.Error(err))
}
cautils.StopSpinner()
return nil
}

View File

@@ -6,10 +6,10 @@ import (
"sync"
"github.com/armosec/k8s-interface/k8sinterface"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/cautils/logger/helpers"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
"github.com/armosec/opa-utils/objectsenvelopes/hostsensor"
"github.com/armosec/opa-utils/reporthandling/apis"
"sigs.k8s.io/yaml"
)
@@ -157,58 +157,77 @@ func (hsh *HostSensorHandler) GetKubeletConfigurations() ([]hostsensor.HostSenso
return res, err
}
func (hsh *HostSensorHandler) CollectResources() ([]hostsensor.HostSensorDataEnvelope, error) {
func (hsh *HostSensorHandler) CollectResources() ([]hostsensor.HostSensorDataEnvelope, map[string]apis.StatusInfo, error) {
res := make([]hostsensor.HostSensorDataEnvelope, 0)
infoMap := make(map[string]apis.StatusInfo)
if hsh.DaemonSet == nil {
return res, nil
return res, nil, nil
}
logger.L().Debug("Accessing host sensor")
cautils.StartSpinner()
defer cautils.StopSpinner()
kcData, err := hsh.GetKubeletConfigurations()
var kcData []hostsensor.HostSensorDataEnvelope
var err error
logger.L().Debug("Accessing host scanner")
kcData, err = hsh.GetKubeletConfigurations()
if err != nil {
return kcData, err
addInfoToMap(KubeletConfiguration, infoMap, err)
logger.L().Warning(err.Error())
}
if len(kcData) > 0 {
res = append(res, kcData...)
}
res = append(res, kcData...)
//
kcData, err = hsh.GetKubeletCommandLine()
if err != nil {
return kcData, err
addInfoToMap(KubeletCommandLine, infoMap, err)
logger.L().Warning(err.Error())
}
if len(kcData) > 0 {
res = append(res, kcData...)
}
res = append(res, kcData...)
//
kcData, err = hsh.GetOsReleaseFile()
if err != nil {
return kcData, err
addInfoToMap(OsReleaseFile, infoMap, err)
logger.L().Warning(err.Error())
}
if len(kcData) > 0 {
res = append(res, kcData...)
}
res = append(res, kcData...)
//
kcData, err = hsh.GetKernelVersion()
if err != nil {
return kcData, err
addInfoToMap(KernelVersion, infoMap, err)
logger.L().Warning(err.Error())
}
if len(kcData) > 0 {
res = append(res, kcData...)
}
res = append(res, kcData...)
//
kcData, err = hsh.GetLinuxSecurityHardeningStatus()
if err != nil {
return kcData, err
addInfoToMap(LinuxSecurityHardeningStatus, infoMap, err)
logger.L().Warning(err.Error())
}
if len(kcData) > 0 {
res = append(res, kcData...)
}
res = append(res, kcData...)
//
kcData, err = hsh.GetOpenPortsList()
if err != nil {
return kcData, err
addInfoToMap(OpenPortsList, infoMap, err)
logger.L().Warning(err.Error())
}
if len(kcData) > 0 {
res = append(res, kcData...)
}
res = append(res, kcData...)
// GetKernelVariables
kcData, err = hsh.GetKernelVariables()
if err != nil {
return kcData, err
addInfoToMap(LinuxKernelVariables, infoMap, err)
logger.L().Warning(err.Error())
}
res = append(res, kcData...)
// finish
logger.L().Debug("Done reading information from host sensor")
return res, nil
if len(kcData) > 0 {
res = append(res, kcData...)
}
logger.L().Debug("Done reading information from host scanner")
return res, infoMap, nil
}

View File

@@ -1,10 +1,13 @@
package hostsensorutils
import "github.com/armosec/opa-utils/objectsenvelopes/hostsensor"
import (
"github.com/armosec/opa-utils/objectsenvelopes/hostsensor"
"github.com/armosec/opa-utils/reporthandling/apis"
)
type IHostSensor interface {
Init() error
TearDown() error
CollectResources() ([]hostsensor.HostSensorDataEnvelope, error)
CollectResources() ([]hostsensor.HostSensorDataEnvelope, map[string]apis.StatusInfo, error)
GetNamespace() string
}

View File

@@ -2,6 +2,7 @@ package hostsensorutils
import (
"github.com/armosec/opa-utils/objectsenvelopes/hostsensor"
"github.com/armosec/opa-utils/reporthandling/apis"
)
type HostSensorHandlerMock struct {
@@ -15,8 +16,8 @@ func (hshm *HostSensorHandlerMock) TearDown() error {
return nil
}
func (hshm *HostSensorHandlerMock) CollectResources() ([]hostsensor.HostSensorDataEnvelope, error) {
return []hostsensor.HostSensorDataEnvelope{}, nil
func (hshm *HostSensorHandlerMock) CollectResources() ([]hostsensor.HostSensorDataEnvelope, map[string]apis.StatusInfo, error) {
return []hostsensor.HostSensorDataEnvelope{}, nil, nil
}
func (hshm *HostSensorHandlerMock) GetNamespace() string {

View File

@@ -0,0 +1,35 @@
package hostsensorutils
import (
"github.com/armosec/k8s-interface/k8sinterface"
"github.com/armosec/opa-utils/reporthandling/apis"
)
var (
KubeletConfiguration = "KubeletConfiguration"
OsReleaseFile = "OsReleaseFile"
KernelVersion = "KernelVersion"
LinuxSecurityHardeningStatus = "LinuxSecurityHardeningStatus"
OpenPortsList = "OpenPortsList"
LinuxKernelVariables = "LinuxKernelVariables"
KubeletCommandLine = "KubeletCommandLine"
MapResourceToApiGroup = map[string]string{
KubeletConfiguration: "hostdata.kubescape.cloud/v1beta0",
OsReleaseFile: "hostdata.kubescape.cloud/v1beta0",
KubeletCommandLine: "hostdata.kubescape.cloud/v1beta0",
KernelVersion: "hostdata.kubescape.cloud/v1beta0",
LinuxSecurityHardeningStatus: "hostdata.kubescape.cloud/v1beta0",
OpenPortsList: "hostdata.kubescape.cloud/v1beta0",
LinuxKernelVariables: "hostdata.kubescape.cloud/v1beta0",
}
)
func addInfoToMap(resource string, infoMap map[string]apis.StatusInfo, err error) {
group, version := k8sinterface.SplitApiVersion(MapResourceToApiGroup[resource])
r := k8sinterface.JoinResourceTriplets(group, version, resource)
infoMap[r] = apis.StatusInfo{
InnerStatus: apis.StatusSkipped,
InnerInfo: err.Error(),
}
}

View File

@@ -6,8 +6,9 @@ import (
"time"
"github.com/armosec/armoapi-go/armotypes"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/core/cautils"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
"github.com/armosec/kubescape/core/pkg/score"
"github.com/armosec/opa-utils/objectsenvelopes"
"github.com/armosec/opa-utils/reporthandling"
@@ -61,7 +62,7 @@ func (opap *OPAProcessor) ProcessRulesListenner() error {
}
func (opap *OPAProcessor) Process(policies *cautils.Policies) error {
logger.L().Info(fmt.Sprintf("Scanning cluster %s", cautils.ClusterName))
logger.L().Info("Scanning", helpers.String("cluster", cautils.ClusterName))
cautils.StartSpinner()
@@ -88,7 +89,8 @@ func (opap *OPAProcessor) Process(policies *cautils.Policies) error {
opap.Report.ReportGenerationTime = time.Now().UTC()
cautils.StopSpinner()
logger.L().Success(fmt.Sprintf("Done scanning cluster %s", cautils.ClusterName))
logger.L().Success("Done scanning", helpers.String("cluster", cautils.ClusterName))
return errs
}
@@ -131,7 +133,7 @@ func (opap *OPAProcessor) processRule(rule *reporthandling.PolicyRule) (map[stri
postureControlInputs := opap.regoDependenciesData.GetFilteredPostureControlInputs(rule.ConfigInputs) // get store
inputResources, err := reporthandling.RegoResourcesAggregator(rule, getAllSupportedObjects(opap.K8SResources, opap.AllResources, rule))
inputResources, err := reporthandling.RegoResourcesAggregator(rule, getAllSupportedObjects(opap.K8SResources, opap.ArmoResource, opap.AllResources, rule))
if err != nil {
return nil, fmt.Errorf("error getting aggregated k8sObjects: %s", err.Error())
}

View File

@@ -4,8 +4,8 @@ import (
"testing"
"github.com/armosec/armoapi-go/armotypes"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/mocks"
"github.com/armosec/kubescape/core/cautils"
"github.com/armosec/kubescape/core/mocks"
"github.com/armosec/opa-utils/objectsenvelopes"
"github.com/armosec/opa-utils/reporthandling"
"github.com/armosec/opa-utils/resources"
@@ -112,10 +112,10 @@ func TestProcessResourcesResult(t *testing.T) {
assert.Equal(t, 0, len(summaryDetails.ListResourcesIDs().Passed()))
// test control listing
assert.Equal(t, len(res.ListControlsIDs(nil).All()), len(summaryDetails.ListControls().All()))
assert.Equal(t, len(res.ListControlsIDs(nil).Passed()), len(summaryDetails.ListControls().Passed()))
assert.Equal(t, len(res.ListControlsIDs(nil).Failed()), len(summaryDetails.ListControls().Failed()))
assert.Equal(t, len(res.ListControlsIDs(nil).Excluded()), len(summaryDetails.ListControls().Excluded()))
assert.Equal(t, len(res.ListControlsIDs(nil).All()), summaryDetails.NumberOfControls().All())
assert.Equal(t, len(res.ListControlsIDs(nil).Passed()), summaryDetails.NumberOfControls().Passed())
assert.Equal(t, len(res.ListControlsIDs(nil).Failed()), summaryDetails.NumberOfControls().Failed())
assert.Equal(t, len(res.ListControlsIDs(nil).Excluded()), summaryDetails.NumberOfControls().Excluded())
assert.True(t, summaryDetails.GetStatus().IsFailed())
opaSessionObj.Exceptions = []armotypes.PostureExceptionPolicy{*mocks.MockExceptionAllKinds(&armotypes.PosturePolicy{FrameworkName: frameworks[0].Name})}

View File

@@ -1,14 +1,13 @@
package opaprocessor
import (
"fmt"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/core/cautils"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/k8s-interface/k8sinterface"
"github.com/armosec/k8s-interface/workloadinterface"
"github.com/armosec/opa-utils/reporthandling"
"github.com/armosec/opa-utils/reporthandling/apis"
resources "github.com/armosec/opa-utils/resources"
)
@@ -46,8 +45,9 @@ func (opap *OPAProcessor) updateResults() {
}
// set result summary
opap.Report.SummaryDetails.InitResourcesSummary()
// map control to error
controlToInfoMap := mapControlToInfo(opap.ResourceToControlsMap, opap.InfoMap)
opap.Report.SummaryDetails.InitResourcesSummary(controlToInfoMap)
// for f := range opap.PostureReport.FrameworkReports {
// // set exceptions
// exceptions.SetFrameworkExceptions(&opap.PostureReport.FrameworkReports[f], opap.Exceptions, cautils.ClusterName)
@@ -60,13 +60,50 @@ func (opap *OPAProcessor) updateResults() {
// }
}
func getAllSupportedObjects(k8sResources *cautils.K8SResources, allResources map[string]workloadinterface.IMetadata, rule *reporthandling.PolicyRule) []workloadinterface.IMetadata {
func mapControlToInfo(mapResourceToControls map[string][]string, infoMap map[string]apis.StatusInfo) map[string]apis.StatusInfo {
controlToInfoMap := make(map[string]apis.StatusInfo)
for resource, statusInfo := range infoMap {
controls := mapResourceToControls[resource]
for _, control := range controls {
controlToInfoMap[control] = statusInfo
}
}
return controlToInfoMap
}
func getAllSupportedObjects(k8sResources *cautils.K8SResources, armoResources *cautils.ArmoResources, allResources map[string]workloadinterface.IMetadata, rule *reporthandling.PolicyRule) []workloadinterface.IMetadata {
k8sObjects := []workloadinterface.IMetadata{}
k8sObjects = append(k8sObjects, getKubernetesObjects(k8sResources, allResources, rule.Match)...)
k8sObjects = append(k8sObjects, getKubernetesObjects(k8sResources, allResources, rule.DynamicMatch)...)
k8sObjects = append(k8sObjects, getArmoObjects(armoResources, allResources, rule.DynamicMatch)...)
return k8sObjects
}
func getArmoObjects(k8sResources *cautils.ArmoResources, allResources map[string]workloadinterface.IMetadata, match []reporthandling.RuleMatchObjects) []workloadinterface.IMetadata {
k8sObjects := []workloadinterface.IMetadata{}
for m := range match {
for _, groups := range match[m].APIGroups {
for _, version := range match[m].APIVersions {
for _, resource := range match[m].Resources {
groupResources := k8sinterface.ResourceGroupToString(groups, version, resource)
for _, groupResource := range groupResources {
if k8sObj, ok := (*k8sResources)[groupResource]; ok {
// if k8sObj == nil {
// logger.L().Debug(fmt.Sprintf("resource '%s' is nil, probably failed to pull the resource", groupResource))
// }
for i := range k8sObj {
k8sObjects = append(k8sObjects, allResources[k8sObj[i]])
}
}
}
}
}
}
}
return filterOutChildResources(k8sObjects, match)
}
func getKubernetesObjects(k8sResources *cautils.K8SResources, allResources map[string]workloadinterface.IMetadata, match []reporthandling.RuleMatchObjects) []workloadinterface.IMetadata {
k8sObjects := []workloadinterface.IMetadata{}
@@ -78,7 +115,7 @@ func getKubernetesObjects(k8sResources *cautils.K8SResources, allResources map[s
for _, groupResource := range groupResources {
if k8sObj, ok := (*k8sResources)[groupResource]; ok {
if k8sObj == nil {
logger.L().Debug(fmt.Sprintf("resource '%s' is nil, probably failed to pull the resource", groupResource))
// logger.L().Debug("skipping", helpers.String("resource", groupResource))
}
for i := range k8sObj {
k8sObjects = append(k8sObjects, allResources[k8sObj[i]])

View File

@@ -1,7 +1,7 @@
package opaprocessor
import (
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/core/cautils"
"github.com/armosec/opa-utils/reporthandling"
"github.com/armosec/opa-utils/reporthandling/results/v1/reportsummary"
)

View File

@@ -3,9 +3,9 @@ package opaprocessor
import (
"testing"
"github.com/armosec/kubescape/mocks"
"github.com/stretchr/testify/assert"
"github.com/armosec/kubescape/core/mocks"
"github.com/armosec/opa-utils/reporthandling"
"github.com/armosec/opa-utils/reporthandling/results/v1/reportsummary"
)

View File

@@ -3,7 +3,7 @@ package policyhandler
import (
"fmt"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/core/cautils"
"github.com/armosec/kubescape/core/pkg/resourcehandler"
"github.com/armosec/opa-utils/reporthandling"
)
@@ -23,7 +23,8 @@ func NewPolicyHandler(resourceHandler resourcehandler.IResourceHandler) *PolicyH
}
func (policyHandler *PolicyHandler) CollectResources(notification *reporthandling.PolicyNotification, scanInfo *cautils.ScanInfo) (*cautils.OPASessionObj, error) {
opaSessionObj := cautils.NewOPASessionObj(nil, nil)
opaSessionObj := cautils.NewOPASessionObj(nil, nil, scanInfo)
// validate notification
// TODO
policyHandler.getters = &scanInfo.Getters
@@ -46,15 +47,16 @@ func (policyHandler *PolicyHandler) CollectResources(notification *reporthandlin
}
func (policyHandler *PolicyHandler) getResources(notification *reporthandling.PolicyNotification, opaSessionObj *cautils.OPASessionObj, scanInfo *cautils.ScanInfo) error {
opaSessionObj.Report.ClusterAPIServerInfo = policyHandler.resourceHandler.GetClusterAPIServerInfo()
resourcesMap, allResources, err := policyHandler.resourceHandler.GetResources(opaSessionObj.Policies, &notification.Designators)
resourcesMap, allResources, armoResources, err := policyHandler.resourceHandler.GetResources(opaSessionObj, &notification.Designators)
if err != nil {
return err
}
opaSessionObj.K8SResources = resourcesMap
opaSessionObj.AllResources = allResources
opaSessionObj.ArmoResource = armoResources
return nil
}

View File

@@ -4,14 +4,19 @@ import (
"fmt"
"strings"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/core/cautils"
"github.com/armosec/kubescape/core/cautils/getter"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
"github.com/armosec/opa-utils/reporthandling"
)
func (policyHandler *PolicyHandler) getPolicies(notification *reporthandling.PolicyNotification, policiesAndResources *cautils.OPASessionObj) error {
logger.L().Info("Downloading/Loading policy definitions")
cautils.StartSpinner()
defer cautils.StopSpinner()
policies, err := policyHandler.getScanPolicies(notification)
if err != nil {
return err
@@ -33,6 +38,8 @@ func (policyHandler *PolicyHandler) getPolicies(notification *reporthandling.Pol
if err == nil {
policiesAndResources.RegoInputData.PostureControlInputs = controlsInputs
}
cautils.StopSpinner()
logger.L().Success("Downloaded/Loaded policy")
return nil
}
@@ -49,6 +56,11 @@ func (policyHandler *PolicyHandler) getScanPolicies(notification *reporthandling
}
if receivedFramework != nil {
frameworks = append(frameworks, *receivedFramework)
cache := getter.GetDefaultPath(rule.Name + ".json")
if err := getter.SaveInFile(receivedFramework, cache); err != nil {
logger.L().Warning("failed to cache file", helpers.String("file", cache), helpers.Error(err))
}
}
}
case reporthandling.KindControl: // Download controls
@@ -62,6 +74,11 @@ func (policyHandler *PolicyHandler) getScanPolicies(notification *reporthandling
}
if receivedControl != nil {
f.Controls = append(f.Controls, *receivedControl)
cache := getter.GetDefaultPath(rule.Name + ".json")
if err := getter.SaveInFile(receivedControl, cache); err != nil {
logger.L().Warning("failed to cache file", helpers.String("file", cache), helpers.Error(err))
}
}
}
frameworks = append(frameworks, f)

View File

@@ -4,9 +4,9 @@ import (
"encoding/json"
"fmt"
"github.com/armosec/kubescape/cautils/getter"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/cautils/logger/helpers"
"github.com/armosec/kubescape/core/cautils/getter"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
"github.com/armosec/kubescape/core/pkg/containerscan"
"github.com/armosec/kubescape/core/pkg/registryadaptors/registryvulnerabilities"
)

View File

@@ -60,6 +60,9 @@ func responseObjectToVulnerabilities(vulnerabilitiesList containerscan.Vulnerabi
vulnerabilities[i].Relevancy = vulnerabilityEntry.Relevancy
vulnerabilities[i].Severity = vulnerabilityEntry.Severity
vulnerabilities[i].UrgentCount = vulnerabilityEntry.UrgentCount
vulnerabilities[i].Categories = registryvulnerabilities.Categories{
IsRCE: vulnerabilityEntry.Categories.IsRCE,
}
}
return vulnerabilities
}

View File

@@ -3,7 +3,7 @@ package v1
import (
"time"
"github.com/armosec/kubescape/cautils/getter"
"github.com/armosec/kubescape/core/cautils/getter"
)
type V2ListRequest struct {

View File

@@ -23,6 +23,10 @@ type FixedIn struct {
ImgTag string `json:"imageTag"`
Version string `json:"version"`
}
type Categories struct {
IsRCE bool `json:"isRce"`
}
type Vulnerability struct {
Name string `json:"name"`
RelatedPackageName string `json:"packageName"`
@@ -36,6 +40,7 @@ type Vulnerability struct {
UrgentCount int `json:"urgent"`
NeglectedCount int `json:"neglected"`
HealthStatus string `json:"healthStatus"`
Categories Categories `json:"categories"`
}
type ContainerImageVulnerabilityReport struct {

View File

@@ -2,15 +2,15 @@ package resourcehandler
import (
"fmt"
"os"
"github.com/armosec/armoapi-go/armotypes"
"github.com/armosec/k8s-interface/workloadinterface"
"k8s.io/apimachinery/pkg/version"
"github.com/armosec/k8s-interface/k8sinterface"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/opa-utils/reporthandling"
"github.com/armosec/kubescape/core/cautils"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
)
// FileResourceHandler handle resources from files and URLs
@@ -27,36 +27,48 @@ func NewFileResourceHandler(inputPatterns []string, registryAdaptors *RegistryAd
}
}
func (fileHandler *FileResourceHandler) GetResources(frameworks []reporthandling.Framework, designator *armotypes.PortalDesignator) (*cautils.K8SResources, map[string]workloadinterface.IMetadata, error) {
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 := setResourceMap(frameworks)
k8sResources := setK8sResourceMap(sessionObj.Policies)
allResources := map[string]workloadinterface.IMetadata{}
workloadIDToSource := make(map[string]string, 0)
armoResources := &cautils.ArmoResources{}
workloads := []workloadinterface.IMetadata{}
// load resource from local file system
w, err := cautils.LoadResourcesFromFiles(fileHandler.inputPatterns)
sourceToWorkloads, err := cautils.LoadResourcesFromFiles(fileHandler.inputPatterns)
if err != nil {
return nil, allResources, err
return nil, allResources, nil, err
}
if w != nil {
workloads = append(workloads, w...)
for source, ws := range sourceToWorkloads {
workloads = append(workloads, ws...)
for i := range ws {
workloadIDToSource[ws[i].GetID()] = source
}
}
logger.L().Debug("files found in local storage", helpers.Int("files", len(sourceToWorkloads)), helpers.Int("workloads", len(workloads)))
// load resources from url
w, err = loadResourcesFromUrl(fileHandler.inputPatterns)
sourceToWorkloads, err = loadResourcesFromUrl(fileHandler.inputPatterns)
if err != nil {
return nil, allResources, err
return nil, allResources, nil, err
}
if w != nil {
workloads = append(workloads, w...)
for source, ws := range sourceToWorkloads {
workloads = append(workloads, ws...)
for i := range ws {
workloadIDToSource[ws[i].GetID()] = source
}
}
if len(workloads) == 0 {
return nil, allResources, fmt.Errorf("empty list of workloads - no workloads found")
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
// map all resources: map["/group/version/kind"][]<k8s workloads>
mappedResources := mapResources(workloads)
@@ -73,11 +85,11 @@ func (fileHandler *FileResourceHandler) GetResources(frameworks []reporthandling
}
}
if err := fileHandler.registryAdaptors.collectImagesVulnerabilities(k8sResources, allResources); err != nil {
cautils.WarningDisplay(os.Stderr, "Warning: failed to collect images vulnerabilities: %s\n", err.Error())
if err := fileHandler.registryAdaptors.collectImagesVulnerabilities(k8sResources, allResources, armoResources); err != nil {
logger.L().Warning("failed to collect images vulnerabilities", helpers.Error(err))
}
return k8sResources, allResources, nil
return k8sResources, allResources, armoResources, nil
}

View File

@@ -5,12 +5,12 @@ import (
"fmt"
"strings"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/cautils/logger/helpers"
"github.com/armosec/kubescape/core/cautils"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
"github.com/armosec/kubescape/core/pkg/hostsensorutils"
"github.com/armosec/opa-utils/objectsenvelopes"
"github.com/armosec/opa-utils/reporthandling"
"github.com/armosec/opa-utils/reporthandling/apis"
"github.com/armosec/k8s-interface/cloudsupport"
"github.com/armosec/k8s-interface/k8sinterface"
@@ -44,45 +44,92 @@ func NewK8sResourceHandler(k8s *k8sinterface.KubernetesApi, fieldSelector IField
}
}
func (k8sHandler *K8sResourceHandler) GetResources(frameworks []reporthandling.Framework, designator *armotypes.PortalDesignator) (*cautils.K8SResources, map[string]workloadinterface.IMetadata, error) {
func (k8sHandler *K8sResourceHandler) GetResources(sessionObj *cautils.OPASessionObj, designator *armotypes.PortalDesignator) (*cautils.K8SResources, map[string]workloadinterface.IMetadata, *cautils.ArmoResources, error) {
allResources := map[string]workloadinterface.IMetadata{}
// get k8s resources
logger.L().Info("Accessing Kubernetes objects")
cautils.StartSpinner()
resourceToControl := make(map[string][]string)
// build resources map
// map resources based on framework required resources: map["/group/version/kind"][]<k8s workloads ids>
k8sResourcesMap := setResourceMap(frameworks)
k8sResourcesMap := setK8sResourceMap(sessionObj.Policies)
// get namespace and labels from designator (ignore cluster labels)
_, namespace, labels := armotypes.DigestPortalDesignator(designator)
// pull k8s recourses
armoResourceMap := setArmoResourceMap(sessionObj.Policies, resourceToControl)
// map of armo resources to control_ids
sessionObj.ResourceToControlsMap = resourceToControl
if err := k8sHandler.pullResources(k8sResourcesMap, allResources, namespace, labels); err != nil {
return k8sResourcesMap, allResources, err
cautils.StopSpinner()
return k8sResourcesMap, allResources, armoResourceMap, err
}
if err := k8sHandler.registryAdaptors.collectImagesVulnerabilities(k8sResourcesMap, allResources); err != nil {
logger.L().Warning("failed to collect image vulnerabilities", helpers.Error(err))
numberOfWorkerNodes, err := k8sHandler.pullWorkerNodesNumber()
if err != nil {
logger.L().Debug("failed to collect worker nodes number", helpers.Error(err))
} else {
if sessionObj.Metadata != nil && sessionObj.Metadata.ContextMetadata.ClusterContextMetadata != nil {
sessionObj.Metadata.ContextMetadata.ClusterContextMetadata.NumberOfWorkerNodes = numberOfWorkerNodes
}
}
if err := k8sHandler.collectHostResources(allResources, k8sResourcesMap); err != nil {
logger.L().Warning("failed to collect host sensor resources", helpers.Error(err))
imgVulnResources := cautils.MapImageVulnResources(armoResourceMap)
// check that controls use image vulnerability resources
if len(imgVulnResources) > 0 {
if err := k8sHandler.registryAdaptors.collectImagesVulnerabilities(k8sResourcesMap, allResources, armoResourceMap); err != nil {
logger.L().Warning("failed to collect image vulnerabilities", helpers.Error(err))
}
}
hostResources := cautils.MapHostResources(armoResourceMap)
// check that controls use host sensor resources
if len(hostResources) > 0 {
if sessionObj.Metadata.ScanMetadata.HostScanner {
infoMap, err := k8sHandler.collectHostResources(allResources, armoResourceMap)
if err != nil {
logger.L().Warning("failed to collect host scanner resources", helpers.Error(err))
cautils.SetInfoMapForResources(err.Error(), hostResources, sessionObj.InfoMap)
} else if k8sHandler.hostSensorHandler == nil {
// using hostSensor mock
cautils.SetInfoMapForResources("failed to init host scanner", hostResources, sessionObj.InfoMap)
} else {
sessionObj.InfoMap = infoMap
}
} else {
cautils.SetInfoMapForResources("enable-host-scan flag not used", hostResources, sessionObj.InfoMap)
}
}
if err := k8sHandler.collectRbacResources(allResources); err != nil {
logger.L().Warning("failed to collect rbac resources", helpers.Error(err))
}
if err := getCloudProviderDescription(allResources, k8sResourcesMap); err != nil {
logger.L().Warning("failed to collect cloud data", helpers.Error(err))
cloudResources := cautils.MapCloudResources(armoResourceMap)
// check that controls use cloud resources
if len(cloudResources) > 0 {
provider, err := getCloudProviderDescription(allResources, armoResourceMap)
if err != nil {
cautils.SetInfoMapForResources(err.Error(), cloudResources, sessionObj.InfoMap)
logger.L().Warning("failed to collect cloud data", helpers.Error(err))
}
if provider != "" {
if sessionObj.Metadata != nil && sessionObj.Metadata.ContextMetadata.ClusterContextMetadata != nil {
sessionObj.Metadata.ContextMetadata.ClusterContextMetadata.CloudProvider = provider
}
}
}
cautils.StopSpinner()
logger.L().Success("Accessed to Kubernetes objects")
return k8sResourcesMap, allResources, nil
return k8sResourcesMap, allResources, armoResourceMap, nil
}
func (k8sHandler *K8sResourceHandler) GetClusterAPIServerInfo() *version.Info {
@@ -95,7 +142,6 @@ func (k8sHandler *K8sResourceHandler) GetClusterAPIServerInfo() *version.Info {
}
func (k8sHandler *K8sResourceHandler) pullResources(k8sResources *cautils.K8SResources, allResources map[string]workloadinterface.IMetadata, namespace string, labels map[string]string) error {
logger.L().Debug("Accessing Kubernetes objects")
var errs error
for groupResource := range *k8sResources {
@@ -180,12 +226,11 @@ func ConvertMapListToMeta(resourceMap []map[string]interface{}) []workloadinterf
// }
// return nil
// }
func (k8sHandler *K8sResourceHandler) collectHostResources(allResources map[string]workloadinterface.IMetadata, resourcesMap *cautils.K8SResources) error {
logger.L().Debug("Collecting host sensor resources")
hostResources, err := k8sHandler.hostSensorHandler.CollectResources()
func (k8sHandler *K8sResourceHandler) collectHostResources(allResources map[string]workloadinterface.IMetadata, armoResourceMap *cautils.ArmoResources) (map[string]apis.StatusInfo, error) {
logger.L().Debug("Collecting host scanner resources")
hostResources, infoMap, err := k8sHandler.hostSensorHandler.CollectResources()
if err != nil {
return err
return nil, err
}
for rscIdx := range hostResources {
@@ -193,13 +238,13 @@ func (k8sHandler *K8sResourceHandler) collectHostResources(allResources map[stri
groupResource := k8sinterface.JoinResourceTriplets(group, version, hostResources[rscIdx].GetKind())
allResources[hostResources[rscIdx].GetID()] = &hostResources[rscIdx]
grpResourceList, ok := (*resourcesMap)[groupResource]
grpResourceList, ok := (*armoResourceMap)[groupResource]
if !ok {
grpResourceList = make([]string, 0)
}
(*resourcesMap)[groupResource] = append(grpResourceList, hostResources[rscIdx].GetID())
(*armoResourceMap)[groupResource] = append(grpResourceList, hostResources[rscIdx].GetID())
}
return nil
return infoMap, nil
}
func (k8sHandler *K8sResourceHandler) collectRbacResources(allResources map[string]workloadinterface.IMetadata) error {
@@ -218,20 +263,19 @@ func (k8sHandler *K8sResourceHandler) collectRbacResources(allResources map[stri
return nil
}
func getCloudProviderDescription(allResources map[string]workloadinterface.IMetadata, k8sResourcesMap *cautils.K8SResources) error {
func getCloudProviderDescription(allResources map[string]workloadinterface.IMetadata, armoResourceMap *cautils.ArmoResources) (string, error) {
logger.L().Debug("Collecting cloud data")
cloudProvider := initCloudProvider()
cluster := cloudProvider.getKubeCluster()
clusterName := cloudProvider.getKubeClusterName()
provider := getCloudProvider()
region, err := cloudProvider.getRegion(cluster, provider)
if err != nil {
return err
return provider, err
}
project, err := cloudProvider.getProject(cluster, provider)
if err != nil {
return err
return provider, err
}
if provider != "" {
@@ -240,19 +284,28 @@ func getCloudProviderDescription(allResources map[string]workloadinterface.IMeta
wl, err := cloudsupport.GetDescriptiveInfoFromCloudProvider(clusterName, provider, region, project)
if err != nil {
// Return error with useful info on how to configure credentials for getting cloud provider info
switch provider {
case "gke":
return fmt.Errorf("could not get descriptive information about gke cluster: %s using sdk client. See https://developers.google.com/accounts/docs/application-default-credentials for more information", cluster)
case "eks":
return fmt.Errorf("could not get descriptive information about eks cluster: %s using sdk client. Check out how to configure credentials in https://docs.aws.amazon.com/sdk-for-go/api/", cluster)
case "aks":
return fmt.Errorf("could not get descriptive information about aks cluster: %s. %v", cluster, err.Error())
}
return err
logger.L().Debug("failed to get descriptive information", helpers.Error(err))
return provider, fmt.Errorf("failed to get %s descriptive information. Read more: https://hub.armo.cloud/docs/kubescape-integration-with-cloud-providers", strings.ToUpper(provider))
}
allResources[wl.GetID()] = wl
(*k8sResourcesMap)[fmt.Sprintf("%s/%s", wl.GetApiVersion(), wl.GetKind())] = []string{wl.GetID()}
(*armoResourceMap)[fmt.Sprintf("%s/%s", wl.GetApiVersion(), wl.GetKind())] = []string{wl.GetID()}
}
return nil
return provider, nil
}
func (k8sHandler *K8sResourceHandler) pullWorkerNodesNumber() (int, error) {
// labels used for control plane
listOptions := metav1.ListOptions{
LabelSelector: "!node-role.kubernetes.io/control-plane,!node-role.kubernetes.io/master",
}
nodesList, err := k8sHandler.k8s.KubernetesClient.CoreV1().Nodes().List(context.TODO(), listOptions)
if err != nil {
return 0, err
}
nodesNumber := 0
if nodesList != nil {
nodesNumber = len(nodesList.Items)
}
return nodesNumber, nil
}

View File

@@ -3,15 +3,24 @@ package resourcehandler
import (
"strings"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/core/cautils"
"github.com/armosec/kubescape/core/pkg/hostsensorutils"
"github.com/armosec/opa-utils/reporthandling"
"k8s.io/utils/strings/slices"
"github.com/armosec/k8s-interface/k8sinterface"
)
func setResourceMap(frameworks []reporthandling.Framework) *cautils.K8SResources {
var (
ClusterDescribe = "ClusterDescribe"
MapResourceToApiGroupCloud = map[string][]string{
ClusterDescribe: {"container.googleapis.com/v1", "eks.amazonaws.com/v1"}}
)
func setK8sResourceMap(frameworks []reporthandling.Framework) *cautils.K8SResources {
k8sResources := make(cautils.K8SResources)
complexMap := setComplexResourceMap(frameworks)
complexMap := setComplexK8sResourceMap(frameworks)
for group := range complexMap {
for version := range complexMap[group] {
for resource := range complexMap[group][version] {
@@ -25,33 +34,87 @@ func setResourceMap(frameworks []reporthandling.Framework) *cautils.K8SResources
return &k8sResources
}
func setArmoResourceMap(frameworks []reporthandling.Framework, resourceToControl map[string][]string) *cautils.ArmoResources {
armoResources := make(cautils.ArmoResources)
complexMap := setComplexArmoResourceMap(frameworks, resourceToControl)
for group := range complexMap {
for version := range complexMap[group] {
for resource := range complexMap[group][version] {
groupResources := k8sinterface.ResourceGroupToString(group, version, resource)
for _, groupResource := range groupResources {
armoResources[groupResource] = nil
}
}
}
}
return &armoResources
}
func convertComplexResourceMap(frameworks []reporthandling.Framework) map[string]map[string]map[string]interface{} {
k8sResources := make(map[string]map[string]map[string]interface{})
for _, framework := range frameworks {
for _, control := range framework.Controls {
for _, rule := range control.Rules {
for _, match := range rule.Match {
insertK8sResources(k8sResources, match)
insertResources(k8sResources, match)
}
}
}
}
return k8sResources
}
func setComplexResourceMap(frameworks []reporthandling.Framework) map[string]map[string]map[string]interface{} {
func setComplexK8sResourceMap(frameworks []reporthandling.Framework) map[string]map[string]map[string]interface{} {
k8sResources := make(map[string]map[string]map[string]interface{})
for _, framework := range frameworks {
for _, control := range framework.Controls {
for _, rule := range control.Rules {
for _, match := range rule.Match {
insertK8sResources(k8sResources, match)
insertResources(k8sResources, match)
}
}
}
}
return k8sResources
}
func insertK8sResources(k8sResources map[string]map[string]map[string]interface{}, match reporthandling.RuleMatchObjects) {
// [group][versionn][resource]
func setComplexArmoResourceMap(frameworks []reporthandling.Framework, resourceToControls map[string][]string) map[string]map[string]map[string]interface{} {
k8sResources := make(map[string]map[string]map[string]interface{})
for _, framework := range frameworks {
for _, control := range framework.Controls {
for _, rule := range control.Rules {
for _, match := range rule.DynamicMatch {
insertArmoResourcesAndControls(k8sResources, match, resourceToControls, control)
}
}
}
}
return k8sResources
}
func mapArmoResourceToApiGroup(resource string) []string {
if val, ok := hostsensorutils.MapResourceToApiGroup[resource]; ok {
return []string{val}
}
return MapResourceToApiGroupCloud[resource]
}
func insertControls(resource string, resourceToControl map[string][]string, control reporthandling.Control) {
armoResources := mapArmoResourceToApiGroup(resource)
for _, armoResource := range armoResources {
group, version := k8sinterface.SplitApiVersion(armoResource)
r := k8sinterface.JoinResourceTriplets(group, version, resource)
if _, ok := resourceToControl[r]; !ok {
resourceToControl[r] = append(resourceToControl[r], control.ControlID)
} else {
if !slices.Contains(resourceToControl[r], control.ControlID) {
resourceToControl[r] = append(resourceToControl[r], control.ControlID)
}
}
}
}
func insertResources(k8sResources map[string]map[string]map[string]interface{}, match reporthandling.RuleMatchObjects) {
for _, apiGroup := range match.APIGroups {
if v, ok := k8sResources[apiGroup]; !ok || v == nil {
k8sResources[apiGroup] = make(map[string]map[string]interface{})
@@ -69,6 +132,25 @@ func insertK8sResources(k8sResources map[string]map[string]map[string]interface{
}
}
func insertArmoResourcesAndControls(k8sResources map[string]map[string]map[string]interface{}, match reporthandling.RuleMatchObjects, resourceToControl map[string][]string, control reporthandling.Control) {
for _, apiGroup := range match.APIGroups {
if v, ok := k8sResources[apiGroup]; !ok || v == nil {
k8sResources[apiGroup] = make(map[string]map[string]interface{})
}
for _, apiVersions := range match.APIVersions {
if v, ok := k8sResources[apiGroup][apiVersions]; !ok || v == nil {
k8sResources[apiGroup][apiVersions] = make(map[string]interface{})
}
for _, resource := range match.Resources {
if _, ok := k8sResources[apiGroup][apiVersions][resource]; !ok {
k8sResources[apiGroup][apiVersions][resource] = nil
}
insertControls(resource, resourceToControl, control)
}
}
}
}
func getGroupNVersion(apiVersion string) (string, string) {
gv := strings.Split(apiVersion, "/")
group, version := "", ""

View File

@@ -13,7 +13,7 @@ func TestGetK8sResources(t *testing.T) {
func TestSetResourceMap(t *testing.T) {
k8sinterface.InitializeMapResourcesMock()
framework := reporthandling.MockFrameworkA()
k8sResources := setResourceMap([]reporthandling.Framework{*framework})
k8sResources := setK8sResourceMap([]reporthandling.Framework{*framework})
resources := k8sinterface.ResourceGroupToString("*", "v1", "Pod")
if len(resources) == 0 {
t.Error("expected resources")
@@ -43,9 +43,9 @@ func TestInsertK8sResources(t *testing.T) {
APIVersions: []string{"v1"},
Resources: []string{"secrets"},
}
insertK8sResources(k8sResources, match1)
insertK8sResources(k8sResources, match2)
insertK8sResources(k8sResources, match3)
insertResources(k8sResources, match1)
insertResources(k8sResources, match2)
insertResources(k8sResources, match3)
apiGroup1, ok := k8sResources["apps"]
if !ok {

View File

@@ -3,10 +3,10 @@ package resourcehandler
import (
"github.com/armosec/k8s-interface/k8sinterface"
"github.com/armosec/k8s-interface/workloadinterface"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/cautils/getter"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/cautils/logger/helpers"
"github.com/armosec/kubescape/core/cautils"
"github.com/armosec/kubescape/core/cautils/getter"
"github.com/armosec/kubescape/core/cautils/logger"
"github.com/armosec/kubescape/core/cautils/logger/helpers"
armosecadaptorv1 "github.com/armosec/kubescape/core/pkg/registryadaptors/armosec/v1"
"github.com/armosec/kubescape/core/pkg/registryadaptors/registryvulnerabilities"
@@ -34,7 +34,7 @@ func NewRegistryAdaptors() (*RegistryAdaptors, error) {
return registryAdaptors, nil
}
func (registryAdaptors *RegistryAdaptors) collectImagesVulnerabilities(k8sResourcesMap *cautils.K8SResources, allResources map[string]workloadinterface.IMetadata) error {
func (registryAdaptors *RegistryAdaptors) collectImagesVulnerabilities(k8sResourcesMap *cautils.K8SResources, allResources map[string]workloadinterface.IMetadata, armoResourceMap *cautils.ArmoResources) error {
logger.L().Debug("Collecting images vulnerabilities")
// list cluster images
@@ -64,7 +64,7 @@ func (registryAdaptors *RegistryAdaptors) collectImagesVulnerabilities(k8sResour
for i := range metaObjs {
allResources[metaObjs[i].GetID()] = metaObjs[i]
}
(*k8sResourcesMap)[k8sinterface.JoinResourceTriplets(ImagevulnerabilitiesObjectGroup, ImagevulnerabilitiesObjectVersion, ImagevulnerabilitiesObjectKind)] = workloadinterface.ListMetaIDs(metaObjs)
(*armoResourceMap)[k8sinterface.JoinResourceTriplets(ImagevulnerabilitiesObjectGroup, ImagevulnerabilitiesObjectVersion, ImagevulnerabilitiesObjectKind)] = workloadinterface.ListMetaIDs(metaObjs)
return nil
}

View File

@@ -4,15 +4,27 @@ import (
"encoding/json"
"fmt"
"net/http"
"os"
"path/filepath"
"strings"
"github.com/armosec/kubescape/cautils/getter"
"github.com/armosec/kubescape/core/cautils/getter"
giturls "github.com/whilp/git-urls"
"k8s.io/utils/strings/slices"
)
type IRepository interface {
parse(fullURL string) error
setBranch(string) error
setTree() error
getYamlFromTree() []string
setIsFile(bool)
getIsFile() bool
getBranch() string
getTree() tree
getFilesFromTree([]string) []string
}
type innerTree struct {
@@ -23,19 +35,24 @@ type tree struct {
}
type GitHubRepository struct {
// name string // <org>/<repo>
host string
name string // <org>/<repo>
owner string //
repo string //
branch string
path string
token string
isFile bool
tree tree
}
type githubDefaultBranchAPI struct {
DefaultBranch string `json:"default_branch"`
}
func NewGitHubRepository(rep string) *GitHubRepository {
func NewGitHubRepository() *GitHubRepository {
return &GitHubRepository{
host: "github",
name: rep,
host: "github.com",
token: os.Getenv("GITHUB_TOKEN"),
}
}
@@ -45,79 +62,143 @@ func ScanRepository(command string, branchOptional string) ([]string, error) {
return nil, err
}
err = repo.setBranch(branchOptional)
if err != nil {
if err := repo.parse(command); err != nil {
return nil, err
}
err = repo.setTree()
if err != nil {
if err := repo.setBranch(branchOptional); err != nil {
return nil, err
}
if err := repo.setTree(); err != nil {
return nil, err
}
// get all paths that are of the yaml type, and build them into a valid url
return repo.getYamlFromTree(), nil
return repo.getFilesFromTree([]string{"yaml", "yml", "json"}), nil
}
func getHostAndRepoName(url string) (string, string, error) {
splitUrl := strings.Split(url, "/")
if len(splitUrl) != 5 {
return "", "", fmt.Errorf("failed to pars url: %s", url)
func getHost(fullURL string) (string, error) {
parsedURL, err := giturls.Parse(fullURL)
if err != nil {
return "", err
}
hostUrl := splitUrl[2] // github.com, gitlab.com, etc.
repository := splitUrl[3] + "/" + strings.Split(splitUrl[4], ".")[0] // user/reposetory
return hostUrl, repository, nil
return parsedURL.Host, nil
}
func getRepository(url string) (IRepository, error) {
hostUrl, repoName, err := getHostAndRepoName(url)
func getRepository(fullURL string) (IRepository, error) {
hostUrl, err := getHost(fullURL)
if err != nil {
return nil, err
}
var repo IRepository
switch repoHost := strings.Split(hostUrl, ".")[0]; repoHost {
case "github":
repo = NewGitHubRepository(repoName)
switch hostUrl {
case "github.com":
repo = NewGitHubRepository()
case "raw.githubusercontent.com":
repo = NewGitHubRepository()
repo.setIsFile(true)
default:
return nil, fmt.Errorf("unknown repository host: %s", repoHost)
return nil, fmt.Errorf("unknown repository host: %s", hostUrl)
}
// Returns the host-url, and the part of the user and repository from the url
return repo, nil
}
func (g *GitHubRepository) parse(fullURL string) error {
parsedURL, err := giturls.Parse(fullURL)
if err != nil {
return err
}
index := 0
splittedRepo := strings.FieldsFunc(parsedURL.Path, func(c rune) bool { return c == '/' })
if len(splittedRepo) < 2 {
return fmt.Errorf("expecting <user>/<repo> in url path, received: '%s'", parsedURL.Path)
}
g.owner = splittedRepo[index]
index += 1
g.repo = splittedRepo[index]
index += 1
// root of repo
if len(splittedRepo) < index+1 {
return nil
}
// is file or dir
switch splittedRepo[index] {
case "blob":
g.isFile = true
index += 1
case "tree":
g.isFile = false
index += 1
}
if len(splittedRepo) < index+1 {
return nil
}
g.branch = splittedRepo[index]
index += 1
if len(splittedRepo) < index+1 {
return nil
}
g.path = strings.Join(splittedRepo[index:], "/")
return nil
}
func (g *GitHubRepository) getBranch() string { return g.branch }
func (g *GitHubRepository) getTree() tree { return g.tree }
func (g *GitHubRepository) setIsFile(isFile bool) { g.isFile = isFile }
func (g *GitHubRepository) getIsFile() bool { return g.isFile }
func (g *GitHubRepository) setBranch(branchOptional string) error {
// Checks whether the repository type is a master or another type.
// By default it is "master", unless the branchOptional came with a value
if branchOptional == "" {
body, err := getter.HttpGetter(&http.Client{}, g.defaultBranchAPI(), nil)
if err != nil {
return err
}
var data githubDefaultBranchAPI
err = json.Unmarshal([]byte(body), &data)
if err != nil {
return err
}
g.branch = data.DefaultBranch
} else {
if branchOptional != "" {
g.branch = branchOptional
}
if g.branch != "" {
return nil
}
body, err := getter.HttpGetter(&http.Client{}, g.defaultBranchAPI(), g.getHeaders())
if err != nil {
return err
}
var data githubDefaultBranchAPI
err = json.Unmarshal([]byte(body), &data)
if err != nil {
return err
}
g.branch = data.DefaultBranch
return nil
}
func (g *GitHubRepository) defaultBranchAPI() string {
return fmt.Sprintf("https://api.github.com/repos/%s", g.name)
func joinOwnerNRepo(owner, repo string) string {
return fmt.Sprintf("%s/%s", owner, repo)
}
func (g *GitHubRepository) defaultBranchAPI() string {
return fmt.Sprintf("https://api.github.com/repos/%s", joinOwnerNRepo(g.owner, g.repo))
}
func (g *GitHubRepository) getHeaders() map[string]string {
if g.token == "" {
return nil
}
return map[string]string{"Authorization": fmt.Sprintf("token %s", g.token)}
}
func (g *GitHubRepository) setTree() error {
body, err := getter.HttpGetter(&http.Client{}, g.treeAPI(), nil)
if g.isFile {
return nil
}
body, err := getter.HttpGetter(&http.Client{}, g.treeAPI(), g.getHeaders())
if err != nil {
return err
}
@@ -135,14 +216,24 @@ func (g *GitHubRepository) setTree() error {
}
func (g *GitHubRepository) treeAPI() string {
return fmt.Sprintf("https://api.github.com/repos/%s/git/trees/%s?recursive=1", g.name, g.branch)
return fmt.Sprintf("https://api.github.com/repos/%s/git/trees/%s?recursive=1", joinOwnerNRepo(g.owner, g.repo), g.branch)
}
// return a list of yaml for a given repository tree
func (g *GitHubRepository) getYamlFromTree() []string {
func (g *GitHubRepository) getFilesFromTree(filesExtensions []string) []string {
var urls []string
if g.isFile {
if slices.Contains(filesExtensions, getFileExtension(g.path)) {
return []string{fmt.Sprintf("%s/%s", g.rowYamlUrl(), g.path)}
} else {
return []string{}
}
}
for _, path := range g.tree.InnerTrees {
if strings.HasSuffix(path.Path, ".yaml") {
if g.path != "" && !strings.HasPrefix(path.Path, g.path) {
continue
}
if slices.Contains(filesExtensions, getFileExtension(path.Path)) {
urls = append(urls, fmt.Sprintf("%s/%s", g.rowYamlUrl(), path.Path))
}
}
@@ -150,5 +241,9 @@ func (g *GitHubRepository) getYamlFromTree() []string {
}
func (g *GitHubRepository) rowYamlUrl() string {
return fmt.Sprintf("https://raw.githubusercontent.com/%s/%s", g.name, g.branch)
return fmt.Sprintf("https://raw.githubusercontent.com/%s/%s", joinOwnerNRepo(g.owner, g.repo), g.branch)
}
func getFileExtension(path string) string {
return strings.TrimPrefix(filepath.Ext(path), ".")
}

View File

@@ -0,0 +1,140 @@
package resourcehandler
import (
"testing"
"github.com/stretchr/testify/assert"
)
var (
urlA = "https://github.com/armosec/kubescape"
urlB = "https://github.com/armosec/kubescape/blob/master/examples/online-boutique/adservice.yaml"
urlC = "https://github.com/armosec/kubescape/tree/master/examples/online-boutique"
urlD = "https://raw.githubusercontent.com/armosec/kubescape/master/examples/online-boutique/adservice.yaml"
)
func TestScanRepository(t *testing.T) {
{
files, err := ScanRepository(urlA, "")
assert.NoError(t, err)
assert.Less(t, 0, len(files))
}
{
files, err := ScanRepository(urlB, "")
assert.NoError(t, err)
assert.Less(t, 0, len(files))
}
{
files, err := ScanRepository(urlC, "")
assert.NoError(t, err)
assert.Less(t, 0, len(files))
}
{
files, err := ScanRepository(urlD, "")
assert.NoError(t, err)
assert.Equal(t, 1, len(files))
}
}
func TestGetHost(t *testing.T) {
{
host, err := getHost(urlA)
assert.NoError(t, err)
assert.Equal(t, "github.com", host)
}
{
host, err := getHost(urlB)
assert.NoError(t, err)
assert.Equal(t, "github.com", host)
}
{
host, err := getHost(urlC)
assert.NoError(t, err)
assert.Equal(t, "github.com", host)
}
{
host, err := getHost(urlD)
assert.NoError(t, err)
assert.Equal(t, "raw.githubusercontent.com", host)
}
}
func TestGithubSetBranch(t *testing.T) {
{
gh := NewGitHubRepository()
assert.NoError(t, gh.parse(urlA))
assert.NoError(t, gh.setBranch(""))
assert.Equal(t, "master", gh.getBranch())
}
{
gh := NewGitHubRepository()
assert.NoError(t, gh.parse(urlB))
err := gh.setBranch("dev")
assert.NoError(t, err)
assert.Equal(t, "dev", gh.getBranch())
}
}
func TestGithubSetTree(t *testing.T) {
{
gh := NewGitHubRepository()
assert.NoError(t, gh.parse(urlA))
assert.NoError(t, gh.setBranch(""))
err := gh.setTree()
assert.NoError(t, err)
assert.Less(t, 0, len(gh.getTree().InnerTrees))
}
}
func TestGithubGetYamlFromTree(t *testing.T) {
{
gh := NewGitHubRepository()
assert.NoError(t, gh.parse(urlA))
assert.NoError(t, gh.setBranch(""))
assert.NoError(t, gh.setTree())
files := gh.getFilesFromTree([]string{"yaml"})
assert.Less(t, 0, len(files))
}
{
gh := NewGitHubRepository()
assert.NoError(t, gh.parse(urlB))
assert.NoError(t, gh.setBranch(""))
assert.NoError(t, gh.setTree())
files := gh.getFilesFromTree([]string{"yaml"})
assert.Equal(t, 1, len(files))
}
{
gh := NewGitHubRepository()
assert.NoError(t, gh.parse(urlC))
assert.NoError(t, gh.setBranch(""))
assert.NoError(t, gh.setTree())
files := gh.getFilesFromTree([]string{"yaml"})
assert.Equal(t, 12, len(files))
}
}
func TestGithubParse(t *testing.T) {
{
gh := NewGitHubRepository()
assert.NoError(t, gh.parse(urlA))
assert.Equal(t, "armosec/kubescape", joinOwnerNRepo(gh.owner, gh.repo))
}
{
gh := NewGitHubRepository()
assert.NoError(t, gh.parse(urlB))
assert.Equal(t, "armosec/kubescape", joinOwnerNRepo(gh.owner, gh.repo))
assert.Equal(t, "master", gh.branch)
assert.Equal(t, "examples/online-boutique/adservice.yaml", gh.path)
assert.True(t, gh.isFile)
assert.Equal(t, 1, len(gh.getFilesFromTree([]string{"yaml"})))
assert.Equal(t, 0, len(gh.getFilesFromTree([]string{"yml"})))
}
{
gh := NewGitHubRepository()
assert.NoError(t, gh.parse(urlC))
assert.Equal(t, "armosec/kubescape", joinOwnerNRepo(gh.owner, gh.repo))
assert.Equal(t, "master", gh.branch)
assert.Equal(t, "examples/online-boutique", gh.path)
assert.False(t, gh.isFile)
}
}

View File

@@ -3,12 +3,11 @@ package resourcehandler
import (
"github.com/armosec/armoapi-go/armotypes"
"github.com/armosec/k8s-interface/workloadinterface"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/opa-utils/reporthandling"
"github.com/armosec/kubescape/core/cautils"
"k8s.io/apimachinery/pkg/version"
)
type IResourceHandler interface {
GetResources([]reporthandling.Framework, *armotypes.PortalDesignator) (*cautils.K8SResources, map[string]workloadinterface.IMetadata, error)
GetResources(*cautils.OPASessionObj, *armotypes.PortalDesignator) (*cautils.K8SResources, map[string]workloadinterface.IMetadata, *cautils.ArmoResources, error)
GetClusterAPIServerInfo() *version.Info
}

View File

@@ -8,11 +8,11 @@ import (
"strings"
"github.com/armosec/k8s-interface/workloadinterface"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/core/cautils"
"github.com/armosec/kubescape/core/cautils/logger"
)
func loadResourcesFromUrl(inputPatterns []string) ([]workloadinterface.IMetadata, error) {
func loadResourcesFromUrl(inputPatterns []string) (map[string][]workloadinterface.IMetadata, error) {
urls := listUrls(inputPatterns)
if len(urls) == 0 {
return nil, nil
@@ -29,14 +29,10 @@ func listUrls(patterns []string) []string {
urls := []string{}
for i := range patterns {
if strings.HasPrefix(patterns[i], "http") {
if !cautils.IsYaml(patterns[i]) && !cautils.IsJson(patterns[i]) { // if url of repo
if yamls, err := ScanRepository(patterns[i], ""); err == nil { // TODO - support branch
urls = append(urls, yamls...)
} else {
logger.L().Error(err.Error())
}
} else { // url of single file
urls = append(urls, patterns[i])
if yamls, err := ScanRepository(patterns[i], ""); err == nil { // TODO - support branch
urls = append(urls, yamls...)
} else {
logger.L().Error(err.Error())
}
}
}
@@ -44,8 +40,8 @@ func listUrls(patterns []string) []string {
return urls
}
func downloadFiles(urls []string) ([]workloadinterface.IMetadata, []error) {
workloads := []workloadinterface.IMetadata{}
func downloadFiles(urls []string) (map[string][]workloadinterface.IMetadata, []error) {
workloads := make(map[string][]workloadinterface.IMetadata, 0)
errs := []error{}
for i := range urls {
f, err := downloadFile(urls[i])
@@ -56,7 +52,12 @@ func downloadFiles(urls []string) ([]workloadinterface.IMetadata, []error) {
w, e := cautils.ReadFile(f, cautils.GetFileFormat(urls[i]))
errs = append(errs, e...)
if w != nil {
workloads = append(workloads, w...)
if _, ok := workloads[urls[i]]; !ok {
workloads[urls[i]] = make([]workloadinterface.IMetadata, 0)
}
wSlice := workloads[urls[i]]
wSlice = append(wSlice, w...)
workloads[urls[i]] = wSlice
}
}
return workloads, errs

View File

@@ -0,0 +1,66 @@
package resourcehandler
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestLoadResourcesFromUrl(t *testing.T) {
{
workloads, err := loadResourcesFromUrl([]string{"https://github.com/armosec/kubescape/tree/master/examples/online-boutique"})
assert.NoError(t, err)
assert.Equal(t, 12, len(workloads))
for i, w := range workloads {
switch i {
case "https://raw.githubusercontent.com/armosec/kubescape/master/examples/online-boutique/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())
}
}
}
{
workloads, err := loadResourcesFromUrl([]string{"https://github.com/armosec/kubescape"})
assert.NoError(t, err)
assert.Less(t, 12, len(workloads))
for i, w := range workloads {
switch i {
case "https://raw.githubusercontent.com/armosec/kubescape/master/examples/online-boutique/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())
}
}
}
{
workloads, err := loadResourcesFromUrl([]string{"https://github.com/armosec/kubescape/blob/master/examples/online-boutique/adservice.yaml"})
assert.NoError(t, err)
assert.Equal(t, 1, len(workloads))
for i, w := range workloads {
switch i {
case "https://raw.githubusercontent.com/armosec/kubescape/master/examples/online-boutique/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())
}
}
}
{
workloads, err := loadResourcesFromUrl([]string{"https://raw.githubusercontent.com/armosec/kubescape/master/examples/online-boutique/adservice.yaml"})
assert.NoError(t, err)
assert.Equal(t, 1, len(workloads))
for i, w := range workloads {
switch i {
case "https://raw.githubusercontent.com/armosec/kubescape/master/examples/online-boutique/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())
}
}
}
}

View File

@@ -5,8 +5,8 @@ import (
"os"
"path/filepath"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/core/cautils"
"github.com/armosec/kubescape/core/cautils/logger"
)
var INDENT = " "

Some files were not shown because too many files have changed in this diff Show More