adding docker build

This commit is contained in:
dwertent
2022-03-14 18:34:34 +02:00
parent f7c0c95d3b
commit 6099f46dea
15 changed files with 211 additions and 46 deletions
+1 -1
View File
@@ -51,7 +51,7 @@ jobs:
ArmoERServer: report.armo.cloud
ArmoWebsite: portal.armo.cloud
CGO_ENABLED: 0
run: python3 --version && python3 build.py
run: cd cmd && python3 --version && python3 build.py
- name: Smoke Testing
env:
+1 -1
View File
@@ -35,7 +35,7 @@ jobs:
ArmoERServer: report.armo.cloud
ArmoWebsite: portal.armo.cloud
CGO_ENABLED: 0
run: python3 --version && python3 build.py
run: cd cmd && python3 --version && python3 build.py
- name: Smoke Testing
env:
+9 -3
View File
@@ -19,8 +19,14 @@ jobs:
with:
go-version: 1.17
- name: Test
run: go test -v ./...
- name: Test cmd pkg
run: cd cmd && go test -v ./...
- name: Test core pkg
run: cd core && go test -v ./...
- name: Test httphandler pkg
run: cd httphandler && go test -v ./...
- name: Build
env:
@@ -30,7 +36,7 @@ jobs:
ArmoERServer: report.armo.cloud
ArmoWebsite: portal.armo.cloud
CGO_ENABLED: 0
run: python3 --version && python3 build.py
run: cd cmd && python3 --version && python3 build.py
- name: Smoke Testing
env:
+2 -1
View File
@@ -17,13 +17,14 @@ RUN pip3 install --no-cache --upgrade pip setuptools
WORKDIR /work
ADD . .
WORKDIR /work/httphandler
RUN python build.py
RUN ls -ltr build/ubuntu-latest
FROM alpine
COPY --from=builder /work/build/ubuntu-latest/kubescape /usr/bin/kubescape
COPY --from=builder /work/httphandler/build/ubuntu-latest/kubescape /usr/bin/kubescape
# # Download the frameworks. Use the "--use-default" flag when running kubescape
# RUN kubescape download framework nsa && kubescape download framework mitre
+2 -2
View File
@@ -18,7 +18,7 @@ def checkStatus(status, msg):
def getBuildDir():
currentPlatform = platform.system()
buildDir = "build/"
buildDir = "../build/"
if currentPlatform == "Windows": buildDir += "windows-latest"
elif currentPlatform == "Linux": buildDir += "ubuntu-latest"
@@ -70,7 +70,7 @@ def main():
ldflags += " -X {}={}".format(WEBSITE_CONST, ArmoWebsite)
if ArmoAuthServer:
ldflags += " -X {}={}".format(AUTH_SERVER_CONST, ArmoAuthServer)
build_command = ["go", "build", "-o", ks_file, "-ldflags" ,ldflags]
print("Building kubescape and saving here: {}".format(ks_file))
+4 -1
View File
@@ -13,7 +13,8 @@ import (
"golang.org/x/mod/semver"
)
const SKIP_VERSION_CHECK = "KUBESCAPE_SKIP_UPDATE_CHECK"
const SKIP_VERSION_CHECK_DEPRECATED = "KUBESCAPE_SKIP_UPDATE_CHECK"
const SKIP_VERSION_CHECK = "KS_SKIP_UPDATE_CHECK"
var BuildNumber string
@@ -29,6 +30,8 @@ func NewIVersionCheckHandler() IVersionCheckHandler {
}
if v, ok := os.LookupEnv(SKIP_VERSION_CHECK); ok && pkgutils.StringToBool(v) {
return NewVersionCheckHandlerMock()
} else if v, ok := os.LookupEnv(SKIP_VERSION_CHECK_DEPRECATED); ok && pkgutils.StringToBool(v) {
return NewVersionCheckHandlerMock()
}
return NewVersionCheckHandler()
}
+13 -14
View File
@@ -5,7 +5,7 @@
Running `kubescape` will start up a webserver on port `8080` which will serve the following paths:
* POST `/v1/scan` - Trigger a kubescape scan. The server will return an ID and will execute the scanning asynchronously
* * `synchronously`: scan synchronously (return results and not ID). Use only in small clusters are with an increased timeout
* * `wait`: scan synchronously (return results and not ID). Use only in small clusters are with an increased timeout
* GET `/v1/results` - Request kubescape scan results
* * query `id=<string>` -> ID returned when triggering the scan action. If empty will return latest results
* * query `remove` -> Remove results from storage after reading the results
@@ -20,15 +20,15 @@ Running `kubescape` will start up a webserver on port `8080` which will serve th
POST /v1/results
body:
```json
```
{
"format": "", // results format [default: json] (same as 'kubescape scan --format')
"excludedNamespaces": null, // list of namespaces to exclude (same as 'kubescape scan --excluded-namespaces')
"includeNamespaces": null, // list of namespaces to include (same as 'kubescape scan --include-namespaces')
"submit": false, // submit results to Kubescape cloud (same as 'kubescape scan --submit')
"hostScanner": false, // deploy kubescape K8s host-scanner DaemonSet in the scanned cluster (same as 'kubescape scan --enable-host-scan')
"keepLocal": false, // do not submit results to Kubescape cloud (same as 'kubescape scan --keep-local')
"account": "" // account ID (same as 'kubescape scan --account')
"format": <str>, // results format [default: json] (same as 'kubescape scan --format')
"excludedNamespaces": <[]str>, // list of namespaces to exclude (same as 'kubescape scan --excluded-namespaces')
"includeNamespaces": <[]str>, // list of namespaces to include (same as 'kubescape scan --include-namespaces')
"submit": <bool>, // submit results to Kubescape cloud (same as 'kubescape scan --submit')
"hostScanner": <bool>, // deploy kubescape K8s host-scanner DaemonSet in the scanned cluster (same as 'kubescape scan --enable-host-scan')
"keepLocal": <bool>, // do not submit results to Kubescape cloud (same as 'kubescape scan --keep-local')
"account": <str> // account ID (same as 'kubescape scan --account')
}
```
@@ -37,11 +37,10 @@ e.g.:
```bash
curl --header "Content-Type: application/json" \
--request POST \
--data '{"account":"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX","hostScanner":true, "submit":true}' \
--data '{"hostScanner":true, "submit":true}' \
http://127.0.0.1:8080/v1/scan
```
## Installation into kubernetes
## Examples
The [yaml](ks-prometheus-support.yaml) file will deploy one instance of kubescape (with all relevant dependencies) to run on your cluster
**NOTE** Make sure the configurations suit your cluster (e.g. `serviceType`, namespace, etc.)
* [Prometheus](examples/prometheus/README.md)
* [Microservice](examples/microservice/README.md)
+92
View File
@@ -0,0 +1,92 @@
import os
import sys
import hashlib
import platform
import subprocess
BASE_GETTER_CONST = "github.com/armosec/kubescape/core/cautils/getter"
BE_SERVER_CONST = BASE_GETTER_CONST + ".ArmoBEURL"
ER_SERVER_CONST = BASE_GETTER_CONST + ".ArmoERURL"
WEBSITE_CONST = BASE_GETTER_CONST + ".ArmoFEURL"
AUTH_SERVER_CONST = BASE_GETTER_CONST + ".armoAUTHURL"
def checkStatus(status, msg):
if status != 0:
sys.stderr.write(msg)
exit(status)
def getBuildDir():
currentPlatform = platform.system()
buildDir = "build/"
if currentPlatform == "Windows": return os.path.join(buildDir, "windows-latest")
if currentPlatform == "Linux": return os.path.join(buildDir, "ubuntu-latest")
if currentPlatform == "Darwin": return os.path.join(buildDir, "macos-latest")
raise OSError("Platform %s is not supported!" % (currentPlatform))
def getPackageName():
packageName = "kubescape"
# if platform.system() == "Windows": packageName += ".exe"
return packageName
def main():
print("Building Kubescape")
# print environment variables
# print(os.environ)
# Set some variables
packageName = getPackageName()
buildUrl = "github.com/armosec/kubescape/core/cautils.BuildNumber"
releaseVersion = os.getenv("RELEASE")
ArmoBEServer = os.getenv("ArmoBEServer")
ArmoERServer = os.getenv("ArmoERServer")
ArmoWebsite = os.getenv("ArmoWebsite")
ArmoAuthServer = os.getenv("ArmoAuthServer")
# Create build directory
buildDir = getBuildDir()
ks_file = os.path.join(buildDir, packageName)
hash_file = ks_file + ".sha256"
if not os.path.isdir(buildDir):
os.makedirs(buildDir)
# Build kubescape
ldflags = "-w -s"
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", "-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)
checkStatus(status, "Failed to build kubescape")
sha256 = hashlib.sha256()
with open(ks_file, "rb") as kube:
sha256.update(kube.read())
with open(hash_file, "w") as kube_sha:
hash = sha256.hexdigest()
print("kubescape hash: {}, file: {}".format(hash, hash_file))
kube_sha.write(sha256.hexdigest())
print("Build Done")
if __name__ == "__main__":
main()
@@ -0,0 +1,20 @@
# Kubescape as a microservice
1. Deploy kubescape microservice
```bash
kubectl apply -f https://raw.githubusercontent.com/armosec/kubescape/master/httphandler/examples/prometheus/kubescape.yaml
```
> **NOTE** Make sure the configurations suit your cluster (e.g. `serviceType`, namespace, etc.)
2. Trigger scan
```bash
curl --header "Content-Type: application/json" \
--request POST \
--data '{"account":"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX","hostScanner":true, "submit":true}' \
http://127.0.0.1:8080/v1/scan
```
3. Get results
```bash
curl --request GET http://127.0.0.1:8080/v1/results -o results.json
```
+19
View File
@@ -0,0 +1,19 @@
# Prometheus Kubescape Integration
1. Deploy kubescape
```bash
kubectl apply -f https://raw.githubusercontent.com/armosec/kubescape/master/httphandler/examples/prometheus/kubescape.yaml
```
> **NOTE** Make sure the configurations suit your cluster (e.g. `serviceType`, etc.)
2. Deploy kube-prometheus-stack
```bash
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack --set prometheus.prometheusSpec.podMonitorSelectorNilUsesHelmValues=false,prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues=false
```
3. Deploy pod monitor
```bash
kubectl apply -f https://raw.githubusercontent.com/armosec/kubescape/master/httphandler/examples/prometheus/kubescape.yaml
```
@@ -51,6 +51,7 @@ spec:
type: NodePort
ports:
- port: 8080
name: http
targetPort: 8080
protocol: TCP
selector:
@@ -76,26 +77,30 @@ spec:
serviceAccountName: kubescape-discovery
containers:
- name: kubescape
# livenessProbe:
# httpGet:
# path: /livez
# port: 8080
# initialDelaySeconds: 3
# periodSeconds: 3
# readinessProbe:
# httpGet:
# path: /readyz
# port: 8080
# initialDelaySeconds: 3
# periodSeconds: 3
image: quay.io/armosec/kubescape:prometheus.v1
livenessProbe:
httpGet:
path: /livez
port: 8080
initialDelaySeconds: 3
periodSeconds: 3
readinessProbe:
httpGet:
path: /readyz
port: 8080
initialDelaySeconds: 3
periodSeconds: 3
image: quay.io/armosec/kubescape:prometheus.v2
env:
- name: KS_RUN_PROMETHEUS_SERVER
value: "true"
- name: KS_DEFAULT_CONFIGMAP_NAMESPACE
value: "ks-scanner"
- name: "KS_SKIP_UPDATE_CHECK" # do not check latest version
value: "true"
- name: KS_ENABLE_HOST_SCANNER # enable host scanner -> https://hub.armo.cloud/docs/host-sensor
value: "true"
ports:
- containerPort: 8080
name: http
protocol: TCP
command:
- kubescape
resources:
@@ -0,0 +1,15 @@
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: kubescape
namespace: ks-scanner
labels:
app: kubescape
spec:
selector:
matchLabels:
app: kubescape
podMetricsEndpoints:
- port: http
interval: 120s
scrapeTimeout: 120s
+6 -5
View File
@@ -50,10 +50,11 @@ func (handler *HTTPHandler) Metrics(w http.ResponseWriter, r *http.Request) {
func getPrometheusDefaultScanCommand(scanID string) *cautils.ScanInfo {
scanInfo := cautils.ScanInfo{}
scanInfo.FrameworkScan = true
scanInfo.ScanAll = true // scan all frameworks
scanInfo.ReportID = scanID // scan ID
scanInfo.HostSensorEnabled.Set(os.Getenv("KS_ENABLE_HOST_SENSOR")) // enable host scanner
scanInfo.FailThreshold = 100 // Do not fail scanning
// scanInfo.Format = "prometheus" // results format
scanInfo.ScanAll = true // scan all frameworks
scanInfo.ReportID = scanID // scan ID
scanInfo.HostSensorEnabled.Set(os.Getenv("KS_ENABLE_HOST_SCANNER")) // enable host scanner
scanInfo.FailThreshold = 100 // Do not fail scanning
scanInfo.Format = "prometheus" // results format
scanInfo.Local = true // Do not publish results to Kubescape SaaS
return &scanInfo
}
@@ -128,7 +128,6 @@ func (handler *HTTPHandler) Results(w http.ResponseWriter, r *http.Request) {
if scanID = r.URL.Query().Get("scanID"); scanID == "" {
scanID = handler.state.getLatestID()
}
logger.L().Info("requesting results", helpers.String("ID", scanID))
if handler.state.isBusy() { // if requested ID is still scanning
if scanID == handler.state.getID() {
@@ -141,6 +140,8 @@ func (handler *HTTPHandler) Results(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
logger.L().Info("requesting results", helpers.String("ID", scanID))
if r.URL.Query().Has("remove") {
defer removeResultsFile(scanID)
}
@@ -152,6 +153,8 @@ func (handler *HTTPHandler) Results(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}
case http.MethodDelete:
logger.L().Info("deleting results", helpers.String("ID", scanID))
if r.URL.Query().Has("all") {
removeResultDirs()
} else {
@@ -11,6 +11,7 @@ import (
func scan(scanRequest *PostScanRequest, scanID string) ([]byte, error) {
scanInfo := getScanCommand(scanRequest, scanID)
ks := core.NewKubescape()
result, err := ks.Scan(scanInfo)
if err != nil {
@@ -34,7 +35,7 @@ func readResultsFile(fileID string) ([]byte, error) {
if fileName := searchFile(fileID); fileName != "" {
return os.ReadFile(fileName)
}
return nil, fmt.Errorf("file not found")
return nil, fmt.Errorf("file %s not found", fileID)
}
func removeResultDirs() {
@@ -59,7 +60,7 @@ func searchFile(fileID string) string {
func findFile(targetDir string, fileName string) (string, error) {
matches, err := filepath.Glob(targetDir + fileName)
matches, err := filepath.Glob(filepath.Join(targetDir, fileName))
if err != nil {
return "", err
}