mirror of
https://github.com/kubescape/kubescape.git
synced 2026-04-15 06:58:11 +00:00
host sensor flag + user input asking
This commit is contained in:
+50
-16
@@ -1,31 +1,65 @@
|
||||
package cautils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/armosec/kubescape/cautils/getter"
|
||||
"github.com/armosec/opa-utils/reporthandling"
|
||||
)
|
||||
|
||||
type BoolPtrFlag struct {
|
||||
valPtr *bool
|
||||
}
|
||||
|
||||
func (bpf *BoolPtrFlag) Type() string {
|
||||
return "bool"
|
||||
}
|
||||
|
||||
func (bpf *BoolPtrFlag) String() string {
|
||||
if bpf.valPtr != nil {
|
||||
return fmt.Sprintf("%v", *bpf.valPtr)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
func (bpf *BoolPtrFlag) Get() *bool {
|
||||
return bpf.valPtr
|
||||
}
|
||||
|
||||
func (bpf *BoolPtrFlag) SetBool(val bool) {
|
||||
bpf.valPtr = &val
|
||||
}
|
||||
|
||||
func (bpf *BoolPtrFlag) Set(val string) error {
|
||||
switch val {
|
||||
case "true":
|
||||
bpf.SetBool(true)
|
||||
case "false":
|
||||
bpf.SetBool(false)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ScanInfo struct {
|
||||
Getters
|
||||
PolicyIdentifier []reporthandling.PolicyIdentifier
|
||||
UseExceptions string // Load file with exceptions configuration
|
||||
ControlsInputs string // Load file with inputs for controls
|
||||
UseFrom []string // Load framework from local file (instead of download). Use when running offline
|
||||
UseDefault bool // Load framework from cached file (instead of download). Use when running offline
|
||||
Format string // Format results (table, json, junit ...)
|
||||
Output string // Store results in an output file, Output file name
|
||||
ExcludedNamespaces string // DEPRECATED?
|
||||
IncludeNamespaces string // DEPRECATED?
|
||||
InputPatterns []string // Yaml files input patterns
|
||||
Silent bool // Silent mode - Do not print progress logs
|
||||
FailThreshold uint16 // Failure score threshold
|
||||
Submit bool // Submit results to Armo BE
|
||||
Local bool // Do not submit results
|
||||
Account string // account ID
|
||||
FrameworkScan bool // false if scanning control
|
||||
ScanAll bool // true if scan all frameworks
|
||||
UseExceptions string // Load file with exceptions configuration
|
||||
ControlsInputs string // Load file with inputs for controls
|
||||
UseFrom []string // Load framework from local file (instead of download). Use when running offline
|
||||
UseDefault bool // Load framework from cached file (instead of download). Use when running offline
|
||||
Format string // Format results (table, json, junit ...)
|
||||
Output string // Store results in an output file, Output file name
|
||||
ExcludedNamespaces string // used for host sensor namespace
|
||||
IncludeNamespaces string // DEPRECATED?
|
||||
InputPatterns []string // Yaml files input patterns
|
||||
Silent bool // Silent mode - Do not print progress logs
|
||||
FailThreshold uint16 // Failure score threshold
|
||||
Submit bool // Submit results to Armo BE
|
||||
HostSensor BoolPtrFlag // Deploy ARMO K8s host sensor to collect data from certain controls
|
||||
Local bool // Do not submit results
|
||||
Account string // account ID
|
||||
FrameworkScan bool // false if scanning control
|
||||
ScanAll bool // true if scan all frameworks
|
||||
}
|
||||
|
||||
type Getters struct {
|
||||
|
||||
@@ -48,4 +48,8 @@ func init() {
|
||||
scanCmd.PersistentFlags().BoolVar(&scanInfo.UseDefault, "use-default", false, "Load local policy object from default path. If not used will download latest")
|
||||
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.ControlsInputs, "controls-config", "", "Path to an controls-config obj. If not set will download controls-config from ARMO management portal")
|
||||
|
||||
hostF := scanCmd.PersistentFlags().VarPF(&scanInfo.HostSensor, "enable-host-scan", "", "Deploy ARMO K8s host-sensor daemonset in the scanned cluster. Deleting it right after we collecting the data. Required to collect valueable data from cluster nodes for certain controls")
|
||||
hostF.NoOptDefVal = "true"
|
||||
hostF.DefValue = "false, for no TTY in stdin"
|
||||
}
|
||||
|
||||
+51
-15
@@ -2,6 +2,7 @@ package clihandler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
|
||||
"github.com/armosec/armoapi-go/armotypes"
|
||||
@@ -27,6 +28,38 @@ type componentInterfaces struct {
|
||||
printerHandler printer.IPrinter
|
||||
}
|
||||
|
||||
func initHostSensor(scanInfo *cautils.ScanInfo, k8s *k8sinterface.KubernetesApi) {
|
||||
|
||||
hasHostSensorControls := true
|
||||
// we need to determined which controls needs host sensor
|
||||
if scanInfo.HostSensor.Get() == nil && hasHostSensorControls {
|
||||
scanInfo.HostSensor.SetBool(askUserForHostSensor())
|
||||
}
|
||||
if hostSensorVal := scanInfo.HostSensor.Get(); hostSensorVal != nil && *hostSensorVal {
|
||||
hostSensorHandler, err := hostsensorutils.NewHostSensorHandler(k8s)
|
||||
if hostSensorHandler != nil {
|
||||
defer func(hostSensorHandler *hostsensorutils.HostSensorHandler) {
|
||||
if err := hostSensorHandler.TearDown(); err != nil {
|
||||
glog.Errorf("failed to tear down host sensor: %v", err)
|
||||
}
|
||||
}(hostSensorHandler)
|
||||
}
|
||||
if err != nil {
|
||||
glog.Errorf("failed to deploy host sensor: %v", err)
|
||||
return
|
||||
}
|
||||
scanInfo.ExcludedNamespaces = fmt.Sprintf("%s,%s", scanInfo.ExcludedNamespaces, hostSensorHandler.DaemonSet.Namespace)
|
||||
data, err := hostSensorHandler.GetKubeletConfigurations()
|
||||
if err != nil {
|
||||
glog.Errorf("failed to get kubelet configuration from host sensor: %v", err)
|
||||
} else {
|
||||
glog.Infof("kubelet configurations from host sensor: %v", data)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("Skipping nodes scanning\n")
|
||||
}
|
||||
}
|
||||
|
||||
func getInterfaces(scanInfo *cautils.ScanInfo) componentInterfaces {
|
||||
var resourceHandler resourcehandler.IResourceHandler
|
||||
var clusterConfig cautils.IClusterConfig
|
||||
@@ -45,21 +78,7 @@ func getInterfaces(scanInfo *cautils.ScanInfo) componentInterfaces {
|
||||
scanningTarget = "yaml"
|
||||
} else {
|
||||
k8s := k8sinterface.NewKubernetesApi()
|
||||
hostSensorHandler, err := hostsensorutils.NewHostSensorHandler(k8s)
|
||||
if err != nil {
|
||||
glog.Errorf("failed to deploy host sensor: %v", err)
|
||||
}
|
||||
data, err := hostSensorHandler.GetKubeletConfigurations()
|
||||
if err != nil {
|
||||
glog.Errorf("failed to get kubelet configuration from host sensor: %v", err)
|
||||
} else {
|
||||
glog.Infof("kubelet configurations from host sensor: %v", data)
|
||||
}
|
||||
if hostSensorHandler != nil {
|
||||
if err := hostSensorHandler.TearDown(); err != nil {
|
||||
glog.Errorf("failed to tear down host sensor: %v", err)
|
||||
}
|
||||
}
|
||||
initHostSensor(scanInfo, k8s)
|
||||
resourceHandler = resourcehandler.NewK8sResourceHandler(k8s, getFieldSelector(scanInfo))
|
||||
clusterConfig = cautils.ClusterConfigSetup(scanInfo, k8s, getter.GetArmoAPIConnector())
|
||||
|
||||
@@ -189,3 +208,20 @@ func Submit(submitInterfaces cliinterfaces.SubmitInterfaces) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func askUserForHostSensor() bool {
|
||||
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.Printf("Would you like to scan K8s nodes? [y/N]. This is required to collect valuable data for certain controls\n")
|
||||
fmt.Printf("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
|
||||
}
|
||||
|
||||
@@ -37,6 +37,13 @@ func NewHostSensorHandler(k8sObj *k8sinterface.KubernetesApi) (*HostSensorHandle
|
||||
if k8sObj == nil {
|
||||
return nil, fmt.Errorf("nil k8s interface received")
|
||||
}
|
||||
// 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.NodeV1().RuntimeClasses().List(k8sObj.Context, metav1.ListOptions{}); err != nil || len(nodeList.Items) == 0 {
|
||||
if err == nil {
|
||||
err = fmt.Errorf("no nodes to scan")
|
||||
}
|
||||
return nil, fmt.Errorf("in NewHostSensorHandler, failed to get nodes list: %v", err)
|
||||
}
|
||||
hsh := &HostSensorHandler{
|
||||
k8sObj: k8sObj,
|
||||
HostSensorPodNames: map[string]string{},
|
||||
|
||||
Reference in New Issue
Block a user