Repository: aquasecurity/kube-bench
Pull request #869 (2021-05-06 13:40:50)

Add detected kubernetes version

codecov[bot]: # [Codecov](https://codecov.io/gh/aquasecurity/kube-bench/pull/869?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity) Report
> Merging [#869](https://codecov.io/gh/aquasecurity/kube-bench/pull/869?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity) (a007f67) into [main](https://codecov.io/gh/aquasecurity/kube-bench/commit/a1bd51db99b70cdfe3a44d0487d04c8a1ff75ecf?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity) (a1bd51d) will **decrease** coverage by `0.01%`.
> The diff coverage is `18.75%`.

[![Impacted file tree graph](https://codecov.io/gh/aquasecurity/kube-bench/pull/869/graphs/tree.svg?width=650&height=150&src=pr&token=MVaDEmdgi9&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity)](https://codecov.io/gh/aquasecurity/kube-bench/pull/869?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity)

```diff
@@            Coverage Diff             @@
##             main     #869      +/-   ##
==========================================
- Coverage   64.91%   64.89%   -0.02%     
==========================================
  Files          14       14              
  Lines        1331     1336       +5     
==========================================
+ Hits          864      867       +3     
- Misses        409      411       +2     
  Partials       58       58              
```


| [Impacted Files](https://codecov.io/gh/aquasecurity/kube-bench/pull/869?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity) | Coverage Δ | |
|---|---|---|
| [cmd/master.go](https://codecov.io/gh/aquasecurity/kube-bench/pull/869/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-Y21kL21hc3Rlci5nbw==) | `50.00% <0.00%> (ø)` | |
| [cmd/node.go](https://codecov.io/gh/aquasecurity/kube-bench/pull/869/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-Y21kL25vZGUuZ28=) | `50.00% <0.00%> (ø)` | |
| [cmd/root.go](https://codecov.io/gh/aquasecurity/kube-bench/pull/869/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-Y21kL3Jvb3QuZ28=) | `38.67% <0.00%> (ø)` | |
| [cmd/run.go](https://codecov.io/gh/aquasecurity/kube-bench/pull/869/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-Y21kL3J1bi5nbw==) | `32.00% <0.00%> (ø)` | |
| [cmd/common.go](https://codecov.io/gh/aquasecurity/kube-bench/pull/869/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-Y21kL2NvbW1vbi5nbw==) | `55.01% <33.33%> (-0.08%)` | :arrow_down: |
| [check/controls.go](https://codecov.io/gh/aquasecurity/kube-bench/pull/869/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-Y2hlY2svY29udHJvbHMuZ28=) | `80.28% <100.00%> (+0.13%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/aquasecurity/kube-bench/pull/869?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/aquasecurity/kube-bench/pull/869?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity). Last update [a1bd51d...a007f67](https://codecov.io/gh/aquasecurity/kube-bench/pull/869?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity).


Patch:
diff --git a/cfg/cis-1.5/controlplane.yaml b/cfg/cis-1.5/controlplane.yaml
index 51c2612..b239a26 100644
--- a/cfg/cis-1.5/controlplane.yaml
+++ b/cfg/cis-1.5/controlplane.yaml
@@ -1,6 +1,6 @@
 ---
 controls:
-version: 1.5
+version: "cis-1.5"
 id: 3
 text: "Control Plane Configuration"
 type: "controlplane"
diff --git a/cfg/cis-1.5/etcd.yaml b/cfg/cis-1.5/etcd.yaml
index 5108ac0..805d96c 100644
--- a/cfg/cis-1.5/etcd.yaml
+++ b/cfg/cis-1.5/etcd.yaml
@@ -1,6 +1,6 @@
 ---
 controls:
-version: 1.15
+version: "cis-1.5"
 id: 2
 text: "Etcd Node Configuration"
 type: "etcd"
diff --git a/cfg/cis-1.5/master.yaml b/cfg/cis-1.5/master.yaml
index 7292f17..e911339 100644
--- a/cfg/cis-1.5/master.yaml
+++ b/cfg/cis-1.5/master.yaml
@@ -1,6 +1,6 @@
 ---
 controls:
-version: 1.5
+version: "cis-1.5"
 id: 1
 text: "Master Node Security Configuration"
 type: "master"
diff --git a/cfg/cis-1.5/node.yaml b/cfg/cis-1.5/node.yaml
index 04e8262..dafda45 100644
--- a/cfg/cis-1.5/node.yaml
+++ b/cfg/cis-1.5/node.yaml
@@ -1,6 +1,6 @@
 ---
 controls:
-version: 1.5
+version: "cis-1.5"
 id: 4
 text: "Worker Node Security Configuration"
 type: "node"
diff --git a/cfg/cis-1.5/policies.yaml b/cfg/cis-1.5/policies.yaml
index 5ba7090..0fab552 100644
--- a/cfg/cis-1.5/policies.yaml
+++ b/cfg/cis-1.5/policies.yaml
@@ -1,6 +1,6 @@
 ---
 controls:
-version: 1.5
+version: "cis-1.5"
 id: 5
 text: "Kubernetes Policies"
 type: "policies"
diff --git a/cfg/cis-1.6/controlplane.yaml b/cfg/cis-1.6/controlplane.yaml
index d4038c3..6ed4453 100644
--- a/cfg/cis-1.6/controlplane.yaml
+++ b/cfg/cis-1.6/controlplane.yaml
@@ -1,6 +1,6 @@
 ---
 controls:
-version: 1.6
+version: "cis-1.6"
 id: 3
 text: "Control Plane Configuration"
 type: "controlplane"
diff --git a/cfg/cis-1.6/etcd.yaml b/cfg/cis-1.6/etcd.yaml
index 8106148..6e9196b 100644
--- a/cfg/cis-1.6/etcd.yaml
+++ b/cfg/cis-1.6/etcd.yaml
@@ -1,6 +1,6 @@
 ---
 controls:
-version: 1.6
+version: "cis-1.6"
 id: 2
 text: "Etcd Node Configuration"
 type: "etcd"
diff --git a/cfg/cis-1.6/master.yaml b/cfg/cis-1.6/master.yaml
index 726df72..9341d18 100644
--- a/cfg/cis-1.6/master.yaml
+++ b/cfg/cis-1.6/master.yaml
@@ -1,6 +1,6 @@
 ---
 controls:
-version: 1.6
+version: "cis-1.6"
 id: 1
 text: "Master Node Security Configuration"
 type: "master"
diff --git a/cfg/cis-1.6/node.yaml b/cfg/cis-1.6/node.yaml
index c19810e..78080d9 100644
--- a/cfg/cis-1.6/node.yaml
+++ b/cfg/cis-1.6/node.yaml
@@ -1,6 +1,6 @@
 ---
 controls:
-version: 1.6
+version: "cis-1.6"
 id: 4
 text: "Worker Node Security Configuration"
 type: "node"
diff --git a/cfg/cis-1.6/policies.yaml b/cfg/cis-1.6/policies.yaml
index 980762a..554a0d6 100644
--- a/cfg/cis-1.6/policies.yaml
+++ b/cfg/cis-1.6/policies.yaml
@@ -1,6 +1,6 @@
 ---
 controls:
-version: 1.6
+version: "cis-1.6"
 id: 5
 text: "Kubernetes Policies"
 type: "policies"
diff --git a/cfg/rh-0.7/master.yaml b/cfg/rh-0.7/master.yaml
index 3517568..358b3a2 100644
--- a/cfg/rh-0.7/master.yaml
+++ b/cfg/rh-0.7/master.yaml
@@ -1,6 +1,6 @@
 ---
 controls:
-version: 3.10
+version: "rh-0.7"
 id: 1
 text: "Securing the OpenShift Master"
 type: "master"
diff --git a/cfg/rh-0.7/node.yaml b/cfg/rh-0.7/node.yaml
index 4436047..3f0e1b5 100644
--- a/cfg/rh-0.7/node.yaml
+++ b/cfg/rh-0.7/node.yaml
@@ -1,5 +1,6 @@
 ---
 controls:
+version: "rh-0.7"
 id: 2
 text: "Worker Node Security Configuration"
 type: "node"
diff --git a/check/controls.go b/check/controls.go
index 665b7f4..dff0c02 100644
--- a/check/controls.go
+++ b/check/controls.go
@@ -47,11 +47,12 @@ type OverallControls struct {
 
 // Controls holds all controls to check for master nodes.
 type Controls struct {
-	ID      string   `yaml:"id" json:"id"`
-	Version string   `json:"version"`
-	Text    string   `json:"text"`
-	Type    NodeType `json:"node_type"`
-	Groups  []*Group `json:"tests"`
+	ID              string   `yaml:"id" json:"id"`
+	Version         string   `json:"version"`
+	DetectedVersion string   `json:"detected_version,omitempty"`
+	Text            string   `json:"text"`
+	Type            NodeType `json:"node_type"`
+	Groups          []*Group `json:"tests"`
 	Summary
 }
 
@@ -79,7 +80,7 @@ type Summary struct {
 type Predicate func(group *Group, check *Check) bool
 
 // NewControls instantiates a new master Controls object.
-func NewControls(t NodeType, in []byte) (*Controls, error) {
+func NewControls(t NodeType, in []byte, detectedVersion string) (*Controls, error) {
 	c := new(Controls)
 
 	err := yaml.Unmarshal(in, c)
@@ -90,7 +91,7 @@ func NewControls(t NodeType, in []byte) (*Controls, error) {
 	if t != c.Type {
 		return nil, fmt.Errorf("non-%s controls file specified", t)
 	}
-
+	c.DetectedVersion = detectedVersion
 	return c, nil
 }
 
diff --git a/cmd/common.go b/cmd/common.go
index 63d0c9d..2cade9a 100644
--- a/cmd/common.go
+++ b/cmd/common.go
@@ -64,7 +64,7 @@ func NewRunFilter(opts FilterOpts) (check.Predicate, error) {
 	}, nil
 }
 
-func runChecks(nodetype check.NodeType, testYamlFile string) {
+func runChecks(nodetype check.NodeType, testYamlFile, detectedVersion string) {
 	// Verify config file was loaded into Viper during Cobra sub-command initialization.
 	if configFileError != nil {
 		colorPrint(check.FAIL, fmt.Sprintf("Failed to read config file: %v\n", configFileError))
@@ -106,7 +106,7 @@ func runChecks(nodetype check.NodeType, testYamlFile string) {
 	s, _ = makeSubstitutions(s, "kubeconfig", kubeconfmap)
 	s, _ = makeSubstitutions(s, "cafile", cafilemap)
 
-	controls, err := check.NewControls(nodetype, []byte(s))
+	controls, err := check.NewControls(nodetype, []byte(s), detectedVersion)
 	if err != nil {
 		exitWithError(fmt.Errorf("error setting up %s controls: %v", nodetype, err))
 	}
@@ -123,7 +123,7 @@ func runChecks(nodetype check.NodeType, testYamlFile string) {
 	controlsCollection = append(controlsCollection, controls)
 }
 
-func generateDefaultEnvAudit(controls *check.Controls, binSubs []string){
+func generateDefaultEnvAudit(controls *check.Controls, binSubs []string) {
 	for _, group := range controls.Groups {
 		for _, checkItem := range group.Checks {
 			if checkItem.Tests != nil && !checkItem.DisableEnvTesting {
@@ -314,11 +314,15 @@ func loadTargetMapping(v *viper.Viper) (map[string][]string, error) {
 }
 
 func getBenchmarkVersion(kubeVersion, benchmarkVersion, platformName string, v *viper.Viper) (bv string, err error) {
+	detecetedKubeVersion = "none"
 	if !isEmpty(kubeVersion) && !isEmpty(benchmarkVersion) {
 		return "", fmt.Errorf("It is an error to specify both --version and --benchmark flags")
 	}
-	if isEmpty(benchmarkVersion) && isEmpty(kubeVersion) && !isEmpty(platformName){
+	if isEmpty(benchmarkVersion) && isEmpty(kubeVersion) && !isEmpty(platformName) {
 		benchmarkVersion = getPlatformBenchmarkVersion(platformName)
+		if !isEmpty(benchmarkVersion) {
+			detecetedKubeVersion = benchmarkVersion
+		}
 	}
 
 	if isEmpty(benchmarkVersion) {
@@ -328,6 +332,7 @@ func getBenchmarkVersion(kubeVersion, benchmarkVersion, platformName string, v *
 				return "", fmt.Errorf("Version check failed: %s\nAlternatively, you can specify the version with --version", err)
 			}
 			kubeVersion = kv.BaseVersion()
+			detecetedKubeVersion = kubeVersion
 		}
 
 		kubeToBenchmarkMap, err := loadVersionMapping(v)
diff --git a/cmd/master.go b/cmd/master.go
index 3135398..7b977e2 100644
--- a/cmd/master.go
+++ b/cmd/master.go
@@ -34,7 +34,7 @@ var masterCmd = &cobra.Command{
 		}
 
 		filename := loadConfig(check.MASTER, bv)
-		runChecks(check.MASTER, filename)
+		runChecks(check.MASTER, filename, detecetedKubeVersion)
 		writeOutput(controlsCollection)
 	},
 	Deprecated: "this command will be retired soon. Please use the `run` command with `--targets=master` instead.",
diff --git a/cmd/node.go b/cmd/node.go
index 2afba59..73a731e 100644
--- a/cmd/node.go
+++ b/cmd/node.go
@@ -34,7 +34,7 @@ var nodeCmd = &cobra.Command{
 		}
 
 		filename := loadConfig(check.NODE, bv)
-		runChecks(check.NODE, filename)
+		runChecks(check.NODE, filename, detecetedKubeVersion)
 		writeOutput(controlsCollection)
 	},
 	Deprecated: "this command will be retired soon. Please use the `run` command with `--targets=node` instead.",
diff --git a/cmd/root.go b/cmd/root.go
index 47907b5..99b802d 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -33,33 +33,34 @@ type FilterOpts struct {
 }
 
 var (
-	envVarsPrefix       = "KUBE_BENCH"
-	defaultKubeVersion  = "1.18"
-	kubeVersion         string
-	benchmarkVersion    string
-	cfgFile             string
-	cfgDir              = "./cfg/"
-	jsonFmt             bool
-	junitFmt            bool
-	pgSQL               bool
-	aSFF                bool
-	masterFile          = "master.yaml"
-	nodeFile            = "node.yaml"
-	etcdFile            = "etcd.yaml"
-	controlplaneFile    = "controlplane.yaml"
-	policiesFile        = "policies.yaml"
-	managedservicesFile = "managedservices.yaml"
-	exitCode            int
-	noResults           bool
-	noSummary           bool
-	noRemediations      bool
-	skipIds             string
-	noTotals            bool
-	filterOpts          FilterOpts
-	includeTestOutput   bool
-	outputFile          string
-	configFileError     error
-	controlsCollection  []*check.Controls
+	envVarsPrefix        = "KUBE_BENCH"
+	defaultKubeVersion   = "1.18"
+	kubeVersion          string
+	detecetedKubeVersion string
+	benchmarkVersion     string
+	cfgFile              string
+	cfgDir               = "./cfg/"
+	jsonFmt              bool
+	junitFmt             bool
+	pgSQL                bool
+	aSFF                 bool
+	masterFile           = "master.yaml"
+	nodeFile             = "node.yaml"
+	etcdFile             = "etcd.yaml"
+	controlplaneFile     = "controlplane.yaml"
+	policiesFile         = "policies.yaml"
+	managedservicesFile  = "managedservices.yaml"
+	exitCode             int
+	noResults            bool
+	noSummary            bool
+	noRemediations       bool
+	skipIds              string
+	noTotals             bool
+	filterOpts           FilterOpts
+	includeTestOutput    bool
+	outputFile           string
+	configFileError      error
+	controlsCollection   []*check.Controls
 )
 
 // RootCmd represents the base command when called without any subcommands
@@ -76,7 +77,7 @@ var RootCmd = &cobra.Command{
 
 		if isMaster() {
 			glog.V(1).Info("== Running master checks ==")
-			runChecks(check.MASTER, loadConfig(check.MASTER, bv))
+			runChecks(check.MASTER, loadConfig(check.MASTER, bv), detecetedKubeVersion)
 
 			// Control Plane is only valid for CIS 1.5 and later,
 			// this a gatekeeper for previous versions
@@ -86,7 +87,7 @@ var RootCmd = &cobra.Command{
 			}
 			if valid {
 				glog.V(1).Info("== Running control plane checks ==")
-				runChecks(check.CONTROLPLANE, loadConfig(check.CONTROLPLANE, bv))
+				runChecks(check.CONTROLPLANE, loadConfig(check.CONTROLPLANE, bv), detecetedKubeVersion)
 			}
 		} else {
 			glog.V(1).Info("== Skipping master checks ==")
@@ -100,13 +101,13 @@ var RootCmd = &cobra.Command{
 		}
 		if valid && isEtcd() {
 			glog.V(1).Info("== Running etcd checks ==")
-			runChecks(check.ETCD, loadConfig(check.ETCD, bv))
+			runChecks(check.ETCD, loadConfig(check.ETCD, bv), detecetedKubeVersion)
 		} else {
 			glog.V(1).Info("== Skipping etcd checks ==")
 		}
 
 		glog.V(1).Info("== Running node checks ==")
-		runChecks(check.NODE, loadConfig(check.NODE, bv))
+		runChecks(check.NODE, loadConfig(check.NODE, bv), detecetedKubeVersion)
 
 		// Policies is only valid for CIS 1.5 and later,
 		// this a gatekeeper for previous versions.
@@ -116,7 +117,7 @@ var RootCmd = &cobra.Command{
 		}
 		if valid {
 			glog.V(1).Info("== Running policies checks ==")
-			runChecks(check.POLICIES, loadConfig(check.POLICIES, bv))
+			runChecks(check.POLICIES, loadConfig(check.POLICIES, bv), detecetedKubeVersion)
 		} else {
 			glog.V(1).Info("== Skipping policies checks ==")
 		}
@@ -129,7 +130,7 @@ var RootCmd = &cobra.Command{
 		}
 		if valid {
 			glog.V(1).Info("== Running managed services checks ==")
-			runChecks(check.MANAGEDSERVICES, loadConfig(check.MANAGEDSERVICES, bv))
+			runChecks(check.MANAGEDSERVICES, loadConfig(check.MANAGEDSERVICES, bv), detecetedKubeVersion)
 		} else {
 			glog.V(1).Info("== Skipping managed services checks ==")
 		}
diff --git a/cmd/run.go b/cmd/run.go
index 2e4c59b..ccd56de 100644
--- a/cmd/run.go
+++ b/cmd/run.go
@@ -75,7 +75,7 @@ func run(targets []string, benchmarkVersion string) (err error) {
 	for _, yamlFile := range yamlFiles {
 		_, name := filepath.Split(yamlFile)
 		testType := check.NodeType(strings.Split(name, ".")[0])
-		runChecks(testType, yamlFile)
+		runChecks(testType, yamlFile, detecetedKubeVersion)
 	}
 
 	writeOutput(controlsCollection)


Test patch:
diff --git a/check/controls_test.go b/check/controls_test.go
index ebe5e29..a0015fa 100644
--- a/check/controls_test.go
+++ b/check/controls_test.go
@@ -83,7 +83,7 @@ type: # not specified
 groups:
 `)
 		// when
-		_, err := NewControls(MASTER, in)
+		_, err := NewControls(MASTER, in, "")
 		// then
 		assert.EqualError(t, err, "non-master controls file specified")
 	})
@@ -92,7 +92,7 @@ groups:
 		// given
 		in := []byte("BOOM")
 		// when
-		_, err := NewControls(MASTER, in)
+		_, err := NewControls(MASTER, in, "")
 		// then
 		assert.EqualError(t, err, "failed to unmarshal YAML: yaml: unmarshal errors:\n  line 1: cannot unmarshal !!str `BOOM` into check.Controls")
 	})
@@ -118,7 +118,7 @@ groups:
   - id: G2/C1
   - id: G2/C2
 `)
-		controls, err := NewControls(MASTER, in)
+		controls, err := NewControls(MASTER, in, "")
 		assert.NoError(t, err)
 
 		var allChecks Predicate = func(group *Group, c *Check) bool {
@@ -153,7 +153,7 @@ groups:
   checks:
   - id: G1/C1
 `)
-		controls, err := NewControls(MASTER, in)
+		controls, err := NewControls(MASTER, in, "")
 		assert.NoError(t, err)
 
 		var allChecks Predicate = func(group *Group, c *Check) bool {
@@ -196,7 +196,7 @@ groups:
     scored: true
 `)
 		// and
-		controls, err := NewControls(MASTER, in)
+		controls, err := NewControls(MASTER, in, "")
 		assert.NoError(t, err)
 		// and
 		runner.On("Run", controls.Groups[0].Checks[0]).Return(PASS)
diff --git a/check/test_test.go b/check/test_test.go
index 12879b4..b918bec 100644
--- a/check/test_test.go
+++ b/check/test_test.go
@@ -38,7 +38,7 @@ func init() {
 	user := os.Getenv("USER")
 	s := strings.Replace(string(in), "$user", user, -1)
 
-	controls, err = NewControls(MASTER, []byte(s))
+	controls, err = NewControls(MASTER, []byte(s), "")
 	// controls, err = NewControls(MASTER, in)
 	if err != nil {
 		panic("Failed creating test controls: " + err.Error())
diff --git a/cmd/common_test.go b/cmd/common_test.go
index fce1ef1..29e417e 100644
--- a/cmd/common_test.go
+++ b/cmd/common_test.go
@@ -630,7 +630,7 @@ groups:
       Edit the config file /this/is/a/file/path and set SomeSampleFlag to true.
     scored: true
 `)
-	controls, err := check.NewControls(check.MASTER, input)
+	controls, err := check.NewControls(check.MASTER, input, "")
 	assert.NoError(t, err)
 
 	binSubs := []string{"TestBinPath"}