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

Use kubectl to check the kubernetes version

This commit is contained in:
Liz Rice 2017-08-11 17:59:57 +01:00
parent 50cce99daf
commit 96c469669c
3 changed files with 125 additions and 12 deletions

View File

@ -45,7 +45,8 @@ var (
errmsgs string errmsgs string
// TODO: Consider specifying this in config file. // TODO: Consider specifying this in config file.
kubeVersion = "1.7.0" kubeMajorVersion = "1"
kubeMinorVersion = "7"
) )
func runChecks(t check.NodeType) { func runChecks(t check.NodeType) {
@ -77,6 +78,7 @@ func runChecks(t check.NodeType) {
fedControllerManagerBin = viper.GetString("installation." + installation + ".federated.bin.controller-manager") fedControllerManagerBin = viper.GetString("installation." + installation + ".federated.bin.controller-manager")
// Run kubernetes installation validation checks. // Run kubernetes installation validation checks.
verifyKubeVersion(kubeMajorVersion, kubeMinorVersion)
verifyNodeType(t) verifyNodeType(t)
switch t { switch t {
@ -150,15 +152,12 @@ func runChecks(t check.NodeType) {
func verifyNodeType(t check.NodeType) { func verifyNodeType(t check.NodeType) {
switch t { switch t {
case check.MASTER: case check.MASTER:
verifyKubeVersion(apiserverBin)
verifyBin(apiserverBin, schedulerBin, controllerManagerBin) verifyBin(apiserverBin, schedulerBin, controllerManagerBin)
verifyConf(apiserverConf, schedulerConf, controllerManagerConf) verifyConf(apiserverConf, schedulerConf, controllerManagerConf)
case check.NODE: case check.NODE:
verifyKubeVersion(kubeletBin)
verifyBin(kubeletBin, proxyBin) verifyBin(kubeletBin, proxyBin)
verifyConf(kubeletConf, proxyConf) verifyConf(kubeletConf, proxyConf)
case check.FEDERATED: case check.FEDERATED:
verifyKubeVersion(fedApiserverBin)
verifyBin(fedApiserverBin, fedControllerManagerBin) verifyBin(fedApiserverBin, fedControllerManagerBin)
} }
} }

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"os" "os"
"os/exec" "os/exec"
"regexp"
"strings" "strings"
"github.com/aquasecurity/kube-bench/check" "github.com/aquasecurity/kube-bench/check"
@ -123,25 +124,61 @@ func verifyBin(binPath ...string) {
} }
} }
func verifyKubeVersion(b string) { func verifyKubeVersion(major string, minor string) {
// These executables might not be on the user's path. // These executables might not be on the user's path.
// TODO! Check the version number using kubectl, which is more likely to be on the path.
_, err := exec.LookPath(b) _, err := exec.LookPath("kubectl")
if err != nil { if err != nil {
continueWithError(err, sprintlnWarn("Kubernetes version check skipped")) continueWithError(err, sprintlnWarn("Kubernetes version check skipped"))
return return
} }
cmd := exec.Command(b, "--version") cmd := exec.Command("kubectl", "version")
out, err := cmd.Output() out, err := cmd.Output()
if err != nil { if err != nil {
continueWithError(err, sprintlnWarn("Kubernetes version check skipped")) s := fmt.Sprintf("Kubernetes version check skipped with error %v", err)
continueWithError(err, sprintlnWarn(s))
return return
} }
matched := strings.Contains(string(out), kubeVersion) msg := checkVersion("Client", string(out), major, minor)
if !matched { if msg != "" {
printlnWarn(fmt.Sprintf("Unsupported kubernetes version: %s", out)) continueWithError(fmt.Errorf(msg), msg)
}
msg = checkVersion("Server", string(out), major, minor)
if msg != "" {
continueWithError(fmt.Errorf(msg), msg)
} }
} }
var regexVersionMajor = regexp.MustCompile("Major:\"([0-9]+)\"")
var regexVersionMinor = regexp.MustCompile("Minor:\"([0-9]+)\"")
func checkVersion(x string, s string, expMajor string, expMinor string) string {
regexVersion, err := regexp.Compile(x + " Version: version.Info{(.*)}")
if err != nil {
return fmt.Sprintf("Error checking Kubernetes version: %v", err)
}
ss := regexVersion.FindString(s)
major := versionMatch(regexVersionMajor, ss)
minor := versionMatch(regexVersionMinor, ss)
if major == "" || minor == "" {
return fmt.Sprintf("Couldn't find %s version from kubectl output '%s'", x, s)
}
if major != expMajor || minor != expMinor {
return fmt.Sprintf("Unexpected %s version %s.%s", x, major, minor)
}
return ""
}
func versionMatch(r *regexp.Regexp, s string) string {
match := r.FindStringSubmatch(s)
if len(match) < 2 {
return ""
}
return match[1]
}

77
cmd/util_test.go Normal file
View File

@ -0,0 +1,77 @@
// Copyright © 2017 Aqua Security Software Ltd. <info@aquasec.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"regexp"
"testing"
)
func TestCheckVersion(t *testing.T) {
kubeoutput := `Client Version: version.Info{Major:"1", Minor:"7", GitVersion:"v1.7.0", GitCommit:"d3ada0119e776222f11ec7945e6d860061339aad", GitTreeState:"clean", BuildDate:"2017-06-30T09:51:01Z", GoVersion:"go1.8.3", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"7", GitVersion:"v1.7.0", GitCommit:"d3ada0119e776222f11ec7945e6d860061339aad", GitTreeState:"clean", BuildDate:"2017-07-26T00:12:31Z", GoVersion:"go1.8.3", Compiler:"gc", Platform:"linux/amd64"}`
cases := []struct {
t string
s string
major string
minor string
exp string
}{
{t: "Client", s: kubeoutput, major: "1", minor: "7"},
{t: "Server", s: kubeoutput, major: "1", minor: "7"},
{t: "Client", s: kubeoutput, major: "1", minor: "6", exp: "Unexpected Client version 1.7"},
{t: "Client", s: kubeoutput, major: "2", minor: "0", exp: "Unexpected Client version 1.7"},
{t: "Server", s: "something unexpected", major: "2", minor: "0", exp: "Couldn't find Server version from kubectl output 'something unexpected'"},
}
for _, c := range cases {
t.Run("", func(t *testing.T) {
m := checkVersion(c.t, c.s, c.major, c.minor)
if m != c.exp {
t.Fatalf("Got: %s, expected: %s", m, c.exp)
}
})
}
}
func TestVersionMatch(t *testing.T) {
minor := regexVersionMinor
major := regexVersionMajor
client := `Client Version: version.Info{Major:"1", Minor:"7", GitVersion:"v1.7.0", GitCommit:"d3ada0119e776222f11ec7945e6d860061339aad", GitTreeState:"clean", BuildDate:"2017-06-30T09:51:01Z", GoVersion:"go1.8.3", Compiler:"gc", Platform:"darwin/amd64"}`
server := `Server Version: version.Info{Major:"1", Minor:"7", GitVersion:"v1.7.0", GitCommit:"d3ada0119e776222f11ec7945e6d860061339aad", GitTreeState:"clean", BuildDate:"2017-07-26T00:12:31Z", GoVersion:"go1.8.3", Compiler:"gc", Platform:"linux/amd64"}`
cases := []struct {
r *regexp.Regexp
s string
exp string
}{
{r: major, s: server, exp: "1"},
{r: minor, s: server, exp: "7"},
{r: major, s: client, exp: "1"},
{r: minor, s: client, exp: "7"},
{r: major, s: "Some unexpected string"},
{r: minor}, // Checking that we don't fall over if the string is empty
}
for _, c := range cases {
t.Run("", func(t *testing.T) {
m := versionMatch(c.r, c.s)
if m != c.exp {
t.Fatalf("Got %s expected %s", m, c.exp)
}
})
}
}