Compare commits

...

21 Commits

Author SHA1 Message Date
Liz Rice
778c662055 Merge pull request #69 from aquasecurity/fix-kubeversion-fail
Exit kube-bench if we can't get valid kubernetes server version
2017-11-21 13:25:11 +00:00
Liz Rice
97485419e2 Can't run kubectl on Travis so I don't know how this test ever worked 2017-11-21 13:21:47 +00:00
Liz Rice
730871f330 Fix kubeVersion regex tests 2017-11-21 13:19:09 +00:00
Abubakr-Sadik Nii Nai Davis
471c02f4d7 Merge branch 'fix-kubeversion-fail' of github.com:aquasecurity/kube-bench into fix-kubeversion-fail 2017-11-21 12:20:22 +00:00
Abubakr-Sadik Nii Nai Davis
c93c94b3f6 Fix version check regexp. 2017-11-21 12:20:02 +00:00
Liz Rice
1d7df75f57 Merge branch 'master' into fix-kubeversion-fail 2017-11-16 10:00:46 +02:00
Abubakr-Sadik Nii Nai Davis
c60c459bc4 Fix bug causing kubectl version to always return default version. 2017-11-14 22:27:55 +00:00
Liz Rice
4907843b7b Merge pull request #71 from aquasecurity/lizrice-patch-2
Correct test config file typo
2017-11-14 18:12:25 +02:00
Liz Rice
d52e326147 Correct test config file typo 2017-11-14 18:05:40 +02:00
Abubakr-Sadik Nii Nai Davis
42a1068964 Add default version if version check fails. 2017-11-13 15:25:34 +00:00
Abubakr-Sadik Nii Nai Davis
f90dd925b8 Exit kube-bench if we can't get valid kubernetes server version and
improve error messages.
2017-11-03 13:11:10 +00:00
Liz Rice
85fb818e41 Merge pull request #67 from aquasecurity/config-spacing
Remove odd spacing and line breaks from test config files
2017-11-02 11:14:03 +00:00
Liz Rice
2eb261b94f Remove odd spacing and line breaks from test config files 2017-11-02 09:51:03 +00:00
Liz Rice
732b987d6d Merge pull request #61 from bitvector2/master
added saving results to PostgreSQL DB as a JSONB document
2017-11-02 08:34:13 +00:00
Steven Logue
909e6cc874 created database.go file and moved DB function into it 2017-11-01 10:15:31 -07:00
Liz Rice
1b13375ff7 Merge branch 'master' into master 2017-11-01 15:06:40 +00:00
Liz Rice
bdb5ccf982 Merge pull request #64 from aquasecurity/lizrice-patch-1
Update README for Kubernetes 1.8 support
2017-11-01 15:06:20 +00:00
Liz Rice
83e58b86db Update README for Kubernetes 1.8 support 2017-11-01 15:04:25 +00:00
Liz Rice
1faeb55b67 Merge branch 'master' into master 2017-11-01 14:46:48 +00:00
Steven Logue
f7d4f03f48 fixed typo in makefile 2017-10-31 13:12:20 -07:00
Steven Logue
d79a2a5478 added support for saving scan results to pgsql 2017-10-31 13:08:46 -07:00
9 changed files with 172 additions and 123 deletions

View File

