1
0
mirror of https://github.com/aquasecurity/kube-bench.git synced 2024-11-21 23:58:06 +00:00

Update auto-detection codes to support check platform version (#1074)

Co-authored-by: Yoav Rotem <yoavrotems97@gmail.com>
This commit is contained in:
Huang Huang 2022-01-10 21:25:15 +08:00 committed by GitHub
parent 7dd6fccd17
commit 1fad8f5083
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 95 additions and 63 deletions

View File

@ -313,13 +313,13 @@ func loadTargetMapping(v *viper.Viper) (map[string][]string, error) {
return benchmarkVersionToTargetsMap, nil
}
func getBenchmarkVersion(kubeVersion, benchmarkVersion, platformName string, v *viper.Viper) (bv string, err error) {
func getBenchmarkVersion(kubeVersion, benchmarkVersion string, platform Platform, 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) {
benchmarkVersion = getPlatformBenchmarkVersion(platformName)
if isEmpty(benchmarkVersion) && isEmpty(kubeVersion) && !isEmpty(platform.Name) {
benchmarkVersion = getPlatformBenchmarkVersion(platform)
if !isEmpty(benchmarkVersion) {
detecetedKubeVersion = benchmarkVersion
}

View File

@ -324,9 +324,9 @@ func TestGetBenchmarkVersion(t *testing.T) {
t.Fatalf("Unable to load config file %v", err)
}
type getBenchmarkVersionFnToTest func(kubeVersion, benchmarkVersion, platformName string, v *viper.Viper) (string, error)
type getBenchmarkVersionFnToTest func(kubeVersion, benchmarkVersion string, platform Platform, v *viper.Viper) (string, error)
withFakeKubectl := func(kubeVersion, benchmarkVersion, platformName string, v *viper.Viper, fn getBenchmarkVersionFnToTest) (string, error) {
withFakeKubectl := func(kubeVersion, benchmarkVersion string, platform Platform, v *viper.Viper, fn getBenchmarkVersionFnToTest) (string, error) {
execCode := `#!/bin/sh
echo '{"serverVersion": {"major": "1", "minor": "18", "gitVersion": "v1.18.10"}}'
`
@ -336,40 +336,40 @@ func TestGetBenchmarkVersion(t *testing.T) {
}
defer restore()
return fn(kubeVersion, benchmarkVersion, platformName, v)
return fn(kubeVersion, benchmarkVersion, platform, v)
}
withNoPath := func(kubeVersion, benchmarkVersion, platformName string, v *viper.Viper, fn getBenchmarkVersionFnToTest) (string, error) {
withNoPath := func(kubeVersion, benchmarkVersion string, platform Platform, v *viper.Viper, fn getBenchmarkVersionFnToTest) (string, error) {
restore, err := prunePath()
if err != nil {
t.Fatal("Failed when calling prunePath ", err)
}
defer restore()
return fn(kubeVersion, benchmarkVersion, platformName, v)
return fn(kubeVersion, benchmarkVersion, platform, v)
}
type getBenchmarkVersionFn func(string, string, string, *viper.Viper, getBenchmarkVersionFnToTest) (string, error)
type getBenchmarkVersionFn func(string, string, Platform, *viper.Viper, getBenchmarkVersionFnToTest) (string, error)
cases := []struct {
n string
kubeVersion string
benchmarkVersion string
platformName string
platform Platform
v *viper.Viper
callFn getBenchmarkVersionFn
exp string
succeed bool
}{
{n: "both versions", kubeVersion: "1.11", benchmarkVersion: "cis-1.3", platformName: "", exp: "cis-1.3", callFn: withNoPath, v: viper.New(), succeed: false},
{n: "no version-missing-kubectl", kubeVersion: "", benchmarkVersion: "", platformName: "", v: viperWithData, exp: "cis-1.6", callFn: withNoPath, succeed: true},
{n: "no version-fakeKubectl", kubeVersion: "", benchmarkVersion: "", platformName: "", v: viperWithData, exp: "cis-1.6", callFn: withFakeKubectl, succeed: true},
{n: "kubeVersion", kubeVersion: "1.15", benchmarkVersion: "", platformName: "", v: viperWithData, exp: "cis-1.5", callFn: withNoPath, succeed: true},
{n: "ocpVersion310", kubeVersion: "ocp-3.10", benchmarkVersion: "", platformName: "", v: viperWithData, exp: "rh-0.7", callFn: withNoPath, succeed: true},
{n: "ocpVersion311", kubeVersion: "ocp-3.11", benchmarkVersion: "", platformName: "", v: viperWithData, exp: "rh-0.7", callFn: withNoPath, succeed: true},
{n: "gke12", kubeVersion: "gke-1.2.0", benchmarkVersion: "", platformName: "", v: viperWithData, exp: "gke-1.2.0", callFn: withNoPath, succeed: true},
{n: "both versions", kubeVersion: "1.11", benchmarkVersion: "cis-1.3", platform: Platform{}, exp: "cis-1.3", callFn: withNoPath, v: viper.New(), succeed: false},
{n: "no version-missing-kubectl", kubeVersion: "", benchmarkVersion: "", platform: Platform{}, v: viperWithData, exp: "cis-1.6", callFn: withNoPath, succeed: true},
{n: "no version-fakeKubectl", kubeVersion: "", benchmarkVersion: "", platform: Platform{}, v: viperWithData, exp: "cis-1.6", callFn: withFakeKubectl, succeed: true},
{n: "kubeVersion", kubeVersion: "1.15", benchmarkVersion: "", platform: Platform{}, v: viperWithData, exp: "cis-1.5", callFn: withNoPath, succeed: true},
{n: "ocpVersion310", kubeVersion: "ocp-3.10", benchmarkVersion: "", platform: Platform{}, v: viperWithData, exp: "rh-0.7", callFn: withNoPath, succeed: true},
{n: "ocpVersion311", kubeVersion: "ocp-3.11", benchmarkVersion: "", platform: Platform{}, v: viperWithData, exp: "rh-0.7", callFn: withNoPath, succeed: true},
{n: "gke12", kubeVersion: "gke-1.2.0", benchmarkVersion: "", platform: Platform{}, v: viperWithData, exp: "gke-1.2.0", callFn: withNoPath, succeed: true},
}
for _, c := range cases {
rv, err := c.callFn(c.kubeVersion, c.benchmarkVersion, c.platformName, c.v, getBenchmarkVersion)
rv, err := c.callFn(c.kubeVersion, c.benchmarkVersion, c.platform, c.v, getBenchmarkVersion)
if c.succeed {
if err != nil {
t.Errorf("[%q]-Unexpected error: %v", c.n, err)

View File

@ -28,7 +28,7 @@ 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) {
bv, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, getPlatformName(), viper.GetViper())
bv, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, getPlatformInfo(), viper.GetViper())
if err != nil {
exitWithError(fmt.Errorf("unable to determine benchmark version: %v", err))
}

View File

@ -28,7 +28,7 @@ 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) {
bv, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, getPlatformName(), viper.GetViper())
bv, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, getPlatformInfo(), viper.GetViper())
if err != nil {
exitWithError(fmt.Errorf("unable to determine benchmark version: %v", err))
}

View File

@ -69,7 +69,7 @@ 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) {
bv, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, getPlatformName(), viper.GetViper())
bv, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, getPlatformInfo(), viper.GetViper())
if err != nil {
exitWithError(fmt.Errorf("unable to determine benchmark version: %v", err))
}

View File

@ -32,7 +32,7 @@ var runCmd = &cobra.Command{
exitWithError(fmt.Errorf("unable to get `targets` from command line :%v", err))
}
bv, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, getPlatformName(), viper.GetViper())
bv, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, getPlatformInfo(), viper.GetViper())
if err != nil {
exitWithError(fmt.Errorf("unable to get benchmark version. error: %v", err))
}

View File

@ -42,6 +42,15 @@ func init() {
getBinariesFunc = getBinaries
}
type Platform struct {
Name string
Version string
}
func (p Platform) String() string {
return fmt.Sprintf("Platform{ Name: %s Version: %s }", p.Name, p.Version)
}
func exitWithError(err error) {
fmt.Fprintf(os.Stderr, "\n%v\n", err)
// flush before exit non-zero
@ -427,49 +436,59 @@ These program names are provided in the config.yaml, section '%s.%s.bins'
return fmt.Sprintf(errMessageTemplate, component, componentRoleName, binList, componentType, component)
}
func getPlatformName() string {
func getPlatformInfo() Platform {
openShiftVersion := getOpenShiftVersion()
if openShiftVersion != "" {
return openShiftVersion
openShiftInfo := getOpenShiftInfo()
if openShiftInfo.Name != "" && openShiftInfo.Version != "" {
return openShiftInfo
}
kv, err := getKubeVersion()
if err != nil {
glog.V(2).Info(err)
return ""
return Platform{}
}
return getPlatformNameFromVersion(kv.GitVersion)
return getPlatformInfoFromVersion(kv.GitVersion)
}
func getPlatformNameFromVersion(s string) string {
versionRe := regexp.MustCompile(`v\d+\.\d+\.\d+-(\w+)(?:[.\-])\w+`)
func getPlatformInfoFromVersion(s string) Platform {
versionRe := regexp.MustCompile(`v(\d+\.\d+)\.\d+-(\w+)(?:[.\-])\w+`)
subs := versionRe.FindStringSubmatch(s)
if len(subs) < 2 {
return ""
if len(subs) < 3 {
return Platform{}
}
return Platform{
Name: subs[2],
Version: subs[1],
}
return subs[1]
}
func getPlatformBenchmarkVersion(platform string) string {
func getPlatformBenchmarkVersion(platform Platform) string {
glog.V(3).Infof("getPlatformBenchmarkVersion platform: %s", platform)
switch platform {
switch platform.Name {
case "eks":
return "eks-1.0.1"
case "gke":
// TODO: support check kubeVersion
return "gke-1.2.0"
switch platform.Version {
case "1.15", "1.16", "1.17", "1.18", "1.19":
return "gke-1.0"
default:
return "gke-1.2.0"
}
case "aliyun":
return "ack-1.0"
case "ocp-3.10":
return "rh-0.7"
case "ocp-4.1":
return "rh-1.0"
case "ocp":
switch platform.Version {
case "3.10":
return "rh-0.7"
case "4.1":
return "rh-1.0"
}
}
return ""
}
func getOpenShiftVersion() string {
func getOpenShiftInfo() Platform {
glog.V(1).Info("Checking for oc")
_, err := exec.LookPath("oc")
@ -485,10 +504,10 @@ func getOpenShiftVersion() string {
subs = versionRe.FindStringSubmatch(string(out))
}
if len(subs) > 1 {
glog.V(2).Infof("OCP output '%s' \nplatform is %s \nocp %v", string(out), getPlatformNameFromVersion(string(out)), subs[1])
glog.V(2).Infof("OCP output '%s' \nplatform is %s \nocp %v", string(out), getPlatformInfoFromVersion(string(out)), subs[1])
ocpBenchmarkVersion, err := getOcpValidVersion(subs[1])
if err == nil {
return fmt.Sprintf("ocp-%s", ocpBenchmarkVersion)
return Platform{Name: "ocp", Version: ocpBenchmarkVersion}
} else {
glog.V(1).Infof("Can't get getOcpValidVersion: %v", err)
}
@ -501,7 +520,7 @@ func getOpenShiftVersion() string {
} else {
glog.V(1).Infof("Can't find oc command: %v", err)
}
return ""
return Platform{}
}
func getOcpValidVersion(ocpVer string) (string, error) {

View File

@ -527,46 +527,45 @@ func Test_getPlatformNameFromKubectlOutput(t *testing.T) {
tests := []struct {
name string
args args
want string
want Platform
}{
{
name: "eks",
args: args{s: "v1.17.9-eks-4c6976"},
want: "eks",
want: Platform{Name: "eks", Version: "1.17"},
},
{
name: "gke",
args: args{s: "v1.17.6-gke.1"},
want: "gke",
want: Platform{Name: "gke", Version: "1.17"},
},
{
name: "ack",
args: args{s: "v1.18.8-aliyun.1"},
want: "aliyun",
want: Platform{Name: "aliyun", Version: "1.18"},
},
{
name: "unknown",
args: args{s: "v1.17.6"},
want: "",
want: Platform{},
},
{
name: "empty string",
args: args{s: ""},
want: "",
want: Platform{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := getPlatformNameFromVersion(tt.args.s); got != tt.want {
t.Errorf("getPlatformNameFromKubectlOutput() = %v, want %v", got, tt.want)
}
got := getPlatformInfoFromVersion(tt.args.s)
assert.Equal(t, tt.want, got)
})
}
}
func Test_getPlatformBenchmarkVersion(t *testing.T) {
type args struct {
platform string
platform Platform
}
tests := []struct {
name string
@ -576,49 +575,63 @@ func Test_getPlatformBenchmarkVersion(t *testing.T) {
{
name: "eks",
args: args{
platform: "eks",
platform: Platform{Name: "eks"},
},
want: "eks-1.0.1",
},
{
name: "gke",
name: "gke 1.19",
args: args{
platform: "gke",
platform: Platform{Name: "gke", Version: "1.19"},
},
want: "gke-1.0",
},
{
name: "gke 1.20",
args: args{
platform: Platform{Name: "gke", Version: "1.20"},
},
want: "gke-1.2.0",
},
{
name: "gke 1.22",
args: args{
platform: Platform{Name: "gke", Version: "1.22"},
},
want: "gke-1.2.0",
},
{
name: "aliyun",
args: args{
platform: "aliyun",
platform: Platform{Name: "aliyun"},
},
want: "ack-1.0",
},
{
name: "unknown",
args: args{
platform: "rh",
platform: Platform{Name: "rh"},
},
want: "",
},
{
name: "empty",
args: args{
platform: "",
platform: Platform{},
},
want: "",
},
{
name: "openshift3",
args: args{
platform: "ocp-3.10",
platform: Platform{Name: "ocp", Version: "3.10"},
},
want: "rh-0.7",
},
{
name: "openshift4",
args: args{
platform: "ocp-4.1",
platform: Platform{Name: "ocp", Version: "4.1"},
},
want: "rh-1.0",
},