mirror of
https://github.com/kubescape/kubescape.git
synced 2026-02-14 18:09:55 +00:00
Support yaml input and silent mode print
Support yaml input and silent mode print
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
package armotypes
|
||||
|
||||
import "github.com/golang/glog"
|
||||
|
||||
var IgnoreLabels = []string{AttributeCluster, AttributeNamespace}
|
||||
|
||||
// DigestPortalDesignator - get cluster namespace and labels from designator
|
||||
@@ -12,7 +10,6 @@ func DigestPortalDesignator(designator *PortalDesignator) (string, string, map[s
|
||||
// case DesignatorWlid: TODO
|
||||
// case DesignatorWildWlid: TODO
|
||||
default:
|
||||
glog.Warningf("in 'digestPortalDesignator' designator type: '%v' not yet supported. please contact Armo team", designator.DesignatorType)
|
||||
}
|
||||
return "", "", nil
|
||||
}
|
||||
|
||||
@@ -10,6 +10,16 @@ import (
|
||||
"github.com/mattn/go-isatty"
|
||||
)
|
||||
|
||||
var silent = false
|
||||
|
||||
func SetSilentMode(s bool) {
|
||||
silent = s
|
||||
}
|
||||
|
||||
func IsSilent() bool {
|
||||
return silent
|
||||
}
|
||||
|
||||
var FailureDisplay = color.New(color.Bold, color.FgHiRed).FprintfFunc()
|
||||
var FailureTextDisplay = color.New(color.Faint, color.FgHiRed).FprintfFunc()
|
||||
var InfoDisplay = color.New(color.Bold, color.FgHiYellow).FprintfFunc()
|
||||
@@ -20,19 +30,41 @@ var DescriptionDisplay = color.New(color.Faint, color.FgWhite).FprintfFunc()
|
||||
|
||||
var Spinner *spinner.Spinner
|
||||
|
||||
func ScanStartDisplay() {
|
||||
if IsSilent() {
|
||||
return
|
||||
}
|
||||
InfoDisplay(os.Stdout, "ARMO security scanner starting\n")
|
||||
}
|
||||
|
||||
func SuccessTextDisplay(str string) {
|
||||
if IsSilent() {
|
||||
return
|
||||
}
|
||||
SuccessDisplay(os.Stdout, "[success] ")
|
||||
SimpleDisplay(os.Stdout, fmt.Sprintf("%s\n", str))
|
||||
|
||||
}
|
||||
|
||||
func ErrorDisplay(str string) {
|
||||
if IsSilent() {
|
||||
return
|
||||
}
|
||||
SuccessDisplay(os.Stdout, "[Error] ")
|
||||
SimpleDisplay(os.Stdout, fmt.Sprintf("%s\n", str))
|
||||
|
||||
}
|
||||
|
||||
func ProgressTextDisplay(str string) {
|
||||
if IsSilent() {
|
||||
return
|
||||
}
|
||||
InfoDisplay(os.Stdout, "[progress] ")
|
||||
SimpleDisplay(os.Stdout, fmt.Sprintf("%s\n", str))
|
||||
|
||||
}
|
||||
func StartSpinner() {
|
||||
if isatty.IsTerminal(os.Stdout.Fd()) {
|
||||
if !IsSilent() && isatty.IsTerminal(os.Stdout.Fd()) {
|
||||
Spinner = spinner.New(spinner.CharSets[7], 100*time.Millisecond) // Build our new spinner
|
||||
Spinner.Start()
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package k8sinterface
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"kube-escape/cautils/apis"
|
||||
|
||||
@@ -15,9 +14,16 @@ import (
|
||||
type IWorkload interface {
|
||||
IBasicWorkload
|
||||
|
||||
// Convert
|
||||
ToUnstructured() (*unstructured.Unstructured, error)
|
||||
ToString() string
|
||||
Json() string // DEPRECATED
|
||||
|
||||
// GET
|
||||
GetWlid() string
|
||||
GetJobID() *apis.JobTracking
|
||||
GetVersion() string
|
||||
GetGroup() string
|
||||
|
||||
// SET
|
||||
SetWlid(string)
|
||||
@@ -27,6 +33,7 @@ type IWorkload interface {
|
||||
SetJobID(apis.JobTracking)
|
||||
SetCompatible()
|
||||
SetIncompatible()
|
||||
SetReplaceheaders()
|
||||
|
||||
// EXIST
|
||||
IsIgnore() bool
|
||||
@@ -37,6 +44,7 @@ type IWorkload interface {
|
||||
|
||||
// REMOVE
|
||||
RemoveWlid()
|
||||
RemoveSecretData()
|
||||
RemoveInject()
|
||||
RemoveIgnore()
|
||||
RemoveUpdateTime()
|
||||
@@ -62,8 +70,8 @@ type IBasicWorkload interface {
|
||||
GetGenerateName() string
|
||||
GetApiVersion() string
|
||||
GetKind() string
|
||||
GetInnerAnnotation() (string, bool)
|
||||
GetPodAnnotation() (string, bool)
|
||||
GetInnerAnnotation(string) (string, bool)
|
||||
GetPodAnnotation(string) (string, bool)
|
||||
GetAnnotation(string) (string, bool)
|
||||
GetLabel(string) (string, bool)
|
||||
GetAnnotations() map[string]string
|
||||
@@ -72,16 +80,17 @@ type IBasicWorkload interface {
|
||||
GetLabels() map[string]string
|
||||
GetInnerLabels() map[string]string
|
||||
GetPodLabels() map[string]string
|
||||
GetJobLabels() map[string]string
|
||||
GetVolumes() []corev1.Volume
|
||||
GetContainers() []corev1.Container
|
||||
GetInitContainers() []corev1.Container
|
||||
GetVolumes() ([]corev1.Volume, error)
|
||||
GetReplicas() int
|
||||
GetContainers() ([]corev1.Container, error)
|
||||
GetInitContainers() ([]corev1.Container, error)
|
||||
GetOwnerReferences() ([]metav1.OwnerReference, error)
|
||||
GetImagePullSecret() ([]corev1.LocalObjectReference, error)
|
||||
GetServiceAccountName() string
|
||||
GetSelector() (*metav1.LabelSelector, error)
|
||||
GetResourceVersion() string
|
||||
GetUID() string
|
||||
GetPodSpec() (*corev1.PodSpec, error)
|
||||
|
||||
GetWorkload() map[string]interface{}
|
||||
|
||||
@@ -115,14 +124,17 @@ func NewWorkloadObj(workload map[string]interface{}) *Workload {
|
||||
}
|
||||
|
||||
func (w *Workload) Json() string {
|
||||
if w.workload == nil {
|
||||
return w.ToString()
|
||||
}
|
||||
func (w *Workload) ToString() string {
|
||||
if w.GetWorkload() == nil {
|
||||
return ""
|
||||
}
|
||||
bWorkload, err := json.Marshal(w.workload)
|
||||
bWorkload, err := json.Marshal(w.GetWorkload())
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
return fmt.Sprintf("%s", bWorkload)
|
||||
return string(bWorkload)
|
||||
}
|
||||
|
||||
func (workload *Workload) DeepCopy(w map[string]interface{}) {
|
||||
|
||||
@@ -117,6 +117,10 @@ func (w *Workload) RemoveUpdateTime() {
|
||||
w.RemoveAnnotation(cautils.CAUpdate) // DEPRECATED
|
||||
w.RemoveAnnotation(cautils.ArmoUpdate)
|
||||
}
|
||||
func (w *Workload) RemoveSecretData() {
|
||||
w.RemoveAnnotation("kubectl.kubernetes.io/last-applied-configuration")
|
||||
delete(w.workload, "data")
|
||||
}
|
||||
|
||||
func (w *Workload) RemovePodStatus() {
|
||||
delete(w.workload, "status")
|
||||
@@ -268,6 +272,26 @@ func (w *Workload) GetApiVersion() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (w *Workload) GetVersion() string {
|
||||
apiVersion := w.GetApiVersion()
|
||||
splitted := strings.Split(apiVersion, "/")
|
||||
if len(splitted) == 1 {
|
||||
return splitted[0]
|
||||
} else if len(splitted) == 2 {
|
||||
return splitted[1]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (w *Workload) GetGroup() string {
|
||||
apiVersion := w.GetApiVersion()
|
||||
splitted := strings.Split(apiVersion, "/")
|
||||
if len(splitted) == 2 {
|
||||
return splitted[0]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (w *Workload) GetGenerateName() string {
|
||||
if v, ok := InspectWorkload(w.workload, "metadata", "generateName"); ok {
|
||||
return v.(string)
|
||||
@@ -275,6 +299,16 @@ func (w *Workload) GetGenerateName() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (w *Workload) GetReplicas() int {
|
||||
if v, ok := InspectWorkload(w.workload, "spec", "replicas"); ok {
|
||||
replicas, isok := v.(float64)
|
||||
if isok {
|
||||
return int(replicas)
|
||||
}
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
func (w *Workload) GetKind() string {
|
||||
if v, ok := InspectWorkload(w.workload, "kind"); ok {
|
||||
return v.(string)
|
||||
@@ -453,7 +487,7 @@ func (w *Workload) GetContainers() ([]corev1.Container, error) {
|
||||
return containers, err
|
||||
}
|
||||
|
||||
// GetContainers -
|
||||
// GetInitContainers -
|
||||
func (w *Workload) GetInitContainers() ([]corev1.Container, error) {
|
||||
containers := []corev1.Container{}
|
||||
|
||||
@@ -606,52 +640,3 @@ func InspectWorkload(workload interface{}, scopes ...string) (val interface{}, k
|
||||
return val, k
|
||||
|
||||
}
|
||||
|
||||
// // InspectWorkload -
|
||||
// func InjectWorkload(workload interface{}, scopes []string, val string) {
|
||||
|
||||
// if len(scopes) == 0 {
|
||||
|
||||
// }
|
||||
// if data, ok := workload.(map[string]interface{}); ok {
|
||||
// InjectWorkload(data[scopes[0]], scopes[1:], val)
|
||||
// } else {
|
||||
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
// InjectWorkload -
|
||||
// func InjectWorkload(workload interface{}, scopes []string, val string) {
|
||||
|
||||
// if len(scopes) == 0 {
|
||||
// workload = ""
|
||||
// }
|
||||
// if data, ok := workload.(map[string]interface{}); ok {
|
||||
// d := InjectWorkload(data[scopes[0]], scopes[1:], val)
|
||||
// data[scopes[0]] = d
|
||||
// return data
|
||||
// } else {
|
||||
|
||||
// }
|
||||
|
||||
// }
|
||||
// func (w *Workload) SetNamespace(ns string) {
|
||||
|
||||
// if v, k := w.workload["metadata"]; k {
|
||||
// if vv, kk := v.(map[string]interface{}); kk {
|
||||
// vv["namespace"] = ""
|
||||
// // if v3, k3 := w.workload["namespace"]; k3 {
|
||||
// // if v4, k4 := v.(map[string]interface{}); kk {
|
||||
|
||||
// // }
|
||||
// // }
|
||||
// v = vv
|
||||
// }
|
||||
// w.workload = v
|
||||
// }
|
||||
// // if data, ok := w.workload.(map[string]interface{}); ok {
|
||||
// // val, k = InspectWorkload(data[scopes[0]], scopes[1:]...)
|
||||
// // }
|
||||
|
||||
// }
|
||||
|
||||
@@ -150,9 +150,9 @@ type PolicyIdentifier struct {
|
||||
}
|
||||
|
||||
type ScanInfo struct {
|
||||
PolicyIdentifier PolicyIdentifier `json:"policyIdentifier"`
|
||||
Output string `json:"output"`
|
||||
ExcludedNamespaces string `json:"excludedNamespaces"`
|
||||
Input []string `json:"input"`
|
||||
Silent bool `json:"silent"`
|
||||
PolicyIdentifier PolicyIdentifier
|
||||
Output string
|
||||
ExcludedNamespaces string
|
||||
InputPatterns []string
|
||||
Silent bool
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"kube-escape/cautils"
|
||||
@@ -18,6 +19,8 @@ import (
|
||||
)
|
||||
|
||||
var scanInfo opapolicy.ScanInfo
|
||||
var supportedFrameworks = []string{"nsa", "mitre"}
|
||||
var isSilent bool
|
||||
|
||||
type CLIHandler struct {
|
||||
policyHandler *policyhandler.PolicyHandler
|
||||
@@ -42,22 +45,22 @@ var frameworkCmd = &cobra.Command{
|
||||
scanInfo.PolicyIdentifier = opapolicy.PolicyIdentifier{}
|
||||
scanInfo.PolicyIdentifier.Kind = opapolicy.KindFramework
|
||||
scanInfo.PolicyIdentifier.Name = args[0]
|
||||
scanInfo.Input = args[1:]
|
||||
scanInfo.InputPatterns = args[1:]
|
||||
cautils.SetSilentMode(scanInfo.Silent)
|
||||
CliSetup()
|
||||
},
|
||||
}
|
||||
|
||||
func isValidFramework(framework string) bool {
|
||||
return framework == "nsa" || framework != "mitre"
|
||||
return cautils.StringInSlice(supportedFrameworks, framework) != cautils.ValueNotFound
|
||||
}
|
||||
|
||||
func init() {
|
||||
scanCmd.AddCommand(frameworkCmd)
|
||||
scanInfo = opapolicy.ScanInfo{}
|
||||
frameworkCmd.Flags().StringVarP(&scanInfo.ExcludedNamespaces, "excluded-namespaces", "e", "", "namespaces to exclude from check")
|
||||
frameworkCmd.Flags().StringVarP(&scanInfo.ExcludedNamespaces, "exclude-namespaces", "e", "", "namespaces to exclude from check")
|
||||
frameworkCmd.Flags().StringVarP(&scanInfo.Output, "output", "o", "pretty-printer", "output format")
|
||||
frameworkCmd.Flags().BoolVarP(&scanInfo.Silent, "silent", "s", false, "silent output")
|
||||
|
||||
}
|
||||
|
||||
func processYamlInput(yamls string) {
|
||||
@@ -106,20 +109,19 @@ func NewCLIHandler(policyHandler *policyhandler.PolicyHandler) *CLIHandler {
|
||||
}
|
||||
|
||||
func (clihandler *CLIHandler) Scan() error {
|
||||
cautils.InfoDisplay(os.Stdout, "ARMO security scanner starting\n")
|
||||
|
||||
cautils.ScanStartDisplay()
|
||||
policyNotification := &opapolicy.PolicyNotification{
|
||||
NotificationType: opapolicy.TypeExecPostureScan,
|
||||
Rules: []opapolicy.PolicyIdentifier{
|
||||
*&clihandler.scanInfo.PolicyIdentifier,
|
||||
clihandler.scanInfo.PolicyIdentifier,
|
||||
},
|
||||
Designators: armotypes.PortalDesignator{},
|
||||
}
|
||||
|
||||
flag.Parse()
|
||||
switch policyNotification.NotificationType {
|
||||
case opapolicy.TypeExecPostureScan:
|
||||
go func() {
|
||||
if err := clihandler.policyHandler.HandleNotificationRequest(policyNotification, scanInfo.ExcludedNamespaces); err != nil {
|
||||
if err := clihandler.policyHandler.HandleNotificationRequest(policyNotification, clihandler.scanInfo); err != nil {
|
||||
fmt.Printf("%v\n", err)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
5
examples/example.sh
Normal file
5
examples/example.sh
Normal file
@@ -0,0 +1,5 @@
|
||||
#! /bin/bash
|
||||
|
||||
echo "Testing Online Boutique yamls (https://github.com/GoogleCloudPlatform/microservices-demo)"
|
||||
|
||||
kubescape scan framework nsa online-boutique/*
|
||||
8
examples/online-boutique/README.md
Normal file
8
examples/online-boutique/README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# ./kubernetes-manifests
|
||||
|
||||
:warning: Kubernetes manifests provided in this directory are not directly
|
||||
deployable to a cluster. They are meant to be used with `skaffold` command to
|
||||
insert the correct `image:` tags.
|
||||
|
||||
Use the manifests in [/release](/release) directory which are configured with
|
||||
pre-built public images.
|
||||
73
examples/online-boutique/adservice.yaml
Normal file
73
examples/online-boutique/adservice.yaml
Normal file
@@ -0,0 +1,73 @@
|
||||
# Copyright 2018 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: adservice
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: adservice
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: adservice
|
||||
spec:
|
||||
serviceAccountName: default
|
||||
terminationGracePeriodSeconds: 5
|
||||
containers:
|
||||
- name: server
|
||||
image: adservice
|
||||
ports:
|
||||
- containerPort: 9555
|
||||
env:
|
||||
- name: PORT
|
||||
value: "9555"
|
||||
# - name: DISABLE_STATS
|
||||
# value: "1"
|
||||
# - name: DISABLE_TRACING
|
||||
# value: "1"
|
||||
#- name: JAEGER_SERVICE_ADDR
|
||||
# value: "jaeger-collector:14268"
|
||||
resources:
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 180Mi
|
||||
limits:
|
||||
cpu: 300m
|
||||
memory: 300Mi
|
||||
readinessProbe:
|
||||
initialDelaySeconds: 20
|
||||
periodSeconds: 15
|
||||
exec:
|
||||
command: ["/bin/grpc_health_probe", "-addr=:9555"]
|
||||
livenessProbe:
|
||||
initialDelaySeconds: 20
|
||||
periodSeconds: 15
|
||||
exec:
|
||||
command: ["/bin/grpc_health_probe", "-addr=:9555"]
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: adservice
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: adservice
|
||||
ports:
|
||||
- name: grpc
|
||||
port: 9555
|
||||
targetPort: 9555
|
||||
59
examples/online-boutique/bi-monitor.yaml
Normal file
59
examples/online-boutique/bi-monitor.yaml
Normal file
@@ -0,0 +1,59 @@
|
||||
apiVersion: v1
|
||||
data:
|
||||
customer: Q3liZXJBcm1vclRlc3Rz
|
||||
password: bml1ZGhmMjgzcnUyM3JrZQ==
|
||||
username: ZHdlcnRlbnRAY3liZXJhcm1vci5pbw==
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: bi-monitor-secret
|
||||
type: Opaque
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: bi-monitor
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: bi-monitor
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
targetPort: 80
|
||||
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: bi-monitor
|
||||
labels:
|
||||
app: bi-monitor
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: bi-monitor
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: bi-monitor
|
||||
spec:
|
||||
containers:
|
||||
- name: monitor
|
||||
image: quay.io/armosec/demoservice:v1-debian
|
||||
env:
|
||||
- name: THREAD_TIMEOUT
|
||||
value: "10"
|
||||
- name: SLEEP_DURATION
|
||||
value: "1"
|
||||
- name: DEMO_TARGETS
|
||||
value: "http://frontend:80 https://cisco.com"
|
||||
- name: CAA_SIGNATURE_DEBUG_DEEP
|
||||
volumeMounts:
|
||||
- name: bi-monitor-secret
|
||||
mountPath: /etc/secrets
|
||||
volumes:
|
||||
- name: bi-monitor-secret
|
||||
secret:
|
||||
secretName: bi-monitor-secret
|
||||
66
examples/online-boutique/cartservice.yaml
Normal file
66
examples/online-boutique/cartservice.yaml
Normal file
@@ -0,0 +1,66 @@
|
||||
# Copyright 2018 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: cartservice
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: cartservice
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: cartservice
|
||||
spec:
|
||||
serviceAccountName: default
|
||||
terminationGracePeriodSeconds: 5
|
||||
containers:
|
||||
- name: server
|
||||
image: cartservice
|
||||
ports:
|
||||
- containerPort: 7070
|
||||
env:
|
||||
- name: REDIS_ADDR
|
||||
value: "redis-cart:6379"
|
||||
resources:
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 64Mi
|
||||
limits:
|
||||
cpu: 300m
|
||||
memory: 128Mi
|
||||
readinessProbe:
|
||||
initialDelaySeconds: 15
|
||||
exec:
|
||||
command: ["/bin/grpc_health_probe", "-addr=:7070", "-rpc-timeout=5s"]
|
||||
livenessProbe:
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 10
|
||||
exec:
|
||||
command: ["/bin/grpc_health_probe", "-addr=:7070", "-rpc-timeout=5s"]
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: cartservice
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: cartservice
|
||||
ports:
|
||||
- name: grpc
|
||||
port: 7070
|
||||
targetPort: 7070
|
||||
82
examples/online-boutique/checkoutservice.yaml
Normal file
82
examples/online-boutique/checkoutservice.yaml
Normal file
@@ -0,0 +1,82 @@
|
||||
# Copyright 2018 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: checkoutservice
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: checkoutservice
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: checkoutservice
|
||||
spec:
|
||||
serviceAccountName: default
|
||||
containers:
|
||||
- name: server
|
||||
image: checkoutservice
|
||||
ports:
|
||||
- containerPort: 5050
|
||||
readinessProbe:
|
||||
exec:
|
||||
command: ["/bin/grpc_health_probe", "-addr=:5050"]
|
||||
livenessProbe:
|
||||
exec:
|
||||
command: ["/bin/grpc_health_probe", "-addr=:5050"]
|
||||
env:
|
||||
- name: PORT
|
||||
value: "5050"
|
||||
- name: PRODUCT_CATALOG_SERVICE_ADDR
|
||||
value: "productcatalogservice:3550"
|
||||
- name: SHIPPING_SERVICE_ADDR
|
||||
value: "shippingservice:50051"
|
||||
- name: PAYMENT_SERVICE_ADDR
|
||||
value: "paymentservice:50051"
|
||||
- name: EMAIL_SERVICE_ADDR
|
||||
value: "emailservice:5000"
|
||||
- name: CURRENCY_SERVICE_ADDR
|
||||
value: "currencyservice:7000"
|
||||
- name: CART_SERVICE_ADDR
|
||||
value: "cartservice:7070"
|
||||
# - name: DISABLE_STATS
|
||||
# value: "1"
|
||||
# - name: DISABLE_TRACING
|
||||
# value: "1"
|
||||
# - name: DISABLE_PROFILER
|
||||
# value: "1"
|
||||
# - name: JAEGER_SERVICE_ADDR
|
||||
# value: "jaeger-collector:14268"
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 64Mi
|
||||
limits:
|
||||
cpu: 200m
|
||||
memory: 128Mi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: checkoutservice
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: checkoutservice
|
||||
ports:
|
||||
- name: grpc
|
||||
port: 5050
|
||||
targetPort: 5050
|
||||
70
examples/online-boutique/currencyservice.yaml
Normal file
70
examples/online-boutique/currencyservice.yaml
Normal file
@@ -0,0 +1,70 @@
|
||||
# Copyright 2018 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: currencyservice
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: currencyservice
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: currencyservice
|
||||
spec:
|
||||
serviceAccountName: default
|
||||
terminationGracePeriodSeconds: 5
|
||||
containers:
|
||||
- name: server
|
||||
image: currencyservice
|
||||
ports:
|
||||
- name: grpc
|
||||
containerPort: 7000
|
||||
env:
|
||||
- name: PORT
|
||||
value: "7000"
|
||||
# - name: DISABLE_TRACING
|
||||
# value: "1"
|
||||
# - name: DISABLE_PROFILER
|
||||
# value: "1"
|
||||
# - name: DISABLE_DEBUGGER
|
||||
# value: "1"
|
||||
readinessProbe:
|
||||
exec:
|
||||
command: ["/bin/grpc_health_probe", "-addr=:7000"]
|
||||
livenessProbe:
|
||||
exec:
|
||||
command: ["/bin/grpc_health_probe", "-addr=:7000"]
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 64Mi
|
||||
limits:
|
||||
cpu: 200m
|
||||
memory: 128Mi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: currencyservice
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: currencyservice
|
||||
ports:
|
||||
- name: grpc
|
||||
port: 7000
|
||||
targetPort: 7000
|
||||
69
examples/online-boutique/emailservice.yaml
Normal file
69
examples/online-boutique/emailservice.yaml
Normal file
@@ -0,0 +1,69 @@
|
||||
# Copyright 2018 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: emailservice
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: emailservice
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: emailservice
|
||||
spec:
|
||||
serviceAccountName: default
|
||||
terminationGracePeriodSeconds: 5
|
||||
containers:
|
||||
- name: server
|
||||
image: emailservice
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
env:
|
||||
- name: PORT
|
||||
value: "8080"
|
||||
# - name: DISABLE_TRACING
|
||||
# value: "1"
|
||||
- name: DISABLE_PROFILER
|
||||
value: "1"
|
||||
readinessProbe:
|
||||
periodSeconds: 5
|
||||
exec:
|
||||
command: ["/bin/grpc_health_probe", "-addr=:8080"]
|
||||
livenessProbe:
|
||||
periodSeconds: 5
|
||||
exec:
|
||||
command: ["/bin/grpc_health_probe", "-addr=:8080"]
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 64Mi
|
||||
limits:
|
||||
cpu: 200m
|
||||
memory: 128Mi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: emailservice
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: emailservice
|
||||
ports:
|
||||
- name: grpc
|
||||
port: 5000
|
||||
targetPort: 8080
|
||||
109
examples/online-boutique/frontend.yaml
Normal file
109
examples/online-boutique/frontend.yaml
Normal file
@@ -0,0 +1,109 @@
|
||||
# Copyright 2018 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: frontend
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: frontend
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: frontend
|
||||
annotations:
|
||||
sidecar.istio.io/rewriteAppHTTPProbers: "true"
|
||||
spec:
|
||||
serviceAccountName: default
|
||||
containers:
|
||||
- name: server
|
||||
image: frontend
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
readinessProbe:
|
||||
initialDelaySeconds: 10
|
||||
httpGet:
|
||||
path: "/_healthz"
|
||||
port: 8080
|
||||
httpHeaders:
|
||||
- name: "Cookie"
|
||||
value: "shop_session-id=x-readiness-probe"
|
||||
livenessProbe:
|
||||
initialDelaySeconds: 10
|
||||
httpGet:
|
||||
path: "/_healthz"
|
||||
port: 8080
|
||||
httpHeaders:
|
||||
- name: "Cookie"
|
||||
value: "shop_session-id=x-liveness-probe"
|
||||
env:
|
||||
- name: PORT
|
||||
value: "8080"
|
||||
- name: PRODUCT_CATALOG_SERVICE_ADDR
|
||||
value: "productcatalogservice:3550"
|
||||
- name: CURRENCY_SERVICE_ADDR
|
||||
value: "currencyservice:7000"
|
||||
- name: CART_SERVICE_ADDR
|
||||
value: "cartservice:7070"
|
||||
- name: RECOMMENDATION_SERVICE_ADDR
|
||||
value: "recommendationservice:8080"
|
||||
- name: SHIPPING_SERVICE_ADDR
|
||||
value: "shippingservice:50051"
|
||||
- name: CHECKOUT_SERVICE_ADDR
|
||||
value: "checkoutservice:5050"
|
||||
- name: AD_SERVICE_ADDR
|
||||
value: "adservice:9555"
|
||||
- name: ENV_PLATFORM
|
||||
value: "gcp"
|
||||
# - name: DISABLE_TRACING
|
||||
# value: "1"
|
||||
# - name: DISABLE_PROFILER
|
||||
# value: "1"
|
||||
# - name: JAEGER_SERVICE_ADDR
|
||||
# value: "jaeger-collector:14268"
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 64Mi
|
||||
limits:
|
||||
cpu: 200m
|
||||
memory: 128Mi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: frontend
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: frontend
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
targetPort: 8080
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: frontend-external
|
||||
spec:
|
||||
type: LoadBalancer
|
||||
selector:
|
||||
app: frontend
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
targetPort: 8080
|
||||
47
examples/online-boutique/loadgenerator.yaml
Normal file
47
examples/online-boutique/loadgenerator.yaml
Normal file
@@ -0,0 +1,47 @@
|
||||
# Copyright 2018 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: loadgenerator
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: loadgenerator
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: loadgenerator
|
||||
annotations:
|
||||
sidecar.istio.io/rewriteAppHTTPProbers: "true"
|
||||
spec:
|
||||
serviceAccountName: default
|
||||
terminationGracePeriodSeconds: 5
|
||||
restartPolicy: Always
|
||||
containers:
|
||||
- name: main
|
||||
image: loadgenerator
|
||||
env:
|
||||
- name: FRONTEND_ADDR
|
||||
value: "frontend:80"
|
||||
- name: USERS
|
||||
value: "10"
|
||||
resources:
|
||||
requests:
|
||||
cpu: 300m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
63
examples/online-boutique/paymentservice.yaml
Normal file
63
examples/online-boutique/paymentservice.yaml
Normal file
@@ -0,0 +1,63 @@
|
||||
# Copyright 2018 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: paymentservice
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: paymentservice
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: paymentservice
|
||||
spec:
|
||||
serviceAccountName: default
|
||||
terminationGracePeriodSeconds: 5
|
||||
containers:
|
||||
- name: server
|
||||
image: paymentservice
|
||||
ports:
|
||||
- containerPort: 50051
|
||||
env:
|
||||
- name: PORT
|
||||
value: "50051"
|
||||
readinessProbe:
|
||||
exec:
|
||||
command: ["/bin/grpc_health_probe", "-addr=:50051"]
|
||||
livenessProbe:
|
||||
exec:
|
||||
command: ["/bin/grpc_health_probe", "-addr=:50051"]
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 64Mi
|
||||
limits:
|
||||
cpu: 200m
|
||||
memory: 128Mi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: paymentservice
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: paymentservice
|
||||
ports:
|
||||
- name: grpc
|
||||
port: 50051
|
||||
targetPort: 50051
|
||||
71
examples/online-boutique/productcatalogservice.yaml
Normal file
71
examples/online-boutique/productcatalogservice.yaml
Normal file
@@ -0,0 +1,71 @@
|
||||
# Copyright 2018 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: productcatalogservice
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: productcatalogservice
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: productcatalogservice
|
||||
spec:
|
||||
serviceAccountName: default
|
||||
terminationGracePeriodSeconds: 5
|
||||
containers:
|
||||
- name: server
|
||||
image: productcatalogservice
|
||||
ports:
|
||||
- containerPort: 3550
|
||||
env:
|
||||
- name: PORT
|
||||
value: "3550"
|
||||
# - name: DISABLE_STATS
|
||||
# value: "1"
|
||||
# - name: DISABLE_TRACING
|
||||
# value: "1"
|
||||
# - name: DISABLE_PROFILER
|
||||
# value: "1"
|
||||
# - name: JAEGER_SERVICE_ADDR
|
||||
# value: "jaeger-collector:14268"
|
||||
readinessProbe:
|
||||
exec:
|
||||
command: ["/bin/grpc_health_probe", "-addr=:3550"]
|
||||
livenessProbe:
|
||||
exec:
|
||||
command: ["/bin/grpc_health_probe", "-addr=:3550"]
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 64Mi
|
||||
limits:
|
||||
cpu: 200m
|
||||
memory: 128Mi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: productcatalogservice
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: productcatalogservice
|
||||
ports:
|
||||
- name: grpc
|
||||
port: 3550
|
||||
targetPort: 3550
|
||||
73
examples/online-boutique/recommendationservice.yaml
Normal file
73
examples/online-boutique/recommendationservice.yaml
Normal file
@@ -0,0 +1,73 @@
|
||||
# Copyright 2018 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: recommendationservice
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: recommendationservice
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: recommendationservice
|
||||
spec:
|
||||
serviceAccountName: default
|
||||
terminationGracePeriodSeconds: 5
|
||||
containers:
|
||||
- name: server
|
||||
image: recommendationservice
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
readinessProbe:
|
||||
periodSeconds: 5
|
||||
exec:
|
||||
command: ["/bin/grpc_health_probe", "-addr=:8080"]
|
||||
livenessProbe:
|
||||
periodSeconds: 5
|
||||
exec:
|
||||
command: ["/bin/grpc_health_probe", "-addr=:8080"]
|
||||
env:
|
||||
- name: PORT
|
||||
value: "8080"
|
||||
- name: PRODUCT_CATALOG_SERVICE_ADDR
|
||||
value: "productcatalogservice:3550"
|
||||
# - name: DISABLE_TRACING
|
||||
# value: "1"
|
||||
# - name: DISABLE_PROFILER
|
||||
# value: "1"
|
||||
# - name: DISABLE_DEBUGGER
|
||||
# value: "1"
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 220Mi
|
||||
limits:
|
||||
cpu: 200m
|
||||
memory: 450Mi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: recommendationservice
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: recommendationservice
|
||||
ports:
|
||||
- name: grpc
|
||||
port: 8080
|
||||
targetPort: 8080
|
||||
66
examples/online-boutique/redis.yaml
Normal file
66
examples/online-boutique/redis.yaml
Normal file
@@ -0,0 +1,66 @@
|
||||
# Copyright 2018 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: redis-cart
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: redis-cart
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: redis-cart
|
||||
spec:
|
||||
containers:
|
||||
- name: redis
|
||||
image: redis:alpine
|
||||
ports:
|
||||
- containerPort: 6379
|
||||
readinessProbe:
|
||||
periodSeconds: 5
|
||||
tcpSocket:
|
||||
port: 6379
|
||||
livenessProbe:
|
||||
periodSeconds: 5
|
||||
tcpSocket:
|
||||
port: 6379
|
||||
volumeMounts:
|
||||
- mountPath: /data
|
||||
name: redis-data
|
||||
resources:
|
||||
limits:
|
||||
memory: 256Mi
|
||||
cpu: 125m
|
||||
requests:
|
||||
cpu: 70m
|
||||
memory: 200Mi
|
||||
volumes:
|
||||
- name: redis-data
|
||||
emptyDir: {}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: redis-cart
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: redis-cart
|
||||
ports:
|
||||
- name: redis
|
||||
port: 6379
|
||||
targetPort: 6379
|
||||
71
examples/online-boutique/shippingservice.yaml
Normal file
71
examples/online-boutique/shippingservice.yaml
Normal file
@@ -0,0 +1,71 @@
|
||||
# Copyright 2018 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: shippingservice
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: shippingservice
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: shippingservice
|
||||
spec:
|
||||
serviceAccountName: default
|
||||
containers:
|
||||
- name: server
|
||||
image: shippingservice
|
||||
ports:
|
||||
- containerPort: 50051
|
||||
env:
|
||||
- name: PORT
|
||||
value: "50051"
|
||||
# - name: DISABLE_STATS
|
||||
# value: "1"
|
||||
# - name: DISABLE_TRACING
|
||||
# value: "1"
|
||||
# - name: DISABLE_PROFILER
|
||||
# value: "1"
|
||||
# - name: JAEGER_SERVICE_ADDR
|
||||
# value: "jaeger-collector:14268"
|
||||
readinessProbe:
|
||||
periodSeconds: 5
|
||||
exec:
|
||||
command: ["/bin/grpc_health_probe", "-addr=:50051"]
|
||||
livenessProbe:
|
||||
exec:
|
||||
command: ["/bin/grpc_health_probe", "-addr=:50051"]
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 64Mi
|
||||
limits:
|
||||
cpu: 200m
|
||||
memory: 128Mi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: shippingservice
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: shippingservice
|
||||
ports:
|
||||
- name: grpc
|
||||
port: 50051
|
||||
targetPort: 50051
|
||||
18
go.mod
18
go.mod
@@ -3,7 +3,7 @@ module kube-escape
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/aws/aws-sdk-go v1.40.20
|
||||
github.com/aws/aws-sdk-go v1.40.30
|
||||
github.com/briandowns/spinner v1.16.0
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible
|
||||
github.com/docker/docker v20.10.8+incompatible
|
||||
@@ -12,23 +12,19 @@ require (
|
||||
github.com/enescakir/emoji v1.0.0
|
||||
github.com/fatih/color v1.12.0
|
||||
github.com/francoispqt/gojay v1.2.13
|
||||
github.com/fsnotify/fsnotify v1.5.0 // indirect
|
||||
github.com/gofrs/uuid v4.0.0+incompatible
|
||||
github.com/golang/glog v0.0.0-20210429001901-424d2337a529
|
||||
github.com/golang/glog v1.0.0
|
||||
github.com/mattn/go-isatty v0.0.13
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/open-policy-agent/opa v0.31.0
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.1 // indirect
|
||||
github.com/pquerna/cachecontrol v0.1.0 // indirect
|
||||
github.com/satori/go.uuid v1.2.0
|
||||
github.com/spf13/cobra v1.2.1
|
||||
golang.org/x/oauth2 v0.0.0-20210810183815-faf39c7919d5
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
k8s.io/api v0.22.0
|
||||
k8s.io/apimachinery v0.22.0
|
||||
k8s.io/client-go v0.22.0
|
||||
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
k8s.io/api v0.22.1
|
||||
k8s.io/apimachinery v0.22.1
|
||||
k8s.io/client-go v0.22.1
|
||||
sigs.k8s.io/controller-runtime v0.9.6
|
||||
)
|
||||
|
||||
@@ -56,7 +56,6 @@ func (opap *OPAProcessor) ProcessRulesListenner() {
|
||||
}
|
||||
|
||||
func (opap *OPAProcessor) ProcessRulesHandler(opaSessionObj *cautils.OPASessionObj) error {
|
||||
glog.Infof(fmt.Sprintf("Starting 'ProcessRulesHandler'. reportID: %s", opaSessionObj.PostureReport.ReportID))
|
||||
cautils.ProgressTextDisplay(fmt.Sprintf("Scanning cluster %s", cautils.ClusterName))
|
||||
cautils.StartSpinner()
|
||||
frameworkReports := []opapolicy.FrameworkReport{}
|
||||
@@ -99,7 +98,6 @@ func (opap *OPAProcessor) ProcessRulesHandler(opaSessionObj *cautils.OPASessionO
|
||||
|
||||
opaSessionObj.PostureReport.FrameworkReports = frameworkReports
|
||||
opaSessionObj.PostureReport.ReportGenerationTime = time.Now().UTC()
|
||||
glog.Infof(fmt.Sprintf("Done 'ProcessRulesHandler'. reportID: %s", opaSessionObj.PostureReport.ReportID))
|
||||
cautils.StopSpinner()
|
||||
cautils.SuccessTextDisplay(fmt.Sprintf("Done scanning cluster %s", cautils.ClusterName))
|
||||
return errs
|
||||
|
||||
@@ -22,7 +22,7 @@ func getKubernetesObjects(k8sResources *cautils.K8SResources, match []opapolicy.
|
||||
for _, groupResource := range groupResources {
|
||||
if k8sObj, ok := (*k8sResources)[groupResource]; ok {
|
||||
if k8sObj == nil {
|
||||
glog.Errorf("Resource '%s' is nil, probably failed to pull the resource", groupResource)
|
||||
// glog.Errorf("Resource '%s' is nil, probably failed to pull the resource", groupResource)
|
||||
} else if v, k := k8sObj.([]map[string]interface{}); k {
|
||||
k8sObjects = append(k8sObjects, v...)
|
||||
} else if v, k := k8sObj.(map[string]interface{}); k {
|
||||
|
||||
185
policyhandler/filesloader.go
Normal file
185
policyhandler/filesloader.go
Normal file
@@ -0,0 +1,185 @@
|
||||
package policyhandler
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"kube-escape/cautils"
|
||||
"kube-escape/cautils/k8sinterface"
|
||||
"kube-escape/cautils/opapolicy"
|
||||
"path/filepath"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
var (
|
||||
YAML_PREFIX = []string{".yaml", ".yml"}
|
||||
JSON_PREFIX = []string{".json"}
|
||||
)
|
||||
|
||||
func (policyHandler *PolicyHandler) loadResources(frameworks []opapolicy.Framework, scanInfo *opapolicy.ScanInfo) (*cautils.K8SResources, error) {
|
||||
|
||||
files, errs := listFiles(scanInfo.InputPatterns)
|
||||
if len(errs) > 0 {
|
||||
cautils.ErrorDisplay(fmt.Sprintf("%v", errs)) // TODO - print error
|
||||
}
|
||||
if len(files) == 0 {
|
||||
return nil, fmt.Errorf("empty list of files - no files found")
|
||||
}
|
||||
|
||||
workloads, errs := loadFiles(files)
|
||||
if len(errs) > 0 {
|
||||
cautils.ErrorDisplay(fmt.Sprintf("%v", errs)) // TODO - print error
|
||||
}
|
||||
if len(workloads) == 0 {
|
||||
return nil, fmt.Errorf("empty list of workloads - no workloads valid workloads found")
|
||||
}
|
||||
|
||||
allResources := mapResources(workloads)
|
||||
|
||||
// build resources map
|
||||
k8sResources := setResourceMap(frameworks)
|
||||
|
||||
// save only relevant resources
|
||||
for i := range allResources {
|
||||
if _, ok := (*k8sResources)[i]; ok {
|
||||
(*k8sResources)[i] = allResources[i]
|
||||
}
|
||||
}
|
||||
|
||||
return k8sResources, nil
|
||||
|
||||
}
|
||||
|
||||
func mapResources(workloads []k8sinterface.IWorkload) map[string][]map[string]interface{} {
|
||||
allResources := map[string][]map[string]interface{}{}
|
||||
for i := range workloads {
|
||||
groupVersionResource, err := k8sinterface.GetGroupVersionResource(workloads[i].GetKind())
|
||||
if err != nil {
|
||||
// TODO - print warning
|
||||
continue
|
||||
}
|
||||
if groupVersionResource.Group != workloads[i].GetGroup() || groupVersionResource.Version != workloads[i].GetVersion() {
|
||||
// TODO - print warning
|
||||
continue
|
||||
}
|
||||
resourceTriplets := k8sinterface.JoinResourceTriplets(groupVersionResource.Group, groupVersionResource.Version, groupVersionResource.Resource)
|
||||
if r, ok := allResources[resourceTriplets]; ok {
|
||||
r = append(r, workloads[i].GetWorkload())
|
||||
allResources[resourceTriplets] = r
|
||||
} else {
|
||||
allResources[resourceTriplets] = []map[string]interface{}{workloads[i].GetWorkload()}
|
||||
}
|
||||
}
|
||||
return allResources
|
||||
|
||||
}
|
||||
|
||||
// // build resources map
|
||||
func loadFiles(filePaths []string) ([]k8sinterface.IWorkload, []error) {
|
||||
workloads := []k8sinterface.IWorkload{}
|
||||
errs := []error{}
|
||||
for i := range filePaths {
|
||||
w, e := loadFile(filePaths[i])
|
||||
errs = append(errs, e...)
|
||||
workloads = append(workloads, w...)
|
||||
}
|
||||
return workloads, errs
|
||||
}
|
||||
|
||||
func loadFile(filePath string) ([]k8sinterface.IWorkload, []error) {
|
||||
if isYaml(filePath) {
|
||||
return loadYamlFile(filePath)
|
||||
} else if isJson(filePath) {
|
||||
return loadJsonFile(filePath)
|
||||
}
|
||||
return nil, []error{fmt.Errorf("file extension %s not supported, file name: %s", filepath.Ext(filePath), filePath)}
|
||||
}
|
||||
func listFiles(patterns []string) ([]string, []error) {
|
||||
files := []string{}
|
||||
errs := []error{}
|
||||
for i := range patterns {
|
||||
f, err := filepath.Glob(patterns[i])
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
} else {
|
||||
files = append(files, f...)
|
||||
}
|
||||
}
|
||||
return files, errs
|
||||
}
|
||||
|
||||
func loadYamlFile(filePath string) ([]k8sinterface.IWorkload, []error) {
|
||||
errs := []error{}
|
||||
yamlFile, err := ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return nil, []error{err}
|
||||
}
|
||||
|
||||
r := bytes.NewReader(yamlFile)
|
||||
dec := yaml.NewDecoder(r)
|
||||
yamlObjs := []k8sinterface.IWorkload{}
|
||||
|
||||
var t interface{}
|
||||
for dec.Decode(&t) == nil {
|
||||
j := convertYamlToJson(t)
|
||||
if obj, ok := j.(map[string]interface{}); ok {
|
||||
yamlObjs = append(yamlObjs, k8sinterface.NewWorkloadObj(obj))
|
||||
} else {
|
||||
errs = append(errs, fmt.Errorf("failed to convert yaml file %s file to map[string]interface", filePath))
|
||||
}
|
||||
}
|
||||
|
||||
return yamlObjs, errs
|
||||
}
|
||||
|
||||
func loadJsonFile(filePath string) ([]k8sinterface.IWorkload, []error) {
|
||||
workloads := []k8sinterface.IWorkload{}
|
||||
jsonFile, err := ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return workloads, []error{err}
|
||||
}
|
||||
var jsonObj interface{}
|
||||
if err = json.Unmarshal(jsonFile, &jsonObj); err != nil {
|
||||
return workloads, []error{err}
|
||||
}
|
||||
|
||||
convertJsonToWorkload(jsonObj, &workloads)
|
||||
|
||||
return workloads, nil
|
||||
}
|
||||
func convertJsonToWorkload(jsonObj interface{}, workloads *[]k8sinterface.IWorkload) {
|
||||
|
||||
switch x := jsonObj.(type) {
|
||||
case map[string]interface{}:
|
||||
(*workloads) = append(*workloads, k8sinterface.NewWorkloadObj(x))
|
||||
case []interface{}:
|
||||
for i := range x {
|
||||
convertJsonToWorkload(x[i], workloads)
|
||||
}
|
||||
}
|
||||
}
|
||||
func convertYamlToJson(i interface{}) interface{} {
|
||||
switch x := i.(type) {
|
||||
case map[interface{}]interface{}:
|
||||
m2 := map[string]interface{}{}
|
||||
for k, v := range x {
|
||||
m2[k.(string)] = convertYamlToJson(v)
|
||||
}
|
||||
return m2
|
||||
case []interface{}:
|
||||
for i, v := range x {
|
||||
x[i] = convertYamlToJson(v)
|
||||
}
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func isYaml(filePath string) bool {
|
||||
return cautils.StringInSlice(YAML_PREFIX, filepath.Ext(filePath)) != cautils.ValueNotFound
|
||||
}
|
||||
|
||||
func isJson(filePath string) bool {
|
||||
return cautils.StringInSlice(YAML_PREFIX, filepath.Ext(filePath)) != cautils.ValueNotFound
|
||||
}
|
||||
66
policyhandler/filesloader_test.go
Normal file
66
policyhandler/filesloader_test.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package policyhandler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"kube-escape/cautils"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func combine(base, rel string) string {
|
||||
finalPath := []string{}
|
||||
sBase := strings.Split(base, "/")
|
||||
sRel := strings.Split(rel, "/")
|
||||
for i := range sBase {
|
||||
if cautils.StringInSlice(sRel, sBase[i]) != cautils.ValueNotFound {
|
||||
finalPath = append(finalPath, sRel...)
|
||||
break
|
||||
}
|
||||
finalPath = append(finalPath, sBase[i])
|
||||
}
|
||||
return fmt.Sprintf("/%s", filepath.Join(finalPath...))
|
||||
}
|
||||
func onlineBoutiquePath() string {
|
||||
o, _ := os.Getwd()
|
||||
return combine(o, "kubescape/examples/online-boutique/*")
|
||||
}
|
||||
func TestListFiles(t *testing.T) {
|
||||
files, errs := listFiles([]string{onlineBoutiquePath()})
|
||||
if len(errs) > 0 {
|
||||
t.Error(errs)
|
||||
}
|
||||
expected := 14
|
||||
if len(files) != expected {
|
||||
t.Errorf("wrong number of files, expected: %d, found: %d", expected, len(files))
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadFiles(t *testing.T) {
|
||||
files, _ := listFiles([]string{onlineBoutiquePath()})
|
||||
loadFiles(files)
|
||||
}
|
||||
|
||||
func TestLoadFile(t *testing.T) {
|
||||
files, _ := listFiles([]string{strings.Replace(onlineBoutiquePath(), "*", "bi-monitor.yaml", 1)})
|
||||
bb, err := loadFile(files[0])
|
||||
if len(err) > 0 {
|
||||
t.Errorf("%v", err)
|
||||
}
|
||||
for i := range bb {
|
||||
t.Errorf("%s", bb[i].ToString())
|
||||
}
|
||||
}
|
||||
func TestLoadResources(t *testing.T) {
|
||||
|
||||
// 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())
|
||||
// }
|
||||
}
|
||||
@@ -7,8 +7,6 @@ import (
|
||||
"kube-escape/cautils/k8sinterface"
|
||||
|
||||
"kube-escape/cautils/opapolicy"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// PolicyHandler -
|
||||
@@ -26,38 +24,27 @@ func NewPolicyHandler(processPolicy *chan *cautils.OPASessionObj, k8s *k8sinterf
|
||||
}
|
||||
}
|
||||
|
||||
func (policyHandler *PolicyHandler) HandleNotificationRequest(notification *opapolicy.PolicyNotification, excludedNamespaces string) error {
|
||||
glog.Infof("Processing notification. reportID: %s", notification.ReportID)
|
||||
func (policyHandler *PolicyHandler) HandleNotificationRequest(notification *opapolicy.PolicyNotification, scanInfo *opapolicy.ScanInfo) error {
|
||||
opaSessionObj := cautils.NewOPASessionObj(nil, nil)
|
||||
// validate notification
|
||||
// TODO
|
||||
|
||||
// get policies
|
||||
glog.Infof(fmt.Sprintf("Getting %d policies from backend. reportID: %s", len(notification.Rules), notification.ReportID))
|
||||
cautils.ProgressTextDisplay("Downloading framework definitions")
|
||||
frameworks, err := policyHandler.GetPoliciesFromBackend(notification)
|
||||
frameworks, err := policyHandler.getPolicies(notification)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(frameworks) == 0 {
|
||||
err := fmt.Errorf("Could not download any policies, please check previous logs")
|
||||
return err
|
||||
return fmt.Errorf("empty list of frameworks")
|
||||
}
|
||||
opaSessionObj.Frameworks = frameworks
|
||||
cautils.SuccessTextDisplay("Downloaded framework")
|
||||
// store policies as configmaps
|
||||
// TODO
|
||||
|
||||
// get k8s resources
|
||||
cautils.ProgressTextDisplay("Accessing Kubernetes objects")
|
||||
glog.Infof(fmt.Sprintf("Getting kubernetes objects. reportID: %s", notification.ReportID))
|
||||
|
||||
k8sResources, err := policyHandler.getK8sResources(frameworks, ¬ification.Designators, excludedNamespaces)
|
||||
if err != nil || len(*k8sResources) == 0 {
|
||||
glog.Error(err)
|
||||
} else {
|
||||
cautils.SuccessTextDisplay("Accessed successfully to Kubernetes objects, let’s start!!!")
|
||||
k8sResources, err := policyHandler.getResources(notification, opaSessionObj, scanInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if k8sResources == nil || len(*k8sResources) == 0 {
|
||||
return fmt.Errorf("empty list of resources")
|
||||
}
|
||||
opaSessionObj.K8SResources = k8sResources
|
||||
|
||||
@@ -65,3 +52,35 @@ func (policyHandler *PolicyHandler) HandleNotificationRequest(notification *opap
|
||||
*policyHandler.processPolicy <- opaSessionObj
|
||||
return nil
|
||||
}
|
||||
|
||||
func (policyHandler *PolicyHandler) getPolicies(notification *opapolicy.PolicyNotification) ([]opapolicy.Framework, error) {
|
||||
|
||||
cautils.ProgressTextDisplay("Downloading framework definitions")
|
||||
|
||||
// TODO - support load policies from local file
|
||||
frameworks, err := policyHandler.GetPoliciesFromBackend(notification)
|
||||
if err != nil {
|
||||
return frameworks, err
|
||||
}
|
||||
|
||||
if len(frameworks) == 0 {
|
||||
err := fmt.Errorf("could not download any policies, please check previous logs")
|
||||
return frameworks, err
|
||||
}
|
||||
cautils.SuccessTextDisplay("Downloaded framework")
|
||||
|
||||
return frameworks, nil
|
||||
}
|
||||
|
||||
func (policyHandler *PolicyHandler) getResources(notification *opapolicy.PolicyNotification, opaSessionObj *cautils.OPASessionObj, scanInfo *opapolicy.ScanInfo) (*cautils.K8SResources, error) {
|
||||
var k8sResources *cautils.K8SResources
|
||||
var err error
|
||||
if len(scanInfo.InputPatterns) > 0 {
|
||||
k8sResources, err = policyHandler.loadResources(opaSessionObj.Frameworks, scanInfo)
|
||||
} else {
|
||||
k8sResources, err = policyHandler.getK8sResources(opaSessionObj.Frameworks, ¬ification.Designators, scanInfo.ExcludedNamespaces)
|
||||
|
||||
}
|
||||
|
||||
return k8sResources, err
|
||||
}
|
||||
|
||||
@@ -20,6 +20,9 @@ import (
|
||||
const SelectAllResources = "*"
|
||||
|
||||
func (policyHandler *PolicyHandler) getK8sResources(frameworks []opapolicy.Framework, designator *armotypes.PortalDesignator, excludedNamespaces string) (*cautils.K8SResources, error) {
|
||||
// get k8s resources
|
||||
cautils.ProgressTextDisplay("Accessing Kubernetes objects")
|
||||
|
||||
// build resources map
|
||||
k8sResourcesMap := setResourceMap(frameworks)
|
||||
|
||||
@@ -31,6 +34,7 @@ func (policyHandler *PolicyHandler) getK8sResources(frameworks []opapolicy.Frame
|
||||
return k8sResourcesMap, err
|
||||
}
|
||||
|
||||
cautils.SuccessTextDisplay("Accessed successfully to Kubernetes objects, let’s start!!!")
|
||||
return k8sResourcesMap, nil
|
||||
}
|
||||
|
||||
@@ -66,7 +70,7 @@ func (policyHandler *PolicyHandler) pullSingleResource(resource *schema.GroupVer
|
||||
listOptions.FieldSelector += "metadata.namespace!=" + excludedNamespace + ","
|
||||
}
|
||||
}
|
||||
if labels != nil && len(labels) > 0 {
|
||||
if len(labels) > 0 {
|
||||
set := k8slabels.Set(labels)
|
||||
listOptions.LabelSelector = set.AsSelector().String()
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ type Printer struct {
|
||||
func NewPrinter(opaSessionObj *chan *cautils.OPASessionObj, printerType string) *Printer {
|
||||
return &Printer{
|
||||
opaSessionObj: opaSessionObj,
|
||||
summary: NewSummery(),
|
||||
summary: NewSummary(),
|
||||
printerType: printerType,
|
||||
}
|
||||
}
|
||||
@@ -42,9 +42,8 @@ func (printer *Printer) ActionPrint() {
|
||||
|
||||
for {
|
||||
opaSessionObj := <-*printer.opaSessionObj
|
||||
|
||||
if printer.printerType == PrettyPrinter {
|
||||
printer.SummerySetup(opaSessionObj.PostureReport)
|
||||
printer.SummarySetup(opaSessionObj.PostureReport)
|
||||
printer.PrintResults()
|
||||
printer.PrintSummaryTable()
|
||||
} else if printer.printerType == JsonPrinter {
|
||||
@@ -66,7 +65,7 @@ func (printer *Printer) ActionPrint() {
|
||||
os.Exit(1)
|
||||
}
|
||||
os.Stdout.Write(postureReportStr)
|
||||
} else {
|
||||
} else if !cautils.IsSilent() {
|
||||
fmt.Println("unknown output printer")
|
||||
os.Exit(1)
|
||||
}
|
||||
@@ -77,19 +76,19 @@ func (printer *Printer) ActionPrint() {
|
||||
}
|
||||
}
|
||||
|
||||
func (printer *Printer) SummerySetup(postureReport *opapolicy.PostureReport) {
|
||||
func (printer *Printer) SummarySetup(postureReport *opapolicy.PostureReport) {
|
||||
for _, fr := range postureReport.FrameworkReports {
|
||||
for _, cr := range fr.ControlReports {
|
||||
if len(cr.RuleReports) == 0 {
|
||||
continue
|
||||
}
|
||||
workloadsSummery := listResultSummery(cr.RuleReports)
|
||||
mapResources := groupByNamespace(workloadsSummery)
|
||||
workloadsSummary := listResultSummary(cr.RuleReports)
|
||||
mapResources := groupByNamespace(workloadsSummary)
|
||||
|
||||
printer.summary[cr.Name] = ControlSummery{
|
||||
printer.summary[cr.Name] = ControlSummary{
|
||||
TotalResources: cr.GetNumberOfResources(),
|
||||
TotalFailed: len(workloadsSummery),
|
||||
WorkloadSummery: mapResources,
|
||||
TotalFailed: len(workloadsSummary),
|
||||
WorkloadSummary: mapResources,
|
||||
Description: cr.Description,
|
||||
Remediation: cr.Remediation,
|
||||
}
|
||||
@@ -101,46 +100,46 @@ func (printer *Printer) SummerySetup(postureReport *opapolicy.PostureReport) {
|
||||
|
||||
func (printer *Printer) PrintResults() {
|
||||
for i := 0; i < len(printer.sortedControlNames); i++ {
|
||||
controlSummery := printer.summary[printer.sortedControlNames[i]]
|
||||
printer.printTitle(printer.sortedControlNames[i], &controlSummery)
|
||||
printer.printResult(printer.sortedControlNames[i], &controlSummery)
|
||||
controlSummary := printer.summary[printer.sortedControlNames[i]]
|
||||
printer.printTitle(printer.sortedControlNames[i], &controlSummary)
|
||||
printer.printResult(printer.sortedControlNames[i], &controlSummary)
|
||||
|
||||
if printer.summary[printer.sortedControlNames[i]].TotalResources > 0 {
|
||||
printer.printSummery(printer.sortedControlNames[i], &controlSummery)
|
||||
printer.printSummary(printer.sortedControlNames[i], &controlSummary)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (print *Printer) printSummery(controlName string, controlSummery *ControlSummery) {
|
||||
func (print *Printer) printSummary(controlName string, controlSummary *ControlSummary) {
|
||||
cautils.SimpleDisplay(os.Stdout, "Summary - ")
|
||||
cautils.SuccessDisplay(os.Stdout, "Passed:%v ", controlSummery.TotalResources-controlSummery.TotalFailed)
|
||||
cautils.FailureDisplay(os.Stdout, "Failed:%v ", controlSummery.TotalFailed)
|
||||
cautils.InfoDisplay(os.Stdout, "Total:%v\n", controlSummery.TotalResources)
|
||||
if controlSummery.TotalFailed > 0 {
|
||||
cautils.DescriptionDisplay(os.Stdout, "Remediation: %v\n", controlSummery.Remediation)
|
||||
cautils.SuccessDisplay(os.Stdout, "Passed:%v ", controlSummary.TotalResources-controlSummary.TotalFailed)
|
||||
cautils.FailureDisplay(os.Stdout, "Failed:%v ", controlSummary.TotalFailed)
|
||||
cautils.InfoDisplay(os.Stdout, "Total:%v\n", controlSummary.TotalResources)
|
||||
if controlSummary.TotalFailed > 0 {
|
||||
cautils.DescriptionDisplay(os.Stdout, "Remediation: %v\n", controlSummary.Remediation)
|
||||
}
|
||||
cautils.DescriptionDisplay(os.Stdout, "\n")
|
||||
|
||||
}
|
||||
|
||||
func (printer *Printer) printTitle(controlName string, controlSummery *ControlSummery) {
|
||||
func (printer *Printer) printTitle(controlName string, controlSummary *ControlSummary) {
|
||||
cautils.InfoDisplay(os.Stdout, "[control: %s] ", controlName)
|
||||
if controlSummery.TotalResources == 0 {
|
||||
if controlSummary.TotalResources == 0 {
|
||||
cautils.InfoDisplay(os.Stdout, "resources not found %v\n", emoji.ConfusedFace)
|
||||
} else if controlSummery.TotalFailed == 0 {
|
||||
} else if controlSummary.TotalFailed == 0 {
|
||||
cautils.SuccessDisplay(os.Stdout, "passed %v\n", emoji.ThumbsUp)
|
||||
} else {
|
||||
cautils.FailureDisplay(os.Stdout, "failed %v\n", emoji.SadButRelievedFace)
|
||||
}
|
||||
|
||||
cautils.DescriptionDisplay(os.Stdout, "Description: %s\n", controlSummery.Description)
|
||||
cautils.DescriptionDisplay(os.Stdout, "Description: %s\n", controlSummary.Description)
|
||||
|
||||
}
|
||||
func (printer *Printer) printResult(controlName string, controlSummery *ControlSummery) {
|
||||
func (printer *Printer) printResult(controlName string, controlSummary *ControlSummary) {
|
||||
|
||||
indent := INDENT
|
||||
for ns, rsc := range controlSummery.WorkloadSummery {
|
||||
for ns, rsc := range controlSummary.WorkloadSummary {
|
||||
preIndent := indent
|
||||
if ns != "" {
|
||||
cautils.SimpleDisplay(os.Stdout, "%sNamespace %s\n", indent, ns)
|
||||
@@ -156,7 +155,7 @@ func (printer *Printer) printResult(controlName string, controlSummery *ControlS
|
||||
|
||||
}
|
||||
|
||||
func generateRow(control string, cs ControlSummery) []string {
|
||||
func generateRow(control string, cs ControlSummary) []string {
|
||||
row := []string{control}
|
||||
row = append(row, cs.ToSlice()...)
|
||||
row = append(row, fmt.Sprintf("%d%s", percentage(cs.TotalResources, cs.TotalFailed), "%"))
|
||||
@@ -195,10 +194,10 @@ func (printer *Printer) PrintSummaryTable() {
|
||||
sumFailed := 0
|
||||
|
||||
for i := 0; i < len(printer.sortedControlNames); i++ {
|
||||
controlSummery := printer.summary[printer.sortedControlNames[i]]
|
||||
summaryTable.Append(generateRow(printer.sortedControlNames[i], controlSummery))
|
||||
sumFailed += controlSummery.TotalFailed
|
||||
sumTotal += controlSummery.TotalResources
|
||||
controlSummary := printer.summary[printer.sortedControlNames[i]]
|
||||
summaryTable.Append(generateRow(printer.sortedControlNames[i], controlSummary))
|
||||
sumFailed += controlSummary.TotalFailed
|
||||
sumTotal += controlSummary.TotalResources
|
||||
}
|
||||
summaryTable.SetFooter(generateFooter(len(printer.summary), sumFailed, sumTotal))
|
||||
summaryTable.Render()
|
||||
|
||||
@@ -4,34 +4,34 @@ import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Summary map[string]ControlSummery
|
||||
type Summary map[string]ControlSummary
|
||||
|
||||
func NewSummery() Summary {
|
||||
return make(map[string]ControlSummery)
|
||||
func NewSummary() Summary {
|
||||
return make(map[string]ControlSummary)
|
||||
}
|
||||
|
||||
type ControlSummery struct {
|
||||
type ControlSummary struct {
|
||||
TotalResources int
|
||||
TotalFailed int
|
||||
Description string
|
||||
Remediation string
|
||||
WorkloadSummery map[string][]WorkloadSummery // <namespace>:[<WorkloadSummery>]
|
||||
WorkloadSummary map[string][]WorkloadSummary // <namespace>:[<WorkloadSummary>]
|
||||
}
|
||||
|
||||
type WorkloadSummery struct {
|
||||
type WorkloadSummary struct {
|
||||
Kind string
|
||||
Name string
|
||||
Namespace string
|
||||
Group string
|
||||
}
|
||||
|
||||
func (controlSummery *ControlSummery) ToSlice() []string {
|
||||
func (controlSummary *ControlSummary) ToSlice() []string {
|
||||
s := []string{}
|
||||
s = append(s, fmt.Sprintf("%d", controlSummery.TotalFailed))
|
||||
s = append(s, fmt.Sprintf("%d", controlSummery.TotalResources))
|
||||
s = append(s, fmt.Sprintf("%d", controlSummary.TotalFailed))
|
||||
s = append(s, fmt.Sprintf("%d", controlSummary.TotalResources))
|
||||
return s
|
||||
}
|
||||
|
||||
func (workloadSummery *WorkloadSummery) ToString() string {
|
||||
return fmt.Sprintf("/%s/%s/%s/%s", workloadSummery.Group, workloadSummery.Namespace, workloadSummery.Kind, workloadSummery.Name)
|
||||
func (workloadSummary *WorkloadSummary) ToString() string {
|
||||
return fmt.Sprintf("/%s/%s/%s/%s", workloadSummary.Group, workloadSummary.Namespace, workloadSummary.Kind, workloadSummary.Name)
|
||||
}
|
||||
|
||||
@@ -7,26 +7,26 @@ import (
|
||||
"kube-escape/cautils/opapolicy"
|
||||
)
|
||||
|
||||
// Group workloads by namespace - return {"namespace": <[]WorkloadSummery>}
|
||||
func groupByNamespace(resources []WorkloadSummery) map[string][]WorkloadSummery {
|
||||
mapResources := make(map[string][]WorkloadSummery)
|
||||
// Group workloads by namespace - return {"namespace": <[]WorkloadSummary>}
|
||||
func groupByNamespace(resources []WorkloadSummary) map[string][]WorkloadSummary {
|
||||
mapResources := make(map[string][]WorkloadSummary)
|
||||
for i := range resources {
|
||||
if r, ok := mapResources[resources[i].Namespace]; ok {
|
||||
r = append(r, resources[i])
|
||||
mapResources[resources[i].Namespace] = r
|
||||
} else {
|
||||
mapResources[resources[i].Namespace] = []WorkloadSummery{resources[i]}
|
||||
mapResources[resources[i].Namespace] = []WorkloadSummary{resources[i]}
|
||||
}
|
||||
}
|
||||
return mapResources
|
||||
}
|
||||
func listResultSummery(ruleReports []opapolicy.RuleReport) []WorkloadSummery {
|
||||
workloadsSummery := []WorkloadSummery{}
|
||||
func listResultSummary(ruleReports []opapolicy.RuleReport) []WorkloadSummary {
|
||||
workloadsSummary := []WorkloadSummary{}
|
||||
track := map[string]bool{}
|
||||
|
||||
for c := range ruleReports {
|
||||
for _, ruleReport := range ruleReports[c].RuleResponses {
|
||||
resource, err := ruleResultSummery(ruleReport.AlertObject)
|
||||
resource, err := ruleResultSummary(ruleReport.AlertObject)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
continue
|
||||
@@ -36,18 +36,18 @@ func listResultSummery(ruleReports []opapolicy.RuleReport) []WorkloadSummery {
|
||||
for i := range resource {
|
||||
if ok := track[resource[i].ToString()]; !ok {
|
||||
track[resource[i].ToString()] = true
|
||||
workloadsSummery = append(workloadsSummery, resource[i])
|
||||
workloadsSummary = append(workloadsSummary, resource[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return workloadsSummery
|
||||
return workloadsSummary
|
||||
}
|
||||
func ruleResultSummery(obj opapolicy.AlertObject) ([]WorkloadSummery, error) {
|
||||
resource := []WorkloadSummery{}
|
||||
func ruleResultSummary(obj opapolicy.AlertObject) ([]WorkloadSummary, error) {
|
||||
resource := []WorkloadSummary{}
|
||||
|
||||
for i := range obj.K8SApiObjects {
|
||||
r, err := newWorkloadSummery(obj.K8SApiObjects[i])
|
||||
r, err := newWorkloadSummary(obj.K8SApiObjects[i])
|
||||
if err != nil {
|
||||
return resource, err
|
||||
}
|
||||
@@ -57,8 +57,8 @@ func ruleResultSummery(obj opapolicy.AlertObject) ([]WorkloadSummery, error) {
|
||||
return resource, nil
|
||||
}
|
||||
|
||||
func newWorkloadSummery(obj map[string]interface{}) (*WorkloadSummery, error) {
|
||||
r := &WorkloadSummery{}
|
||||
func newWorkloadSummary(obj map[string]interface{}) (*WorkloadSummary, error) {
|
||||
r := &WorkloadSummary{}
|
||||
|
||||
workload := k8sinterface.NewWorkloadObj(obj)
|
||||
if workload == nil {
|
||||
|
||||
Reference in New Issue
Block a user