mirror of
https://github.com/kubescape/kubescape.git
synced 2026-02-22 22:03:50 +00:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54020d317e | ||
|
|
91d1ec6c2f | ||
|
|
1d3fd0dc9d | ||
|
|
8a7511cecb | ||
|
|
0af0c01ec0 | ||
|
|
4f1971a63d | ||
|
|
afb6ea1d9c | ||
|
|
b3d16875d6 | ||
|
|
cf086e6614 | ||
|
|
a27d2d41f2 |
25
.github/workflows/build.yaml
vendored
25
.github/workflows/build.yaml
vendored
@@ -28,38 +28,29 @@ jobs:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- uses: actions/checkout@v1
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.18
|
||||
go-version: 1.17
|
||||
# - name: Test cmd pkg
|
||||
# run: cd cmd && go test -v ./...
|
||||
|
||||
- name: Install libgit2
|
||||
run: make libgit2
|
||||
if: matrix.os != 'windows-latest'
|
||||
|
||||
- name: Test core pkg
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: go test -tags=static -v ./...
|
||||
run: go test -v ./...
|
||||
|
||||
- name: Test httphandler pkg
|
||||
run: cd httphandler && go test -tags=static -v ./...
|
||||
run: cd httphandler && go test -v ./...
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
RELEASE: v2.0.${{ github.run_number }}
|
||||
CLIENT: release
|
||||
ArmoBEServer: api.armo.cloud
|
||||
ArmoAuthServer: auth.armo.cloud
|
||||
ArmoERServer: report.armo.cloud
|
||||
ArmoWebsite: portal.armo.cloud
|
||||
CGO_ENABLED: 1
|
||||
CGO_ENABLED: 0
|
||||
run: python3 --version && python3 build.py
|
||||
|
||||
- name: Smoke Testing
|
||||
@@ -101,8 +92,6 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Set image version
|
||||
id: image-version
|
||||
@@ -125,7 +114,7 @@ jobs:
|
||||
run: docker login -u="${QUAY_USERNAME}" -p="${QUAY_PASSWORD}" quay.io
|
||||
|
||||
- name: Build the Docker image
|
||||
run: docker buildx build . --file build/Dockerfile --tag ${{ steps.image-name.outputs.IMAGE_NAME }}:${{ steps.image-version.outputs.IMAGE_VERSION }} --tag ${{ steps.image-name.outputs.IMAGE_NAME }}:latest --build-arg image_version=${{ steps.image-version.outputs.IMAGE_VERSION }} --build-arg client=image-release --push --platform linux/amd64,linux/arm64
|
||||
run: docker buildx build . --file build/Dockerfile --tag ${{ steps.image-name.outputs.IMAGE_NAME }}:${{ steps.image-version.outputs.IMAGE_VERSION }} --tag ${{ steps.image-name.outputs.IMAGE_NAME }}:latest --build-arg image_version=${{ steps.image-version.outputs.IMAGE_VERSION }} --push --platform linux/amd64,linux/arm64
|
||||
|
||||
# - name: Login to GitHub Container Registry
|
||||
# uses: docker/login-action@v1
|
||||
|
||||
24
.github/workflows/build_dev.yaml
vendored
24
.github/workflows/build_dev.yaml
vendored
@@ -11,13 +11,12 @@ jobs:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
- uses: actions/checkout@v1
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.18
|
||||
go-version: 1.17
|
||||
|
||||
# - name: Test cmd pkg
|
||||
# run: cd cmd && go test -v ./...
|
||||
@@ -30,27 +29,22 @@ jobs:
|
||||
# - name: Test cmd pkg
|
||||
# run: cd cmd && go test -v ./...
|
||||
|
||||
- name: Install libgit2
|
||||
run: make libgit2
|
||||
if: matrix.os != 'windows-latest'
|
||||
|
||||
- name: Test core pkg
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: go test -tags=static -v ./...
|
||||
run: go test -v ./...
|
||||
|
||||
- name: Test httphandler pkg
|
||||
run: cd httphandler && go test -tags=static -v ./...
|
||||
run: cd httphandler && go test -v ./...
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
RELEASE: v2.0.${{ github.run_number }}
|
||||
CLIENT: release-dev
|
||||
ArmoBEServer: api.armo.cloud
|
||||
ArmoAuthServer: auth.armo.cloud
|
||||
ArmoERServer: report.armo.cloud
|
||||
ArmoWebsite: portal.armo.cloud
|
||||
CGO_ENABLED: 1
|
||||
CGO_ENABLED: 0
|
||||
run: python3 --version && python3 build.py
|
||||
|
||||
- name: Smoke Testing
|
||||
@@ -77,8 +71,6 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Set image version
|
||||
id: image-version
|
||||
@@ -101,4 +93,4 @@ jobs:
|
||||
run: docker login -u="${QUAY_USERNAME}" -p="${QUAY_PASSWORD}" quay.io
|
||||
|
||||
- name: Build the Docker image
|
||||
run: docker buildx build . --file build/Dockerfile --tag ${{ steps.image-name.outputs.IMAGE_NAME }}:${{ steps.image-version.outputs.IMAGE_VERSION }} --build-arg image_version=${{ steps.image-version.outputs.IMAGE_VERSION }} --build-arg client=image-dev --push --platform linux/amd64,linux/arm64
|
||||
run: docker buildx build . --file build/Dockerfile --tag ${{ steps.image-name.outputs.IMAGE_NAME }}:${{ steps.image-version.outputs.IMAGE_VERSION }} --build-arg image_version=${{ steps.image-version.outputs.IMAGE_VERSION }} --push --platform linux/amd64,linux/arm64
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
name: pr-checks
|
||||
name: master-pr
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ master, dev ]
|
||||
branches: [ master ]
|
||||
types: [ edited, opened, synchronize, reopened ]
|
||||
jobs:
|
||||
build:
|
||||
@@ -12,18 +12,12 @@ jobs:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
- uses: actions/checkout@v1
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.18
|
||||
|
||||
- name: Install libgit2
|
||||
run: make libgit2
|
||||
if: matrix.os != 'windows-latest'
|
||||
go-version: 1.17
|
||||
|
||||
# - name: Test cmd pkg
|
||||
# run: cd cmd && go test -v ./...
|
||||
@@ -31,20 +25,19 @@ jobs:
|
||||
- name: Test core pkg
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: go test -tags=static -v ./...
|
||||
run: go test -v ./...
|
||||
|
||||
- name: Test httphandler pkg
|
||||
run: cd httphandler && go test -tags=static -v ./...
|
||||
run: cd httphandler && go test -v ./...
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
RELEASE: v2.0.${{ github.run_number }}
|
||||
CLIENT: test
|
||||
ArmoBEServer: api.armo.cloud
|
||||
ArmoAuthServer: auth.armo.cloud
|
||||
ArmoERServer: report.armo.cloud
|
||||
ArmoWebsite: portal.armo.cloud
|
||||
CGO_ENABLED: 1
|
||||
CGO_ENABLED: 0
|
||||
run: python3 --version && python3 build.py
|
||||
|
||||
- name: Smoke Testing
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,5 +4,4 @@
|
||||
*vender*
|
||||
*.pyc*
|
||||
.idea
|
||||
.history
|
||||
ca.srl
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +0,0 @@
|
||||
[submodule "git2go"]
|
||||
path = git2go
|
||||
url = https://github.com/libgit2/git2go.git
|
||||
20
Makefile
20
Makefile
@@ -1,20 +0,0 @@
|
||||
.PHONY: test all build libgit2
|
||||
|
||||
# default task invoked while running make
|
||||
all: libgit2 build
|
||||
|
||||
export CGO_ENABLED=1
|
||||
|
||||
# build and install libgit2
|
||||
libgit2:
|
||||
git submodule update --init --recursive
|
||||
cd git2go; make install-static
|
||||
|
||||
# go build tags
|
||||
TAGS = "static"
|
||||
|
||||
build:
|
||||
go build -v -tags=$(TAGS) .
|
||||
|
||||
test:
|
||||
go test -v -tags=$(TAGS) ./...
|
||||
145
README.md
145
README.md
@@ -28,7 +28,7 @@ Kubescape integrates natively with other DevOps tools, including Jenkins, Circle
|
||||
|
||||
# TL;DR
|
||||
## Install:
|
||||
```sh
|
||||
```
|
||||
curl -s https://raw.githubusercontent.com/armosec/kubescape/master/install.sh | /bin/bash
|
||||
```
|
||||
|
||||
@@ -36,12 +36,8 @@ curl -s https://raw.githubusercontent.com/armosec/kubescape/master/install.sh |
|
||||
|
||||
[Install on macOS](#install-on-macos)
|
||||
|
||||
[Install on NixOS or Linux/macOS via nix](#install-on-nixos-or-with-nix-community)
|
||||
|
||||
[Install using Go](#install-using-go)
|
||||
|
||||
## Run:
|
||||
```sh
|
||||
```
|
||||
kubescape scan --submit --enable-host-scan --verbose
|
||||
```
|
||||
|
||||
@@ -74,7 +70,7 @@ Want to contribute? Want to discuss something? Have an issue?
|
||||
|
||||
# Options and examples
|
||||
|
||||
[Kubescape docs](https://hub.armosec.io/docs)
|
||||
[Kubescape docs](https://hub.armo.cloud/docs)
|
||||
|
||||
## Playground
|
||||
* [Kubescape playground](https://www.katacoda.com/pathaksaiyam/scenarios/kubescape)
|
||||
@@ -105,46 +101,13 @@ Set-ExecutionPolicy RemoteSigned -scope CurrentUser
|
||||
|
||||
## Install on macOS
|
||||
|
||||
1. ```sh
|
||||
1. ```
|
||||
brew tap armosec/kubescape
|
||||
```
|
||||
2. ```sh
|
||||
2. ```
|
||||
brew install kubescape
|
||||
```
|
||||
|
||||
## Install on NixOS or with nix (Community)
|
||||
|
||||
Direct issues installing `kubescape` via `nix` through the channels mentioned [here](https://nixos.wiki/wiki/Support)
|
||||
|
||||
You can use `nix` on Linux or macOS and on other platforms unofficially.
|
||||
|
||||
Try it out in an ephemeral shell: `nix-shell -p kubescape`
|
||||
|
||||
Install declarative as usual
|
||||
|
||||
NixOS:
|
||||
|
||||
```nix
|
||||
# your other config ...
|
||||
environment.systemPackages = with pkgs; [
|
||||
# your other packages ...
|
||||
kubescape
|
||||
];
|
||||
```
|
||||
|
||||
home-manager:
|
||||
|
||||
```nix
|
||||
# your other config ...
|
||||
home.packages = with pkgs; [
|
||||
# your other packages ...
|
||||
kubescape
|
||||
];
|
||||
```
|
||||
|
||||
Or to your profile (not preferred): `nix-env --install -A nixpkgs.kubescape`
|
||||
|
||||
|
||||
## Usage & Examples
|
||||
|
||||
### Examples
|
||||
@@ -155,7 +118,7 @@ Or to your profile (not preferred): `nix-env --install -A nixpkgs.kubescape`
|
||||
kubescape scan --submit --enable-host-scan --verbose
|
||||
```
|
||||
|
||||
> Read [here](https://hub.armosec.io/docs/host-sensor) more about the `enable-host-scan` flag
|
||||
> Read [here](https://hub.armo.cloud/docs/host-sensor) more about the `enable-host-scan` flag
|
||||
|
||||
#### Scan a running Kubernetes cluster with [`nsa`](https://www.nsa.gov/Press-Room/News-Highlights/Article/Article/2716980/nsa-cisa-release-kubernetes-hardening-guidance/) framework and submit results to the [Kubescape SaaS version](https://portal.armo.cloud/)
|
||||
```
|
||||
@@ -169,7 +132,7 @@ kubescape scan framework mitre --submit
|
||||
```
|
||||
|
||||
|
||||
#### Scan a running Kubernetes cluster with a specific control using the control name or control ID. [List of controls](https://hub.armosec.io/docs/controls)
|
||||
#### Scan a running Kubernetes cluster with a specific control using the control name or control ID. [List of controls](https://hub.armo.cloud/docs/controls)
|
||||
```
|
||||
kubescape scan control "Privileged container"
|
||||
```
|
||||
@@ -184,14 +147,14 @@ kubescape scan --include-namespaces development,staging,production
|
||||
kubescape scan --exclude-namespaces kube-system,kube-public
|
||||
```
|
||||
|
||||
#### Scan local `yaml`/`json` files before deploying. [Take a look at the demonstration](https://youtu.be/Ox6DaR7_4ZI) Submit the results in case the directory is a git repo. [docs](https://hub.armosec.io/docs/repository-scanning)
|
||||
#### Scan local `yaml`/`json` files before deploying. [Take a look at the demonstration](https://youtu.be/Ox6DaR7_4ZI)
|
||||
```
|
||||
kubescape scan *.yaml --submit
|
||||
kubescape scan *.yaml
|
||||
```
|
||||
|
||||
#### Scan kubernetes manifest files from a git repository [and submit the results](https://hub.armosec.io/docs/repository-scanning)
|
||||
#### Scan kubernetes manifest files from a public github repository
|
||||
```
|
||||
kubescape scan https://github.com/armosec/kubescape --submit
|
||||
kubescape scan https://github.com/armosec/kubescape
|
||||
```
|
||||
|
||||
#### Display all scanned resources (including the resources who passed)
|
||||
@@ -230,11 +193,16 @@ kubescape scan --format prometheus
|
||||
kubescape scan --exceptions examples/exceptions/exclude-kube-namespaces.json
|
||||
```
|
||||
|
||||
#### Scan Helm charts
|
||||
#### Scan Helm charts - Render the helm chart using [`helm template`](https://helm.sh/docs/helm/helm_template/) and pass to stdout
|
||||
```
|
||||
kubescape scan </path/to/directory> --submit
|
||||
helm template [NAME] [CHART] [flags] --dry-run | kubescape scan -
|
||||
```
|
||||
> Kubescape will load the default values file
|
||||
|
||||
e.g.
|
||||
```
|
||||
helm template bitnami/mysql --generate-name --dry-run | kubescape scan -
|
||||
```
|
||||
|
||||
|
||||
### Offline/Air-gaped Environment Support
|
||||
|
||||
@@ -271,7 +239,7 @@ kubescape scan framework nsa --use-from /path/nsa.json
|
||||
|
||||
|
||||
## Scan Periodically using Helm - Contributed by [@yonahd](https://github.com/yonahd)
|
||||
[Please follow the instructions here](https://hub.armosec.io/docs/installation-of-armo-in-cluster)
|
||||
[Please follow the instructions here](https://hub.armo.cloud/docs/installation-of-armo-in-cluster)
|
||||
[helm chart repo](https://github.com/armosec/armo-helm)
|
||||
|
||||
## Scan using docker image
|
||||
@@ -299,6 +267,7 @@ Now you can submit the results to the Kubescape SaaS version -
|
||||
kubescape submit results path/to/results.json
|
||||
```
|
||||
|
||||
|
||||
# Integrations
|
||||
|
||||
## VS Code Extension
|
||||
@@ -311,78 +280,6 @@ Scan the YAML files while writing them using the [vs code extension](https://git
|
||||
|
||||
View Kubescape scan results directly in [Lens IDE](https://k8slens.dev/) using kubescape [Lens extension](https://github.com/armosec/lens-kubescape/blob/master/README.md)
|
||||
|
||||
|
||||
# Building Kubescape
|
||||
|
||||
## Windows
|
||||
|
||||
```
|
||||
go build .
|
||||
```
|
||||
OR
|
||||
```
|
||||
make build
|
||||
```
|
||||
|
||||
## Linux / MacOS
|
||||
|
||||
1. Install libgit2 dependency
|
||||
|
||||
```
|
||||
make libgit2
|
||||
```
|
||||
|
||||
> `cmake` is required to build libgit2. You can install it by running `sudo apt-get install cmake` (Linux) or `brew install cmake` (MacOS)
|
||||
|
||||
2. Build
|
||||
|
||||
```
|
||||
make build
|
||||
```
|
||||
3. Test
|
||||
|
||||
```
|
||||
make test
|
||||
```
|
||||
|
||||
## VS code configuration samples
|
||||
|
||||
You can use the samples files below to setup your VS code environment for building and debugging purposes.
|
||||
|
||||
|
||||
```json5
|
||||
// .vscode/settings.json
|
||||
{
|
||||
"go.testTags": "static",
|
||||
"go.buildTags": "static",
|
||||
"go.toolsEnvVars": {
|
||||
"CGO_ENABLED": "1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json5
|
||||
// .vscode/launch.json
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch Package",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "auto",
|
||||
"program": "${workspaceFolder}/main.go",
|
||||
"args": [
|
||||
"scan",
|
||||
"--logger",
|
||||
"debug"
|
||||
],
|
||||
"buildFlags": "-tags=static"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
# Under the hood
|
||||
|
||||
## Technology
|
||||
|
||||
80
build.py
80
build.py
@@ -10,76 +10,74 @@ ER_SERVER_CONST = BASE_GETTER_CONST + ".ArmoERURL"
|
||||
WEBSITE_CONST = BASE_GETTER_CONST + ".ArmoFEURL"
|
||||
AUTH_SERVER_CONST = BASE_GETTER_CONST + ".armoAUTHURL"
|
||||
|
||||
def check_status(status, msg):
|
||||
def checkStatus(status, msg):
|
||||
if status != 0:
|
||||
sys.stderr.write(msg)
|
||||
exit(status)
|
||||
|
||||
|
||||
def get_build_dir():
|
||||
current_platform = platform.system()
|
||||
build_dir = "./build/"
|
||||
def getBuildDir():
|
||||
currentPlatform = platform.system()
|
||||
buildDir = "./build/"
|
||||
|
||||
if current_platform == "Windows": build_dir += "windows-latest"
|
||||
elif current_platform == "Linux": build_dir += "ubuntu-latest"
|
||||
elif current_platform == "Darwin": build_dir += "macos-latest"
|
||||
else: raise OSError("Platform %s is not supported!" % (current_platform))
|
||||
if currentPlatform == "Windows": buildDir += "windows-latest"
|
||||
elif currentPlatform == "Linux": buildDir += "ubuntu-latest"
|
||||
elif currentPlatform == "Darwin": buildDir += "macos-latest"
|
||||
else: raise OSError("Platform %s is not supported!" % (currentPlatform))
|
||||
|
||||
return build_dir
|
||||
return buildDir
|
||||
|
||||
def get_package_name():
|
||||
package_name = "kubescape"
|
||||
# if platform.system() == "Windows": package_name += ".exe"
|
||||
def getPackageName():
|
||||
packageName = "kubescape"
|
||||
# if platform.system() == "Windows": packageName += ".exe"
|
||||
|
||||
return package_name
|
||||
return packageName
|
||||
|
||||
|
||||
def main():
|
||||
print("Building Kubescape")
|
||||
|
||||
# print environment variables
|
||||
# print(os.environ)
|
||||
|
||||
# Set some variables
|
||||
package_name = get_package_name()
|
||||
build_url = "github.com/armosec/kubescape/v2/core/cautils.BuildNumber"
|
||||
release_version = os.getenv("RELEASE")
|
||||
armo_be_server = os.getenv("ArmoBEServer")
|
||||
armo_er_server = os.getenv("ArmoERServer")
|
||||
armo_website = os.getenv("ArmoWebsite")
|
||||
armo_auth_server = os.getenv("ArmoAuthServer")
|
||||
packageName = getPackageName()
|
||||
buildUrl = "github.com/armosec/kubescape/v2/core/cautils.BuildNumber"
|
||||
releaseVersion = os.getenv("RELEASE")
|
||||
ArmoBEServer = os.getenv("ArmoBEServer")
|
||||
ArmoERServer = os.getenv("ArmoERServer")
|
||||
ArmoWebsite = os.getenv("ArmoWebsite")
|
||||
ArmoAuthServer = os.getenv("ArmoAuthServer")
|
||||
|
||||
client_var = "github.com/armosec/kubescape/v2/core/cautils.Client"
|
||||
client_name = os.getenv("CLIENT")
|
||||
|
||||
# Create build directory
|
||||
build_dir = get_build_dir()
|
||||
buildDir = getBuildDir()
|
||||
|
||||
ks_file = os.path.join(build_dir, package_name)
|
||||
ks_file = os.path.join(buildDir, packageName)
|
||||
hash_file = ks_file + ".sha256"
|
||||
|
||||
if not os.path.isdir(build_dir):
|
||||
os.makedirs(build_dir)
|
||||
if not os.path.isdir(buildDir):
|
||||
os.makedirs(buildDir)
|
||||
|
||||
# Build kubescape
|
||||
ldflags = "-w -s"
|
||||
if release_version:
|
||||
ldflags += " -X {}={}".format(build_url, release_version)
|
||||
if client_name:
|
||||
ldflags += " -X {}={}".format(client_var, client_name)
|
||||
if armo_be_server:
|
||||
ldflags += " -X {}={}".format(BE_SERVER_CONST, armo_be_server)
|
||||
if armo_er_server:
|
||||
ldflags += " -X {}={}".format(ER_SERVER_CONST, armo_er_server)
|
||||
if armo_website:
|
||||
ldflags += " -X {}={}".format(WEBSITE_CONST, armo_website)
|
||||
if armo_auth_server:
|
||||
ldflags += " -X {}={}".format(AUTH_SERVER_CONST, armo_auth_server)
|
||||
if releaseVersion:
|
||||
ldflags += " -X {}={}".format(buildUrl, releaseVersion)
|
||||
if ArmoBEServer:
|
||||
ldflags += " -X {}={}".format(BE_SERVER_CONST, ArmoBEServer)
|
||||
if ArmoERServer:
|
||||
ldflags += " -X {}={}".format(ER_SERVER_CONST, ArmoERServer)
|
||||
if ArmoWebsite:
|
||||
ldflags += " -X {}={}".format(WEBSITE_CONST, ArmoWebsite)
|
||||
if ArmoAuthServer:
|
||||
ldflags += " -X {}={}".format(AUTH_SERVER_CONST, ArmoAuthServer)
|
||||
|
||||
build_command = ["go", "build", "-tags=static", "-o", ks_file, "-ldflags" ,ldflags]
|
||||
build_command = ["go", "build", "-o", ks_file, "-ldflags" ,ldflags]
|
||||
|
||||
print("Building kubescape and saving here: {}".format(ks_file))
|
||||
print("Build command: {}".format(" ".join(build_command)))
|
||||
|
||||
status = subprocess.call(build_command)
|
||||
check_status(status, "Failed to build kubescape")
|
||||
checkStatus(status, "Failed to build kubescape")
|
||||
|
||||
sha256 = hashlib.sha256()
|
||||
with open(ks_file, "rb") as kube:
|
||||
|
||||
@@ -1,28 +1,23 @@
|
||||
FROM golang:1.18-alpine as builder
|
||||
FROM golang:1.17-alpine as builder
|
||||
#ENV GOPROXY=https://goproxy.io,direct
|
||||
|
||||
ARG image_version
|
||||
ARG client
|
||||
|
||||
ENV RELEASE=$image_version
|
||||
ENV CLIENT=$client
|
||||
|
||||
ENV GO111MODULE=
|
||||
|
||||
ENV CGO_ENABLED=1
|
||||
ENV CGO_ENABLED=0
|
||||
|
||||
# Install required python/pip
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
RUN apk add --update --no-cache python3 git openssl-dev musl-dev gcc make cmake pkgconfig && ln -sf python3 /usr/bin/python
|
||||
RUN apk add --update --no-cache python3 && ln -sf python3 /usr/bin/python
|
||||
RUN python3 -m ensurepip
|
||||
RUN pip3 install --no-cache --upgrade pip setuptools
|
||||
|
||||
WORKDIR /work
|
||||
ADD . .
|
||||
|
||||
# install libgit2
|
||||
WORKDIR /work
|
||||
RUN rm -rf git2go && make libgit2
|
||||
|
||||
# build kubescape server
|
||||
WORKDIR /work/httphandler
|
||||
RUN python build.py
|
||||
|
||||
@@ -25,8 +25,8 @@ func GetDeleteCmd(ks meta.IKubescape) *cobra.Command {
|
||||
},
|
||||
}
|
||||
deleteCmd.PersistentFlags().StringVarP(&deleteInfo.Credentials.Account, "account", "", "", "Kubescape SaaS account ID. Default will load account ID from cache")
|
||||
deleteCmd.PersistentFlags().StringVarP(&deleteInfo.Credentials.ClientID, "client-id", "", "", "Kubescape SaaS client ID. Default will load client ID from cache, read more - https://hub.armosec.io/docs/authentication")
|
||||
deleteCmd.PersistentFlags().StringVarP(&deleteInfo.Credentials.SecretKey, "secret-key", "", "", "Kubescape SaaS secret key. Default will load secret key from cache, read more - https://hub.armosec.io/docs/authentication")
|
||||
deleteCmd.PersistentFlags().StringVarP(&deleteInfo.Credentials.ClientID, "client-id", "", "", "Kubescape SaaS client ID. Default will load client ID from cache, read more - https://hub.armo.cloud/docs/authentication")
|
||||
deleteCmd.PersistentFlags().StringVarP(&deleteInfo.Credentials.SecretKey, "secret-key", "", "", "Kubescape SaaS secret key. Default will load secret key from cache, read more - https://hub.armo.cloud/docs/authentication")
|
||||
|
||||
deleteCmd.AddCommand(getExceptionsCmd(ks, &deleteInfo))
|
||||
|
||||
|
||||
@@ -74,8 +74,8 @@ func GeDownloadCmd(ks meta.IKubescape) *cobra.Command {
|
||||
}
|
||||
|
||||
downloadCmd.PersistentFlags().StringVarP(&downloadInfo.Credentials.Account, "account", "", "", "Kubescape SaaS account ID. Default will load account ID from cache")
|
||||
downloadCmd.PersistentFlags().StringVarP(&downloadInfo.Credentials.ClientID, "client-id", "", "", "Kubescape SaaS client ID. Default will load client ID from cache, read more - https://hub.armosec.io/docs/authentication")
|
||||
downloadCmd.PersistentFlags().StringVarP(&downloadInfo.Credentials.SecretKey, "secret-key", "", "", "Kubescape SaaS secret key. Default will load secret key from cache, read more - https://hub.armosec.io/docs/authentication")
|
||||
downloadCmd.PersistentFlags().StringVarP(&downloadInfo.Credentials.ClientID, "client-id", "", "", "Kubescape SaaS client ID. Default will load client ID from cache, read more - https://hub.armo.cloud/docs/authentication")
|
||||
downloadCmd.PersistentFlags().StringVarP(&downloadInfo.Credentials.SecretKey, "secret-key", "", "", "Kubescape SaaS secret key. Default will load secret key from cache, read more - https://hub.armo.cloud/docs/authentication")
|
||||
downloadCmd.Flags().StringVarP(&downloadInfo.Path, "output", "o", "", "Output file. If not specified, will save in `~/.kubescape/<policy name>.json`")
|
||||
|
||||
return downloadCmd
|
||||
|
||||
@@ -27,7 +27,7 @@ var (
|
||||
kubescape list controls --id
|
||||
|
||||
Control documentation:
|
||||
https://hub.armosec.io/docs/controls
|
||||
https://hub.armo.cloud/docs/controls
|
||||
`
|
||||
)
|
||||
|
||||
@@ -60,8 +60,8 @@ func GetListCmd(ks meta.IKubescape) *cobra.Command {
|
||||
},
|
||||
}
|
||||
listCmd.PersistentFlags().StringVarP(&listPolicies.Credentials.Account, "account", "", "", "Kubescape SaaS account ID. Default will load account ID from cache")
|
||||
listCmd.PersistentFlags().StringVarP(&listPolicies.Credentials.ClientID, "client-id", "", "", "Kubescape SaaS client ID. Default will load client ID from cache, read more - https://hub.armosec.io/docs/authentication")
|
||||
listCmd.PersistentFlags().StringVarP(&listPolicies.Credentials.SecretKey, "secret-key", "", "", "Kubescape SaaS secret key. Default will load secret key from cache, read more - https://hub.armosec.io/docs/authentication")
|
||||
listCmd.PersistentFlags().StringVarP(&listPolicies.Credentials.ClientID, "client-id", "", "", "Kubescape SaaS client ID. Default will load client ID from cache, read more - https://hub.armo.cloud/docs/authentication")
|
||||
listCmd.PersistentFlags().StringVarP(&listPolicies.Credentials.SecretKey, "secret-key", "", "", "Kubescape SaaS secret key. Default will load secret key from cache, read more - https://hub.armo.cloud/docs/authentication")
|
||||
listCmd.PersistentFlags().StringVar(&listPolicies.Format, "format", "pretty-print", "output format. supported: 'pretty-printer'/'json'")
|
||||
listCmd.PersistentFlags().BoolVarP(&listPolicies.ListIDs, "id", "", false, "List control ID's instead of controls names")
|
||||
|
||||
|
||||
@@ -47,7 +47,8 @@ func getRootCmd(ks meta.IKubescape) *cobra.Command {
|
||||
|
||||
rootCmd := &cobra.Command{
|
||||
Use: "kubescape",
|
||||
Short: "Kubescape is a tool for testing Kubernetes security posture. Docs: https://hub.armosec.io/docs",
|
||||
Version: cautils.BuildNumber,
|
||||
Short: "Kubescape is a tool for testing Kubernetes security posture. Docs: https://hub.armo.cloud/docs",
|
||||
Example: ksExamples,
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ var (
|
||||
Run 'kubescape list controls' for the list of supported controls
|
||||
|
||||
Control documentation:
|
||||
https://hub.armosec.io/docs/controls
|
||||
https://hub.armo.cloud/docs/controls
|
||||
`
|
||||
)
|
||||
|
||||
|
||||
@@ -64,15 +64,15 @@ func GetScanCommand(ks meta.IKubescape) *cobra.Command {
|
||||
}
|
||||
|
||||
scanCmd.PersistentFlags().StringVarP(&scanInfo.Credentials.Account, "account", "", "", "Kubescape SaaS account ID. Default will load account ID from cache")
|
||||
scanCmd.PersistentFlags().StringVarP(&scanInfo.Credentials.ClientID, "client-id", "", "", "Kubescape SaaS client ID. Default will load client ID from cache, read more - https://hub.armosec.io/docs/authentication")
|
||||
scanCmd.PersistentFlags().StringVarP(&scanInfo.Credentials.SecretKey, "secret-key", "", "", "Kubescape SaaS secret key. Default will load secret key from cache, read more - https://hub.armosec.io/docs/authentication")
|
||||
scanCmd.PersistentFlags().StringVarP(&scanInfo.Credentials.ClientID, "client-id", "", "", "Kubescape SaaS client ID. Default will load client ID from cache, read more - https://hub.armo.cloud/docs/authentication")
|
||||
scanCmd.PersistentFlags().StringVarP(&scanInfo.Credentials.SecretKey, "secret-key", "", "", "Kubescape SaaS secret key. Default will load secret key from cache, read more - https://hub.armo.cloud/docs/authentication")
|
||||
scanCmd.PersistentFlags().StringVarP(&scanInfo.KubeContext, "kube-context", "", "", "Kube context. Default will use the current-context")
|
||||
scanCmd.PersistentFlags().StringVar(&scanInfo.ControlsInputs, "controls-config", "", "Path to an controls-config obj. If not set will download controls-config from ARMO management portal")
|
||||
scanCmd.PersistentFlags().StringVar(&scanInfo.UseExceptions, "exceptions", "", "Path to an exceptions obj. If not set will download exceptions from ARMO management portal")
|
||||
scanCmd.PersistentFlags().StringVar(&scanInfo.UseArtifactsFrom, "use-artifacts-from", "", "Load artifacts from local directory. If not used will download them")
|
||||
scanCmd.PersistentFlags().StringVarP(&scanInfo.ExcludedNamespaces, "exclude-namespaces", "e", "", "Namespaces to exclude from scanning. Recommended: kube-system,kube-public")
|
||||
scanCmd.PersistentFlags().Float32VarP(&scanInfo.FailThreshold, "fail-threshold", "t", 100, "Failure threshold is the percent above which the command fails and returns exit code 1")
|
||||
scanCmd.PersistentFlags().StringVarP(&scanInfo.Format, "format", "f", "pretty-printer", `Output format. Supported formats: "pretty-printer", "json", "junit", "prometheus", "pdf", "html"`)
|
||||
scanCmd.PersistentFlags().StringVarP(&scanInfo.Format, "format", "f", "pretty-printer", `Output format. Supported formats: "pretty-printer","json","junit","prometheus","pdf"`)
|
||||
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")
|
||||
|
||||
@@ -21,8 +21,8 @@ func GetSubmitCmd(ks meta.IKubescape) *cobra.Command {
|
||||
},
|
||||
}
|
||||
submitCmd.PersistentFlags().StringVarP(&submitInfo.Credentials.Account, "account", "", "", "Kubescape SaaS account ID. Default will load account ID from cache")
|
||||
submitCmd.PersistentFlags().StringVarP(&submitInfo.Credentials.ClientID, "client-id", "", "", "Kubescape SaaS client ID. Default will load client ID from cache, read more - https://hub.armosec.io/docs/authentication")
|
||||
submitCmd.PersistentFlags().StringVarP(&submitInfo.Credentials.SecretKey, "secret-key", "", "", "Kubescape SaaS secret key. Default will load secret key from cache, read more - https://hub.armosec.io/docs/authentication")
|
||||
submitCmd.PersistentFlags().StringVarP(&submitInfo.Credentials.ClientID, "client-id", "", "", "Kubescape SaaS client ID. Default will load client ID from cache, read more - https://hub.armo.cloud/docs/authentication")
|
||||
submitCmd.PersistentFlags().StringVarP(&submitInfo.Credentials.SecretKey, "secret-key", "", "", "Kubescape SaaS secret key. Default will load secret key from cache, read more - https://hub.armo.cloud/docs/authentication")
|
||||
|
||||
submitCmd.AddCommand(getExceptionsCmd(ks, &submitInfo))
|
||||
submitCmd.AddCommand(getResultsCmd(ks, &submitInfo))
|
||||
|
||||
@@ -19,7 +19,7 @@ type OPASessionObj struct {
|
||||
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]reporthandling.Source // resources sources, 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
|
||||
@@ -39,7 +39,7 @@ func NewOPASessionObj(frameworks []reporthandling.Framework, k8sResources *K8SRe
|
||||
ResourcesResult: make(map[string]resourcesresults.Result),
|
||||
InfoMap: make(map[string]apis.StatusInfo),
|
||||
ResourceToControlsMap: make(map[string][]string),
|
||||
ResourceSource: make(map[string]reporthandling.Source),
|
||||
ResourceSource: make(map[string]string),
|
||||
SessionID: scanInfo.ScanID,
|
||||
PostureReport: &reporthandling.PostureReport{
|
||||
ClusterName: ClusterName,
|
||||
@@ -62,11 +62,6 @@ func NewOPASessionObjMock() *OPASessionObj {
|
||||
ReportID: "",
|
||||
JobID: "",
|
||||
},
|
||||
Metadata: &reporthandlingv2.Metadata{
|
||||
ScanMetadata: reporthandlingv2.ScanMetadata{
|
||||
ScanningTarget: 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,11 +9,8 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/armosec/k8s-interface/workloadinterface"
|
||||
|
||||
"github.com/armosec/kubescape/v2/core/cautils/logger"
|
||||
"github.com/armosec/kubescape/v2/core/cautils/logger/helpers"
|
||||
"github.com/armosec/opa-utils/objectsenvelopes"
|
||||
"github.com/armosec/opa-utils/objectsenvelopes/localworkload"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
@@ -29,52 +26,23 @@ const (
|
||||
JSON_FILE_FORMAT FileFormat = "json"
|
||||
)
|
||||
|
||||
// LoadResourcesFromHelmCharts scans a given path (recuresively) for helm charts, renders the templates and returns a list of workloads
|
||||
func LoadResourcesFromHelmCharts(basePath string) map[string][]workloadinterface.IMetadata {
|
||||
directories, _ := listDirs(basePath)
|
||||
helmDirectories := make([]string, 0)
|
||||
for _, dir := range directories {
|
||||
if ok, _ := IsHelmDirectory(dir); ok {
|
||||
helmDirectories = append(helmDirectories, dir)
|
||||
}
|
||||
}
|
||||
|
||||
result := map[string][]workloadinterface.IMetadata{}
|
||||
for _, helmDir := range helmDirectories {
|
||||
chart, err := NewHelmChart(helmDir)
|
||||
if err == nil {
|
||||
wls, errs := chart.GetWorkloadsWithDefaultValues()
|
||||
if len(errs) > 0 {
|
||||
logger.L().Error(fmt.Sprintf("Rendering of Helm chart template failed: %v", errs))
|
||||
continue
|
||||
}
|
||||
|
||||
for k, v := range wls {
|
||||
result[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func LoadResourcesFromFiles(input, rootPath string) map[string][]workloadinterface.IMetadata {
|
||||
files, errs := listFiles(input)
|
||||
func LoadResourcesFromFiles(inputPatterns []string) (map[string][]workloadinterface.IMetadata, error) {
|
||||
files, errs := listFiles(inputPatterns)
|
||||
if len(errs) > 0 {
|
||||
logger.L().Error(fmt.Sprintf("%v", errs))
|
||||
}
|
||||
if len(files) == 0 {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
workloads, errs := loadFiles(rootPath, files)
|
||||
workloads, errs := loadFiles(files)
|
||||
if len(errs) > 0 {
|
||||
logger.L().Error(fmt.Sprintf("%v", errs))
|
||||
}
|
||||
|
||||
return workloads
|
||||
return workloads, nil
|
||||
}
|
||||
|
||||
func loadFiles(rootPath string, filePaths []string) (map[string][]workloadinterface.IMetadata, []error) {
|
||||
func loadFiles(filePaths []string) (map[string][]workloadinterface.IMetadata, []error) {
|
||||
workloads := make(map[string][]workloadinterface.IMetadata, 0)
|
||||
errs := []error{}
|
||||
for i := range filePaths {
|
||||
@@ -83,30 +51,15 @@ func loadFiles(rootPath string, filePaths []string) (map[string][]workloadinterf
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
if len(f) == 0 {
|
||||
continue // empty file
|
||||
}
|
||||
|
||||
w, e := ReadFile(f, GetFileFormat(filePaths[i]))
|
||||
if e != nil {
|
||||
logger.L().Debug("failed to read file", helpers.String("file", filePaths[i]), helpers.Error(e))
|
||||
}
|
||||
if len(w) != 0 {
|
||||
path := filePaths[i]
|
||||
if _, ok := workloads[path]; !ok {
|
||||
workloads[path] = []workloadinterface.IMetadata{}
|
||||
errs = append(errs, e...)
|
||||
if w != nil {
|
||||
if _, ok := workloads[filePaths[i]]; !ok {
|
||||
workloads[filePaths[i]] = []workloadinterface.IMetadata{}
|
||||
}
|
||||
wSlice := workloads[path]
|
||||
for j := range w {
|
||||
lw := localworkload.NewLocalWorkload(w[j].GetObject())
|
||||
if relPath, err := filepath.Rel(rootPath, path); err == nil {
|
||||
lw.SetPath(relPath)
|
||||
} else {
|
||||
lw.SetPath(path)
|
||||
}
|
||||
wSlice = append(wSlice, lw)
|
||||
}
|
||||
workloads[path] = wSlice
|
||||
wSlice := workloads[filePaths[i]]
|
||||
wSlice = append(wSlice, w...)
|
||||
workloads[filePaths[i]] = wSlice
|
||||
}
|
||||
}
|
||||
return workloads, errs
|
||||
@@ -115,64 +68,45 @@ func loadFiles(rootPath string, filePaths []string) (map[string][]workloadinterf
|
||||
func loadFile(filePath string) ([]byte, error) {
|
||||
return os.ReadFile(filePath)
|
||||
}
|
||||
func ReadFile(fileContent []byte, fileFormat FileFormat) ([]workloadinterface.IMetadata, error) {
|
||||
func ReadFile(fileContent []byte, fileFromat FileFormat) ([]workloadinterface.IMetadata, []error) {
|
||||
|
||||
switch fileFormat {
|
||||
switch fileFromat {
|
||||
case YAML_FILE_FORMAT:
|
||||
return readYamlFile(fileContent)
|
||||
case JSON_FILE_FORMAT:
|
||||
return readJsonFile(fileContent)
|
||||
default:
|
||||
return nil, nil
|
||||
return nil, nil // []error{fmt.Errorf("file extension %s not supported", fileFromat)}
|
||||
}
|
||||
}
|
||||
|
||||
// listFiles returns the list of absolute paths, full file path and list of errors. The list of abs paths and full path have the same length
|
||||
func listFiles(pattern string) ([]string, []error) {
|
||||
return listFilesOrDirectories(pattern, false)
|
||||
}
|
||||
|
||||
// listDirs returns the list of absolute paths, full directories path and list of errors. The list of abs paths and full path have the same length
|
||||
func listDirs(pattern string) ([]string, []error) {
|
||||
return listFilesOrDirectories(pattern, true)
|
||||
}
|
||||
|
||||
func listFilesOrDirectories(pattern string, onlyDirectories bool) ([]string, []error) {
|
||||
var paths []string
|
||||
func listFiles(patterns []string) ([]string, []error) {
|
||||
files := []string{}
|
||||
errs := []error{}
|
||||
|
||||
if !filepath.IsAbs(pattern) {
|
||||
o, _ := os.Getwd()
|
||||
pattern = filepath.Join(o, pattern)
|
||||
for i := range patterns {
|
||||
if strings.HasPrefix(patterns[i], "http") {
|
||||
continue
|
||||
}
|
||||
if !filepath.IsAbs(patterns[i]) {
|
||||
o, _ := os.Getwd()
|
||||
patterns[i] = filepath.Join(o, patterns[i])
|
||||
}
|
||||
if IsFile(patterns[i]) {
|
||||
files = append(files, patterns[i])
|
||||
} else {
|
||||
f, err := glob(filepath.Split(patterns[i])) //filepath.Glob(patterns[i])
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
} else {
|
||||
files = append(files, f...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !onlyDirectories && IsFile(pattern) {
|
||||
paths = append(paths, pattern)
|
||||
return paths, errs
|
||||
}
|
||||
|
||||
root, shouldMatch := filepath.Split(pattern)
|
||||
|
||||
if IsDir(pattern) {
|
||||
root = pattern
|
||||
shouldMatch = "*"
|
||||
}
|
||||
if shouldMatch == "" {
|
||||
shouldMatch = "*"
|
||||
}
|
||||
|
||||
f, err := glob(root, shouldMatch, onlyDirectories)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
} else {
|
||||
paths = append(paths, f...)
|
||||
}
|
||||
|
||||
return paths, errs
|
||||
return files, errs
|
||||
}
|
||||
|
||||
func readYamlFile(yamlFile []byte) ([]workloadinterface.IMetadata, error) {
|
||||
defer recover()
|
||||
func readYamlFile(yamlFile []byte) ([]workloadinterface.IMetadata, []error) {
|
||||
errs := []error{}
|
||||
|
||||
r := bytes.NewReader(yamlFile)
|
||||
dec := yaml.NewDecoder(r)
|
||||
@@ -192,17 +126,19 @@ func readYamlFile(yamlFile []byte) ([]workloadinterface.IMetadata, error) {
|
||||
yamlObjs = append(yamlObjs, o)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
errs = append(errs, fmt.Errorf("failed to convert yaml file to map[string]interface, file content: %v", j))
|
||||
}
|
||||
}
|
||||
|
||||
return yamlObjs, nil
|
||||
return yamlObjs, errs
|
||||
}
|
||||
|
||||
func readJsonFile(jsonFile []byte) ([]workloadinterface.IMetadata, error) {
|
||||
func readJsonFile(jsonFile []byte) ([]workloadinterface.IMetadata, []error) {
|
||||
workloads := []workloadinterface.IMetadata{}
|
||||
var jsonObj interface{}
|
||||
if err := json.Unmarshal(jsonFile, &jsonObj); err != nil {
|
||||
return workloads, err
|
||||
return workloads, []error{err}
|
||||
}
|
||||
|
||||
convertJsonToWorkload(jsonObj, &workloads)
|
||||
@@ -248,40 +184,21 @@ func IsJson(filePath string) bool {
|
||||
return StringInSlice(JSON_PREFIX, strings.ReplaceAll(filepath.Ext(filePath), ".", "")) != ValueNotFound
|
||||
}
|
||||
|
||||
func glob(root, pattern string, onlyDirectories bool) ([]string, error) {
|
||||
func glob(root, pattern string) ([]string, error) {
|
||||
var matches []string
|
||||
|
||||
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// listing only directotries
|
||||
if onlyDirectories {
|
||||
if info.IsDir() {
|
||||
if matched, err := filepath.Match(pattern, filepath.Base(path)); err != nil {
|
||||
return err
|
||||
} else if matched {
|
||||
matches = append(matches, path)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// listing only files
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
fileFormat := GetFileFormat(path)
|
||||
if !(fileFormat == JSON_FILE_FORMAT || fileFormat == YAML_FILE_FORMAT) {
|
||||
return nil
|
||||
}
|
||||
if matched, err := filepath.Match(pattern, filepath.Base(path)); err != nil {
|
||||
return err
|
||||
} else if matched {
|
||||
matches = append(matches, path)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
@@ -289,8 +206,6 @@ func glob(root, pattern string, onlyDirectories bool) ([]string, error) {
|
||||
}
|
||||
return matches, nil
|
||||
}
|
||||
|
||||
// IsFile checks if a given path is a file
|
||||
func IsFile(name string) bool {
|
||||
if fi, err := os.Stat(name); err == nil {
|
||||
if fi.Mode().IsRegular() {
|
||||
@@ -300,16 +215,6 @@ func IsFile(name string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsDir checks if a given path is a directory
|
||||
func IsDir(name string) bool {
|
||||
if info, err := os.Stat(name); err == nil {
|
||||
if info.IsDir() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func GetFileFormat(filePath string) FileFormat {
|
||||
if IsYaml(filePath) {
|
||||
return YAML_FILE_FORMAT
|
||||
|
||||
@@ -6,99 +6,59 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/armosec/opa-utils/objectsenvelopes/localworkload"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func onlineBoutiquePath() string {
|
||||
o, _ := os.Getwd()
|
||||
return filepath.Join(filepath.Dir(o), "..", "examples", "online-boutique")
|
||||
}
|
||||
|
||||
func helmChartPath() string {
|
||||
o, _ := os.Getwd()
|
||||
return filepath.Join(filepath.Dir(o), "..", "examples", "helm_chart")
|
||||
return filepath.Join(filepath.Dir(o), "../examples/online-boutique/*")
|
||||
}
|
||||
|
||||
func TestListFiles(t *testing.T) {
|
||||
|
||||
filesPath := onlineBoutiquePath()
|
||||
|
||||
files, errs := listFiles(filesPath)
|
||||
files, errs := listFiles([]string{filesPath})
|
||||
assert.Equal(t, 0, len(errs))
|
||||
assert.Equal(t, 12, len(files))
|
||||
}
|
||||
|
||||
func TestLoadResourcesFromFiles(t *testing.T) {
|
||||
workloads := LoadResourcesFromFiles(onlineBoutiquePath(), "")
|
||||
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", getRelativePath(w[0].GetID()))
|
||||
assert.Equal(t, "/v1//Service/adservice", getRelativePath(w[1].GetID()))
|
||||
assert.Equal(t, "apps/v1//Deployment/adservice", w[0].GetID())
|
||||
assert.Equal(t, "/v1//Service/adservice", w[1].GetID())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadResourcesFromHelmCharts(t *testing.T) {
|
||||
sourceToWorkloads := LoadResourcesFromHelmCharts(helmChartPath())
|
||||
assert.Equal(t, 6, len(sourceToWorkloads))
|
||||
|
||||
for file, workloads := range sourceToWorkloads {
|
||||
assert.Equalf(t, 1, len(workloads), "expected 1 workload in file %s", file)
|
||||
|
||||
w := workloads[0]
|
||||
assert.True(t, localworkload.IsTypeLocalWorkload(w.GetObject()), "Expected localworkload as object type")
|
||||
|
||||
switch filepath.Base(file) {
|
||||
case "serviceaccount.yaml":
|
||||
assert.Equal(t, "/v1//ServiceAccount/kubescape-discovery", getRelativePath(w.GetID()))
|
||||
case "clusterrole.yaml":
|
||||
assert.Equal(t, "rbac.authorization.k8s.io/v1//ClusterRole/-kubescape", getRelativePath(w.GetID()))
|
||||
case "cronjob.yaml":
|
||||
assert.Equal(t, "batch/v1//CronJob/-kubescape", getRelativePath(w.GetID()))
|
||||
case "role.yaml":
|
||||
assert.Equal(t, "rbac.authorization.k8s.io/v1//Role/-kubescape", getRelativePath(w.GetID()))
|
||||
case "rolebinding.yaml":
|
||||
assert.Equal(t, "rbac.authorization.k8s.io/v1//RoleBinding/-kubescape", getRelativePath(w.GetID()))
|
||||
case "clusterrolebinding.yaml":
|
||||
assert.Equal(t, "rbac.authorization.k8s.io/v1//ClusterRoleBinding/-kubescape", getRelativePath(w.GetID()))
|
||||
default:
|
||||
assert.Failf(t, "missing case for file: %s", filepath.Base(file))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadFiles(t *testing.T) {
|
||||
files, _ := listFiles(onlineBoutiquePath())
|
||||
_, err := loadFiles("", files)
|
||||
files, _ := listFiles([]string{onlineBoutiquePath()})
|
||||
_, err := loadFiles(files)
|
||||
assert.Equal(t, 0, len(err))
|
||||
}
|
||||
|
||||
func TestListDirs(t *testing.T) {
|
||||
dirs, _ := listDirs(filepath.Join(onlineBoutiquePath(), "adservice.yaml"))
|
||||
assert.Equal(t, 0, len(dirs))
|
||||
|
||||
expectedDirs := []string{filepath.Join("examples", "helm_chart"), filepath.Join("examples", "helm_chart", "templates")}
|
||||
dirs, _ = listDirs(helmChartPath())
|
||||
assert.Equal(t, len(expectedDirs), len(dirs))
|
||||
for i := range expectedDirs {
|
||||
assert.Contains(t, dirs[i], expectedDirs[i])
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadFile(t *testing.T) {
|
||||
files, _ := listFiles(filepath.Join(onlineBoutiquePath(), "adservice.yaml"))
|
||||
files, _ := listFiles([]string{strings.Replace(onlineBoutiquePath(), "*", "adservice.yaml", 1)})
|
||||
assert.Equal(t, 1, len(files))
|
||||
|
||||
_, err := loadFile(files[0])
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func getRelativePath(p string) string {
|
||||
pp := strings.SplitAfter(p, "api=")
|
||||
return pp[1]
|
||||
func TestMapResources(t *testing.T) {
|
||||
// policyHandler := &PolicyHandler{}
|
||||
// k8sResources, err := policyHandler.loadResources(opaSessionObj.Frameworks, scanInfo)
|
||||
// files, _ := listFiles([]string{onlineBoutiquePath()})
|
||||
// bb, err := loadFile(files[0])
|
||||
// if len(err) > 0 {
|
||||
// t.Errorf("%v", err)
|
||||
// }
|
||||
// for i := range bb {
|
||||
// t.Errorf("%s", bb[i].ToString())
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -23,19 +23,19 @@ var (
|
||||
// ATTENTION!!!
|
||||
// Changes in this URLs variable names, or in the usage is affecting the build process! BE CAREFUL
|
||||
armoERURL = "report.armo.cloud"
|
||||
armoBEURL = "api.armosec.io"
|
||||
armoFEURL = "cloud.armosec.io"
|
||||
armoAUTHURL = "auth.armosec.io"
|
||||
armoBEURL = "api.armo.cloud"
|
||||
armoFEURL = "portal.armo.cloud"
|
||||
armoAUTHURL = "auth.armo.cloud"
|
||||
|
||||
armoStageERURL = "report-ks.eustage2.cyberarmorsoft.com"
|
||||
armoStageBEURL = "api-stage.armosec.io"
|
||||
armoStageFEURL = "armoui-stage.armosec.io"
|
||||
armoStageAUTHURL = "eggauth-stage.armosec.io"
|
||||
armoStageBEURL = "api-stage.armo.cloud"
|
||||
armoStageFEURL = "armoui.eustage2.cyberarmorsoft.com"
|
||||
armoStageAUTHURL = "eggauth.eustage2.cyberarmorsoft.com"
|
||||
|
||||
armoDevERURL = "report.eudev3.cyberarmorsoft.com"
|
||||
armoDevBEURL = "api-dev.armosec.io"
|
||||
armoDevFEURL = "cloud-dev.armosec.io"
|
||||
armoDevAUTHURL = "eggauth-dev.armosec.io"
|
||||
armoDevBEURL = "api-dev.armo.cloud"
|
||||
armoDevFEURL = "armoui-dev.eudev3.cyberarmorsoft.com"
|
||||
armoDevAUTHURL = "eggauth.eudev3.cyberarmorsoft.com"
|
||||
)
|
||||
|
||||
// Armo API for downloading policies
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
package cautils
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/armosec/k8s-interface/workloadinterface"
|
||||
"github.com/armosec/kubescape/v2/core/cautils/logger"
|
||||
"github.com/armosec/kubescape/v2/core/cautils/logger/helpers"
|
||||
"github.com/armosec/opa-utils/objectsenvelopes/localworkload"
|
||||
helmchart "helm.sh/helm/v3/pkg/chart"
|
||||
helmloader "helm.sh/helm/v3/pkg/chart/loader"
|
||||
helmchartutil "helm.sh/helm/v3/pkg/chartutil"
|
||||
helmengine "helm.sh/helm/v3/pkg/engine"
|
||||
)
|
||||
|
||||
type HelmChart struct {
|
||||
chart *helmchart.Chart
|
||||
path string
|
||||
}
|
||||
|
||||
func IsHelmDirectory(path string) (bool, error) {
|
||||
return helmchartutil.IsChartDir(path)
|
||||
}
|
||||
|
||||
func NewHelmChart(path string) (*HelmChart, error) {
|
||||
chart, err := helmloader.Load(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &HelmChart{
|
||||
chart: chart,
|
||||
path: path,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (hc *HelmChart) GetName() string {
|
||||
return hc.chart.Name()
|
||||
}
|
||||
|
||||
func (hc *HelmChart) GetDefaultValues() map[string]interface{} {
|
||||
return hc.chart.Values
|
||||
}
|
||||
|
||||
// GetWorkloads renders chart template using the default values and returns a map of source file to its workloads
|
||||
func (hc *HelmChart) GetWorkloadsWithDefaultValues() (map[string][]workloadinterface.IMetadata, []error) {
|
||||
return hc.GetWorkloads(hc.GetDefaultValues())
|
||||
}
|
||||
|
||||
// GetWorkloads renders chart template using the provided values and returns a map of source (absolute) file path to its workloads
|
||||
func (hc *HelmChart) GetWorkloads(values map[string]interface{}) (map[string][]workloadinterface.IMetadata, []error) {
|
||||
vals, err := helmchartutil.ToRenderValues(hc.chart, values, helmchartutil.ReleaseOptions{}, nil)
|
||||
if err != nil {
|
||||
return nil, []error{err}
|
||||
}
|
||||
|
||||
sourceToFile, err := helmengine.Render(hc.chart, vals)
|
||||
if err != nil {
|
||||
return nil, []error{err}
|
||||
}
|
||||
|
||||
workloads := make(map[string][]workloadinterface.IMetadata, 0)
|
||||
errs := []error{}
|
||||
|
||||
for path, renderedYaml := range sourceToFile {
|
||||
if !IsYaml(strings.ToLower(path)) {
|
||||
continue
|
||||
}
|
||||
|
||||
wls, e := ReadFile([]byte(renderedYaml), YAML_FILE_FORMAT)
|
||||
if e != nil {
|
||||
logger.L().Debug("failed to read rendered yaml file", helpers.String("file", path), helpers.Error(e))
|
||||
}
|
||||
if len(wls) == 0 {
|
||||
continue
|
||||
}
|
||||
// separate base path and file name. We do not use the os.Separator because the paths returned from the helm engine are not OS specific (e.g. mychart/templates/myfile.yaml)
|
||||
if firstPathSeparatorIndex := strings.Index(path, string("/")); firstPathSeparatorIndex != -1 {
|
||||
absPath := filepath.Join(hc.path, path[firstPathSeparatorIndex:])
|
||||
|
||||
workloads[absPath] = []workloadinterface.IMetadata{}
|
||||
for i := range wls {
|
||||
lw := localworkload.NewLocalWorkload(wls[i].GetObject())
|
||||
lw.SetPath(absPath)
|
||||
workloads[absPath] = append(workloads[absPath], lw)
|
||||
}
|
||||
}
|
||||
}
|
||||
return workloads, errs
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
package cautils
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/armosec/opa-utils/objectsenvelopes/localworkload"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
type HelmChartTestSuite struct {
|
||||
suite.Suite
|
||||
helmChartPath string
|
||||
expectedFiles []string
|
||||
expectedDefaultValues map[string]interface{}
|
||||
}
|
||||
|
||||
func TestHelmChartTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(HelmChartTestSuite))
|
||||
}
|
||||
|
||||
func (s *HelmChartTestSuite) SetupSuite() {
|
||||
o, _ := os.Getwd()
|
||||
|
||||
s.helmChartPath = filepath.Join(filepath.Dir(o), "..", "examples", "helm_chart")
|
||||
|
||||
s.expectedFiles = []string{
|
||||
filepath.Join(s.helmChartPath, "templates", "clusterrolebinding.yaml"),
|
||||
filepath.Join(s.helmChartPath, "templates", "clusterrole.yaml"),
|
||||
filepath.Join(s.helmChartPath, "templates", "serviceaccount.yaml"),
|
||||
filepath.Join(s.helmChartPath, "templates", "rolebinding.yaml"),
|
||||
filepath.Join(s.helmChartPath, "templates", "role.yaml"),
|
||||
filepath.Join(s.helmChartPath, "templates", "cronjob.yaml"),
|
||||
}
|
||||
|
||||
var obj interface{}
|
||||
file, _ := ioutil.ReadFile(filepath.Join("testdata", "helm_expected_default_values.json"))
|
||||
_ = json.Unmarshal([]byte(file), &obj)
|
||||
s.expectedDefaultValues = obj.(map[string]interface{})
|
||||
}
|
||||
|
||||
func (s *HelmChartTestSuite) TestInvalidHelmDirectory() {
|
||||
_, err := NewHelmChart("/invalid_path")
|
||||
s.Error(err)
|
||||
}
|
||||
|
||||
func (s *HelmChartTestSuite) TestValidHelmDirectory() {
|
||||
chart, err := NewHelmChart(s.helmChartPath)
|
||||
s.NoError(err)
|
||||
s.NotNil(chart)
|
||||
}
|
||||
|
||||
func (s *HelmChartTestSuite) TestGetName() {
|
||||
chart, _ := NewHelmChart(s.helmChartPath)
|
||||
s.Equal("kubescape", chart.GetName())
|
||||
}
|
||||
|
||||
func (s *HelmChartTestSuite) TestGetDefaultValues() {
|
||||
chart, _ := NewHelmChart(s.helmChartPath)
|
||||
|
||||
values := chart.GetDefaultValues()
|
||||
|
||||
valuesJson, _ := json.Marshal(values)
|
||||
expectedValuesJson, _ := json.Marshal(s.expectedDefaultValues)
|
||||
|
||||
s.JSONEq(string(valuesJson), string(expectedValuesJson))
|
||||
}
|
||||
|
||||
func (s *HelmChartTestSuite) TestGetWorkloadsWithOverride() {
|
||||
chart, err := NewHelmChart(s.helmChartPath)
|
||||
s.NoError(err, "Expected a valid helm chart")
|
||||
|
||||
values := chart.GetDefaultValues()
|
||||
|
||||
// Default pullPolicy value = Always
|
||||
pullPolicyValue := values["image"].(map[string]interface{})["pullPolicy"].(string)
|
||||
s.Equal(pullPolicyValue, "Always")
|
||||
|
||||
// Override default value
|
||||
values["image"].(map[string]interface{})["pullPolicy"] = "Never"
|
||||
|
||||
fileToWorkloads, errs := chart.GetWorkloads(values)
|
||||
s.Len(errs, 0)
|
||||
|
||||
s.Lenf(fileToWorkloads, len(s.expectedFiles), "Expected %d files", len(s.expectedFiles))
|
||||
|
||||
for _, expectedFile := range s.expectedFiles {
|
||||
s.Contains(fileToWorkloads, expectedFile)
|
||||
s.FileExists(expectedFile)
|
||||
s.GreaterOrEqualf(len(fileToWorkloads[expectedFile]), 1, "Expected at least one workload in %q", expectedFile)
|
||||
|
||||
for i := range fileToWorkloads[expectedFile] {
|
||||
pathInWorkload := fileToWorkloads[expectedFile][i].(*localworkload.LocalWorkload).GetPath()
|
||||
s.Equal(pathInWorkload, expectedFile, "Expected GetPath() to return a valid path on workload")
|
||||
}
|
||||
|
||||
if strings.Contains(expectedFile, "cronjob.yaml") {
|
||||
jsonBytes, _ := json.Marshal(fileToWorkloads[expectedFile][0].GetObject())
|
||||
s.Contains(string(jsonBytes), "\"imagePullPolicy\":\"Never\"", "Expected to overriden value of imagePullPolicy to be 'Never'")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *HelmChartTestSuite) TestGetWorkloadsMissingValue() {
|
||||
chart, _ := NewHelmChart(s.helmChartPath)
|
||||
|
||||
values := chart.GetDefaultValues()
|
||||
delete(values, "image")
|
||||
|
||||
fileToWorkloads, errs := chart.GetWorkloads(values)
|
||||
s.Nil(fileToWorkloads)
|
||||
s.Len(errs, 1, "Expected an error due to missing value")
|
||||
|
||||
expectedErrMsg := "<.Values.image.repository>: nil pointer"
|
||||
s.Containsf(errs[0].Error(), expectedErrMsg, "expected error containing %q, got %q", expectedErrMsg, errs[0])
|
||||
}
|
||||
|
||||
func (s *HelmChartTestSuite) TestIsHelmDirectory() {
|
||||
ok, err := IsHelmDirectory(s.helmChartPath)
|
||||
s.True(ok)
|
||||
s.NoError(err)
|
||||
|
||||
o, _ := os.Getwd()
|
||||
nonHelmDir := filepath.Join(filepath.Dir(o), "../examples/online-boutique")
|
||||
ok, err = IsHelmDirectory(nonHelmDir)
|
||||
s.False(ok)
|
||||
s.Contains(err.Error(), "no Chart.yaml exists in directory")
|
||||
}
|
||||
@@ -1,249 +0,0 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package cautils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/armosec/go-git-url/apis"
|
||||
gitv5 "github.com/go-git/go-git/v5"
|
||||
configv5 "github.com/go-git/go-git/v5/config"
|
||||
plumbingv5 "github.com/go-git/go-git/v5/plumbing"
|
||||
git2go "github.com/libgit2/git2go/v33"
|
||||
)
|
||||
|
||||
type LocalGitRepository struct {
|
||||
goGitRepo *gitv5.Repository
|
||||
git2GoRepo *git2go.Repository
|
||||
head *plumbingv5.Reference
|
||||
config *configv5.Config
|
||||
fileToLastCommit map[string]*git2go.Commit
|
||||
}
|
||||
|
||||
func NewLocalGitRepository(path string) (*LocalGitRepository, error) {
|
||||
goGitRepo, err := gitv5.PlainOpenWithOptions(path, &gitv5.PlainOpenOptions{DetectDotGit: true})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
head, err := goGitRepo.Head()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !head.Name().IsBranch() {
|
||||
return nil, fmt.Errorf("current HEAD reference is not a branch")
|
||||
}
|
||||
|
||||
config, err := goGitRepo.Config()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(config.Remotes) == 0 {
|
||||
return nil, fmt.Errorf("no remotes found")
|
||||
}
|
||||
|
||||
l := &LocalGitRepository{
|
||||
goGitRepo: goGitRepo,
|
||||
head: head,
|
||||
config: config,
|
||||
}
|
||||
|
||||
if repoRoot, err := l.GetRootDir(); err == nil {
|
||||
git2GoRepo, err := git2go.OpenRepository(repoRoot)
|
||||
if err != nil {
|
||||
return l, err
|
||||
}
|
||||
l.git2GoRepo = git2GoRepo
|
||||
}
|
||||
|
||||
return l, nil
|
||||
}
|
||||
|
||||
// GetBranchName get current branch name
|
||||
func (g *LocalGitRepository) GetBranchName() string {
|
||||
return g.head.Name().Short()
|
||||
}
|
||||
|
||||
// GetRemoteUrl get default remote URL
|
||||
func (g *LocalGitRepository) GetRemoteUrl() (string, error) {
|
||||
branchName := g.GetBranchName()
|
||||
if branchRef, branchFound := g.config.Branches[branchName]; branchFound {
|
||||
remoteName := branchRef.Remote
|
||||
if len(g.config.Remotes[remoteName].URLs) == 0 {
|
||||
return "", fmt.Errorf("expected to find URLs for remote '%s', branch '%s'", remoteName, branchName)
|
||||
}
|
||||
return g.config.Remotes[remoteName].URLs[0], nil
|
||||
}
|
||||
|
||||
const defaultRemoteName string = "origin"
|
||||
if len(g.config.Remotes[defaultRemoteName].URLs) == 0 {
|
||||
return "", fmt.Errorf("expected to find URLs for remote '%s'", defaultRemoteName)
|
||||
}
|
||||
return g.config.Remotes[defaultRemoteName].URLs[0], nil
|
||||
}
|
||||
|
||||
// GetName get origin name without the .git suffix
|
||||
func (g *LocalGitRepository) GetName() (string, error) {
|
||||
originUrl, err := g.GetRemoteUrl()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
baseName := path.Base(originUrl)
|
||||
// remove .git
|
||||
return strings.TrimSuffix(baseName, ".git"), nil
|
||||
}
|
||||
|
||||
// GetLastCommit get latest commit object
|
||||
func (g *LocalGitRepository) GetLastCommit() (*apis.Commit, error) {
|
||||
cIter, err := g.goGitRepo.Log(&gitv5.LogOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
commit, err := cIter.Next()
|
||||
defer cIter.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &apis.Commit{
|
||||
SHA: commit.Hash.String(),
|
||||
Author: apis.Committer{
|
||||
Name: commit.Author.Name,
|
||||
Email: commit.Author.Email,
|
||||
Date: commit.Author.When,
|
||||
},
|
||||
Message: commit.Message,
|
||||
Committer: apis.Committer{},
|
||||
Files: []apis.Files{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (g *LocalGitRepository) getAllCommits() ([]*git2go.Commit, error) {
|
||||
logItr, itrErr := g.git2GoRepo.Walk()
|
||||
if itrErr != nil {
|
||||
|
||||
return nil, itrErr
|
||||
}
|
||||
|
||||
pushErr := logItr.PushHead()
|
||||
if pushErr != nil {
|
||||
return nil, pushErr
|
||||
}
|
||||
|
||||
var allCommits []*git2go.Commit
|
||||
err := logItr.Iterate(func(commit *git2go.Commit) bool {
|
||||
if commit != nil {
|
||||
allCommits = append(allCommits, commit)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return allCommits, nil
|
||||
}
|
||||
|
||||
func (g *LocalGitRepository) GetFileLastCommit(filePath string) (*apis.Commit, error) {
|
||||
if len(g.fileToLastCommit) == 0 {
|
||||
filePathToCommitTime := map[string]time.Time{}
|
||||
filePathToCommit := map[string]*git2go.Commit{}
|
||||
allCommits, _ := g.getAllCommits()
|
||||
|
||||
// builds a map of all files to their last commit
|
||||
for _, commit := range allCommits {
|
||||
// Ignore merge commits (2+ parents)
|
||||
if commit.ParentCount() <= 1 {
|
||||
tree, err := commit.Tree()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// ParentCount can be either 1 or 0 (initial commit)
|
||||
// In case it's the initial commit, prevTree is nil
|
||||
var prevTree *git2go.Tree
|
||||
if commit.ParentCount() == 1 {
|
||||
prevCommit := commit.Parent(0)
|
||||
prevTree, err = prevCommit.Tree()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
diff, err := g.git2GoRepo.DiffTreeToTree(prevTree, tree, nil)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
numDeltas, err := diff.NumDeltas()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
for i := 0; i < numDeltas; i++ {
|
||||
delta, err := diff.Delta(i)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
deltaFilePath := delta.NewFile.Path
|
||||
commitTime := commit.Author().When
|
||||
|
||||
// In case we have the commit information for the file which is not the latest - we override it
|
||||
if currentCommitTime, exists := filePathToCommitTime[deltaFilePath]; exists {
|
||||
if currentCommitTime.Before(commitTime) {
|
||||
filePathToCommitTime[deltaFilePath] = commitTime
|
||||
filePathToCommit[deltaFilePath] = commit
|
||||
}
|
||||
} else {
|
||||
filePathToCommitTime[deltaFilePath] = commitTime
|
||||
filePathToCommit[deltaFilePath] = commit
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
g.fileToLastCommit = filePathToCommit
|
||||
}
|
||||
|
||||
if relevantCommit, exists := g.fileToLastCommit[filePath]; exists {
|
||||
return g.getCommit(relevantCommit), nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("failed to get commit information for file: %s", filePath)
|
||||
}
|
||||
|
||||
func (g *LocalGitRepository) getCommit(commit *git2go.Commit) *apis.Commit {
|
||||
return &apis.Commit{
|
||||
SHA: commit.Id().String(),
|
||||
Author: apis.Committer{
|
||||
Name: commit.Author().Name,
|
||||
Email: commit.Author().Email,
|
||||
Date: commit.Author().When,
|
||||
},
|
||||
Message: commit.Message(),
|
||||
Committer: apis.Committer{},
|
||||
Files: []apis.Files{},
|
||||
}
|
||||
}
|
||||
|
||||
func (g *LocalGitRepository) GetRootDir() (string, error) {
|
||||
wt, err := g.goGitRepo.Worktree()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get repo root")
|
||||
}
|
||||
|
||||
return wt.Filesystem.Root(), nil
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
package cautils
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
var TEST_REPOS = [...]string{"localrepo", "withoutremotes"}
|
||||
|
||||
type LocalGitRepositoryTestSuite struct {
|
||||
suite.Suite
|
||||
archives map[string]*zip.ReadCloser
|
||||
gitRepositoryPaths map[string]string
|
||||
destinationPath string
|
||||
}
|
||||
|
||||
func unzipFile(zipPath, destinationFolder string) (*zip.ReadCloser, error) {
|
||||
archive, err := zip.OpenReader(zipPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, f := range archive.File {
|
||||
filePath := filepath.Join(destinationFolder, f.Name)
|
||||
if !strings.HasPrefix(filePath, filepath.Clean(destinationFolder)+string(os.PathSeparator)) {
|
||||
return nil, fmt.Errorf("invalid file path")
|
||||
}
|
||||
if f.FileInfo().IsDir() {
|
||||
os.MkdirAll(filePath, os.ModePerm)
|
||||
continue
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dstFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fileInArchive, err := f.Open()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := io.Copy(dstFile, fileInArchive); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dstFile.Close()
|
||||
fileInArchive.Close()
|
||||
}
|
||||
|
||||
return archive, err
|
||||
|
||||
}
|
||||
|
||||
func (s *LocalGitRepositoryTestSuite) SetupSuite() {
|
||||
s.archives = make(map[string]*zip.ReadCloser)
|
||||
s.gitRepositoryPaths = make(map[string]string)
|
||||
|
||||
destinationPath := filepath.Join(".", "testdata", "temp")
|
||||
s.destinationPath = destinationPath
|
||||
os.RemoveAll(destinationPath)
|
||||
for _, repo := range TEST_REPOS {
|
||||
zippedFixturePath := filepath.Join(".", "testdata", repo+".git")
|
||||
gitRepositoryPath := filepath.Join(destinationPath, repo)
|
||||
archive, err := unzipFile(zippedFixturePath, destinationPath)
|
||||
|
||||
if err == nil {
|
||||
s.archives[repo] = archive
|
||||
s.gitRepositoryPaths[repo] = gitRepositoryPath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalGitRepositoryTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(LocalGitRepositoryTestSuite))
|
||||
}
|
||||
|
||||
func (s *LocalGitRepositoryTestSuite) TearDownSuite() {
|
||||
if s.archives != nil {
|
||||
for _, archive := range s.archives {
|
||||
if archive != nil {
|
||||
archive.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
os.RemoveAll(s.destinationPath)
|
||||
}
|
||||
|
||||
func (s *LocalGitRepositoryTestSuite) TestInvalidRepositoryPath() {
|
||||
if _, err := NewLocalGitRepository("/invalidpath"); s.Error(err) {
|
||||
s.Equal("repository does not exist", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (s *LocalGitRepositoryTestSuite) TestRepositoryWithoutRemotes() {
|
||||
if _, err := NewLocalGitRepository(s.gitRepositoryPaths["withoutremotes"]); s.Error(err) {
|
||||
s.Equal("no remotes found", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (s *LocalGitRepositoryTestSuite) TestGetBranchName() {
|
||||
if localRepo, err := NewLocalGitRepository(s.gitRepositoryPaths["localrepo"]); s.NoError(err) {
|
||||
s.Equal("master", localRepo.GetBranchName())
|
||||
}
|
||||
}
|
||||
|
||||
func (s *LocalGitRepositoryTestSuite) TestGetName() {
|
||||
if localRepo, err := NewLocalGitRepository(s.gitRepositoryPaths["localrepo"]); s.NoError(err) {
|
||||
if name, err := localRepo.GetName(); s.NoError(err) {
|
||||
s.Equal("localrepo", name)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (s *LocalGitRepositoryTestSuite) TestGetOriginUrl() {
|
||||
if localRepo, err := NewLocalGitRepository(s.gitRepositoryPaths["localrepo"]); s.NoError(err) {
|
||||
if url, err := localRepo.GetRemoteUrl(); s.NoError(err) {
|
||||
s.Equal("git@github.com:testuser/localrepo", url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *LocalGitRepositoryTestSuite) TestGetLastCommit() {
|
||||
if localRepo, err := NewLocalGitRepository(s.gitRepositoryPaths["localrepo"]); s.NoError(err) {
|
||||
if commit, err := localRepo.GetLastCommit(); s.NoError(err) {
|
||||
s.Equal("7e09312b8017695fadcd606882e3779f10a5c832", commit.SHA)
|
||||
s.Equal("Amir Malka", commit.Author.Name)
|
||||
s.Equal("amirm@armosec.io", commit.Author.Email)
|
||||
s.Equal("2022-05-22 19:11:57 +0300 +0300", commit.Author.Date.String())
|
||||
s.Equal("added file B\n", commit.Message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *LocalGitRepositoryTestSuite) TestGetFileLastCommit() {
|
||||
s.Run("fileA", func() {
|
||||
if localRepo, err := NewLocalGitRepository(s.gitRepositoryPaths["localrepo"]); s.NoError(err) {
|
||||
if runtime.GOOS != "windows" {
|
||||
if commit, err := localRepo.GetFileLastCommit("fileA"); s.NoError(err) {
|
||||
s.Equal("9fae4be19624297947d2b605cefbff516628612d", commit.SHA)
|
||||
s.Equal("Amir Malka", commit.Author.Name)
|
||||
s.Equal("amirm@armosec.io", commit.Author.Email)
|
||||
s.Equal("2022-05-22 18:55:48 +0300 +0300", commit.Author.Date.String())
|
||||
s.Equal("added file A\n", commit.Message)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
s.Run("fileB", func() {
|
||||
if localRepo, err := NewLocalGitRepository(s.gitRepositoryPaths["localrepo"]); s.NoError(err) {
|
||||
if runtime.GOOS != "windows" {
|
||||
if commit, err := localRepo.GetFileLastCommit("dirA/fileB"); s.NoError(err) {
|
||||
s.Equal("7e09312b8017695fadcd606882e3779f10a5c832", commit.SHA)
|
||||
s.Equal("Amir Malka", commit.Author.Name)
|
||||
s.Equal("amirm@armosec.io", commit.Author.Email)
|
||||
s.Equal("2022-05-22 19:11:57 +0300 +0300", commit.Author.Date.String())
|
||||
s.Equal("added file B\n", commit.Message)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package cautils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/armosec/go-git-url/apis"
|
||||
gitv5 "github.com/go-git/go-git/v5"
|
||||
configv5 "github.com/go-git/go-git/v5/config"
|
||||
plumbingv5 "github.com/go-git/go-git/v5/plumbing"
|
||||
)
|
||||
|
||||
type LocalGitRepository struct {
|
||||
goGitRepo *gitv5.Repository
|
||||
head *plumbingv5.Reference
|
||||
config *configv5.Config
|
||||
}
|
||||
|
||||
func NewLocalGitRepository(path string) (*LocalGitRepository, error) {
|
||||
goGitRepo, err := gitv5.PlainOpenWithOptions(path, &gitv5.PlainOpenOptions{DetectDotGit: true})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
head, err := goGitRepo.Head()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !head.Name().IsBranch() {
|
||||
return nil, fmt.Errorf("current HEAD reference is not a branch")
|
||||
}
|
||||
|
||||
config, err := goGitRepo.Config()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(config.Remotes) == 0 {
|
||||
return nil, fmt.Errorf("no remotes found")
|
||||
}
|
||||
|
||||
return &LocalGitRepository{
|
||||
goGitRepo: goGitRepo,
|
||||
head: head,
|
||||
config: config,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetBranchName get current branch name
|
||||
func (g *LocalGitRepository) GetBranchName() string {
|
||||
return g.head.Name().Short()
|
||||
}
|
||||
|
||||
// GetRemoteUrl get default remote URL
|
||||
func (g *LocalGitRepository) GetRemoteUrl() (string, error) {
|
||||
branchName := g.GetBranchName()
|
||||
if branchRef, branchFound := g.config.Branches[branchName]; branchFound {
|
||||
remoteName := branchRef.Remote
|
||||
if len(g.config.Remotes[remoteName].URLs) == 0 {
|
||||
return "", fmt.Errorf("expected to find URLs for remote '%s', branch '%s'", remoteName, branchName)
|
||||
}
|
||||
return g.config.Remotes[remoteName].URLs[0], nil
|
||||
}
|
||||
|
||||
const defaultRemoteName string = "origin"
|
||||
if len(g.config.Remotes[defaultRemoteName].URLs) == 0 {
|
||||
return "", fmt.Errorf("expected to find URLs for remote '%s'", defaultRemoteName)
|
||||
}
|
||||
return g.config.Remotes[defaultRemoteName].URLs[0], nil
|
||||
}
|
||||
|
||||
// GetName get origin name without the .git suffix
|
||||
func (g *LocalGitRepository) GetName() (string, error) {
|
||||
originUrl, err := g.GetRemoteUrl()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
baseName := path.Base(originUrl)
|
||||
// remove .git
|
||||
return strings.TrimSuffix(baseName, ".git"), nil
|
||||
}
|
||||
|
||||
// GetLastCommit get latest commit object
|
||||
func (g *LocalGitRepository) GetLastCommit() (*apis.Commit, error) {
|
||||
cIter, err := g.goGitRepo.Log(&gitv5.LogOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
commit, err := cIter.Next()
|
||||
defer cIter.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &apis.Commit{
|
||||
SHA: commit.Hash.String(),
|
||||
Author: apis.Committer{
|
||||
Name: commit.Author.Name,
|
||||
Email: commit.Author.Email,
|
||||
Date: commit.Author.When,
|
||||
},
|
||||
Message: commit.Message,
|
||||
Committer: apis.Committer{},
|
||||
Files: []apis.Files{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (g *LocalGitRepository) GetFileLastCommit(filePath string) (*apis.Commit, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (g *LocalGitRepository) GetRootDir() (string, error) {
|
||||
wt, err := g.goGitRepo.Worktree()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get repo root")
|
||||
}
|
||||
|
||||
return wt.Filesystem.Root(), nil
|
||||
}
|
||||
@@ -21,23 +21,9 @@ import (
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type ScanningContext string
|
||||
|
||||
const (
|
||||
ContextCluster ScanningContext = "cluster"
|
||||
ContextFile ScanningContext = "single-file"
|
||||
ContextDir ScanningContext = "local-dir"
|
||||
ContextGitURL ScanningContext = "git-url"
|
||||
ContextGitLocal ScanningContext = "git-local"
|
||||
)
|
||||
|
||||
const ( // deprecated
|
||||
ScopeCluster = "cluster"
|
||||
ScopeYAML = "yaml"
|
||||
)
|
||||
const (
|
||||
// ScanCluster string = "cluster"
|
||||
// ScanLocalFiles string = "yaml"
|
||||
ScanCluster string = "cluster"
|
||||
ScanLocalFiles string = "yaml"
|
||||
localControlInputsFilename string = "controls-inputs.json"
|
||||
localExceptionsFilename string = "exceptions.json"
|
||||
)
|
||||
@@ -204,12 +190,12 @@ func (scanInfo *ScanInfo) setOutputFile() {
|
||||
}
|
||||
}
|
||||
|
||||
// func (scanInfo *ScanInfo) GetScanningEnvironment() string {
|
||||
// if len(scanInfo.InputPatterns) != 0 {
|
||||
// return ScanLocalFiles
|
||||
// }
|
||||
// return ScanCluster
|
||||
// }
|
||||
func (scanInfo *ScanInfo) GetScanningEnvironment() string {
|
||||
if len(scanInfo.InputPatterns) != 0 {
|
||||
return ScanLocalFiles
|
||||
}
|
||||
return ScanCluster
|
||||
}
|
||||
|
||||
func (scanInfo *ScanInfo) SetPolicyIdentifiers(policies []string, kind apisv1.NotificationPolicyKind) {
|
||||
for _, policy := range policies {
|
||||
@@ -262,189 +248,71 @@ func scanInfoToScanMetadata(scanInfo *ScanInfo) *reporthandlingv2.Metadata {
|
||||
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]
|
||||
}
|
||||
switch GetScanningContext(inputFiles) {
|
||||
case ContextCluster:
|
||||
// cluster
|
||||
metadata.ScanMetadata.ScanningTarget = reporthandlingv2.Cluster
|
||||
case ContextFile:
|
||||
// local file
|
||||
metadata.ScanMetadata.ScanningTarget = reporthandlingv2.File
|
||||
case ContextGitURL:
|
||||
// url
|
||||
metadata.ScanMetadata.ScanningTarget = reporthandlingv2.Repo
|
||||
case ContextGitLocal:
|
||||
// local-git
|
||||
metadata.ScanMetadata.ScanningTarget = reporthandlingv2.GitLocal
|
||||
case ContextDir:
|
||||
// directory
|
||||
metadata.ScanMetadata.ScanningTarget = reporthandlingv2.Directory
|
||||
|
||||
}
|
||||
|
||||
setContextMetadata(&metadata.ContextMetadata, inputFiles)
|
||||
|
||||
return metadata
|
||||
}
|
||||
|
||||
func (scanInfo *ScanInfo) GetScanningContext() ScanningContext {
|
||||
input := ""
|
||||
if len(scanInfo.InputPatterns) > 0 {
|
||||
input = scanInfo.InputPatterns[0]
|
||||
}
|
||||
return GetScanningContext(input)
|
||||
}
|
||||
|
||||
// GetScanningContext get scanning context from the input param
|
||||
func GetScanningContext(input string) ScanningContext {
|
||||
func setContextMetadata(contextMetadata *reporthandlingv2.ContextMetadata, input string) {
|
||||
// cluster
|
||||
if input == "" {
|
||||
return ContextCluster
|
||||
contextMetadata.ClusterContextMetadata = &reporthandlingv2.ClusterMetadata{
|
||||
ContextName: k8sinterface.GetContextName(),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// url
|
||||
if _, err := giturl.NewGitURL(input); err == nil {
|
||||
return ContextGitURL
|
||||
if gitParser, err := giturl.NewGitURL(input); err == nil {
|
||||
if gitParser.GetBranch() == "" {
|
||||
gitParser.SetDefaultBranch()
|
||||
}
|
||||
contextMetadata.RepoContextMetadata = &reporthandlingv2.RepoContextMetadata{
|
||||
Repo: gitParser.GetRepo(),
|
||||
Owner: gitParser.GetOwner(),
|
||||
Branch: gitParser.GetBranch(),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if !filepath.IsAbs(input) { // parse path
|
||||
if !filepath.IsAbs(input) {
|
||||
if o, err := os.Getwd(); err == nil {
|
||||
input = filepath.Join(o, input)
|
||||
}
|
||||
}
|
||||
|
||||
// local git repo
|
||||
if _, err := NewLocalGitRepository(input); err == nil {
|
||||
return ContextGitLocal
|
||||
}
|
||||
|
||||
// single file
|
||||
if IsFile(input) {
|
||||
return ContextFile
|
||||
contextMetadata.FileContextMetadata = &reporthandlingv2.FileContextMetadata{
|
||||
FilePath: input,
|
||||
HostName: getHostname(),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// dir/glob
|
||||
return ContextDir
|
||||
}
|
||||
func setContextMetadata(contextMetadata *reporthandlingv2.ContextMetadata, input string) {
|
||||
switch GetScanningContext(input) {
|
||||
case ContextCluster:
|
||||
contextMetadata.ClusterContextMetadata = &reporthandlingv2.ClusterMetadata{
|
||||
ContextName: k8sinterface.GetContextName(),
|
||||
}
|
||||
case ContextGitURL:
|
||||
// url
|
||||
context, err := metadataGitURL(input)
|
||||
if err != nil {
|
||||
logger.L().Warning("in setContextMetadata", helpers.Interface("case", ContextGitURL), helpers.Error(err))
|
||||
}
|
||||
contextMetadata.RepoContextMetadata = context
|
||||
case ContextDir:
|
||||
if !IsFile(input) {
|
||||
contextMetadata.DirectoryContextMetadata = &reporthandlingv2.DirectoryContextMetadata{
|
||||
BasePath: getAbsPath(input),
|
||||
BasePath: input,
|
||||
HostName: getHostname(),
|
||||
}
|
||||
case ContextFile:
|
||||
contextMetadata.FileContextMetadata = &reporthandlingv2.FileContextMetadata{
|
||||
FilePath: getAbsPath(input),
|
||||
HostName: getHostname(),
|
||||
}
|
||||
case ContextGitLocal:
|
||||
// local
|
||||
context, err := metadataGitLocal(input)
|
||||
if err != nil {
|
||||
logger.L().Warning("in setContextMetadata", helpers.Interface("case", ContextGitURL), helpers.Error(err))
|
||||
}
|
||||
contextMetadata.RepoContextMetadata = context
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func metadataGitURL(input string) (*reporthandlingv2.RepoContextMetadata, error) {
|
||||
context := &reporthandlingv2.RepoContextMetadata{}
|
||||
gitParser, err := giturl.NewGitAPI(input)
|
||||
if err != nil {
|
||||
return context, fmt.Errorf("%w", err)
|
||||
}
|
||||
if gitParser.GetBranchName() == "" {
|
||||
gitParser.SetDefaultBranchName()
|
||||
}
|
||||
context.Provider = gitParser.GetProvider()
|
||||
context.Repo = gitParser.GetRepoName()
|
||||
context.Owner = gitParser.GetOwnerName()
|
||||
context.Branch = gitParser.GetBranchName()
|
||||
context.RemoteURL = gitParser.GetURL().String()
|
||||
|
||||
commit, err := gitParser.GetLatestCommit()
|
||||
if err != nil {
|
||||
return context, fmt.Errorf("%w", err)
|
||||
}
|
||||
|
||||
context.LastCommit = reporthandling.LastCommit{
|
||||
Hash: commit.SHA,
|
||||
Date: commit.Committer.Date,
|
||||
CommitterName: commit.Committer.Name,
|
||||
}
|
||||
|
||||
return context, nil
|
||||
}
|
||||
|
||||
func metadataGitLocal(input string) (*reporthandlingv2.RepoContextMetadata, error) {
|
||||
gitParser, err := NewLocalGitRepository(input)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w", err)
|
||||
}
|
||||
remoteURL, err := gitParser.GetRemoteUrl()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w", err)
|
||||
}
|
||||
context := &reporthandlingv2.RepoContextMetadata{}
|
||||
gitParserURL, err := giturl.NewGitURL(remoteURL)
|
||||
if err != nil {
|
||||
return context, fmt.Errorf("%w", err)
|
||||
}
|
||||
gitParserURL.SetBranchName(gitParser.GetBranchName())
|
||||
|
||||
context.Provider = gitParserURL.GetProvider()
|
||||
context.Repo = gitParserURL.GetRepoName()
|
||||
context.Owner = gitParserURL.GetOwnerName()
|
||||
context.Branch = gitParserURL.GetBranchName()
|
||||
context.RemoteURL = gitParserURL.GetURL().String()
|
||||
|
||||
commit, err := gitParser.GetLastCommit()
|
||||
if err != nil {
|
||||
return context, fmt.Errorf("%w", err)
|
||||
}
|
||||
context.LastCommit = reporthandling.LastCommit{
|
||||
Hash: commit.SHA,
|
||||
Date: commit.Committer.Date,
|
||||
CommitterName: commit.Committer.Name,
|
||||
}
|
||||
|
||||
return context, nil
|
||||
}
|
||||
func getHostname() string {
|
||||
if h, e := os.Hostname(); e == nil {
|
||||
return h
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getAbsPath(p string) string {
|
||||
if !filepath.IsAbs(p) { // parse path
|
||||
if o, err := os.Getwd(); err == nil {
|
||||
return filepath.Join(o, p)
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// ScanningContextToScanningScope convert the context to the deprecated scope
|
||||
func ScanningContextToScanningScope(scanningContext ScanningContext) string {
|
||||
if scanningContext == ContextCluster {
|
||||
return ScopeCluster
|
||||
}
|
||||
return ScopeYAML
|
||||
}
|
||||
|
||||
@@ -18,6 +18,34 @@ func TestSetContextMetadata(t *testing.T) {
|
||||
assert.Nil(t, ctx.HelmContextMetadata)
|
||||
assert.Nil(t, ctx.RepoContextMetadata)
|
||||
}
|
||||
{
|
||||
ctx := reporthandlingv2.ContextMetadata{}
|
||||
setContextMetadata(&ctx, "file")
|
||||
|
||||
assert.Nil(t, ctx.ClusterContextMetadata)
|
||||
assert.NotNil(t, ctx.DirectoryContextMetadata)
|
||||
assert.Nil(t, ctx.FileContextMetadata)
|
||||
assert.Nil(t, ctx.HelmContextMetadata)
|
||||
assert.Nil(t, ctx.RepoContextMetadata)
|
||||
|
||||
hostName := getHostname()
|
||||
assert.Contains(t, ctx.DirectoryContextMetadata.BasePath, "file")
|
||||
assert.Equal(t, hostName, ctx.DirectoryContextMetadata.HostName)
|
||||
}
|
||||
{
|
||||
ctx := reporthandlingv2.ContextMetadata{}
|
||||
setContextMetadata(&ctx, "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)
|
||||
|
||||
hostName := getHostname()
|
||||
assert.Contains(t, ctx.FileContextMetadata.FilePath, "scaninfo_test.go")
|
||||
assert.Equal(t, hostName, ctx.FileContextMetadata.HostName)
|
||||
}
|
||||
{
|
||||
ctx := reporthandlingv2.ContextMetadata{}
|
||||
setContextMetadata(&ctx, "https://github.com/armosec/kubescape")
|
||||
@@ -37,11 +65,3 @@ func TestSetContextMetadata(t *testing.T) {
|
||||
func TestGetHostname(t *testing.T) {
|
||||
assert.NotEqual(t, "", getHostname())
|
||||
}
|
||||
|
||||
func TestGetScanningContext(t *testing.T) {
|
||||
assert.Equal(t, ContextCluster, GetScanningContext(""))
|
||||
// assert.Equal(t, ContextDir, GetScanningContext("/"))
|
||||
assert.Equal(t, ContextGitURL, GetScanningContext("https://github.com/armosec/kubescape"))
|
||||
// assert.Equal(t, ContextFile, GetScanningContext(path.Join(".", "testdata", "localrepo.git")))
|
||||
// assert.Equal(t, ContextGitLocal, GetScanningContext(path.Join(".", "testdata")))
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
{
|
||||
"affinity": {},
|
||||
"configMap": {
|
||||
"create": false,
|
||||
"params": {
|
||||
"clusterName": "<MyK8sClusterName>",
|
||||
"customerGUID": "<MyGUID>"
|
||||
}
|
||||
},
|
||||
"fullnameOverride": "",
|
||||
"image": {
|
||||
"imageName": "kubescape",
|
||||
"pullPolicy": "Always",
|
||||
"repository": "quay.io/armosec",
|
||||
"tag": "latest"
|
||||
},
|
||||
"imagePullSecrets": [],
|
||||
"nameOverride": "",
|
||||
"nodeSelector": {},
|
||||
"podAnnotations": {},
|
||||
"podSecurityContext": {},
|
||||
"resources": {
|
||||
"limits": {
|
||||
"cpu": "500m",
|
||||
"memory": "512Mi"
|
||||
},
|
||||
"requests": {
|
||||
"cpu": "200m",
|
||||
"memory": "256Mi"
|
||||
}
|
||||
},
|
||||
"schedule": "* * 1 * *",
|
||||
"securityContext": {},
|
||||
"serviceAccount": {
|
||||
"annotations": {},
|
||||
"create": true,
|
||||
"name": "kubescape-discovery"
|
||||
},
|
||||
"tolerations": []
|
||||
}
|
||||
BIN
core/cautils/testdata/localrepo.git
vendored
BIN
core/cautils/testdata/localrepo.git
vendored
Binary file not shown.
BIN
core/cautils/testdata/withoutremotes.git
vendored
BIN
core/cautils/testdata/withoutremotes.git
vendored
Binary file not shown.
@@ -17,7 +17,6 @@ const SKIP_VERSION_CHECK_DEPRECATED = "KUBESCAPE_SKIP_UPDATE_CHECK"
|
||||
const SKIP_VERSION_CHECK = "KS_SKIP_UPDATE_CHECK"
|
||||
|
||||
var BuildNumber string
|
||||
var Client string
|
||||
|
||||
const UnknownBuildNumber = "unknown"
|
||||
|
||||
@@ -49,12 +48,10 @@ type VersionCheckHandler struct {
|
||||
}
|
||||
type VersionCheckRequest struct {
|
||||
Client string `json:"client"` // kubescape
|
||||
ClientBuild string `json:"clientBuild"` // client build environment
|
||||
ClientVersion string `json:"clientVersion"` // kubescape version
|
||||
Framework string `json:"framework"` // framework name
|
||||
FrameworkVersion string `json:"frameworkVersion"` // framework version
|
||||
ScanningTarget string `json:"target"` // Deprecated
|
||||
ScanningContext string `json:"context"` // scanning context- cluster/file/gitURL/localGit/dir
|
||||
ScanningTarget string `json:"target"` // scanning target- cluster/yaml
|
||||
}
|
||||
|
||||
type VersionCheckResponse struct {
|
||||
@@ -77,12 +74,8 @@ func NewVersionCheckRequest(buildNumber, frameworkName, frameworkVersion, scanni
|
||||
if scanningTarget == "" {
|
||||
scanningTarget = "unknown"
|
||||
}
|
||||
if Client == "" {
|
||||
Client = "local-build"
|
||||
}
|
||||
return &VersionCheckRequest{
|
||||
Client: "kubescape",
|
||||
ClientBuild: Client,
|
||||
ClientVersion: buildNumber,
|
||||
Framework: frameworkName,
|
||||
FrameworkVersion: frameworkVersion,
|
||||
|
||||
@@ -14,10 +14,7 @@ var (
|
||||
"KernelVersion",
|
||||
"LinuxSecurityHardeningStatus",
|
||||
"OpenPortsList",
|
||||
"LinuxKernelVariables",
|
||||
"KubeletInfo",
|
||||
"KubeProxyInfo",
|
||||
}
|
||||
"LinuxKernelVariables"}
|
||||
CloudResources = []string{"ClusterDescribe"}
|
||||
)
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"github.com/armosec/kubescape/v2/core/pkg/resourcehandler"
|
||||
"github.com/armosec/kubescape/v2/core/pkg/resultshandling/reporter"
|
||||
reporterv2 "github.com/armosec/kubescape/v2/core/pkg/resultshandling/reporter/v2"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/armosec/rbac-utils/rbacscanner"
|
||||
)
|
||||
@@ -123,6 +122,7 @@ func policyIdentifierNames(pi []cautils.PolicyIdentifier) string {
|
||||
func setSubmitBehavior(scanInfo *cautils.ScanInfo, tenantConfig cautils.ITenantConfig) {
|
||||
|
||||
/*
|
||||
|
||||
If "First run (local config not found)" -
|
||||
Default/keep-local - Do not send report
|
||||
Submit - Create tenant & Submit report
|
||||
@@ -139,20 +139,8 @@ func setSubmitBehavior(scanInfo *cautils.ScanInfo, tenantConfig cautils.ITenantC
|
||||
return
|
||||
}
|
||||
|
||||
scanningContext := scanInfo.GetScanningContext()
|
||||
if scanningContext == cautils.ContextFile || scanningContext == cautils.ContextDir {
|
||||
scanInfo.Submit = false
|
||||
return
|
||||
}
|
||||
|
||||
if tenantConfig.IsConfigFound() { // config found in cache (submitted)
|
||||
if !scanInfo.Local {
|
||||
if tenantConfig.GetAccountID() != "" {
|
||||
if _, err := uuid.Parse(tenantConfig.GetAccountID()); err != nil {
|
||||
scanInfo.Submit = false
|
||||
return
|
||||
}
|
||||
}
|
||||
// Submit report
|
||||
scanInfo.Submit = true
|
||||
}
|
||||
@@ -176,6 +164,20 @@ func getPolicyGetter(loadPoliciesFromFile []string, tennatEmail string, framewor
|
||||
|
||||
}
|
||||
|
||||
// func setGetArmoAPIConnector(scanInfo *cautils.ScanInfo, customerGUID string) {
|
||||
// g := getter.GetArmoAPIConnector() // download policy from ARMO backend
|
||||
// g.SetCustomerGUID(customerGUID)
|
||||
// scanInfo.PolicyGetter = g
|
||||
// if scanInfo.ScanAll {
|
||||
// frameworks, err := g.ListCustomFrameworks(customerGUID)
|
||||
// if err != nil {
|
||||
// glog.Error("failed to get custom frameworks") // handle error
|
||||
// return
|
||||
// }
|
||||
// scanInfo.SetPolicyIdentifiers(frameworks, reporthandling.KindFramework)
|
||||
// }
|
||||
// }
|
||||
|
||||
// setConfigInputsGetter sets the config input getter - local file/github release/ArmoAPI
|
||||
func getConfigInputsGetter(ControlsInputs string, accountID string, downloadReleasedPolicy *getter.DownloadReleasedPolicy) getter.IControlsInputsGetter {
|
||||
if len(ControlsInputs) > 0 {
|
||||
|
||||
@@ -34,7 +34,7 @@ func getInterfaces(scanInfo *cautils.ScanInfo) componentInterfaces {
|
||||
|
||||
// ================== setup k8s interface object ======================================
|
||||
var k8s *k8sinterface.KubernetesApi
|
||||
if scanInfo.GetScanningContext() == cautils.ContextCluster {
|
||||
if scanInfo.GetScanningEnvironment() == cautils.ScanCluster {
|
||||
k8s = getKubernetesApi()
|
||||
if k8s == nil {
|
||||
logger.L().Fatal("failed connecting to Kubernetes cluster")
|
||||
@@ -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 {
|
||||
@@ -58,7 +63,7 @@ func getInterfaces(scanInfo *cautils.ScanInfo) componentInterfaces {
|
||||
// ================== version testing ======================================
|
||||
|
||||
v := cautils.NewIVersionCheckHandler()
|
||||
v.CheckLatestVersion(cautils.NewVersionCheckRequest(cautils.BuildNumber, policyIdentifierNames(scanInfo.PolicyIdentifier), "", cautils.ScanningContextToScanningScope(scanInfo.GetScanningContext())))
|
||||
v.CheckLatestVersion(cautils.NewVersionCheckRequest(cautils.BuildNumber, policyIdentifierNames(scanInfo.PolicyIdentifier), "", scanInfo.GetScanningEnvironment()))
|
||||
|
||||
// ================== setup host scanner object ======================================
|
||||
|
||||
@@ -149,7 +154,7 @@ func (ks *Kubescape) Scan(scanInfo *cautils.ScanInfo) (*resultshandling.ResultsH
|
||||
reportResults := opaprocessor.NewOPAProcessor(scanData, deps)
|
||||
if err := reportResults.ProcessRulesListenner(); err != nil {
|
||||
// TODO - do something
|
||||
return resultsHandling, fmt.Errorf("%w", err)
|
||||
return resultsHandling, err
|
||||
}
|
||||
|
||||
// ========================= results handling =====================
|
||||
@@ -161,3 +166,25 @@ func (ks *Kubescape) Scan(scanInfo *cautils.ScanInfo) (*resultshandling.ResultsH
|
||||
|
||||
return resultsHandling, nil
|
||||
}
|
||||
|
||||
// func askUserForHostSensor() bool {
|
||||
// return false
|
||||
|
||||
// if !isatty.IsTerminal(os.Stdin.Fd()) {
|
||||
// return false
|
||||
// }
|
||||
// if ssss, err := os.Stdin.Stat(); err == nil {
|
||||
// // fmt.Printf("Found stdin type: %s\n", ssss.Mode().Type())
|
||||
// if ssss.Mode().Type()&(fs.ModeDevice|fs.ModeCharDevice) > 0 { //has TTY
|
||||
// fmt.Fprintf(os.Stderr, "Would you like to scan K8s nodes? [y/N]. This is required to collect valuable data for certain controls\n")
|
||||
// fmt.Fprintf(os.Stderr, "Use --enable-host-scan flag to suppress this message\n")
|
||||
// var b []byte = make([]byte, 1)
|
||||
// if n, err := os.Stdin.Read(b); err == nil {
|
||||
// if n > 0 && len(b) > 0 && (b[0] == 'y' || b[0] == 'Y') {
|
||||
// return true
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return false
|
||||
// }
|
||||
|
||||
@@ -35,7 +35,6 @@ type HostSensorHandler struct {
|
||||
DaemonSet *appsv1.DaemonSet
|
||||
podListLock sync.RWMutex
|
||||
gracePeriod int64
|
||||
workerPool workerPool
|
||||
}
|
||||
|
||||
func NewHostSensorHandler(k8sObj *k8sinterface.KubernetesApi, hostSensorYAMLFile string) (*HostSensorHandler, error) {
|
||||
@@ -55,7 +54,6 @@ func NewHostSensorHandler(k8sObj *k8sinterface.KubernetesApi, hostSensorYAMLFile
|
||||
HostSensorPodNames: map[string]string{},
|
||||
HostSensorUnscheduledPodNames: map[string]string{},
|
||||
gracePeriod: int64(15),
|
||||
workerPool: NewWorkerPool(),
|
||||
}
|
||||
// Don't deploy on cluster with no nodes. Some cloud providers prevents termination of K8s objects for cluster with no nodes!!!
|
||||
if nodeList, err := k8sObj.KubernetesClient.CoreV1().Nodes().List(k8sObj.Context, metav1.ListOptions{}); err != nil || len(nodeList.Items) == 0 {
|
||||
@@ -91,7 +89,7 @@ func (hsh *HostSensorHandler) Init() error {
|
||||
|
||||
func (hsh *HostSensorHandler) applyYAML() error {
|
||||
workloads, err := cautils.ReadFile([]byte(hostSensorYAML), cautils.YAML_FILE_FORMAT)
|
||||
if err != nil {
|
||||
if len(err) != 0 {
|
||||
return fmt.Errorf("failed to read YAML files, reason: %v", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -32,23 +32,7 @@ func (hsh *HostSensorHandler) HTTPGetToPod(podName, path string) ([]byte, error)
|
||||
|
||||
restProxy := hsh.k8sObj.KubernetesClient.CoreV1().Pods(hsh.DaemonSet.Namespace).ProxyGet("http", podName, fmt.Sprintf("%d", hsh.HostSensorPort), path, map[string]string{})
|
||||
return restProxy.DoRaw(hsh.k8sObj.Context)
|
||||
}
|
||||
|
||||
func (hsh *HostSensorHandler) getResourcesFromPod(podName, nodeName, resourceKind, path string) (hostsensor.HostSensorDataEnvelope, error) {
|
||||
// send the request and pack the response as an hostSensorDataEnvelope
|
||||
|
||||
resBytes, err := hsh.HTTPGetToPod(podName, path)
|
||||
if err != nil {
|
||||
return hostsensor.HostSensorDataEnvelope{}, err
|
||||
}
|
||||
|
||||
hostSensorDataEnvelope := hostsensor.HostSensorDataEnvelope{}
|
||||
hostSensorDataEnvelope.SetApiVersion(k8sinterface.JoinGroupVersion(hostsensor.GroupHostSensor, hostsensor.Version))
|
||||
hostSensorDataEnvelope.SetKind(resourceKind)
|
||||
hostSensorDataEnvelope.SetName(nodeName)
|
||||
hostSensorDataEnvelope.SetData(resBytes)
|
||||
|
||||
return hostSensorDataEnvelope, nil
|
||||
}
|
||||
|
||||
func (hsh *HostSensorHandler) ForwardToPod(podName, path string) ([]byte, error) {
|
||||
@@ -75,26 +59,35 @@ func (hsh *HostSensorHandler) ForwardToPod(podName, path string) ([]byte, error)
|
||||
|
||||
// sendAllPodsHTTPGETRequest fills the raw byte response in the envelope and the node name, but not the GroupVersionKind
|
||||
// so the caller is responsible to convert the raw data to some structured data and add the GroupVersionKind details
|
||||
//
|
||||
// The function produces a worker-pool with a fixed number of workers.
|
||||
// For each node the request is pushed to the jobs channel, the worker sends the request and pushes the result to the result channel.
|
||||
// When all workers have finished, the function returns a list of results
|
||||
func (hsh *HostSensorHandler) sendAllPodsHTTPGETRequest(path, requestKind string) ([]hostsensor.HostSensorDataEnvelope, error) {
|
||||
podList, err := hsh.getPodList()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to sendAllPodsHTTPGETRequest: %v", err)
|
||||
}
|
||||
|
||||
res := make([]hostsensor.HostSensorDataEnvelope, 0, len(podList))
|
||||
var wg sync.WaitGroup
|
||||
// initialization of the channels
|
||||
hsh.workerPool.init(len(podList))
|
||||
|
||||
hsh.workerPool.hostSensorApplyJobs(podList, path, requestKind)
|
||||
hsh.workerPool.hostSensorGetResults(&res)
|
||||
hsh.workerPool.createWorkerPool(hsh, &wg)
|
||||
hsh.workerPool.waitForDone(&wg)
|
||||
resLock := sync.Mutex{}
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(len(podList))
|
||||
for podName := range podList {
|
||||
go func(podName, path string) {
|
||||
defer wg.Done()
|
||||
resBytes, err := hsh.HTTPGetToPod(podName, path)
|
||||
if err != nil {
|
||||
logger.L().Error("failed to get data", helpers.String("path", path), helpers.String("podName", podName), helpers.Error(err))
|
||||
} else {
|
||||
resLock.Lock()
|
||||
defer resLock.Unlock()
|
||||
hostSensorDataEnvelope := hostsensor.HostSensorDataEnvelope{}
|
||||
hostSensorDataEnvelope.SetApiVersion(k8sinterface.JoinGroupVersion(hostsensor.GroupHostSensor, hostsensor.Version))
|
||||
hostSensorDataEnvelope.SetKind(requestKind)
|
||||
hostSensorDataEnvelope.SetName(podList[podName])
|
||||
hostSensorDataEnvelope.SetData(resBytes)
|
||||
res = append(res, hostSensorDataEnvelope)
|
||||
}
|
||||
|
||||
}(podName, path)
|
||||
}
|
||||
wg.Wait()
|
||||
return res, nil
|
||||
}
|
||||
|
||||
@@ -116,18 +109,6 @@ func (hsh *HostSensorHandler) GetLinuxSecurityHardeningStatus() ([]hostsensor.Ho
|
||||
return hsh.sendAllPodsHTTPGETRequest("/linuxSecurityHardening", "LinuxSecurityHardeningStatus")
|
||||
}
|
||||
|
||||
// return list of KubeletInfo
|
||||
func (hsh *HostSensorHandler) GetKubeletInfo() ([]hostsensor.HostSensorDataEnvelope, error) {
|
||||
// loop over pods and port-forward it to each of them
|
||||
return hsh.sendAllPodsHTTPGETRequest("/kubeletInfo", "KubeletInfo")
|
||||
}
|
||||
|
||||
// return list of KubeProxyInfo
|
||||
func (hsh *HostSensorHandler) GetKubeProxyInfo() ([]hostsensor.HostSensorDataEnvelope, error) {
|
||||
// loop over pods and port-forward it to each of them
|
||||
return hsh.sendAllPodsHTTPGETRequest("/kubeProxyInfo", "KubeProxyInfo")
|
||||
}
|
||||
|
||||
// return list of KubeletCommandLine
|
||||
func (hsh *HostSensorHandler) GetKubeletCommandLine() ([]hostsensor.HostSensorDataEnvelope, error) {
|
||||
// loop over pods and port-forward it to each of them
|
||||
@@ -247,27 +228,6 @@ func (hsh *HostSensorHandler) CollectResources() ([]hostsensor.HostSensorDataEnv
|
||||
if len(kcData) > 0 {
|
||||
res = append(res, kcData...)
|
||||
}
|
||||
|
||||
// GetKubeletInfo
|
||||
kcData, err = hsh.GetKubeletInfo()
|
||||
if err != nil {
|
||||
addInfoToMap(KubeletInfo, infoMap, err)
|
||||
logger.L().Warning(err.Error())
|
||||
}
|
||||
if len(kcData) > 0 {
|
||||
res = append(res, kcData...)
|
||||
}
|
||||
|
||||
// GetKubeProxyInfo
|
||||
kcData, err = hsh.GetKubeProxyInfo()
|
||||
if err != nil {
|
||||
addInfoToMap(KubeProxyInfo, infoMap, err)
|
||||
logger.L().Warning(err.Error())
|
||||
}
|
||||
if len(kcData) > 0 {
|
||||
res = append(res, kcData...)
|
||||
}
|
||||
|
||||
logger.L().Debug("Done reading information from host scanner")
|
||||
return res, infoMap, nil
|
||||
}
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
package hostsensorutils
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/armosec/kubescape/v2/core/cautils/logger"
|
||||
"github.com/armosec/kubescape/v2/core/cautils/logger/helpers"
|
||||
"github.com/armosec/opa-utils/objectsenvelopes/hostsensor"
|
||||
)
|
||||
|
||||
const noOfWorkers int = 10
|
||||
|
||||
type job struct {
|
||||
podName string
|
||||
nodeName string
|
||||
requestKind string
|
||||
path string
|
||||
}
|
||||
|
||||
type workerPool struct {
|
||||
jobs chan job
|
||||
results chan hostsensor.HostSensorDataEnvelope
|
||||
done chan bool
|
||||
noOfWorkers int
|
||||
}
|
||||
|
||||
func NewWorkerPool() workerPool {
|
||||
wp := workerPool{}
|
||||
wp.noOfWorkers = noOfWorkers
|
||||
wp.init()
|
||||
return wp
|
||||
}
|
||||
|
||||
func (wp *workerPool) init(noOfPods ...int) {
|
||||
if noOfPods != nil && len(noOfPods) > 0 && noOfPods[0] < noOfWorkers {
|
||||
wp.noOfWorkers = noOfPods[0]
|
||||
}
|
||||
// init the channels
|
||||
wp.jobs = make(chan job, noOfWorkers)
|
||||
wp.results = make(chan hostsensor.HostSensorDataEnvelope, noOfWorkers)
|
||||
wp.done = make(chan bool)
|
||||
}
|
||||
|
||||
// The worker takes a job out of the chan, executes the request, and pushes the result to the results chan
|
||||
func (wp *workerPool) hostSensorWorker(hsh *HostSensorHandler, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
for job := range wp.jobs {
|
||||
hostSensorDataEnvelope, err := hsh.getResourcesFromPod(job.podName, job.nodeName, job.requestKind, job.path)
|
||||
if err != nil {
|
||||
logger.L().Error("failed to get data", helpers.String("path", job.path), helpers.String("podName", job.podName), helpers.Error(err))
|
||||
} else {
|
||||
wp.results <- hostSensorDataEnvelope
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wp *workerPool) createWorkerPool(hsh *HostSensorHandler, wg *sync.WaitGroup) {
|
||||
for i := 0; i < noOfWorkers; i++ {
|
||||
wg.Add(1)
|
||||
go wp.hostSensorWorker(hsh, wg)
|
||||
}
|
||||
}
|
||||
|
||||
func (wp *workerPool) waitForDone(wg *sync.WaitGroup) {
|
||||
// Waiting for workers to finish
|
||||
wg.Wait()
|
||||
close(wp.results)
|
||||
|
||||
// Waiting for the results to be processed
|
||||
<-wp.done
|
||||
}
|
||||
|
||||
func (wp *workerPool) hostSensorGetResults(result *[]hostsensor.HostSensorDataEnvelope) {
|
||||
go func() {
|
||||
for res := range wp.results {
|
||||
*result = append(*result, res)
|
||||
}
|
||||
wp.done <- true
|
||||
}()
|
||||
}
|
||||
|
||||
func (wp *workerPool) hostSensorApplyJobs(podList map[string]string, path, requestKind string) {
|
||||
go func() {
|
||||
for podName, nodeName := range podList {
|
||||
job := job{
|
||||
podName: podName,
|
||||
nodeName: nodeName,
|
||||
requestKind: requestKind,
|
||||
path: path,
|
||||
}
|
||||
wp.jobs <- job
|
||||
|
||||
}
|
||||
close(wp.jobs)
|
||||
}()
|
||||
}
|
||||
@@ -13,8 +13,6 @@ var (
|
||||
OpenPortsList = "OpenPortsList"
|
||||
LinuxKernelVariables = "LinuxKernelVariables"
|
||||
KubeletCommandLine = "KubeletCommandLine"
|
||||
KubeletInfo = "KubeletInfo"
|
||||
KubeProxyInfo = "KubeProxyInfo"
|
||||
|
||||
MapHostSensorResourceToApiGroup = map[string]string{
|
||||
KubeletConfiguration: "hostdata.kubescape.cloud/v1beta0",
|
||||
@@ -24,8 +22,6 @@ var (
|
||||
LinuxSecurityHardeningStatus: "hostdata.kubescape.cloud/v1beta0",
|
||||
OpenPortsList: "hostdata.kubescape.cloud/v1beta0",
|
||||
LinuxKernelVariables: "hostdata.kubescape.cloud/v1beta0",
|
||||
KubeletInfo: "hostdata.kubescape.cloud/v1beta0",
|
||||
KubeProxyInfo: "hostdata.kubescape.cloud/v1beta0",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ import (
|
||||
|
||||
"github.com/armosec/k8s-interface/workloadinterface"
|
||||
|
||||
reporthandlingv2 "github.com/armosec/opa-utils/reporthandling/v2"
|
||||
"github.com/armosec/opa-utils/resources"
|
||||
"github.com/open-policy-agent/opa/ast"
|
||||
"github.com/open-policy-agent/opa/rego"
|
||||
@@ -63,7 +62,7 @@ func (opap *OPAProcessor) ProcessRulesListenner() error {
|
||||
}
|
||||
|
||||
func (opap *OPAProcessor) Process(policies *cautils.Policies) error {
|
||||
opap.loggerStartScanning()
|
||||
logger.L().Info("Scanning", helpers.String("cluster", cautils.ClusterName))
|
||||
|
||||
cautils.StartSpinner()
|
||||
|
||||
@@ -90,30 +89,11 @@ func (opap *OPAProcessor) Process(policies *cautils.Policies) error {
|
||||
opap.Report.ReportGenerationTime = time.Now().UTC()
|
||||
|
||||
cautils.StopSpinner()
|
||||
|
||||
opap.loggerDoneScanning()
|
||||
logger.L().Success("Done scanning", helpers.String("cluster", cautils.ClusterName))
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
func (opap *OPAProcessor) loggerStartScanning() {
|
||||
targetScan := opap.OPASessionObj.Metadata.ScanMetadata.ScanningTarget
|
||||
if reporthandlingv2.Cluster == targetScan {
|
||||
logger.L().Info("Scanning", helpers.String(targetScan.String(), cautils.ClusterName))
|
||||
} else {
|
||||
logger.L().Info("Scanning " + targetScan.String())
|
||||
}
|
||||
}
|
||||
|
||||
func (opap *OPAProcessor) loggerDoneScanning() {
|
||||
targetScan := opap.OPASessionObj.Metadata.ScanMetadata.ScanningTarget
|
||||
if reporthandlingv2.Cluster == targetScan {
|
||||
logger.L().Success("Done scanning", helpers.String(targetScan.String(), cautils.ClusterName))
|
||||
} else {
|
||||
logger.L().Success("Done scanning " + targetScan.String())
|
||||
}
|
||||
}
|
||||
|
||||
func (opap *OPAProcessor) processControl(control *reporthandling.Control) (map[string]resourcesresults.ResourceAssociatedControl, error) {
|
||||
var errs error
|
||||
|
||||
|
||||
@@ -33,8 +33,6 @@ func (policyHandler *PolicyHandler) getPolicies(policyIdentifier []cautils.Polic
|
||||
exceptionPolicies, err := policyHandler.getters.ExceptionsGetter.GetExceptions(cautils.ClusterName)
|
||||
if err == nil {
|
||||
policiesAndResources.Exceptions = exceptionPolicies
|
||||
} else {
|
||||
logger.L().Error("failed to load exceptions", helpers.Error(err))
|
||||
}
|
||||
|
||||
// get account configuration
|
||||
|
||||
@@ -83,7 +83,7 @@ func (armoCivAdaptor *ArmoCivAdaptor) GetImageVulnerability(imageID *registryvul
|
||||
}
|
||||
|
||||
func (armoCivAdaptor *ArmoCivAdaptor) DescribeAdaptor() string {
|
||||
return "armo image vulnerabilities scanner, docs: https://hub.armosec.io/docs/configuration-of-image-vulnerabilities"
|
||||
return "armo image vulnerabilities scanner, docs: https://hub.armo.cloud/docs/cluster-vulnerability-scanning"
|
||||
}
|
||||
|
||||
func (armoCivAdaptor *ArmoCivAdaptor) GetImagesInformation(imageIDs []registryvulnerabilities.ContainerImageIdentifier) ([]registryvulnerabilities.ContainerImageInformation, error) {
|
||||
|
||||
@@ -2,12 +2,9 @@ package resourcehandler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/armosec/armoapi-go/armotypes"
|
||||
"github.com/armosec/k8s-interface/workloadinterface"
|
||||
"github.com/armosec/opa-utils/reporthandling"
|
||||
"k8s.io/apimachinery/pkg/version"
|
||||
|
||||
"github.com/armosec/k8s-interface/k8sinterface"
|
||||
@@ -32,137 +29,48 @@ func NewFileResourceHandler(inputPatterns []string, registryAdaptors *RegistryAd
|
||||
|
||||
func (fileHandler *FileResourceHandler) GetResources(sessionObj *cautils.OPASessionObj, designator *armotypes.PortalDesignator) (*cautils.K8SResources, map[string]workloadinterface.IMetadata, *cautils.ArmoResources, error) {
|
||||
|
||||
//
|
||||
// build resources map
|
||||
// map resources based on framework required resources: map["/group/version/kind"][]<k8s workloads ids>
|
||||
k8sResources := setK8sResourceMap(sessionObj.Policies)
|
||||
allResources := map[string]workloadinterface.IMetadata{}
|
||||
workloadIDToSource := make(map[string]reporthandling.Source, 0)
|
||||
workloadIDToSource := make(map[string]string, 0)
|
||||
armoResources := &cautils.ArmoResources{}
|
||||
|
||||
workloads := []workloadinterface.IMetadata{}
|
||||
|
||||
if len(fileHandler.inputPatterns) == 0 {
|
||||
return nil, nil, nil, fmt.Errorf("missing input")
|
||||
}
|
||||
path := fileHandler.inputPatterns[0]
|
||||
|
||||
clonedRepo, err := cloneGitRepo(&path)
|
||||
// load resource from local file system
|
||||
sourceToWorkloads, err := cautils.LoadResourcesFromFiles(fileHandler.inputPatterns)
|
||||
if err != nil {
|
||||
return nil, allResources, nil, err
|
||||
}
|
||||
if clonedRepo != "" {
|
||||
defer os.RemoveAll(clonedRepo)
|
||||
}
|
||||
|
||||
// Get repo root
|
||||
repoRoot := ""
|
||||
gitRepo, err := cautils.NewLocalGitRepository(path)
|
||||
if err == nil && gitRepo != nil {
|
||||
repoRoot, _ = gitRepo.GetRootDir()
|
||||
}
|
||||
|
||||
// load resource from local file system
|
||||
logger.L().Info("Accessing local objects")
|
||||
cautils.StartSpinner()
|
||||
|
||||
sourceToWorkloads := cautils.LoadResourcesFromFiles(path, repoRoot)
|
||||
|
||||
// update workloads and workloadIDToSource
|
||||
for source, ws := range sourceToWorkloads {
|
||||
workloads = append(workloads, ws...)
|
||||
|
||||
relSource, err := filepath.Rel(repoRoot, source)
|
||||
if err == nil {
|
||||
source = relSource
|
||||
}
|
||||
|
||||
var filetype string
|
||||
if cautils.IsYaml(source) {
|
||||
filetype = reporthandling.SourceTypeYaml
|
||||
} else if cautils.IsJson(source) {
|
||||
filetype = reporthandling.SourceTypeJson
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
|
||||
var lastCommit reporthandling.LastCommit
|
||||
if gitRepo != nil {
|
||||
commitInfo, _ := gitRepo.GetFileLastCommit(source)
|
||||
if commitInfo != nil {
|
||||
lastCommit = reporthandling.LastCommit{
|
||||
Hash: commitInfo.SHA,
|
||||
Date: commitInfo.Author.Date,
|
||||
CommitterName: commitInfo.Author.Name,
|
||||
CommitterEmail: commitInfo.Author.Email,
|
||||
Message: commitInfo.Message,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
workloadSource := reporthandling.Source{
|
||||
RelativePath: source,
|
||||
FileType: filetype,
|
||||
LastCommit: lastCommit,
|
||||
}
|
||||
|
||||
for i := range ws {
|
||||
workloadIDToSource[ws[i].GetID()] = workloadSource
|
||||
workloadIDToSource[ws[i].GetID()] = source
|
||||
}
|
||||
}
|
||||
logger.L().Debug("files found in local storage", helpers.Int("files", len(sourceToWorkloads)), helpers.Int("workloads", len(workloads)))
|
||||
|
||||
if len(workloads) == 0 {
|
||||
logger.L().Debug("files found in local storage", helpers.Int("files", len(sourceToWorkloads)), helpers.Int("workloads", len(workloads)))
|
||||
// load resources from url
|
||||
sourceToWorkloads, err = loadResourcesFromUrl(fileHandler.inputPatterns)
|
||||
if err != nil {
|
||||
return nil, allResources, nil, err
|
||||
}
|
||||
|
||||
// load resources from helm charts
|
||||
helmSourceToWorkloads := cautils.LoadResourcesFromHelmCharts(path)
|
||||
for source, ws := range helmSourceToWorkloads {
|
||||
for source, ws := range sourceToWorkloads {
|
||||
workloads = append(workloads, ws...)
|
||||
|
||||
relSource, err := filepath.Rel(repoRoot, source)
|
||||
if err == nil {
|
||||
source = relSource
|
||||
}
|
||||
|
||||
var lastCommit reporthandling.LastCommit
|
||||
if gitRepo != nil {
|
||||
commitInfo, _ := gitRepo.GetFileLastCommit(source)
|
||||
if commitInfo != nil {
|
||||
lastCommit = reporthandling.LastCommit{
|
||||
Hash: commitInfo.SHA,
|
||||
Date: commitInfo.Author.Date,
|
||||
CommitterName: commitInfo.Author.Name,
|
||||
CommitterEmail: commitInfo.Author.Email,
|
||||
Message: commitInfo.Message,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
workloadSource := reporthandling.Source{
|
||||
RelativePath: source,
|
||||
FileType: reporthandling.SourceTypeHelmChart,
|
||||
LastCommit: lastCommit,
|
||||
}
|
||||
|
||||
for i := range ws {
|
||||
workloadIDToSource[ws[i].GetID()] = workloadSource
|
||||
workloadIDToSource[ws[i].GetID()] = source
|
||||
}
|
||||
}
|
||||
|
||||
if len(helmSourceToWorkloads) > 0 {
|
||||
logger.L().Debug("helm templates found in local storage", helpers.Int("helmTemplates", len(helmSourceToWorkloads)), helpers.Int("workloads", len(workloads)))
|
||||
}
|
||||
|
||||
// addCommitData(fileHandler.inputPatterns[0], workloadIDToSource)
|
||||
|
||||
if len(workloads) == 0 {
|
||||
return nil, allResources, nil, fmt.Errorf("empty list of workloads - no workloads found")
|
||||
}
|
||||
logger.L().Debug("files found in git repo", helpers.Int("files", len(sourceToWorkloads)), helpers.Int("workloads", len(workloads)))
|
||||
|
||||
sessionObj.ResourceSource = workloadIDToSource
|
||||
|
||||
// map all resources: map["/apiVersion/version/kind"][]<k8s workloads>
|
||||
// map all resources: map["/group/version/kind"][]<k8s workloads>
|
||||
mappedResources := mapResources(workloads)
|
||||
|
||||
// save only relevant resources
|
||||
@@ -181,12 +89,39 @@ func (fileHandler *FileResourceHandler) GetResources(sessionObj *cautils.OPASess
|
||||
logger.L().Warning("failed to collect images vulnerabilities", helpers.Error(err))
|
||||
}
|
||||
|
||||
cautils.StopSpinner()
|
||||
logger.L().Success("Accessed to local objects")
|
||||
|
||||
return k8sResources, allResources, armoResources, nil
|
||||
|
||||
}
|
||||
|
||||
func (fileHandler *FileResourceHandler) GetClusterAPIServerInfo() *version.Info {
|
||||
return nil
|
||||
}
|
||||
|
||||
// build resources map
|
||||
func mapResources(workloads []workloadinterface.IMetadata) map[string][]workloadinterface.IMetadata {
|
||||
|
||||
allResources := map[string][]workloadinterface.IMetadata{}
|
||||
for i := range workloads {
|
||||
groupVersionResource, err := k8sinterface.GetGroupVersionResource(workloads[i].GetKind())
|
||||
if err != nil {
|
||||
// TODO - print warning
|
||||
continue
|
||||
}
|
||||
|
||||
if k8sinterface.IsTypeWorkload(workloads[i].GetObject()) {
|
||||
w := workloadinterface.NewWorkloadObj(workloads[i].GetObject())
|
||||
if groupVersionResource.Group != w.GetGroup() || groupVersionResource.Version != w.GetVersion() {
|
||||
// TODO - print warning
|
||||
continue
|
||||
}
|
||||
}
|
||||
resourceTriplets := k8sinterface.JoinResourceTriplets(groupVersionResource.Group, groupVersionResource.Version, groupVersionResource.Resource)
|
||||
if r, ok := allResources[resourceTriplets]; ok {
|
||||
allResources[resourceTriplets] = append(r, workloads[i])
|
||||
} else {
|
||||
allResources[resourceTriplets] = []workloadinterface.IMetadata{workloads[i]}
|
||||
}
|
||||
}
|
||||
return allResources
|
||||
|
||||
}
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
package resourcehandler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
giturl "github.com/armosec/go-git-url"
|
||||
"github.com/armosec/k8s-interface/k8sinterface"
|
||||
"github.com/armosec/k8s-interface/workloadinterface"
|
||||
"github.com/armosec/kubescape/v2/core/cautils"
|
||||
"github.com/armosec/kubescape/v2/core/cautils/logger"
|
||||
"github.com/armosec/kubescape/v2/core/cautils/logger/helpers"
|
||||
"github.com/armosec/opa-utils/reporthandling"
|
||||
)
|
||||
|
||||
// Clone git repository
|
||||
func cloneGitRepo(path *string) (string, error) {
|
||||
var clonedDir string
|
||||
|
||||
// Clone git repository if needed
|
||||
gitURL, err := giturl.NewGitURL(*path)
|
||||
if err == nil {
|
||||
logger.L().Info("cloning", helpers.String("repository url", gitURL.GetURL().String()))
|
||||
cautils.StartSpinner()
|
||||
clonedDir, err = cloneRepo(gitURL)
|
||||
cautils.StopSpinner()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to clone git repo '%s', %w", gitURL.GetURL().String(), err)
|
||||
}
|
||||
|
||||
*path = filepath.Join(clonedDir, gitURL.GetPath())
|
||||
|
||||
}
|
||||
return clonedDir, nil
|
||||
}
|
||||
|
||||
// build resources map
|
||||
func mapResources(workloads []workloadinterface.IMetadata) map[string][]workloadinterface.IMetadata {
|
||||
|
||||
allResources := map[string][]workloadinterface.IMetadata{}
|
||||
for i := range workloads {
|
||||
groupVersionResource, err := k8sinterface.GetGroupVersionResource(workloads[i].GetKind())
|
||||
if err != nil {
|
||||
// TODO - print warning
|
||||
continue
|
||||
}
|
||||
|
||||
if k8sinterface.IsTypeWorkload(workloads[i].GetObject()) {
|
||||
w := workloadinterface.NewWorkloadObj(workloads[i].GetObject())
|
||||
if groupVersionResource.Group != w.GetGroup() || groupVersionResource.Version != w.GetVersion() {
|
||||
// TODO - print warning
|
||||
continue
|
||||
}
|
||||
}
|
||||
resourceTriplets := k8sinterface.JoinResourceTriplets(groupVersionResource.Group, groupVersionResource.Version, groupVersionResource.Resource)
|
||||
if r, ok := allResources[resourceTriplets]; ok {
|
||||
allResources[resourceTriplets] = append(r, workloads[i])
|
||||
} else {
|
||||
allResources[resourceTriplets] = []workloadinterface.IMetadata{workloads[i]}
|
||||
}
|
||||
}
|
||||
return allResources
|
||||
|
||||
}
|
||||
|
||||
func addCommitData(input string, workloadIDToSource map[string]reporthandling.Source) {
|
||||
giRepo, err := cautils.NewLocalGitRepository(input)
|
||||
if err != nil || giRepo == nil {
|
||||
return
|
||||
}
|
||||
for k := range workloadIDToSource {
|
||||
sourceObj := workloadIDToSource[k]
|
||||
lastCommit, err := giRepo.GetFileLastCommit(sourceObj.RelativePath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
sourceObj.LastCommit = reporthandling.LastCommit{
|
||||
Hash: lastCommit.SHA,
|
||||
Date: lastCommit.Author.Date,
|
||||
CommitterName: lastCommit.Author.Name,
|
||||
CommitterEmail: lastCommit.Author.Email,
|
||||
Message: lastCommit.Message,
|
||||
}
|
||||
workloadIDToSource[k] = sourceObj
|
||||
}
|
||||
}
|
||||
@@ -89,7 +89,7 @@ func (k8sHandler *K8sResourceHandler) GetResources(sessionObj *cautils.OPASessio
|
||||
cautils.SetInfoMapForResources(fmt.Sprintf("failed to pull image scanning data: %s", err.Error()), imgVulnResources, sessionObj.InfoMap)
|
||||
} else {
|
||||
if isEmptyImgVulns(*armoResourceMap) {
|
||||
cautils.SetInfoMapForResources("image scanning is not configured. for more information: https://hub.armosec.io/docs/configuration-of-image-vulnerabilities", imgVulnResources, sessionObj.InfoMap)
|
||||
cautils.SetInfoMapForResources("image scanning is not configured. for more information: https://hub.armo.cloud/docs/cluster-vulnerability-scanning", imgVulnResources, sessionObj.InfoMap)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -109,7 +109,7 @@ func (k8sHandler *K8sResourceHandler) GetResources(sessionObj *cautils.OPASessio
|
||||
sessionObj.InfoMap = infoMap
|
||||
}
|
||||
} else {
|
||||
cautils.SetInfoMapForResources("enable-host-scan flag not used. For more information: https://hub.armosec.io/docs/host-sensor", hostResources, sessionObj.InfoMap)
|
||||
cautils.SetInfoMapForResources("enable-host-scan flag not used. For more information: https://hub.armo.cloud/docs/host-sensor", hostResources, sessionObj.InfoMap)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,7 +283,7 @@ func getCloudProviderDescription(allResources map[string]workloadinterface.IMeta
|
||||
if err != nil {
|
||||
// Return error with useful info on how to configure credentials for getting cloud provider info
|
||||
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.armosec.io/docs/kubescape-integration-with-cloud-providers", strings.ToUpper(provider))
|
||||
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
|
||||
(*armoResourceMap)[fmt.Sprintf("%s/%s", wl.GetApiVersion(), wl.GetKind())] = []string{wl.GetID()}
|
||||
|
||||
@@ -20,8 +20,6 @@ var (
|
||||
LinuxKernelVariables = "LinuxKernelVariables"
|
||||
KubeletCommandLine = "KubeletCommandLine"
|
||||
ImageVulnerabilities = "ImageVulnerabilities"
|
||||
KubeletInfo = "KubeletInfo"
|
||||
KubeProxyInfo = "KubeProxyInfo"
|
||||
|
||||
MapResourceToApiGroup = map[string]string{
|
||||
KubeletConfiguration: "hostdata.kubescape.cloud/v1beta0",
|
||||
@@ -31,8 +29,6 @@ var (
|
||||
LinuxSecurityHardeningStatus: "hostdata.kubescape.cloud/v1beta0",
|
||||
OpenPortsList: "hostdata.kubescape.cloud/v1beta0",
|
||||
LinuxKernelVariables: "hostdata.kubescape.cloud/v1beta0",
|
||||
KubeletInfo: "hostdata.kubescape.cloud/v1beta0",
|
||||
KubeProxyInfo: "hostdata.kubescape.cloud/v1beta0",
|
||||
}
|
||||
MapResourceToApiGroupVuln = map[string][]string{
|
||||
ImageVulnerabilities: {"armo.vuln.images/v1", "image.vulnscan.com/v1"}}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
package resourcehandler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
giturl "github.com/armosec/go-git-url"
|
||||
"github.com/go-git/go-git/v5"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
)
|
||||
|
||||
// cloneRepo clones a repository to a local temporary directory and returns the directory
|
||||
func cloneRepo(gitURL giturl.IGitURL) (string, error) {
|
||||
|
||||
// Create temp directory
|
||||
tmpDir, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create temporary directory: %w", err)
|
||||
}
|
||||
|
||||
// Clone option
|
||||
cloneURL := gitURL.GetHttpCloneURL()
|
||||
cloneOpts := git.CloneOptions{URL: cloneURL}
|
||||
if gitURL.GetBranchName() != "" {
|
||||
cloneOpts.ReferenceName = plumbing.NewBranchReferenceName(gitURL.GetBranchName())
|
||||
cloneOpts.SingleBranch = true
|
||||
}
|
||||
|
||||
// Actual clone
|
||||
_, err = git.PlainClone(tmpDir, false, &cloneOpts)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to clone %s. %w", gitURL.GetRepoName(), err)
|
||||
}
|
||||
|
||||
return tmpDir, nil
|
||||
}
|
||||
@@ -12,7 +12,7 @@ func loadResourcesFromUrl(inputPatterns []string) (map[string][]workloadinterfac
|
||||
if len(inputPatterns) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
g, err := giturl.NewGitAPI(inputPatterns[0])
|
||||
g, err := giturl.NewGitURL(inputPatterns[0])
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -33,7 +33,7 @@ func loadResourcesFromUrl(inputPatterns []string) (map[string][]workloadinterfac
|
||||
|
||||
for i, j := range files {
|
||||
w, e := cautils.ReadFile(j, cautils.GetFileFormat(i))
|
||||
if e != nil || len(w) == 0 {
|
||||
if len(e) != 0 || len(w) == 0 {
|
||||
continue
|
||||
}
|
||||
if _, ok := workloads[i]; !ok {
|
||||
|
||||
@@ -17,7 +17,6 @@ const (
|
||||
JunitResultFormat string = "junit"
|
||||
PrometheusFormat string = "prometheus"
|
||||
PdfFormat string = "pdf"
|
||||
HtmlFormat string = "html"
|
||||
)
|
||||
|
||||
type IPrinter interface {
|
||||
|
||||
@@ -1,154 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Kubescape Scan Report</title>
|
||||
</head>
|
||||
<style>
|
||||
:root {
|
||||
--cell-padding-vertical: 0.25em;
|
||||
--cell-padding-horizontal: 0.25em;
|
||||
--font-family-sans: system-ui, -apple-system, sans-serif;
|
||||
}
|
||||
body {
|
||||
max-width: 60em;
|
||||
margin: auto;
|
||||
font-family: var(--font-family-sans);
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
border-top: 0.1em solid black;
|
||||
border-bottom: 0.1em solid black;
|
||||
border-collapse: collapse;
|
||||
table-layout: fixed;
|
||||
}
|
||||
th {
|
||||
text-align: left;
|
||||
}
|
||||
td, th {
|
||||
padding-top: var(--cell-padding-vertical);
|
||||
padding-bottom: var(--cell-padding-vertical);
|
||||
padding-right: var(--cell-padding-horizontal);
|
||||
vertical-align: top;
|
||||
}
|
||||
td > p {
|
||||
margin: 0;
|
||||
word-break: break-all;
|
||||
hyphens: auto;
|
||||
}
|
||||
thead {
|
||||
border-bottom: 0.01em solid black;
|
||||
}
|
||||
.numericCell {
|
||||
text-align: right;
|
||||
}
|
||||
.controlSeverityCell {
|
||||
width: 10%;
|
||||
}
|
||||
.controlNameCell {
|
||||
width: 50%;
|
||||
}
|
||||
.controlRiskCell {
|
||||
width: 10%;
|
||||
}
|
||||
.resourceSeverityCell {
|
||||
width: 10%;
|
||||
}
|
||||
.resourceNameCell {
|
||||
width: 30%;
|
||||
}
|
||||
.resourceURLCell {
|
||||
width: 10%;
|
||||
}
|
||||
.resourceRemediationCell {
|
||||
width: 50%;
|
||||
}
|
||||
.logo {
|
||||
width: 25%;
|
||||
float: right;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<img class="logo" src="https://raw.githubusercontent.com/armosec/kubescape/master/core/pkg/resultshandling/printer/v2/pdf/logo.png">
|
||||
<h1>Kubescape Scan Report</h1>
|
||||
{{ with .OPASessionObj.Report.SummaryDetails }}
|
||||
<h2>By Controls</h2>
|
||||
<h3>Summary</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>All</th>
|
||||
<th>Failed</th>
|
||||
<th>Excluded</th>
|
||||
<th>Skipped</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{ .NumberOfControls.All }}</td>
|
||||
<td>{{ .NumberOfControls.Failed }}</td>
|
||||
<td>{{ .NumberOfControls.Excluded }}</td>
|
||||
<td>{{ .NumberOfControls.Skipped }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>Details</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="controlSeverityCell">Severity</th>
|
||||
<th class="controlNameCell">Control Name</th>
|
||||
<th class="controlRiskCell">Failed Resources</th>
|
||||
<th class="controlRiskCell">Excluded Resources</th>
|
||||
<th class="controlRiskCell">All Resources</th>
|
||||
<th class="controlRiskCell">Risk Score, %</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ $sorted := sortBySeverityName .Controls }}
|
||||
{{ range $control := $sorted }}
|
||||
<tr>
|
||||
<td class="controlSeverityCell">{{ controlSeverityToString $control.ScoreFactor }}</td>
|
||||
<td class="controlNameCell">{{ $control.Name }}</td>
|
||||
<td class="controlRiskCell numericCell">{{ $control.ResourceCounters.FailedResources }}</td>
|
||||
<td class="controlRiskCell numericCell">{{ $control.ResourceCounters.ExcludedResources }}</td>
|
||||
<td class="controlRiskCell numericCell">{{ sum $control.ResourceCounters.ExcludedResources $control.ResourceCounters.FailedResources $control.ResourceCounters.PassedResources }}</td>
|
||||
<td class="controlRiskCell numericCell">{{ float32ToInt $control.Score }}</td>
|
||||
</tr>
|
||||
</tr>
|
||||
{{ end }}
|
||||
<tbody>
|
||||
</table>
|
||||
{{ end }}
|
||||
<h2>By Resource</h2>
|
||||
{{ $sortedResourceTableView := sortByNamespace .ResourceTableView }}
|
||||
{{ range $sortedResourceTableView }}
|
||||
<h3>Name: {{ .Resource.GetName }}</h3>
|
||||
<p>ApiVersion: {{ .Resource.GetApiVersion }}</p>
|
||||
<p>Kind: {{ .Resource.GetKind }}</p>
|
||||
<p>Name: {{ .Resource.GetName }}</p>
|
||||
<p>Namespace: {{ .Resource.GetNamespace }}</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="resourceSeverityCell">Severity</th>
|
||||
<th class="resourceNameCell">Name</th>
|
||||
<th class="resourceURLCell">Docs</th>
|
||||
<th class="resourceRemediationCell">Assistant Remediation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ range .ControlsResult }}
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">{{ .Severity }}</td>
|
||||
<td class="resourceNameCell">{{ .Name }}</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/{{ lower .URL }}">{{ .URL }}</a></td>
|
||||
<td class="resourceRemediationCell">{{ range .FailedPaths }} <p>{{ . }}</p> {{ end }}</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{ end }}
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,151 +0,0 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"html/template"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/armosec/kubescape/v2/core/cautils"
|
||||
"github.com/armosec/kubescape/v2/core/cautils/logger"
|
||||
"github.com/armosec/kubescape/v2/core/cautils/logger/helpers"
|
||||
"github.com/armosec/kubescape/v2/core/pkg/resultshandling/printer"
|
||||
"github.com/armosec/opa-utils/reporthandling/apis"
|
||||
"github.com/armosec/opa-utils/reporthandling/results/v1/reportsummary"
|
||||
"github.com/armosec/opa-utils/reporthandling/results/v1/resourcesresults"
|
||||
)
|
||||
|
||||
const (
|
||||
htmlOutputFile = "report"
|
||||
htmlOutputExt = ".html"
|
||||
)
|
||||
|
||||
//go:embed html/report.gohtml
|
||||
var reportTemplate string
|
||||
|
||||
type HTMLReportingCtx struct {
|
||||
OPASessionObj *cautils.OPASessionObj
|
||||
ResourceTableView ResourceTableView
|
||||
}
|
||||
|
||||
type HtmlPrinter struct {
|
||||
writer *os.File
|
||||
}
|
||||
|
||||
func NewHtmlPrinter() *HtmlPrinter {
|
||||
return &HtmlPrinter{}
|
||||
}
|
||||
|
||||
func (htmlPrinter *HtmlPrinter) SetWriter(outputFile string) {
|
||||
if outputFile == "" {
|
||||
outputFile = htmlOutputFile
|
||||
}
|
||||
if filepath.Ext(strings.TrimSpace(outputFile)) != htmlOutputExt {
|
||||
outputFile = outputFile + htmlOutputExt
|
||||
}
|
||||
htmlPrinter.writer = printer.GetWriter(outputFile)
|
||||
}
|
||||
|
||||
func (htmlPrinter *HtmlPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
|
||||
tplFuncMap := template.FuncMap{
|
||||
"sum": func(nums ...int) int {
|
||||
total := 0
|
||||
for _, n := range nums {
|
||||
total += n
|
||||
}
|
||||
return total
|
||||
},
|
||||
"float32ToInt": cautils.Float32ToInt,
|
||||
"lower": strings.ToLower,
|
||||
"sortByNamespace": func(resourceTableView ResourceTableView) ResourceTableView {
|
||||
sortedResourceTableView := make(ResourceTableView, len(resourceTableView))
|
||||
copy(sortedResourceTableView, resourceTableView)
|
||||
|
||||
sort.SliceStable(
|
||||
sortedResourceTableView,
|
||||
func(i, j int) bool {
|
||||
return sortedResourceTableView[i].Resource.GetNamespace() < sortedResourceTableView[j].Resource.GetNamespace()
|
||||
},
|
||||
)
|
||||
return sortedResourceTableView
|
||||
},
|
||||
"controlSeverityToString": apis.ControlSeverityToString,
|
||||
"sortBySeverityName": func(controlSummaries map[string]reportsummary.ControlSummary) []reportsummary.ControlSummary {
|
||||
sortedSlice := make([]reportsummary.ControlSummary, 0, len(controlSummaries))
|
||||
for _, val := range controlSummaries {
|
||||
sortedSlice = append(sortedSlice, val)
|
||||
}
|
||||
|
||||
sort.SliceStable(
|
||||
sortedSlice,
|
||||
func(i, j int) bool {
|
||||
//First sort by Severity descending
|
||||
iSeverity := apis.ControlSeverityToInt(sortedSlice[i].GetScoreFactor())
|
||||
jSeverity := apis.ControlSeverityToInt(sortedSlice[j].GetScoreFactor())
|
||||
if iSeverity > jSeverity {
|
||||
return true
|
||||
}
|
||||
if iSeverity < jSeverity {
|
||||
return false
|
||||
}
|
||||
//And then by Name ascending
|
||||
return sortedSlice[i].GetName() < sortedSlice[j].GetName()
|
||||
},
|
||||
)
|
||||
|
||||
return sortedSlice
|
||||
},
|
||||
}
|
||||
tpl := template.Must(
|
||||
template.New("htmlReport").Funcs(tplFuncMap).Parse(reportTemplate),
|
||||
)
|
||||
|
||||
resourceTableView := buildResourceTableView(opaSessionObj)
|
||||
reportingCtx := HTMLReportingCtx{opaSessionObj, resourceTableView}
|
||||
err := tpl.Execute(htmlPrinter.writer, reportingCtx)
|
||||
if err != nil {
|
||||
logger.L().Error("failed to render template", helpers.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
func (htmlPrinter *HtmlPrinter) Score(score float32) {
|
||||
return
|
||||
}
|
||||
|
||||
func buildResourceTableView(opaSessionObj *cautils.OPASessionObj) ResourceTableView {
|
||||
resourceTableView := make(ResourceTableView, 0)
|
||||
for resourceID, result := range opaSessionObj.ResourcesResult {
|
||||
if result.GetStatus(nil).IsFailed() {
|
||||
resource := opaSessionObj.AllResources[resourceID]
|
||||
ctlResults := buildResourceControlResultTable(result.AssociatedControls, &opaSessionObj.Report.SummaryDetails)
|
||||
resourceTableView = append(resourceTableView, ResourceResult{resource, ctlResults})
|
||||
}
|
||||
}
|
||||
|
||||
return resourceTableView
|
||||
}
|
||||
|
||||
func buildResourceControlResult(resourceControl resourcesresults.ResourceAssociatedControl, control reportsummary.IControlSummary) ResourceControlResult {
|
||||
ctlSeverity := apis.ControlSeverityToString(control.GetScoreFactor())
|
||||
ctlName := resourceControl.GetName()
|
||||
ctlURL := resourceControl.GetID()
|
||||
failedPaths := failedPathsToString(&resourceControl)
|
||||
|
||||
return ResourceControlResult{ctlSeverity, ctlName, ctlURL, failedPaths}
|
||||
}
|
||||
|
||||
func buildResourceControlResultTable(resourceControls []resourcesresults.ResourceAssociatedControl, summaryDetails *reportsummary.SummaryDetails) []ResourceControlResult {
|
||||
var ctlResults []ResourceControlResult
|
||||
for _, resourceControl := range resourceControls {
|
||||
if resourceControl.GetStatus(nil).IsFailed() {
|
||||
control := summaryDetails.Controls.GetControl(reportsummary.EControlCriteriaName, resourceControl.GetName())
|
||||
ctlResult := buildResourceControlResult(resourceControl, control)
|
||||
|
||||
ctlResults = append(ctlResults, ctlResult)
|
||||
}
|
||||
}
|
||||
|
||||
return ctlResults
|
||||
}
|
||||
@@ -49,7 +49,7 @@ type JUnitTestSuite struct {
|
||||
XMLName xml.Name `xml:"testsuite"`
|
||||
Name string `xml:"name,attr"` // Full (class) name of the test for non-aggregated testsuite documents. Class name without the package for aggregated testsuites documents. Required
|
||||
Disabled int `xml:"disabled,attr"` // The total number of disabled tests in the suite. optional. not supported by maven surefire.
|
||||
Errors int `xml:"errors,attr"` // The total number of tests in the suite that errors
|
||||
Errors int `xml:"errors,attr"` // The total number of tests in the suite that errored
|
||||
Failures int `xml:"failures,attr"` // The total number of tests in the suite that failed
|
||||
Hostname string `xml:"hostname,attr"` // Host on which the tests were executed ? cluster name ?
|
||||
ID int `xml:"id,attr"` // Starts at 0 for the first testsuite and is incremented by 1 for each following testsuite
|
||||
@@ -181,7 +181,7 @@ func testsCases(results *cautils.OPASessionObj, controls reportsummary.IControls
|
||||
testCase.Failure = &testCaseFailure
|
||||
} else if control.GetStatus().IsSkipped() {
|
||||
testCase.SkipMessage = &JUnitSkipMessage{
|
||||
Message: "", // TODO - fill after statusInfo is supported
|
||||
Message: "", // TODO - fill after statusInfo is supportred
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ func NewPrettyPrinter(verboseMode bool, formatVersion string, viewType cautils.V
|
||||
}
|
||||
|
||||
func (prettyPrinter *PrettyPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
|
||||
fmt.Fprintf(prettyPrinter.writer, "\n"+getSeparator("^")+"\n")
|
||||
fmt.Fprintf(prettyPrinter.writer, "\n"+getSperator("^")+"\n")
|
||||
|
||||
sortedControlNames := getSortedControlsNames(opaSessionObj.Report.SummaryDetails.Controls) // ListControls().All())
|
||||
|
||||
@@ -188,10 +188,6 @@ func generateFooter(summaryDetails *reportsummary.SummaryDetails) []string {
|
||||
}
|
||||
func (prettyPrinter *PrettyPrinter) printSummaryTable(summaryDetails *reportsummary.SummaryDetails, sortedControlNames [][]string) {
|
||||
|
||||
if summaryDetails.NumberOfControls().All() == 0 {
|
||||
fmt.Fprintf(prettyPrinter.writer, "\nKubescape did not scan any of the resources, make sure you are scanning valid kubernetes manifests (Deployments, Pods, etc.)\n")
|
||||
return
|
||||
}
|
||||
cautils.InfoTextDisplay(prettyPrinter.writer, "\n"+controlCountersForSummary(summaryDetails.NumberOfControls())+"\n\n")
|
||||
|
||||
summaryTable := tablewriter.NewWriter(prettyPrinter.writer)
|
||||
@@ -200,16 +196,10 @@ func (prettyPrinter *PrettyPrinter) printSummaryTable(summaryDetails *reportsumm
|
||||
summaryTable.SetHeaderLine(true)
|
||||
summaryTable.SetColumnAlignment(getColumnsAlignments())
|
||||
|
||||
printAll := prettyPrinter.verboseMode
|
||||
if summaryDetails.NumberOfResources().Failed() == 0 {
|
||||
// if there are no failed controls, print the resource table and detailed information
|
||||
printAll = true
|
||||
}
|
||||
|
||||
infoToPrintInfo := mapInfoToPrintInfo(summaryDetails.Controls)
|
||||
for i := len(sortedControlNames) - 1; i >= 0; i-- {
|
||||
for _, c := range sortedControlNames[i] {
|
||||
row := generateRow(summaryDetails.Controls.GetControl(reportsummary.EControlCriteriaName, c), infoToPrintInfo, printAll)
|
||||
row := generateRow(summaryDetails.Controls.GetControl(reportsummary.EControlCriteriaName, c), infoToPrintInfo, prettyPrinter.verboseMode)
|
||||
if len(row) > 0 {
|
||||
summaryTable.Append(row)
|
||||
}
|
||||
@@ -253,7 +243,7 @@ func frameworksScoresToString(frameworks []reportsummary.IFrameworkSummary) stri
|
||||
}
|
||||
|
||||
func getControlLink(controlID string) string {
|
||||
return fmt.Sprintf("https://hub.armosec.io/docs/%s", strings.ToLower(controlID))
|
||||
return fmt.Sprintf("https://hub.armo.cloud/docs/%s", strings.ToLower(controlID))
|
||||
}
|
||||
|
||||
func controlCountersForSummary(counters reportsummary.ICounters) string {
|
||||
@@ -263,7 +253,7 @@ func controlCountersForSummary(counters reportsummary.ICounters) string {
|
||||
func controlCountersForResource(l *helpersv1.AllLists) string {
|
||||
return fmt.Sprintf("Controls: %d (Failed: %d, Excluded: %d)", len(l.All()), len(l.Failed()), len(l.Excluded()))
|
||||
}
|
||||
func getSeparator(sep string) string {
|
||||
func getSperator(sep string) string {
|
||||
s := ""
|
||||
for i := 0; i < 80; i++ {
|
||||
s += sep
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
"github.com/armosec/k8s-interface/workloadinterface"
|
||||
)
|
||||
|
||||
type ResourceTableView []ResourceResult
|
||||
|
||||
type ResourceResult struct {
|
||||
Resource workloadinterface.IMetadata
|
||||
ControlsResult []ResourceControlResult
|
||||
}
|
||||
|
||||
type ResourceControlResult struct {
|
||||
Severity string
|
||||
Name string
|
||||
URL string
|
||||
FailedPaths []string
|
||||
}
|
||||
@@ -29,10 +29,10 @@ func (prettyPrinter *PrettyPrinter) resourceTable(opaSessionObj *cautils.OPASess
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(prettyPrinter.writer, "\n%s\n", getSeparator("#"))
|
||||
fmt.Fprintf(prettyPrinter.writer, "\n"+getSperator("#")+"\n\n")
|
||||
|
||||
if source, ok := opaSessionObj.ResourceSource[resourceID]; ok {
|
||||
fmt.Fprintf(prettyPrinter.writer, "Source: %s\n", source.RelativePath)
|
||||
fmt.Fprintf(prettyPrinter.writer, "Source: %s\n", source)
|
||||
}
|
||||
fmt.Fprintf(prettyPrinter.writer, "ApiVersion: %s\n", resource.GetApiVersion())
|
||||
fmt.Fprintf(prettyPrinter.writer, "Kind: %s\n", resource.GetKind())
|
||||
@@ -73,7 +73,7 @@ func generateResourceRows(controls []resourcesresults.ResourceAssociatedControl,
|
||||
continue
|
||||
}
|
||||
|
||||
row[resourceColumnURL] = fmt.Sprintf("https://hub.armosec.io/docs/%s", strings.ToLower(controls[i].GetID()))
|
||||
row[resourceColumnURL] = fmt.Sprintf("https://hub.armo.cloud/docs/%s", strings.ToLower(controls[i].GetID()))
|
||||
row[resourceColumnPath] = strings.Join(failedPathsToString(&controls[i]), "\n")
|
||||
row[resourceColumnName] = controls[i].GetName()
|
||||
|
||||
|
||||
@@ -62,13 +62,13 @@ func mapInfoToPrintInfo(controls reportsummary.ControlSummaries) []infoStars {
|
||||
return infoToPrintInfo
|
||||
}
|
||||
|
||||
func finalizeResources(results []resourcesresults.Result, allResources map[string]workloadinterface.IMetadata, resourcesSource map[string]reporthandling.Source) []reporthandling.Resource {
|
||||
func finalizeResources(results []resourcesresults.Result, allResources map[string]workloadinterface.IMetadata, resourcesSource map[string]string) []reporthandling.Resource {
|
||||
resources := make([]reporthandling.Resource, 0)
|
||||
for i := range results {
|
||||
if obj, ok := allResources[results[i].ResourceID]; ok {
|
||||
resource := *reporthandling.NewResourceIMetadata(obj)
|
||||
if r, ok := resourcesSource[results[i].ResourceID]; ok {
|
||||
resource.SetSource(&r)
|
||||
resource.SetSource(&reporthandling.Source{Path: r})
|
||||
}
|
||||
resources = append(resources, resource)
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ func TestGetURL(t *testing.T) {
|
||||
},
|
||||
"",
|
||||
)
|
||||
assert.Equal(t, "https://cloud.armosec.io/configuration-scanning/test?utm_campaign=Submit&utm_medium=CLI&utm_source=GitHub", reporter.GetURL())
|
||||
assert.Equal(t, "https://portal.armo.cloud/configuration-scanning/test?utm_campaign=Submit&utm_medium=CLI&utm_source=GitHub", reporter.GetURL())
|
||||
}
|
||||
|
||||
// Test submit and NOT registered url
|
||||
@@ -33,16 +33,16 @@ func TestGetURL(t *testing.T) {
|
||||
},
|
||||
"",
|
||||
)
|
||||
assert.Equal(t, "https://cloud.armosec.io/account/sign-up?customerGUID=1234&invitationToken=token&utm_campaign=Submit&utm_medium=CLI&utm_source=GitHub", reporter.GetURL())
|
||||
assert.Equal(t, "https://portal.armo.cloud/account/sign-up?customerGUID=1234&invitationToken=token&utm_campaign=Submit&utm_medium=CLI&utm_source=GitHub", reporter.GetURL())
|
||||
}
|
||||
// Test None submit url
|
||||
{
|
||||
reporter := NewReportMock(NO_SUBMIT_QUERY, "")
|
||||
assert.Equal(t, "https://cloud.armosec.io/account/sign-up?utm_source=GitHub&utm_medium=CLI&utm_campaign=no_submit", reporter.GetURL())
|
||||
assert.Equal(t, "https://portal.armo.cloud/account/sign-up?utm_source=GitHub&utm_medium=CLI&utm_campaign=no_submit", reporter.GetURL())
|
||||
}
|
||||
// Test None report url
|
||||
{
|
||||
reporter := NewReportMock("", "")
|
||||
assert.Equal(t, "https://cloud.armosec.io/account/sign-up", reporter.GetURL())
|
||||
assert.Equal(t, "https://portal.armo.cloud/account/sign-up", reporter.GetURL())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,12 +7,12 @@ import (
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"github.com/armosec/armoapi-go/apis"
|
||||
"github.com/armosec/k8s-interface/workloadinterface"
|
||||
"github.com/armosec/kubescape/v2/core/cautils"
|
||||
"github.com/armosec/kubescape/v2/core/cautils/getter"
|
||||
"github.com/armosec/kubescape/v2/core/cautils/logger"
|
||||
"github.com/armosec/kubescape/v2/core/cautils/logger/helpers"
|
||||
|
||||
"github.com/armosec/opa-utils/reporthandling"
|
||||
"github.com/armosec/opa-utils/reporthandling/results/v1/resourcesresults"
|
||||
reporthandlingv2 "github.com/armosec/opa-utils/reporthandling/v2"
|
||||
@@ -74,12 +74,6 @@ func (report *ReportEventReceiver) SetClusterName(clusterName string) {
|
||||
}
|
||||
|
||||
func (report *ReportEventReceiver) prepareReport(opaSessionObj *cautils.OPASessionObj) error {
|
||||
// All scans whose target is not a cluster, currently their target is a file, which is what the backend expects
|
||||
// (e.g. local-git, directory, etc)
|
||||
if opaSessionObj.Metadata.ScanMetadata.ScanningTarget != reporthandlingv2.Cluster {
|
||||
opaSessionObj.Metadata.ScanMetadata.ScanningTarget = reporthandlingv2.File
|
||||
}
|
||||
|
||||
report.initEventReceiverURL()
|
||||
host := hostToString(report.eventReceiverURL, report.reportID)
|
||||
|
||||
@@ -99,11 +93,7 @@ func (report *ReportEventReceiver) GetURL() string {
|
||||
q := u.Query()
|
||||
|
||||
if report.customerAdminEMail != "" || report.token == "" { // data has been submitted
|
||||
if report.clusterName != "" {
|
||||
u.Path = fmt.Sprintf("configuration-scanning/%s", report.clusterName)
|
||||
} else {
|
||||
u.Path = fmt.Sprintf("repositories-scan/%s", report.reportID)
|
||||
}
|
||||
u.Path = fmt.Sprintf("configuration-scanning/%s", report.clusterName)
|
||||
} else {
|
||||
u.Path = "account/sign-up"
|
||||
q.Add("invitationToken", report.token)
|
||||
@@ -130,7 +120,6 @@ func (report *ReportEventReceiver) sendResources(host string, opaSessionObj *cau
|
||||
if err := report.setResults(splittedPostureReport, opaSessionObj.ResourcesResult, &counter, &reportCounter, host); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return report.sendReport(host, splittedPostureReport, reportCounter, true)
|
||||
}
|
||||
func (report *ReportEventReceiver) setResults(reportObj *reporthandlingv2.PostureReport, results map[string]resourcesresults.Result, counter, reportCounter *int, host string) error {
|
||||
@@ -162,11 +151,11 @@ func (report *ReportEventReceiver) setResults(reportObj *reporthandlingv2.Postur
|
||||
return nil
|
||||
}
|
||||
|
||||
func (report *ReportEventReceiver) setResources(reportObj *reporthandlingv2.PostureReport, allResources map[string]workloadinterface.IMetadata, resourcesSource map[string]reporthandling.Source, counter, reportCounter *int, host string) error {
|
||||
func (report *ReportEventReceiver) setResources(reportObj *reporthandlingv2.PostureReport, allResources map[string]workloadinterface.IMetadata, resourcesSource map[string]string, counter, reportCounter *int, host string) error {
|
||||
for resourceID, v := range allResources {
|
||||
resource := reporthandling.NewResourceIMetadata(v)
|
||||
if r, ok := resourcesSource[resourceID]; ok {
|
||||
resource.SetSource(&r)
|
||||
resource.SetSource(&reporthandling.Source{Path: r})
|
||||
}
|
||||
r, err := json.Marshal(resource)
|
||||
if err != nil {
|
||||
@@ -195,7 +184,7 @@ func (report *ReportEventReceiver) setResources(reportObj *reporthandlingv2.Post
|
||||
return nil
|
||||
}
|
||||
func (report *ReportEventReceiver) sendReport(host string, postureReport *reporthandlingv2.PostureReport, counter int, isLastReport bool) error {
|
||||
postureReport.PaginationInfo = apis.PaginationMarks{
|
||||
postureReport.PaginationInfo = reporthandlingv2.PaginationMarks{
|
||||
ReportNumber: counter,
|
||||
IsLastReport: isLastReport,
|
||||
}
|
||||
|
||||
@@ -16,8 +16,7 @@ func (report *ReportEventReceiver) initEventReceiverURL() {
|
||||
urlObj.Path = "/k8s/v2/postureReport"
|
||||
q := urlObj.Query()
|
||||
q.Add("customerGUID", uuid.MustParse(report.customerGUID).String())
|
||||
q.Add("contextName", report.clusterName)
|
||||
q.Add("clusterName", report.clusterName) // deprecated
|
||||
q.Add("clusterName", report.clusterName)
|
||||
|
||||
urlObj.RawQuery = q.Encode()
|
||||
|
||||
|
||||
@@ -95,8 +95,6 @@ func NewPrinter(printFormat, formatVersion string, verboseMode bool, viewType ca
|
||||
return printerv2.NewPrometheusPrinter(verboseMode)
|
||||
case printer.PdfFormat:
|
||||
return printerv2.NewPdfPrinter()
|
||||
case printer.HtmlFormat:
|
||||
return printerv2.NewHtmlPrinter()
|
||||
default:
|
||||
return printerv2.NewPrettyPrinter(verboseMode, formatVersion, viewType)
|
||||
}
|
||||
|
||||
1
git2go
1
git2go
Submodule git2go deleted from eae00773cc
150
go.mod
150
go.mod
@@ -1,44 +1,41 @@
|
||||
module github.com/armosec/kubescape/v2
|
||||
|
||||
go 1.18
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/armosec/armoapi-go v0.0.98
|
||||
github.com/armosec/go-git-url v0.0.13
|
||||
github.com/armosec/k8s-interface v0.0.79
|
||||
github.com/armosec/opa-utils v0.0.160
|
||||
github.com/armosec/armoapi-go v0.0.73
|
||||
github.com/armosec/go-git-url v0.0.4
|
||||
github.com/armosec/k8s-interface v0.0.76
|
||||
github.com/armosec/opa-utils v0.0.140
|
||||
github.com/armosec/rbac-utils v0.0.14
|
||||
github.com/armosec/utils-go v0.0.7
|
||||
github.com/armosec/utils-k8s-go v0.0.7
|
||||
github.com/armosec/utils-go v0.0.5
|
||||
github.com/armosec/utils-k8s-go v0.0.6
|
||||
github.com/briandowns/spinner v1.18.1
|
||||
github.com/enescakir/emoji v1.0.0
|
||||
github.com/fatih/color v1.13.0
|
||||
github.com/francoispqt/gojay v1.2.13
|
||||
github.com/go-git/go-git/v5 v5.4.2
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/johnfercher/maroto v0.37.0
|
||||
github.com/libgit2/git2go/v33 v33.0.9
|
||||
github.com/johnfercher/maroto v0.36.1
|
||||
github.com/mattn/go-isatty v0.0.14
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/open-policy-agent/opa v0.42.1
|
||||
github.com/spf13/cobra v1.5.0
|
||||
github.com/stretchr/testify v1.8.0
|
||||
github.com/open-policy-agent/opa v0.39.0
|
||||
github.com/spf13/cobra v1.4.0
|
||||
github.com/stretchr/testify v1.7.1
|
||||
github.com/whilp/git-urls v1.0.0
|
||||
go.uber.org/zap v1.21.0
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3
|
||||
golang.org/x/mod v0.5.1
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
helm.sh/helm/v3 v3.9.0
|
||||
k8s.io/api v0.24.2
|
||||
k8s.io/apimachinery v0.24.2
|
||||
k8s.io/client-go v0.24.2
|
||||
k8s.io/utils v0.0.0-20220706174534-f6158b442e7c
|
||||
k8s.io/api v0.23.5
|
||||
k8s.io/apimachinery v0.23.5
|
||||
k8s.io/client-go v0.23.5
|
||||
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9
|
||||
sigs.k8s.io/yaml v1.3.0
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go/compute v1.7.0 // indirect
|
||||
cloud.google.com/go/container v1.2.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go v66.0.0+incompatible // indirect
|
||||
cloud.google.com/go v0.99.0 // indirect
|
||||
cloud.google.com/go/container v1.0.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go v63.0.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest/autorest v0.11.24 // indirect
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.18 // indirect
|
||||
@@ -49,120 +46,89 @@ require (
|
||||
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
|
||||
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||
github.com/BurntSushi/toml v1.0.0 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.1.1 // indirect
|
||||
github.com/Masterminds/sprig/v3 v3.2.2 // indirect
|
||||
github.com/Microsoft/go-winio v0.5.1 // indirect
|
||||
github.com/OneOfOne/xxhash v1.2.8 // indirect
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 // indirect
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/acomagu/bufpipe v1.0.3 // indirect
|
||||
github.com/agnivade/levenshtein v1.0.1 // indirect
|
||||
github.com/aws/aws-sdk-go v1.44.51 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.16.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.15.13 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.12.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.14 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/eks v1.21.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.11 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.16.9 // indirect
|
||||
github.com/aws/smithy-go v1.12.0 // 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.1 // indirect
|
||||
github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490 // indirect
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.3 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dimchansky/utfbom v1.1.1 // indirect
|
||||
github.com/docker/docker v20.10.17+incompatible // 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/emicklei/go-restful v2.9.5+incompatible // indirect
|
||||
github.com/emirpasic/gods v1.12.0 // indirect
|
||||
github.com/envoyproxy/go-control-plane v0.10.1 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v0.6.2 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/go-git/gcfg v1.5.0 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.3.1 // indirect
|
||||
github.com/go-gota/gota v0.12.0 // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.5 // indirect
|
||||
github.com/go-openapi/swag v0.19.14 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.2.0 // indirect
|
||||
github.com/golang/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/gnostic v0.5.7-v3refs // indirect
|
||||
github.com/google/go-cmp v0.5.8 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.4.0 // indirect
|
||||
github.com/huandu/xstrings v1.3.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/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/jung-kurt/gofpdf v1.16.2 // indirect
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
|
||||
github.com/mailru/easyjson v0.7.6 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.2 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/pquerna/cachecontrol v0.1.0 // indirect
|
||||
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect
|
||||
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58 // indirect
|
||||
github.com/sergi/go-diff v1.1.0 // indirect
|
||||
github.com/shopspring/decimal v1.2.0 // indirect
|
||||
github.com/spf13/cast v1.4.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/vektah/gqlparser/v2 v2.4.5 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.0 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
github.com/yashtewari/glob-intersection v0.1.0 // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0 // indirect
|
||||
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d // indirect
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect
|
||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
|
||||
gonum.org/v1/gonum v0.9.1 // indirect
|
||||
google.golang.org/api v0.84.0 // indirect
|
||||
google.golang.org/api v0.62.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220708155623-50e5f4832e73 // indirect
|
||||
google.golang.org/grpc v1.47.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
|
||||
google.golang.org/grpc v1.45.0 // indirect
|
||||
google.golang.org/protobuf v1.28.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.24.2 // indirect
|
||||
k8s.io/klog/v2 v2.60.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 // indirect
|
||||
sigs.k8s.io/controller-runtime v0.12.3 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
k8s.io/klog/v2 v2.30.0 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect
|
||||
sigs.k8s.io/controller-runtime v0.11.1 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
|
||||
)
|
||||
|
||||
replace github.com/libgit2/git2go/v33 => ./git2go
|
||||
|
||||
@@ -69,7 +69,7 @@ def main():
|
||||
if ArmoAuthServer:
|
||||
ldflags += " -X {}={}".format(AUTH_SERVER_CONST, ArmoAuthServer)
|
||||
|
||||
build_command = ["go", "build", "-tags=static", "-o", ks_file, "-ldflags" ,ldflags]
|
||||
build_command = ["go", "build", "-o", ks_file, "-ldflags" ,ldflags]
|
||||
|
||||
print("Building kubescape and saving here: {}".format(ks_file))
|
||||
print("Build command: {}".format(" ".join(build_command)))
|
||||
|
||||
@@ -99,7 +99,7 @@ spec:
|
||||
fieldPath: metadata.namespace
|
||||
- name: "KS_SKIP_UPDATE_CHECK" # do not check latest version
|
||||
value: "true"
|
||||
- name: KS_ENABLE_HOST_SCANNER # enable host scanner -> https://hub.armosec.io/docs/host-sensor
|
||||
- name: KS_ENABLE_HOST_SCANNER # enable host scanner -> https://hub.armo.cloud/docs/host-sensor
|
||||
value: "true"
|
||||
- name: KS_DOWNLOAD_ARTIFACTS # When set to true the artifacts will be downloaded every scan execution
|
||||
value: "true"
|
||||
|
||||
@@ -1,542 +0,0 @@
|
||||
{
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"target": {
|
||||
"limit": 100,
|
||||
"matchAny": false,
|
||||
"tags": [],
|
||||
"type": "dashboard"
|
||||
},
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"id": 27,
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 13,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 2,
|
||||
"pointSize": 4,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "auto",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 2,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "hidden",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"expr": "kubescape_cluster_riskScore",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Overtime Cluster Risk score",
|
||||
"transparent": true,
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "points",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 4,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": true,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "short"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 8
|
||||
},
|
||||
"id": 7,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "multi",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "8.5.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"expr": "sum (kubescape_control_riskScore) by (name)",
|
||||
"instant": false,
|
||||
"interval": "",
|
||||
"legendFormat": "{{link}}",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Overtime Controls Risk score ",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 0,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "auto",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"__systemRef": "hideSeriesFrom",
|
||||
"matcher": {
|
||||
"id": "byNames",
|
||||
"options": {
|
||||
"mode": "exclude",
|
||||
"names": [
|
||||
"{__name__=\"kubescape_framework_riskScore\", container=\"kubescape\", endpoint=\"http\", instance=\"172.17.0.9:8080\", job=\"armo-kubescape\", name=\"DevOpsBest\", namespace=\"armo-system\", pod=\"armo-kubescape-66555d4db6-wznwg\", service=\"armo-kubescape\"}"
|
||||
],
|
||||
"prefix": "All except:",
|
||||
"readOnly": true
|
||||
}
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "custom.hideFrom",
|
||||
"value": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 8
|
||||
},
|
||||
"id": 5,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"expr": "sum(kubescape_framework_riskScore) by (name)",
|
||||
"hide": false,
|
||||
"instant": true,
|
||||
"legendFormat": "{{name}}",
|
||||
"range": false,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Overtime Frameworks Risk score",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"description": "Number of Resources that failed/passed or excluded",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
}
|
||||
},
|
||||
"mappings": []
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 16
|
||||
},
|
||||
"id": 4,
|
||||
"options": {
|
||||
"displayLabels": [
|
||||
"percent"
|
||||
],
|
||||
"legend": {
|
||||
"displayMode": "list",
|
||||
"placement": "right",
|
||||
"values": []
|
||||
},
|
||||
"pieType": "pie",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "multi",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "8.5.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(kubescape_control_count_resources_passed)",
|
||||
"hide": false,
|
||||
"legendFormat": "passed",
|
||||
"range": true,
|
||||
"refId": "C"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"expr": "sum(kubescape_control_count_resources_failed)",
|
||||
"hide": false,
|
||||
"instant": true,
|
||||
"legendFormat": "failed",
|
||||
"range": false,
|
||||
"refId": "A"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"expr": "sum(kubescape_control_count_resources_exclude)",
|
||||
"hide": false,
|
||||
"instant": false,
|
||||
"legendFormat": "exclude",
|
||||
"range": true,
|
||||
"refId": "B"
|
||||
}
|
||||
],
|
||||
"title": "Resources by Status",
|
||||
"type": "piechart"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"description": "Number of controls that failed/passed or excluded\n",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
}
|
||||
},
|
||||
"mappings": []
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 16
|
||||
},
|
||||
"id": 8,
|
||||
"options": {
|
||||
"displayLabels": [
|
||||
"percent"
|
||||
],
|
||||
"legend": {
|
||||
"displayMode": "list",
|
||||
"placement": "right",
|
||||
"values": []
|
||||
},
|
||||
"pieType": "pie",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "8.5.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"expr": "kubescape_cluster_count_control_failed",
|
||||
"hide": false,
|
||||
"instant": true,
|
||||
"legendFormat": "failed",
|
||||
"range": false,
|
||||
"refId": "A"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"expr": "kubescape_cluster_count_control_exclude",
|
||||
"hide": false,
|
||||
"instant": false,
|
||||
"legendFormat": "exclude",
|
||||
"range": true,
|
||||
"refId": "B"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"expr": "kubescape_cluster_count_control_passed",
|
||||
"hide": false,
|
||||
"instant": false,
|
||||
"legendFormat": "passed",
|
||||
"range": true,
|
||||
"refId": "C"
|
||||
}
|
||||
],
|
||||
"title": "Controls by Status",
|
||||
"type": "piechart"
|
||||
}
|
||||
],
|
||||
"schemaVersion": 36,
|
||||
"style": "dark",
|
||||
"tags": [],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "Kubescape",
|
||||
"uid": "SwdcJornz",
|
||||
"version": 7,
|
||||
"weekStart": ""
|
||||
}
|
||||
@@ -99,7 +99,7 @@ spec:
|
||||
fieldPath: metadata.namespace
|
||||
- name: "KS_SKIP_UPDATE_CHECK" # do not check latest version
|
||||
value: "true"
|
||||
- name: KS_ENABLE_HOST_SCANNER # enable host scanner -> https://hub.armosec.io/docs/host-sensor
|
||||
- name: KS_ENABLE_HOST_SCANNER # enable host scanner -> https://hub.armo.cloud/docs/host-sensor
|
||||
value: "false" # TODO - add permissions to rbac
|
||||
- name: KS_DOWNLOAD_ARTIFACTS # When set to true the artifacts will be downloaded every scan execution
|
||||
value: "false"
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
module github.com/armosec/kubescape/v2/httphandler
|
||||
|
||||
go 1.18
|
||||
go 1.17
|
||||
|
||||
replace github.com/armosec/kubescape/v2 => ../
|
||||
|
||||
require (
|
||||
github.com/armosec/kubescape/v2 v2.0.0-00010101000000-000000000000
|
||||
github.com/armosec/opa-utils v0.0.160
|
||||
github.com/armosec/utils-go v0.0.7
|
||||
github.com/armosec/opa-utils v0.0.140
|
||||
github.com/armosec/utils-go v0.0.5
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/gorilla/schema v1.2.0
|
||||
github.com/stretchr/testify v1.8.0
|
||||
k8s.io/utils v0.0.0-20220706174534-f6158b442e7c
|
||||
github.com/stretchr/testify v1.7.1
|
||||
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go/compute v1.7.0 // indirect
|
||||
cloud.google.com/go/container v1.2.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go v66.0.0+incompatible // indirect
|
||||
cloud.google.com/go v0.99.0 // indirect
|
||||
cloud.google.com/go/container v1.0.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go v63.0.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest/autorest v0.11.24 // indirect
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.18 // indirect
|
||||
@@ -29,143 +29,109 @@ require (
|
||||
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
|
||||
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||
github.com/BurntSushi/toml v1.0.0 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.1.1 // indirect
|
||||
github.com/Masterminds/sprig/v3 v3.2.2 // indirect
|
||||
github.com/Microsoft/go-winio v0.5.1 // indirect
|
||||
github.com/OneOfOne/xxhash v1.2.8 // indirect
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 // indirect
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/acomagu/bufpipe v1.0.3 // indirect
|
||||
github.com/agnivade/levenshtein v1.0.1 // indirect
|
||||
github.com/armosec/armoapi-go v0.0.98 // indirect
|
||||
github.com/armosec/go-git-url v0.0.13 // indirect
|
||||
github.com/armosec/k8s-interface v0.0.79 // indirect
|
||||
github.com/armosec/armoapi-go v0.0.73 // indirect
|
||||
github.com/armosec/go-git-url v0.0.4 // indirect
|
||||
github.com/armosec/k8s-interface v0.0.76 // indirect
|
||||
github.com/armosec/rbac-utils v0.0.14 // indirect
|
||||
github.com/armosec/utils-k8s-go v0.0.7 // indirect
|
||||
github.com/aws/aws-sdk-go v1.44.51 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.16.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.15.13 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.12.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.14 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/eks v1.21.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.11 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.16.9 // indirect
|
||||
github.com/aws/smithy-go v1.12.0 // indirect
|
||||
github.com/armosec/utils-k8s-go v0.0.6 // indirect
|
||||
github.com/aws/aws-sdk-go v1.41.11 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.12.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.12.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.7.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.9.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.1.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/eks v1.17.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.6.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.8.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.13.0 // indirect
|
||||
github.com/aws/smithy-go v1.9.1 // indirect
|
||||
github.com/boombuler/barcode v1.0.1 // indirect
|
||||
github.com/briandowns/spinner v1.18.1 // indirect
|
||||
github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490 // indirect
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.3 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dimchansky/utfbom v1.1.1 // indirect
|
||||
github.com/docker/docker v20.10.17+incompatible // 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/emicklei/go-restful v2.9.5+incompatible // indirect
|
||||
github.com/emirpasic/gods v1.12.0 // indirect
|
||||
github.com/enescakir/emoji v1.0.0 // indirect
|
||||
github.com/envoyproxy/go-control-plane v0.10.1 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v0.6.2 // indirect
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/francoispqt/gojay v1.2.13 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/go-git/gcfg v1.5.0 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.3.1 // indirect
|
||||
github.com/go-git/go-git/v5 v5.4.2 // indirect
|
||||
github.com/go-gota/gota v0.12.0 // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.5 // indirect
|
||||
github.com/go-openapi/swag v0.19.14 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.2.0 // indirect
|
||||
github.com/golang/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/gnostic v0.5.7-v3refs // indirect
|
||||
github.com/google/go-cmp v0.5.8 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.4.0 // indirect
|
||||
github.com/huandu/xstrings v1.3.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/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/johnfercher/maroto v0.37.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/johnfercher/maroto v0.36.1 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/jung-kurt/gofpdf v1.16.2 // indirect
|
||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||
github.com/libgit2/git2go/v33 v33.0.9 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/open-policy-agent/opa v0.42.1 // indirect
|
||||
github.com/open-policy-agent/opa v0.39.0 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.2 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/pquerna/cachecontrol v0.1.0 // indirect
|
||||
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect
|
||||
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58 // indirect
|
||||
github.com/sergi/go-diff v1.1.0 // indirect
|
||||
github.com/shopspring/decimal v1.2.0 // indirect
|
||||
github.com/spf13/cast v1.4.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/vektah/gqlparser/v2 v2.4.5 // indirect
|
||||
github.com/whilp/git-urls v1.0.0 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.0 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
github.com/yashtewari/glob-intersection v0.1.0 // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
go.uber.org/zap v1.21.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0 // indirect
|
||||
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d // indirect
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect
|
||||
golang.org/x/mod v0.5.1 // indirect
|
||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
|
||||
gonum.org/v1/gonum v0.9.1 // indirect
|
||||
google.golang.org/api v0.84.0 // indirect
|
||||
google.golang.org/api v0.62.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220708155623-50e5f4832e73 // indirect
|
||||
google.golang.org/grpc v1.47.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
|
||||
google.golang.org/grpc v1.45.0 // indirect
|
||||
google.golang.org/protobuf v1.28.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
helm.sh/helm/v3 v3.9.0 // indirect
|
||||
k8s.io/api v0.24.2 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.24.2 // indirect
|
||||
k8s.io/apimachinery v0.24.2 // indirect
|
||||
k8s.io/client-go v0.24.2 // indirect
|
||||
k8s.io/klog/v2 v2.60.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 // indirect
|
||||
sigs.k8s.io/controller-runtime v0.12.3 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
k8s.io/api v0.23.5 // indirect
|
||||
k8s.io/apimachinery v0.23.5 // indirect
|
||||
k8s.io/client-go v0.23.5 // indirect
|
||||
k8s.io/klog/v2 v2.30.0 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect
|
||||
sigs.k8s.io/controller-runtime v0.11.1 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
|
||||
sigs.k8s.io/yaml v1.3.0 // indirect
|
||||
)
|
||||
|
||||
replace github.com/libgit2/git2go/v33 => ../git2go
|
||||
|
||||
1071
httphandler/go.sum
1071
httphandler/go.sum
File diff suppressed because it is too large
Load Diff
16
install.sh
16
install.sh
@@ -1,20 +1,9 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
while getopts v: option
|
||||
do
|
||||
case ${option} in
|
||||
v) RELEASE="download/${OPTARG}";;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z ${RELEASE} ]; then
|
||||
RELEASE="latest/download"
|
||||
fi
|
||||
|
||||
echo -e "\033[0;36mInstalling Kubescape..."
|
||||
echo
|
||||
|
||||
|
||||
BASE_DIR=~/.kubescape
|
||||
KUBESCAPE_EXEC=kubescape
|
||||
KUBESCAPE_ZIP=kubescape.zip
|
||||
@@ -31,8 +20,7 @@ fi
|
||||
mkdir -p $BASE_DIR
|
||||
|
||||
OUTPUT=$BASE_DIR/$KUBESCAPE_EXEC
|
||||
DOWNLOAD_URL="https://github.com/armosec/kubescape/releases/${RELEASE}/kubescape-${osName}-latest"
|
||||
|
||||
DOWNLOAD_URL="https://github.com/armosec/kubescape/releases/latest/download/kubescape-${osName}-latest"
|
||||
curl --progress-bar -L $DOWNLOAD_URL -o $OUTPUT
|
||||
|
||||
# Checking if SUDO needed/exists
|
||||
|
||||
Reference in New Issue
Block a user