mirror of
https://github.com/kubescape/kubescape.git
synced 2026-04-15 06:58:11 +00:00
215 lines
7.2 KiB
Go
215 lines
7.2 KiB
Go
package clihandler
|
|
|
|
import (
|
|
"fmt"
|
|
"io/fs"
|
|
"os"
|
|
|
|
"github.com/armosec/k8s-interface/k8sinterface"
|
|
"github.com/armosec/kubescape/resultshandling/printer"
|
|
printerv1 "github.com/armosec/kubescape/resultshandling/printer/v1"
|
|
|
|
// printerv2 "github.com/armosec/kubescape/resultshandling/printer/v2"
|
|
|
|
"github.com/armosec/armoapi-go/armotypes"
|
|
"github.com/armosec/kubescape/cautils"
|
|
"github.com/armosec/kubescape/cautils/getter"
|
|
"github.com/armosec/kubescape/clihandler/cliinterfaces"
|
|
"github.com/armosec/kubescape/hostsensorutils"
|
|
"github.com/armosec/kubescape/opaprocessor"
|
|
"github.com/armosec/kubescape/policyhandler"
|
|
"github.com/armosec/kubescape/resourcehandler"
|
|
"github.com/armosec/kubescape/resultshandling"
|
|
"github.com/armosec/kubescape/resultshandling/reporter"
|
|
"github.com/armosec/opa-utils/reporthandling"
|
|
"github.com/mattn/go-isatty"
|
|
)
|
|
|
|
type componentInterfaces struct {
|
|
tenantConfig cautils.ITenantConfig
|
|
resourceHandler resourcehandler.IResourceHandler
|
|
report reporter.IReport
|
|
printerHandler printer.IPrinter
|
|
hostSensorHandler hostsensorutils.IHostSensor
|
|
}
|
|
|
|
func getInterfaces(scanInfo *cautils.ScanInfo) componentInterfaces {
|
|
|
|
var k8s *k8sinterface.KubernetesApi
|
|
if scanInfo.GetScanningEnvironment() == cautils.ScanCluster {
|
|
k8s = getKubernetesApi()
|
|
if k8s == nil {
|
|
fmt.Println("Failed connecting to Kubernetes cluster")
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
tenantConfig := getTenantConfig(scanInfo.Account, scanInfo.KubeContext, k8s)
|
|
|
|
// Set submit behavior AFTER loading tenant config
|
|
setSubmitBehavior(scanInfo, tenantConfig)
|
|
|
|
hostSensorHandler := getHostSensorHandler(scanInfo, k8s)
|
|
if err := hostSensorHandler.Init(); err != nil {
|
|
errMsg := "failed to init host sensor"
|
|
if scanInfo.VerboseMode {
|
|
errMsg = fmt.Sprintf("%s: %v", errMsg, err)
|
|
}
|
|
cautils.ErrorDisplay(errMsg)
|
|
hostSensorHandler = &hostsensorutils.HostSensorHandlerMock{}
|
|
}
|
|
// excluding hostsensor namespace
|
|
if len(scanInfo.IncludeNamespaces) == 0 && hostSensorHandler.GetNamespace() != "" {
|
|
scanInfo.ExcludedNamespaces = fmt.Sprintf("%s,%s", scanInfo.ExcludedNamespaces, hostSensorHandler.GetNamespace())
|
|
}
|
|
|
|
resourceHandler := getResourceHandler(scanInfo, tenantConfig, k8s, hostSensorHandler)
|
|
|
|
// reporting behavior - setup reporter
|
|
reportHandler := getReporter(tenantConfig, scanInfo.Submit)
|
|
|
|
v := cautils.NewIVersionCheckHandler()
|
|
v.CheckLatestVersion(cautils.NewVersionCheckRequest(cautils.BuildNumber, policyIdentifierNames(scanInfo.PolicyIdentifier), "", scanInfo.GetScanningEnvironment()))
|
|
|
|
// setup printer
|
|
printerHandler := printerv1.GetPrinter(scanInfo.Format, scanInfo.VerboseMode)
|
|
// printerHandler = printerv2.GetPrinter(scanInfo.Format, scanInfo.VerboseMode)
|
|
printerHandler.SetWriter(scanInfo.Output)
|
|
|
|
return componentInterfaces{
|
|
tenantConfig: tenantConfig,
|
|
resourceHandler: resourceHandler,
|
|
report: reportHandler,
|
|
printerHandler: printerHandler,
|
|
hostSensorHandler: hostSensorHandler,
|
|
}
|
|
}
|
|
|
|
func ScanCliSetup(scanInfo *cautils.ScanInfo) error {
|
|
cautils.ScanStartDisplay()
|
|
|
|
interfaces := getInterfaces(scanInfo)
|
|
// setPolicyGetter(scanInfo, interfaces.clusterConfig.GetCustomerGUID())
|
|
|
|
processNotification := make(chan *cautils.OPASessionObj)
|
|
reportResults := make(chan *cautils.OPASessionObj)
|
|
|
|
cautils.ClusterName = interfaces.tenantConfig.GetClusterName() // TODO - Deprecated
|
|
cautils.CustomerGUID = interfaces.tenantConfig.GetCustomerGUID() // TODO - Deprecated
|
|
interfaces.report.SetClusterName(interfaces.tenantConfig.GetClusterName())
|
|
interfaces.report.SetCustomerGUID(interfaces.tenantConfig.GetCustomerGUID())
|
|
|
|
downloadReleasedPolicy := getter.NewDownloadReleasedPolicy() // download config inputs from github release
|
|
|
|
// set policy getter only after setting the customerGUID
|
|
scanInfo.Getters.PolicyGetter = getPolicyGetter(scanInfo.UseFrom, interfaces.tenantConfig.GetCustomerGUID(), scanInfo.FrameworkScan, downloadReleasedPolicy)
|
|
scanInfo.Getters.ControlsInputsGetter = getConfigInputsGetter(scanInfo.ControlsInputs, interfaces.tenantConfig.GetCustomerGUID(), downloadReleasedPolicy)
|
|
scanInfo.Getters.ExceptionsGetter = getExceptionsGetter(scanInfo.UseExceptions)
|
|
|
|
// TODO - list supported frameworks/controls
|
|
if scanInfo.ScanAll {
|
|
scanInfo.SetPolicyIdentifiers(listFrameworksNames(scanInfo.Getters.PolicyGetter), reporthandling.KindFramework)
|
|
}
|
|
|
|
//
|
|
defer func() {
|
|
if err := interfaces.hostSensorHandler.TearDown(); err != nil {
|
|
errMsg := "failed to tear down host sensor"
|
|
if scanInfo.VerboseMode {
|
|
errMsg = fmt.Sprintf("%s: %v", errMsg, err)
|
|
}
|
|
cautils.ErrorDisplay(errMsg)
|
|
}
|
|
}()
|
|
|
|
// cli handler setup
|
|
go func() {
|
|
// policy handler setup
|
|
policyHandler := policyhandler.NewPolicyHandler(&processNotification, interfaces.resourceHandler)
|
|
|
|
if err := Scan(policyHandler, scanInfo); err != nil {
|
|
fmt.Println(err)
|
|
os.Exit(1)
|
|
}
|
|
}()
|
|
|
|
// processor setup - rego run
|
|
go func() {
|
|
opaprocessorObj := opaprocessor.NewOPAProcessorHandler(&processNotification, &reportResults)
|
|
opaprocessorObj.ProcessRulesListenner()
|
|
}()
|
|
|
|
resultsHandling := resultshandling.NewResultsHandler(&reportResults, interfaces.report, interfaces.printerHandler)
|
|
score := resultsHandling.HandleResults(scanInfo)
|
|
|
|
// print report url
|
|
interfaces.report.DisplayReportURL()
|
|
|
|
if score > float32(scanInfo.FailThreshold) {
|
|
return fmt.Errorf("scan risk-score %.2f is above permitted threshold %d", score, scanInfo.FailThreshold)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func Scan(policyHandler *policyhandler.PolicyHandler, scanInfo *cautils.ScanInfo) error {
|
|
policyNotification := &reporthandling.PolicyNotification{
|
|
NotificationType: reporthandling.TypeExecPostureScan,
|
|
Rules: scanInfo.PolicyIdentifier,
|
|
Designators: armotypes.PortalDesignator{},
|
|
}
|
|
switch policyNotification.NotificationType {
|
|
case reporthandling.TypeExecPostureScan:
|
|
if err := policyHandler.HandleNotificationRequest(policyNotification, scanInfo); err != nil {
|
|
return err
|
|
}
|
|
|
|
default:
|
|
return fmt.Errorf("notification type '%s' Unknown", policyNotification.NotificationType)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func Submit(submitInterfaces cliinterfaces.SubmitInterfaces) error {
|
|
|
|
// list resources
|
|
postureReport, err := submitInterfaces.SubmitObjects.SetResourcesReport()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
allresources, err := submitInterfaces.SubmitObjects.ListAllResources()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// report
|
|
if err := submitInterfaces.Reporter.ActionSendReport(&cautils.OPASessionObj{PostureReport: postureReport, AllResources: allresources}); err != nil {
|
|
return err
|
|
}
|
|
fmt.Printf("\nData has been submitted successfully")
|
|
submitInterfaces.Reporter.DisplayReportURL()
|
|
|
|
return 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.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
|
|
}
|