From a6161aa8684818157d583e1e64b56d4c6b51046d Mon Sep 17 00:00:00 2001 From: Liz Rice <liz@lizrice.com> Date: Tue, 4 Aug 2020 16:04:02 +0100 Subject: [PATCH] Warn if kubectl can't autodetect the version (#656) * Add warning if lacking kubeconfig for auto-detect * Only run getbenchmarkVersion once * Remove call to continueWithError --- cmd/common.go | 8 +------- cmd/master.go | 10 +++++++++- cmd/node.go | 10 +++++++++- cmd/root.go | 22 +++++++++++----------- cmd/util.go | 6 +++++- 5 files changed, 35 insertions(+), 21 deletions(-) diff --git a/cmd/common.go b/cmd/common.go index 0dd5c51..0bc815e 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -191,7 +191,7 @@ func prettyPrint(r *check.Controls, summary check.Summary) { // loadConfig finds the correct config dir based on the kubernetes version, // merges any specific config.yaml file found with the main config // and returns the benchmark file to use. -func loadConfig(nodetype check.NodeType) string { +func loadConfig(nodetype check.NodeType, benchmarkVersion string) string { var file string var err error @@ -210,11 +210,6 @@ func loadConfig(nodetype check.NodeType) string { file = managedservicesFile } - benchmarkVersion, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, viper.GetViper()) - if err != nil { - exitWithError(fmt.Errorf("failed to get benchMark version: %v", err)) - } - path, err := getConfigFilePath(benchmarkVersion, file) if err != nil { exitWithError(fmt.Errorf("can't find %s controls file in %s: %v", nodetype, cfgDir, err)) @@ -302,7 +297,6 @@ func getBenchmarkVersion(kubeVersion, benchmarkVersion string, v *viper.Viper) ( // isMaster verify if master components are running on the node. func isMaster() bool { - loadConfig(check.MASTER) return isThisNodeRunning(check.MASTER) } diff --git a/cmd/master.go b/cmd/master.go index 76ccd5b..5b345e9 100644 --- a/cmd/master.go +++ b/cmd/master.go @@ -15,8 +15,11 @@ package cmd import ( + "fmt" + "github.com/aquasecurity/kube-bench/check" "github.com/spf13/cobra" + "github.com/spf13/viper" ) // masterCmd represents the master command @@ -25,7 +28,12 @@ var masterCmd = &cobra.Command{ Short: "Run Kubernetes benchmark checks from the master.yaml file.", Long: `Run Kubernetes benchmark checks from the master.yaml file in cfg/<version>.`, Run: func(cmd *cobra.Command, args []string) { - filename := loadConfig(check.MASTER) + bv, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, viper.GetViper()) + if err != nil { + exitWithError(fmt.Errorf("unable to determine benchmark version: %v", err)) + } + + filename := loadConfig(check.MASTER, bv) runChecks(check.MASTER, filename) writeOutput(controlsCollection) }, diff --git a/cmd/node.go b/cmd/node.go index d2f0b72..707bff6 100644 --- a/cmd/node.go +++ b/cmd/node.go @@ -15,8 +15,11 @@ package cmd import ( + "fmt" + "github.com/aquasecurity/kube-bench/check" "github.com/spf13/cobra" + "github.com/spf13/viper" ) // nodeCmd represents the node command @@ -25,7 +28,12 @@ var nodeCmd = &cobra.Command{ Short: "Run Kubernetes benchmark checks from the node.yaml file.", Long: `Run Kubernetes benchmark checks from the node.yaml file in cfg/<version>.`, Run: func(cmd *cobra.Command, args []string) { - filename := loadConfig(check.NODE) + bv, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, viper.GetViper()) + if err != nil { + exitWithError(fmt.Errorf("unable to determine benchmark version: %v", err)) + } + + filename := loadConfig(check.NODE, bv) runChecks(check.NODE, filename) writeOutput(controlsCollection) }, diff --git a/cmd/root.go b/cmd/root.go index 33c3819..702ab15 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -64,45 +64,45 @@ var RootCmd = &cobra.Command{ Short: "Run CIS Benchmarks checks against a Kubernetes deployment", Long: `This tool runs the CIS Kubernetes Benchmark (https://www.cisecurity.org/benchmark/kubernetes/)`, Run: func(cmd *cobra.Command, args []string) { - benchmarkVersion, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, viper.GetViper()) + bv, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, viper.GetViper()) if err != nil { exitWithError(fmt.Errorf("unable to determine benchmark version: %v", err)) } if isMaster() { glog.V(1).Info("== Running master checks ==\n") - runChecks(check.MASTER, loadConfig(check.MASTER)) + runChecks(check.MASTER, loadConfig(check.MASTER, bv)) // Control Plane is only valid for CIS 1.5 and later, // this a gatekeeper for previous versions - if validTargets(benchmarkVersion, []string{string(check.CONTROLPLANE)}) { + if validTargets(bv, []string{string(check.CONTROLPLANE)}) { glog.V(1).Info("== Running control plane checks ==\n") - runChecks(check.CONTROLPLANE, loadConfig(check.CONTROLPLANE)) + runChecks(check.CONTROLPLANE, loadConfig(check.CONTROLPLANE, bv)) } } // Etcd is only valid for CIS 1.5 and later, // this a gatekeeper for previous versions. - if validTargets(benchmarkVersion, []string{string(check.ETCD)}) && isEtcd() { + if validTargets(bv, []string{string(check.ETCD)}) && isEtcd() { glog.V(1).Info("== Running etcd checks ==\n") - runChecks(check.ETCD, loadConfig(check.ETCD)) + runChecks(check.ETCD, loadConfig(check.ETCD, bv)) } glog.V(1).Info("== Running node checks ==\n") - runChecks(check.NODE, loadConfig(check.NODE)) + runChecks(check.NODE, loadConfig(check.NODE, bv)) // Policies is only valid for CIS 1.5 and later, // this a gatekeeper for previous versions. - if validTargets(benchmarkVersion, []string{string(check.POLICIES)}) { + if validTargets(bv, []string{string(check.POLICIES)}) { glog.V(1).Info("== Running policies checks ==\n") - runChecks(check.POLICIES, loadConfig(check.POLICIES)) + runChecks(check.POLICIES, loadConfig(check.POLICIES, bv)) } // Managedservices is only valid for GKE 1.0 and later, // this a gatekeeper for previous versions. - if validTargets(benchmarkVersion, []string{string(check.MANAGEDSERVICES)}) { + if validTargets(bv, []string{string(check.MANAGEDSERVICES)}) { glog.V(1).Info("== Running managed services checks ==\n") - runChecks(check.MANAGEDSERVICES, loadConfig(check.MANAGEDSERVICES)) + runChecks(check.MANAGEDSERVICES, loadConfig(check.MANAGEDSERVICES, bv)) } writeOutput(controlsCollection) diff --git a/cmd/util.go b/cmd/util.go index da1444c..c716ecf 100644 --- a/cmd/util.go +++ b/cmd/util.go @@ -276,7 +276,7 @@ func multiWordReplace(s string, subname string, sub string) string { const missingKubectlKubeletMessage = ` Unable to find the programs kubectl or kubelet in the PATH. These programs are used to determine which version of Kubernetes is running. -Make sure the /usr/local/mount-from-host/bin directory is mapped to the container, +Make sure the /usr/local/mount-from-host/bin directory is mapped to the container, either in the job.yaml file, or Docker command. For job.yaml: @@ -346,6 +346,10 @@ func getVersionFromKubectlOutput(s string) string { serverVersionRe := regexp.MustCompile(`Server Version: v(\d+.\d+)`) subs := serverVersionRe.FindStringSubmatch(s) if len(subs) < 2 { + if strings.Contains(s, "The connection to the server") { + msg := fmt.Sprintf(`Warning: Kubernetes version was not auto-detected because kubectl could not connect to the Kubernetes server. This may be because the kubeconfig information is missing or has credentials that do not match the server. Assuming default version %s`, defaultKubeVersion) + fmt.Fprintln(os.Stderr, msg) + } glog.V(1).Info(fmt.Sprintf("Unable to get Kubernetes version from kubectl, using default version: %s", defaultKubeVersion)) return defaultKubeVersion } -- GitLab