diff --git a/cfg/cis-1.5/controlplane.yaml b/cfg/cis-1.5/controlplane.yaml index 51c2612b1..b239a2653 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 5108ac092..805d96cf8 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 7292f1784..e91133923 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 04e826254..dafda4587 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 5ba709094..0fab55249 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 d4038c3b4..6ed445312 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 810614811..6e9196ba5 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 726df72c8..9341d181c 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 c19810e61..78080d90f 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 980762a76..554a0d66c 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 3517568ea..358b3a2eb 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 4436047cf..3f0e1b511 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 665b7f4ce..dff0c02ae 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/check/controls_test.go b/check/controls_test.go index ebe5e2908..a0015facb 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 12879b4b3..b918bec20 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.go b/cmd/common.go index 63d0c9d40..2cade9adb 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/common_test.go b/cmd/common_test.go index fce1ef152..29e417e7c 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"} diff --git a/cmd/master.go b/cmd/master.go index 31353989f..7b977e2f7 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 2afba5919..73a731ecd 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 47907b515..99b802ddb 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 2e4c59b4a..ccd56de26 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)