Files
kubescape/clihandler/initcliutils.go
2022-01-13 11:04:09 +02:00

222 lines
7.7 KiB
Go

package clihandler
import (
"fmt"
"os"
"github.com/armosec/k8s-interface/k8sinterface"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/cautils/getter"
"github.com/armosec/kubescape/hostsensorutils"
"github.com/armosec/kubescape/resourcehandler"
"github.com/armosec/kubescape/resultshandling/reporter"
reporterv1 "github.com/armosec/kubescape/resultshandling/reporter/v1"
reporterv2 "github.com/armosec/kubescape/resultshandling/reporter/v2"
"github.com/armosec/opa-utils/reporthandling"
"github.com/armosec/rbac-utils/rbacscanner"
)
// getKubernetesApi
func getKubernetesApi() *k8sinterface.KubernetesApi {
if !k8sinterface.IsConnectedToCluster() {
return nil
}
return k8sinterface.NewKubernetesApi()
}
func getTenantConfig(Account, clusterName string, k8s *k8sinterface.KubernetesApi) cautils.ITenantConfig {
if !k8sinterface.IsConnectedToCluster() || k8s == nil {
return cautils.NewLocalConfig(getter.GetArmoAPIConnector(), Account, clusterName)
}
return cautils.NewClusterConfig(k8s, getter.GetArmoAPIConnector(), Account, clusterName)
}
func getExceptionsGetter(useExceptions string) getter.IExceptionsGetter {
if useExceptions != "" {
// load exceptions from file
return getter.NewLoadPolicy([]string{useExceptions})
} else {
return getter.GetArmoAPIConnector()
}
}
func getRBACHandler(tenantConfig cautils.ITenantConfig, k8s *k8sinterface.KubernetesApi, submit bool) *cautils.RBACObjects {
if submit {
return cautils.NewRBACObjects(rbacscanner.NewRbacScannerFromK8sAPI(k8s, tenantConfig.GetCustomerGUID(), tenantConfig.GetClusterName()))
}
return nil
}
func getReporter(tenantConfig cautils.ITenantConfig, submit bool) reporter.IReport {
if submit {
// return reporterv1.NewReportEventReceiver(tenantConfig.GetConfigObj())
return reporterv2.NewReportEventReceiver(tenantConfig.GetConfigObj())
}
return reporterv1.NewReportMock()
}
func getResourceHandler(scanInfo *cautils.ScanInfo, tenantConfig cautils.ITenantConfig, k8s *k8sinterface.KubernetesApi, hostSensorHandler hostsensorutils.IHostSensor) resourcehandler.IResourceHandler {
if len(scanInfo.InputPatterns) > 0 || k8s == nil {
return resourcehandler.NewFileResourceHandler(scanInfo.InputPatterns)
}
rbacObjects := getRBACHandler(tenantConfig, k8s, scanInfo.Submit)
return resourcehandler.NewK8sResourceHandler(k8s, getFieldSelector(scanInfo), hostSensorHandler, rbacObjects)
}
func getHostSensorHandler(scanInfo *cautils.ScanInfo, k8s *k8sinterface.KubernetesApi) hostsensorutils.IHostSensor {
if !k8sinterface.IsConnectedToCluster() || k8s == nil {
return &hostsensorutils.HostSensorHandlerMock{}
}
hasHostSensorControls := true
// we need to determined which controls needs host sensor
if scanInfo.HostSensor.Get() == nil && hasHostSensorControls {
scanInfo.HostSensor.SetBool(askUserForHostSensor())
cautils.WarningDisplay(os.Stderr, "Warning: Kubernetes cluster nodes scanning is disabled. This is required to collect valuable data for certain controls. You can enable it using the --enable-host-scan flag\n")
}
if hostSensorVal := scanInfo.HostSensor.Get(); hostSensorVal != nil && *hostSensorVal {
hostSensorHandler, err := hostsensorutils.NewHostSensorHandler(k8s)
if err != nil {
cautils.WarningDisplay(os.Stderr, fmt.Sprintf("Warning: failed to create host sensor: %v\n", err.Error()))
return &hostsensorutils.HostSensorHandlerMock{}
}
return hostSensorHandler
}
return &hostsensorutils.HostSensorHandlerMock{}
}
func getFieldSelector(scanInfo *cautils.ScanInfo) resourcehandler.IFieldSelector {
if scanInfo.IncludeNamespaces != "" {
return resourcehandler.NewIncludeSelector(scanInfo.IncludeNamespaces)
}
if scanInfo.ExcludedNamespaces != "" {
return resourcehandler.NewExcludeSelector(scanInfo.ExcludedNamespaces)
}
return &resourcehandler.EmptySelector{}
}
func policyIdentifierNames(pi []reporthandling.PolicyIdentifier) string {
policiesNames := ""
for i := range pi {
policiesNames += pi[i].Name
if i+1 < len(pi) {
policiesNames += ","
}
}
if policiesNames == "" {
policiesNames = "all"
}
return policiesNames
}
// setSubmitBehavior - Setup the desired cluster behavior regarding submittion to the Armo BE
func setSubmitBehavior(scanInfo *cautils.ScanInfo, tenantConfig cautils.ITenantConfig) {
/*
If "First run (local config not found)" -
Default/keep-local - Do not send report
Submit - Create tenant & Submit report
If "Submitted" -
keep-local - Do not send report
Default/Submit - Submit report
*/
// do not submit control scanning
if !scanInfo.FrameworkScan {
scanInfo.Submit = false
return
}
if tenantConfig.IsConfigFound() { // config found in cache (submitted)
if !scanInfo.Local {
// Submit report
scanInfo.Submit = true
}
} else { // config not found in cache (not submitted)
if scanInfo.Submit {
// submit - Create tenant & Submit report
if err := tenantConfig.SetTenant(); err != nil {
fmt.Println(err)
}
}
}
}
// setPolicyGetter set the policy getter - local file/github release/ArmoAPI
func getPolicyGetter(loadPoliciesFromFile []string, accountID string, frameworkScope bool, downloadReleasedPolicy *getter.DownloadReleasedPolicy) getter.IPolicyGetter {
if len(loadPoliciesFromFile) > 0 {
return getter.NewLoadPolicy(loadPoliciesFromFile)
}
if accountID != "" && frameworkScope {
g := getter.GetArmoAPIConnector() // download policy from ARMO backend
g.SetCustomerGUID(accountID)
return g
}
if downloadReleasedPolicy == nil {
downloadReleasedPolicy = getter.NewDownloadReleasedPolicy()
}
return getDownloadReleasedPolicy(downloadReleasedPolicy)
}
// func setGetArmoAPIConnector(scanInfo *cautils.ScanInfo, customerGUID string) {
// g := getter.GetArmoAPIConnector() // download policy from ARMO backend
// g.SetCustomerGUID(customerGUID)
// scanInfo.PolicyGetter = g
// if scanInfo.ScanAll {
// frameworks, err := g.ListCustomFrameworks(customerGUID)
// if err != nil {
// glog.Error("failed to get custom frameworks") // handle error
// return
// }
// scanInfo.SetPolicyIdentifiers(frameworks, reporthandling.KindFramework)
// }
// }
// setConfigInputsGetter sets the config input getter - local file/github release/ArmoAPI
func getConfigInputsGetter(ControlsInputs string, accountID string, downloadReleasedPolicy *getter.DownloadReleasedPolicy) getter.IControlsInputsGetter {
if len(ControlsInputs) > 0 {
return getter.NewLoadPolicy([]string{ControlsInputs})
}
if accountID != "" {
g := getter.GetArmoAPIConnector() // download config from ARMO backend
g.SetCustomerGUID(accountID)
return g
}
if downloadReleasedPolicy == nil {
downloadReleasedPolicy = getter.NewDownloadReleasedPolicy()
}
if err := downloadReleasedPolicy.SetRegoObjects(); err != nil { // if failed to pull config inputs, fallback to BE
cautils.WarningDisplay(os.Stderr, "Warning: failed to get config inputs from github release, this may affect the scanning results\n")
}
return downloadReleasedPolicy
}
func getDownloadReleasedPolicy(downloadReleasedPolicy *getter.DownloadReleasedPolicy) getter.IPolicyGetter {
if err := downloadReleasedPolicy.SetRegoObjects(); err != nil { // if failed to pull policy, fallback to cache
cautils.WarningDisplay(os.Stderr, "Warning: failed to get policies from github release, loading policies from cache\n")
return getter.NewLoadPolicy(getDefaultFrameworksPaths())
} else {
return downloadReleasedPolicy
}
}
func getDefaultFrameworksPaths() []string {
fwPaths := []string{}
for i := range getter.NativeFrameworks {
fwPaths = append(fwPaths, getter.GetDefaultPath(getter.NativeFrameworks[i]))
}
return fwPaths
}
func listFrameworksNames(policyGetter getter.IPolicyGetter) []string {
fw, err := policyGetter.ListFrameworks()
if err != nil {
fw = getDefaultFrameworksPaths()
}
return fw
}