@@ -11,6 +11,9 @@ Tests are configured with YAML files, making this tool easy to update as test sp
![Kubernetes Bench for Security](https://raw.githubusercontent.com/aquasecurity/kube-bench/master/images/output.png "Kubernetes Bench for Security")
## CIS Kubernetes Benchmark support
kube-bench supports the tests for multiple versions of Kubernetes (1.6, 1.7 and 1.8) as defined in the CIS Benchmarks 1.0.0, 1.1.0 and 1.2.0 respectively. It will determine the test set to run based on the Kubernetes version running on the machine.
## Installation
@@ -50,7 +53,9 @@ Kubernetes config and binary file locations and names can vary from installation
For each type of node (*master*, *node* or *federated*) there is a list of components, and for each component there is a set of binaries (*bins*) and config files (*confs*) that kube-bench will look for (in the order they are listed). If your installation uses a different binary name or config file location for a Kubernetes component, you can add it to `cfg/config.yaml`.
* **bins** - If there is a *bins* list for a component, at least one of these binaries must be running. The tests will consider the parameters for the first binary in the list found to be running.
* **podspecs** - From version 1.2.0 of the benchmark (tests for Kubernetes 1.8), the remediation instructions were updated to assume that the configuration for several kubernetes components is defined in a pod YAML file, and podspec settings define where to look for that configuration.
* **confs** - If one of the listed config files is found, this will be considered for the test. Tests can continue even if no config file is found. If no file is found at any of the listed locations, and a *defaultconf* location is given for the component, the test will give remediation advice using the *defaultconf* location.
* **unitfiles** - From version 1.2.0 of the benchmark (tests for Kubernetes 1.8), the remediation instructions were updated to assume that kubelet configuration is defined in a service file, and this setting defines where to look for that configuration.
## Test config YAML representation
The tests are represented as YAML documents (installed by default into ./cfg).
@@ -110,4 +115,6 @@ These operations are:
- `nothave`: tests if the flag value does not contain the compared value.
# Roadmap
The tests are up-to-date with the CIS Benchmark 1.1.0, which refers to Kubernetes 1.7. Going forward we should release updates to kube-bench to reflect new releases of the Benchmark, which in turn we can anticipate being made for each new Kubernetes release.
Going forward we plan to release updates to kube-bench to add support for new releases of the Benchmark, which in turn we can anticipate being made for each new Kubernetes release.
We welcome PRs and issue reports.

View File

@@ -19,9 +19,8 @@ groups:
value: false
set: true
remediation: |
Edit the deployment specs and set --anonymous-auth=false .
kubectl edit deployments federation-apiserver-deployment --
namespace=federation-system
Edit the deployment specs and set --anonymous-auth=false.
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
scored: true
- id: 3.1.2
@@ -33,9 +32,8 @@ groups:
set: false
remediation: |
Follow the documentation and configure alternate mechanisms for authentication. Then,
edit the deployment specs and remove "--basic-auth-file=<filename>" .
kubectl edit deployments federation-apiserver-deployment --
namespace=federation-system
edit the deployment specs and remove "--basic-auth-file=<filename>".
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
scored: true
- id: 3.1.3
@@ -46,9 +44,8 @@ groups:
- flag: "--insecure-allow-any-token"
set: false
remediation: |
Edit the deployment specs and remove --insecure-allow-any-token .
kubectl edit deployments federation-apiserver-deployment --
namespace=federation-system
Edit the deployment specs and remove --insecure-allow-any-token.
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
scored: true
- id: 3.1.4
@@ -59,9 +56,8 @@ groups:
- flag: "--insecure-bind-address"
set: false
remediation: |
Edit the deployment specs and remove --insecure-bind-address .
kubectl edit deployments federation-apiserver-deployment --
namespace=federation-system
Edit the deployment specs and remove --insecure-bind-address.
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
scored: true
- id: 3.1.5
@@ -75,9 +71,8 @@ groups:
value: 0
set: true
remediation: |
Edit the deployment specs and set --insecure-port=0 .
kubectl edit deployments federation-apiserver-deployment --
namespace=federation-system
Edit the deployment specs and set --insecure-port=0.
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
scored: true
- id: 3.1.6
@@ -95,8 +90,7 @@ groups:
set: false
remediation: |
Edit the deployment specs and set the --secure-port argument to the desired port.
kubectl edit deployments federation-apiserver-deployment --
namespace=federation-system
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
scored: true
- id: 3.1.7
@@ -110,9 +104,8 @@ groups:
value: false
set: true
remediation: |
Edit the deployment specs and set "--profiling=false" :
kubectl edit deployments federation-apiserver-deployment --
namespace=federation-system
Edit the deployment specs and set "--profiling=false":
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
score: true
- id: 3.1.8
@@ -128,8 +121,7 @@ groups:
remediation: |
Edit the deployment specs and set --admission-control argument to a value that does not
include AlwaysAdmit .
kubectl edit deployments federation-apiserver-deployment --
namespace=federation-system
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
scored: true
- id: 3.1.9
@@ -144,9 +136,8 @@ groups:
set: true
remediation: |
Edit the deployment specs and set --admission-control argument to a value that includes
NamespaceLifecycle .
kubectl edit deployments federation-apiserver-deployment --
namespace=federation-system
NamespaceLifecycle.
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
scored: true
- id: 3.1.10
@@ -172,8 +163,7 @@ groups:
set: true
remediation: |
Edit the deployment specs and set --audit-log-maxage to 30 or as appropriate.
kubectl edit deployments federation-apiserver-deployment --
namespace=federation-system
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
scored: true
- id: 3.1.12
@@ -188,8 +178,7 @@ groups:
set: true
remediation: |
Edit the deployment specs and set --audit-log-maxbackup to 10 or as appropriate.
kubectl edit deployments federation-apiserver-deployment --
namespace=federation-system
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
scored: true
- id: 3.1.13
@@ -204,8 +193,7 @@ groups:
set: true
remediation: |
Edit the deployment specs and set --audit-log-maxsize=100 to 100 or as appropriate.
kubectl edit deployments federation-apiserver-deployment --
namespace=federation-system
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
scored: true
- id: 3.1.14
@@ -221,8 +209,7 @@ groups:
remediation: |
Edit the deployment specs and set --authorization-mode argument to a value other than
AlwaysAllow
kubectl edit deployments federation-apiserver-deployment --
namespace=federation-system
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
scored: true
- id: 3.1.15
@@ -235,8 +222,7 @@ groups:
remediation: |
Follow the documentation and configure alternate mechanisms for authentication. Then,
edit the deployment specs and remove the --token-auth-file=<filename> argument.
kubectl edit deployments federation-apiserver-deployment --
namespace=federation-system
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
scored: true
- id: 3.1.16
@@ -251,8 +237,7 @@ groups:
set: true
remediation: |
Edit the deployment specs and set "--service-account-lookup=true" .
kubectl edit deployments federation-apiserver-deployment --
namespace=federation-system
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
scored: true
- id: 3.1.17
@@ -264,8 +249,7 @@ groups:
set: true
remediation: |
Edit the deployment specs and set --service-account-key-file argument as appropriate.
kubectl edit deployments federation-apiserver-deployment --
namespace=federation-system
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
scored: true
- id: 3.1.18
@@ -281,11 +265,10 @@ groups:
set: true
remediation: |
Follow the Kubernetes documentation and set up the TLS connection between the
federation apiserver and etcd. Then, edit the deployment specs and set "--etcd-
certfile=<path/to/client-certificate-file>" and "--etcd-
keyfile=<path/to/client-key-file>" arguments.
kubectl edit deployments federation-apiserver-deployment --
namespace=federation-system
federation apiserver and etcd. Then, edit the deployment specs and set
"--etcd-certfile=<path/to/client-certificate-file>" and
"--etcd-keyfile=<path/to/client-key-file>" arguments.
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
scored: true
- id: 3.1.19
@@ -301,10 +284,10 @@ groups:
set: true
remediation: |
Follow the Kubernetes documentation and set up the TLS connection on the federation
apiserver. Then, edit the deployment specs and set "--tls-cert-file=<path/to/tls-
certificate-file>" and "--tls-private-key-file=<path/to/tls-key-file>" :
kubectl edit deployments federation-apiserver-deployment --
namespace=federation-system
apiserver. Then, edit the deployment specs and set
"--tls-cert-file=<path/to/tls-certificate-file>" and
"--tls-private-key-file=<path/to/tls-key-file>":
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
scored: true
- id: 3.2
@@ -321,7 +304,6 @@ groups:
value: false
set: true
remediation: |
Edit the deployment specs and set "--profiling=false" :
kubectl edit deployments federation-controller-manager-deployment --
namespace=federation-system
Edit the deployment specs and set "--profiling=false":
kubectl edit deployments federation-controller-manager-deployment --namespace=federation-system
scored: true

View File

@@ -163,7 +163,7 @@ groups:
remediation: |
Edit the API server pod specification file $apiserverpodspec
on the master node and set the --admission-control parameter to a
value that does not include AlwaysAdmit .
value that does not include AlwaysAdmit.
scored: true
- id: 1.1.11
@@ -179,7 +179,7 @@ groups:
remediation: |
Edit the API server pod specification file $apiserverpodspec
on the master node and set the --admission-control parameter to
include AlwaysPullImages .
include AlwaysPullImages.
--admission-control=...,AlwaysPullImages,...
scored: true
@@ -196,7 +196,7 @@ groups:
remediation: |
Edit the API server pod specification file $apiserverpodspec
on the master node and set the --admission-control parameter to a
value that includes DenyEscalatingExec .
value that includes DenyEscalatingExec.
--admission-control=...,DenyEscalatingExec,...
scored: true
@@ -213,7 +213,7 @@ groups:
remediation: |
Edit the API server pod specification file $apiserverpodspec
on the master node and set the --admission-control parameter to
include SecurityContextDeny .
include SecurityContextDeny.
--admission-control=...,SecurityContextDeny,...
scored: true
@@ -230,7 +230,7 @@ groups:
remediation: |
Edit the API server pod specification file $apiserverpodspec
on the master node and set the --admission-control parameter to
include NamespaceLifecycle .
include NamespaceLifecycle.
--admission-control=...,NamespaceLifecycle,...
scored: true
@@ -312,7 +312,7 @@ groups:
remediation: |
Edit the API server pod specification file $apiserverpodspec
on the master node and set the --authorization-mode parameter to
values other than AlwaysAllow . One such example could be as below.
values other than AlwaysAllow. One such example could be as below.
--authorization-mode=RBAC
scored: true
@@ -450,7 +450,7 @@ groups:
Follow the documentation and create ServiceAccount objects as per your environment.
Then, edit the API server pod specification file $apiserverpodspec
on the master node and set the --admission-control parameter to a
value that includes ServiceAccount .
value that includes ServiceAccount.
--admission-control=...,ServiceAccount,...
scored: true
@@ -516,7 +516,7 @@ groups:
remediation: |
Edit the API server pod specification file $apiserverpodspec
on the master node and set the --authorization-mode parameter to a
value that includes Node .
value that includes Node.
--authorization-mode=Node,RBAC
scored: true
@@ -539,7 +539,7 @@ groups:
scored: true
- id: 1.1.33
text: "1.1.34 Ensure that the --experimental-encryption-provider-config argument is
text: "Ensure that the --experimental-encryption-provider-config argument is
set as appropriate (Scored)"
audit: "ps -ef | grep $apiserverbin | grep -v grep"
tests:
@@ -598,8 +598,7 @@ groups:
type: "manual"
remediation: |
Follow the Kubernetes documentation and set the desired audit policy in the
/etc/kubernetes/audit-policy.yaml file.
Then, edit the API server pod specification file $apiserverpodspec
/etc/kubernetes/audit-policy.yaml file. Then, edit the API server pod specification file $apiserverpodspec
and set the below parameters.
--audit-policy-file=/etc/kubernetes/audit-policy.yaml
scored: true
@@ -646,8 +645,7 @@ groups:
set: true
remediation: |
Edit the Controller Manager pod specification file $apiserverpodspec
on the master node and set the --terminated-pod-gc-
threshold to an appropriate threshold, for example:
on the master node and set the --terminated-pod-gc-threshold to an appropriate threshold, for example:
--terminated-pod-gc-threshold=10
scored: true
@@ -707,7 +705,7 @@ groups:
remediation: |
Edit the Controller Manager pod specification file $apiserverpodspec
on the master node and set the --root-ca-file parameter to
the certificate bundle file`.
the certificate bundle file.
--root-ca-file=<path/to/file>
scored: true
@@ -1124,7 +1122,7 @@ groups:
value: true
remediation: |
Edit the etcd pod specification file $etcdpodspec on the master
node and either remove the --auto-tls parameter or set it to false .
node and either remove the --auto-tls parameter or set it to false.
--auto-tls=false
scored: true
@@ -1140,8 +1138,7 @@ groups:
set: true
remediation: |
Follow the etcd service documentation and configure peer TLS encryption as appropriate
for your etcd cluster.
Then, edit the etcd pod specification file $etcdpodspec on the
for your etcd cluster. Then, edit the etcd pod specification file $etcdpodspec on the
master node and set the below parameters.
--peer-client-file=</path/to/peer-cert-file>
--peer-key-file=</path/to/peer-key-file>
@@ -1178,7 +1175,7 @@ groups:
set: true
remediation: |
Edit the etcd pod specification file $etcdpodspec on the master
node and either remove the --peer-auto-tls parameter or set it to false .
node and either remove the --peer-auto-tls parameter or set it to false.
--peer-auto-tls=false
scored: true

View File

@@ -23,11 +23,11 @@ import (
// Controls holds all controls to check for master nodes.
type Controls struct {
ID string `yaml:"id"`
ID string `yaml:"id"`
Version string
Text string
Type NodeType
Groups []*Group
Text string
Type NodeType
Groups []*Group
Summary
}

View File

@@ -62,7 +62,9 @@ func runChecks(t check.NodeType) {
}
ver := getKubeVersion()
path := fmt.Sprintf("%s/%s/%s", cfgDir, ver.Server, file)
glog.V(1).Info(fmt.Sprintf("Running tests for Kubernetes version: %s", ver))
path := fmt.Sprintf("%s/%s/%s", cfgDir, ver, file)
in, err := ioutil.ReadFile(path)
if err != nil {
exitWithError(fmt.Errorf("error opening %s controls file: %v", t, err))
@@ -104,7 +106,17 @@ func runChecks(t check.NodeType) {
fmt.Println(string(out))
} else {
prettyPrint(controls, summary)
// if we want to store in PostgreSQL, convert to JSON and save it
if (summary.Fail > 0 || summary.Warn > 0 || summary.Pass > 0) && pgSql {
out, err := controls.JSON()
if err != nil {
exitWithError(fmt.Errorf("failed to output in JSON format: %v", err))
}
savePgsql(string(out))
} else {
prettyPrint(controls, summary)
}
}
}

60
cmd/database.go Normal file
View File

@@ -0,0 +1,60 @@
package cmd
import (
"fmt"
"os"
"time"
"github.com/golang/glog"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/postgres"
"github.com/spf13/viper"
)
func savePgsql(jsonInfo string) {
envVars := map[string]string{
"PGSQL_HOST": viper.GetString("PGSQL_HOST"),
"PGSQL_USER": viper.GetString("PGSQL_USER"),
"PGSQL_DBNAME": viper.GetString("PGSQL_DBNAME"),
"PGSQL_SSLMODE": viper.GetString("PGSQL_SSLMODE"),
"PGSQL_PASSWORD": viper.GetString("PGSQL_PASSWORD"),
}
for k, v := range envVars {
if v == "" {
exitWithError(fmt.Errorf("environment variable %s is missing", envVarsPrefix+"_"+k))
}
}
connInfo := fmt.Sprintf("host=%s user=%s dbname=%s sslmode=%s password=%s",
envVars["PGSQL_HOST"],
envVars["PGSQL_USER"],
envVars["PGSQL_DBNAME"],
envVars["PGSQL_SSLMODE"],
envVars["PGSQL_PASSWORD"],
)
hostname, err := os.Hostname()
if err != nil {
exitWithError(fmt.Errorf("received error looking up hostname: %s", err))
}
timestamp := time.Now()
type ScanResult struct {
gorm.Model
ScanHost string `gorm:"type:varchar(63) not null"` // https://www.ietf.org/rfc/rfc1035.txt
ScanTime time.Time `gorm:"not null"`
ScanInfo string `gorm:"type:jsonb not null"`
}
db, err := gorm.Open("postgres", connInfo)
defer db.Close()
if err != nil {
exitWithError(fmt.Errorf("received error connecting to database: %s", err))
}
db.Debug().AutoMigrate(&ScanResult{})
db.Save(&ScanResult{ScanHost: hostname, ScanTime: timestamp, ScanInfo: jsonInfo})
glog.V(2).Info(fmt.Sprintf("successfully stored result to: %s", envVars["PGSQL_HOST"]))
}

View File

@@ -25,15 +25,17 @@ import (
)
var (
cfgDir = "./cfg"
cfgFile string
jsonFmt bool
checkList string
groupList string
masterFile string
nodeFile string
federatedFile string
envVarsPrefix = "KUBE_BENCH"
cfgDir = "./cfg"
defaultKubeVersion = "1.6"
cfgFile string
jsonFmt bool
pgSql bool
checkList string
groupList string
masterFile string
nodeFile string
federatedFile string
)
// RootCmd represents the base command when called without any subcommands
@@ -59,6 +61,7 @@ func init() {
cobra.OnInitialize(initConfig)
RootCmd.PersistentFlags().BoolVar(&jsonFmt, "json", false, "Prints the results as JSON")
RootCmd.PersistentFlags().BoolVar(&pgSql, "pgsql", false, "Save the results to PostgreSQL")
RootCmd.PersistentFlags().StringVarP(
&checkList,
"check",
@@ -90,7 +93,7 @@ func initConfig() {
viper.AddConfigPath(cfgDir) // adding ./cfg as first search path
}
viper.SetEnvPrefix("KUBE_BENCH")
viper.SetEnvPrefix(envVarsPrefix)
viper.AutomaticEnv() // read in environment variables that match
// If a config file is found, read it in.

View File

@@ -213,39 +213,30 @@ func multiWordReplace(s string, subname string, sub string) string {
return strings.Replace(s, subname, sub, -1)
}
type version struct {
Server string
Client string
}
func getKubeVersion() *version {
ver := new(version)
func getKubeVersion() string {
// These executables might not be on the user's path.
_, err := exec.LookPath("kubectl")
if err != nil {
s := fmt.Sprintf("Kubernetes version check skipped with error %v", err)
continueWithError(err, sprintlnWarn(s))
return nil
exitWithError(fmt.Errorf("kubernetes version check failed: %v", err))
}
cmd := exec.Command("kubectl", "version")
out, err := cmd.Output()
cmd := exec.Command("kubectl", "version", "--short")
out, err := cmd.CombinedOutput()
if err != nil {
s := fmt.Sprintf("Kubernetes version check skipped, with error getting kubectl version")
continueWithError(err, sprintlnWarn(s))
return nil
continueWithError(fmt.Errorf("%s", out), "")
}
clientVerRe := regexp.MustCompile(`Client.*Major:"(\d+)".*Minor:"(\d+)"`)
svrVerRe := regexp.MustCompile(`Server.*Major:"(\d+)".*Minor:"(\d+)"`)
return getVersionFromKubectlOutput(string(out))
}
sub := clientVerRe.FindStringSubmatch(string(out))
ver.Client = sub[1] + "." + sub[2]
sub = svrVerRe.FindStringSubmatch(string(out))
ver.Server = sub[1] + "." + sub[2]
return ver
func getVersionFromKubectlOutput(s string) string {
serverVersionRe := regexp.MustCompile(`Server Version: v(\d+.\d+)`)
subs := serverVersionRe.FindStringSubmatch(s)
if len(subs) < 2 {
printlnWarn(fmt.Sprintf("Unable to get kubectl version, using default version: %s", defaultKubeVersion))
return defaultKubeVersion
}
return subs[1]
}
func makeSubstitutions(s string, ext string, m map[string]string) string {

View File

@@ -17,7 +17,6 @@ package cmd
import (
"os"
"reflect"
"regexp"
"strconv"
"testing"
@@ -182,19 +181,17 @@ func TestMultiWordReplace(t *testing.T) {
}
}
func TestGetKubeVersion(t *testing.T) {
ver := getKubeVersion()
if ver == nil {
t.Log("Expected non nil version info.")
} else {
if ok, err := regexp.MatchString(`\d+.\d+`, ver.Client); !ok && err != nil {
t.Logf("Expected:%v got %v\n", "n.m", ver.Client)
}
if ok, err := regexp.MatchString(`\d+.\d+`, ver.Server); !ok && err != nil {
t.Logf("Expected:%v got %v\n", "n.m", ver.Server)
}
func TestKubeVersionRegex(t *testing.T) {
ver := getVersionFromKubectlOutput(`Client Version: v1.8.0
Server Version: v1.8.12
`)
if ver != "1.8" {
t.Fatalf("Expected 1.8 got %s", ver)
}
ver = getVersionFromKubectlOutput("Something completely different")
if ver != "1.6" {
t.Fatalf("Expected 1.6 got %s", ver)
}
}