1
0
mirror of https://github.com/aquasecurity/kube-bench.git synced 2024-11-22 08:08:07 +00:00

move target mapping to config.yaml - updated version (#682)

* move target mapping to config.yaml

* Update config.yaml

* Update common.go

* Add support for eks-1.0

Add also eks-1.0 to map

* chore: merge correction

* Move file only used for testing

* Tidier logs

* Add target mapping for GKE and EKS

* fingers cross this finishes target mapping

Co-authored-by: Murali Paluru <leodotcloud@gmail.com>
Co-authored-by: Roberto Rojas <robertojrojas@gmail.com>
Co-authored-by: yoavrotems <yoavrotems97@gmail.com>
This commit is contained in:
Liz Rice 2020-08-30 08:16:21 +01:00 committed by GitHub
parent 01c77b2315
commit 772839fc92
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 119 additions and 54 deletions

View File

@ -201,3 +201,33 @@ version_mapping:
"gke-1.0": "gke-1.0" "gke-1.0": "gke-1.0"
"ocp-3.10": "rh-0.7" "ocp-3.10": "rh-0.7"
"ocp-3.11": "rh-0.7" "ocp-3.11": "rh-0.7"
target_mapping:
"cis-1.3":
- "master"
- "node"
"cis-1.4":
- "master"
- "node"
"cis-1.5":
- "master"
- "node"
- "controlplane"
- "etcd"
- "policies"
"gke-1.0":
- "master"
- "node"
- "controlplane"
- "etcd"
- "policies"
- "managedservices"
"eks-1.0":
- "master"
- "node"
- "controlplane"
- "policies"
- "managedservices"
"rh-0.7":
- "master"
- "node"

View File

@ -249,7 +249,7 @@ func mapToBenchmarkVersion(kubeToBenchmarkMap map[string]string, kv string) (str
if !found { if !found {
glog.V(1).Info(fmt.Sprintf("mapToBenchmarkVersion unable to find a match for: %q", kvOriginal)) glog.V(1).Info(fmt.Sprintf("mapToBenchmarkVersion unable to find a match for: %q", kvOriginal))
glog.V(3).Info(fmt.Sprintf("mapToBenchmarkVersion kubeToBenchmarkSMap: %#v", kubeToBenchmarkMap)) glog.V(3).Info(fmt.Sprintf("mapToBenchmarkVersion kubeToBenchmarkMap: %#v", kubeToBenchmarkMap))
return "", fmt.Errorf("unable to find a matching Benchmark Version match for kubernetes version: %s", kvOriginal) return "", fmt.Errorf("unable to find a matching Benchmark Version match for kubernetes version: %s", kvOriginal)
} }
@ -265,6 +265,15 @@ func loadVersionMapping(v *viper.Viper) (map[string]string, error) {
return kubeToBenchmarkMap, nil return kubeToBenchmarkMap, nil
} }
func loadTargetMapping(v *viper.Viper) (map[string][]string, error) {
benchmarkVersionToTargetsMap := v.GetStringMapStringSlice("target_mapping")
if len(benchmarkVersionToTargetsMap) == 0 {
return nil, fmt.Errorf("config file is missing 'target_mapping' section")
}
return benchmarkVersionToTargetsMap, nil
}
func getBenchmarkVersion(kubeVersion, benchmarkVersion string, v *viper.Viper) (bv string, err error) { func getBenchmarkVersion(kubeVersion, benchmarkVersion string, v *viper.Viper) (bv string, err error) {
if !isEmpty(kubeVersion) && !isEmpty(benchmarkVersion) { if !isEmpty(kubeVersion) && !isEmpty(benchmarkVersion) {
return "", fmt.Errorf("It is an error to specify both --version and --benchmark flags") return "", fmt.Errorf("It is an error to specify both --version and --benchmark flags")
@ -306,16 +315,16 @@ func isEtcd() bool {
} }
func isThisNodeRunning(nodeType check.NodeType) bool { func isThisNodeRunning(nodeType check.NodeType) bool {
glog.V(2).Infof("Checking if the current node is running %s components", nodeType) glog.V(3).Infof("Checking if the current node is running %s components", nodeType)
etcdConf := viper.Sub(string(nodeType)) nodeTypeConf := viper.Sub(string(nodeType))
if etcdConf == nil { if nodeTypeConf == nil {
glog.V(2).Infof("No %s components found to be running", nodeType) glog.V(2).Infof("No config for %s components found", nodeType)
return false return false
} }
components, err := getBinariesFunc(etcdConf, nodeType) components, err := getBinariesFunc(nodeTypeConf, nodeType)
if err != nil { if err != nil {
glog.V(2).Info(err) glog.V(2).Infof("Failed to find %s binaries: %v", nodeType, err)
return false return false
} }
if len(components) == 0 { if len(components) == 0 {
@ -323,6 +332,7 @@ func isThisNodeRunning(nodeType check.NodeType) bool {
return false return false
} }
glog.V(2).Infof("Node is running %s components", nodeType)
return true return true
} }
@ -337,7 +347,7 @@ func writeOutput(controlsCollection []*check.Controls) {
return return
} }
if jsonFmt { if jsonFmt {
writeJsonOutput(controlsCollection) writeJSONOutput(controlsCollection)
return return
} }
if pgSQL { if pgSQL {
@ -347,12 +357,12 @@ func writeOutput(controlsCollection []*check.Controls) {
writeStdoutOutput(controlsCollection) writeStdoutOutput(controlsCollection)
} }
func writeJsonOutput(controlsCollection []*check.Controls) { func writeJSONOutput(controlsCollection []*check.Controls) {
out, err := json.Marshal(controlsCollection) out, err := json.Marshal(controlsCollection)
if err != nil { if err != nil {
exitWithError(fmt.Errorf("failed to output in JSON format: %v", err)) exitWithError(fmt.Errorf("failed to output in JSON format: %v", err))
} }
PrintOutput(string(out), outputFile) printOutput(string(out), outputFile)
} }
func writeJunitOutput(controlsCollection []*check.Controls) { func writeJunitOutput(controlsCollection []*check.Controls) {
@ -361,7 +371,7 @@ func writeJunitOutput(controlsCollection []*check.Controls) {
if err != nil { if err != nil {
exitWithError(fmt.Errorf("failed to output in JUnit format: %v", err)) exitWithError(fmt.Errorf("failed to output in JUnit format: %v", err))
} }
PrintOutput(string(out), outputFile) printOutput(string(out), outputFile)
} }
} }
@ -400,7 +410,7 @@ func writeOutputToFile(output string, outputFile string) error {
return w.Flush() return w.Flush()
} }
func PrintOutput(output string, outputFile string) { func printOutput(output string, outputFile string) {
if len(outputFile) == 0 { if len(outputFile) == 0 {
fmt.Println(output) fmt.Println(output)
} else { } else {
@ -411,20 +421,16 @@ func PrintOutput(output string, outputFile string) {
} }
} }
var benchmarkVersionToTargetsMap = map[string][]string{
"cis-1.3": []string{string(check.MASTER), string(check.NODE)},
"cis-1.4": []string{string(check.MASTER), string(check.NODE)},
"cis-1.5": []string{string(check.MASTER), string(check.NODE), string(check.CONTROLPLANE), string(check.ETCD), string(check.POLICIES)},
"gke-1.0": []string{string(check.MASTER), string(check.NODE), string(check.CONTROLPLANE), string(check.ETCD), string(check.POLICIES), string(check.MANAGEDSERVICES)},
"eks-1.0": []string{string(check.NODE), string(check.CONTROLPLANE), string(check.POLICIES), string(check.MANAGEDSERVICES)},
}
// validTargets helps determine if the targets // validTargets helps determine if the targets
// are legitimate for the benchmarkVersion. // are legitimate for the benchmarkVersion.
func validTargets(benchmarkVersion string, targets []string) bool { func validTargets(benchmarkVersion string, targets []string, v *viper.Viper) (bool, error) {
benchmarkVersionToTargetsMap, err := loadTargetMapping(v)
if err != nil {
return false, err
}
providedTargets, found := benchmarkVersionToTargetsMap[benchmarkVersion] providedTargets, found := benchmarkVersionToTargetsMap[benchmarkVersion]
if !found { if !found {
return false return false, fmt.Errorf("No targets configured for %s", benchmarkVersion)
} }
for _, pt := range targets { for _, pt := range targets {
@ -437,9 +443,9 @@ func validTargets(benchmarkVersion string, targets []string) bool {
} }
if !f { if !f {
return false return false, nil
} }
} }
return true return true, nil
} }

View File

@ -154,7 +154,7 @@ func TestIsMaster(t *testing.T) {
}, },
{ {
name: "valid config, does not include master", name: "valid config, does not include master",
cfgFile: "../cfg/node_only.yaml", cfgFile: "../hack/node_only.yaml",
isMaster: false, isMaster: false,
}, },
} }
@ -364,6 +364,10 @@ func TestGetBenchmarkVersion(t *testing.T) {
} }
func TestValidTargets(t *testing.T) { func TestValidTargets(t *testing.T) {
viperWithData, err := loadConfigForTest()
if err != nil {
t.Fatalf("Unable to load config file %v", err)
}
cases := []struct { cases := []struct {
name string name string
benchmark string benchmark string
@ -410,7 +414,10 @@ func TestValidTargets(t *testing.T) {
for _, c := range cases { for _, c := range cases {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
ret := validTargets(c.benchmark, c.targets) ret, err := validTargets(c.benchmark, c.targets, viperWithData)
if err != nil {
t.Fatalf("Expected nil error, got: %v", err)
}
if ret != c.expected { if ret != c.expected {
t.Fatalf("Expected %t, got %t", c.expected, ret) t.Fatalf("Expected %t, got %t", c.expected, ret)
} }
@ -451,7 +458,7 @@ func TestIsEtcd(t *testing.T) {
}, },
{ {
name: "valid config, does not include etcd", name: "valid config, does not include etcd",
cfgFile: "../cfg/node_only.yaml", cfgFile: "../hack/node_only.yaml",
isEtcd: false, isEtcd: false,
}, },
} }
@ -532,11 +539,10 @@ func parseControlsJsonFile(filepath string) ([]*check.Controls, error) {
func loadConfigForTest() (*viper.Viper, error) { func loadConfigForTest() (*viper.Viper, error) {
viperWithData := viper.New() viperWithData := viper.New()
viperWithData.SetConfigFile(filepath.Join("..", cfgDir, "config.yaml")) viperWithData.SetConfigFile("../cfg/config.yaml")
if err := viperWithData.ReadInConfig(); err != nil { if err := viperWithData.ReadInConfig(); err != nil {
return nil, err return nil, err
} }
return viperWithData, nil return viperWithData, nil
} }

View File

@ -68,40 +68,57 @@ var RootCmd = &cobra.Command{
if err != nil { if err != nil {
exitWithError(fmt.Errorf("unable to determine benchmark version: %v", err)) exitWithError(fmt.Errorf("unable to determine benchmark version: %v", err))
} }
glog.V(1).Infof("Running checks for benchmark %v", bv)
if isMaster() { if isMaster() {
glog.V(1).Info("== Running master checks ==\n") glog.V(1).Info("== Running master checks ==")
runChecks(check.MASTER, loadConfig(check.MASTER, bv)) runChecks(check.MASTER, loadConfig(check.MASTER, bv))
// Control Plane is only valid for CIS 1.5 and later, // Control Plane is only valid for CIS 1.5 and later,
// this a gatekeeper for previous versions // this a gatekeeper for previous versions
if validTargets(bv, []string{string(check.CONTROLPLANE)}) { valid, err := validTargets(bv, []string{string(check.CONTROLPLANE)}, viper.GetViper())
glog.V(1).Info("== Running control plane checks ==\n") if err != nil {
exitWithError(fmt.Errorf("error validating targets: %v", err))
}
if valid {
glog.V(1).Info("== Running control plane checks ==")
runChecks(check.CONTROLPLANE, loadConfig(check.CONTROLPLANE, bv)) runChecks(check.CONTROLPLANE, loadConfig(check.CONTROLPLANE, bv))
} }
} }
// Etcd is only valid for CIS 1.5 and later, // Etcd is only valid for CIS 1.5 and later,
// this a gatekeeper for previous versions. // this a gatekeeper for previous versions.
if validTargets(bv, []string{string(check.ETCD)}) && isEtcd() { valid, err := validTargets(bv, []string{string(check.ETCD)}, viper.GetViper())
glog.V(1).Info("== Running etcd checks ==\n") if err != nil {
exitWithError(fmt.Errorf("error validating targets: %v", err))
}
if valid && isEtcd() {
glog.V(1).Info("== Running etcd checks ==")
runChecks(check.ETCD, loadConfig(check.ETCD, bv)) runChecks(check.ETCD, loadConfig(check.ETCD, bv))
} }
glog.V(1).Info("== Running node checks ==\n") glog.V(1).Info("== Running node checks ==")
runChecks(check.NODE, loadConfig(check.NODE, bv)) runChecks(check.NODE, loadConfig(check.NODE, bv))
// Policies is only valid for CIS 1.5 and later, // Policies is only valid for CIS 1.5 and later,
// this a gatekeeper for previous versions. // this a gatekeeper for previous versions.
if validTargets(bv, []string{string(check.POLICIES)}) { valid, err = validTargets(bv, []string{string(check.POLICIES)}, viper.GetViper())
glog.V(1).Info("== Running policies checks ==\n") if err != nil {
exitWithError(fmt.Errorf("error validating targets: %v", err))
}
if valid {
glog.V(1).Info("== Running policies checks ==")
runChecks(check.POLICIES, loadConfig(check.POLICIES, bv)) runChecks(check.POLICIES, loadConfig(check.POLICIES, bv))
} }
// Managedservices is only valid for GKE 1.0 and later, // Managedservices is only valid for GKE 1.0 and later,
// this a gatekeeper for previous versions. // this a gatekeeper for previous versions.
if validTargets(bv, []string{string(check.MANAGEDSERVICES)}) { valid, err = validTargets(bv, []string{string(check.MANAGEDSERVICES)}, viper.GetViper())
glog.V(1).Info("== Running managed services checks ==\n") if err != nil {
exitWithError(fmt.Errorf("error validating targets: %v", err))
}
if valid {
glog.V(1).Info("== Running managed services checks ==")
runChecks(check.MANAGEDSERVICES, loadConfig(check.MANAGEDSERVICES, bv)) runChecks(check.MANAGEDSERVICES, loadConfig(check.MANAGEDSERVICES, bv))
} }

View File

@ -32,21 +32,29 @@ var runCmd = &cobra.Command{
exitWithError(fmt.Errorf("unable to get `targets` from command line :%v", err)) exitWithError(fmt.Errorf("unable to get `targets` from command line :%v", err))
} }
benchmarkVersion, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, viper.GetViper()) bv, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, viper.GetViper())
if err != nil { if err != nil {
exitWithError(fmt.Errorf("unable to get benchmark version. error: %v", err)) exitWithError(fmt.Errorf("unable to get benchmark version. error: %v", err))
} }
glog.V(2).Infof("Checking targets %v for %v", targets, benchmarkVersion) glog.V(2).Infof("Checking targets %v for %v", targets, bv)
if len(targets) > 0 && !validTargets(benchmarkVersion, targets) { benchmarkVersionToTargetsMap, err := loadTargetMapping(viper.GetViper())
exitWithError(fmt.Errorf(fmt.Sprintf(`The specified --targets "%s" does not apply to the CIS Benchmark %s \n Valid targets %v`, strings.Join(targets, ","), benchmarkVersion, benchmarkVersionToTargetsMap[benchmarkVersion]))) if err != nil {
exitWithError(fmt.Errorf("error loading targets: %v", err))
}
valid, err := validTargets(bv, targets, viper.GetViper())
if err != nil {
exitWithError(fmt.Errorf("error validating targets: %v", err))
}
if len(targets) > 0 && !valid {
exitWithError(fmt.Errorf(fmt.Sprintf(`The specified --targets "%s" are not configured for the CIS Benchmark %s\n Valid targets %v`, strings.Join(targets, ","), bv, benchmarkVersionToTargetsMap[bv])))
} }
// Merge version-specific config if any. // Merge version-specific config if any.
path := filepath.Join(cfgDir, benchmarkVersion) path := filepath.Join(cfgDir, bv)
mergeConfig(path) mergeConfig(path)
err = run(targets, benchmarkVersion) err = run(targets, bv)
if err != nil { if err != nil {
fmt.Printf("Error in run: %v\n", err) fmt.Printf("Error in run: %v\n", err)
} }

View File

@ -214,9 +214,8 @@ func verifyBin(bin string) bool {
// but apiserver is not a match for kube-apiserver // but apiserver is not a match for kube-apiserver
reFirstWord := regexp.MustCompile(`^(\S*\/)*` + bin) reFirstWord := regexp.MustCompile(`^(\S*\/)*` + bin)
lines := strings.Split(out, "\n") lines := strings.Split(out, "\n")
glog.V(2).Info(fmt.Sprintf("verifyBin - lines(%d)", len(lines)))
for _, l := range lines { for _, l := range lines {
glog.V(2).Info(fmt.Sprintf("reFirstWord.Match(%s)\n\n\n\n", l)) glog.V(3).Info(fmt.Sprintf("reFirstWord.Match(%s)", l))
if reFirstWord.Match([]byte(l)) { if reFirstWord.Match([]byte(l)) {
return true return true
} }

View File

@ -20,4 +20,3 @@ var versionCmd = &cobra.Command{
func init() { func init() {
RootCmd.AddCommand(versionCmd) RootCmd.AddCommand(versionCmd)
} }