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:
parent
01c77b2315
commit
772839fc92
@ -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"
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
37
cmd/root.go
37
cmd/root.go
@ -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))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
cmd/run.go
20
cmd/run.go
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -20,4 +20,3 @@ var versionCmd = &cobra.Command{
|
|||||||
func init() {
|
func init() {
|
||||||
RootCmd.AddCommand(versionCmd)
|
RootCmd.AddCommand(versionCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user