mirror of
https://github.com/aquasecurity/kube-bench.git
synced 2026-03-01 01:00:22 +00:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d56afd4104 | ||
|
|
8894b1dc4f | ||
|
|
ff59938f94 | ||
|
|
cc43fcbb7e | ||
|
|
2f4f55a363 | ||
|
|
e9076233dd | ||
|
|
b1e41d345f | ||
|
|
ccc2b6c9ae | ||
|
|
668a9e10ce | ||
|
|
8c3bb62dd4 | ||
|
|
9d0141871a | ||
|
|
344d2bfd24 | ||
|
|
ecd14ed682 | ||
|
|
223ac14642 | ||
|
|
c44e0db97b | ||
|
|
0bc004468b | ||
|
|
83704a7d89 | ||
|
|
024b7ed396 | ||
|
|
c5e04677cf | ||
|
|
2073e08363 | ||
|
|
db096c9f51 | ||
|
|
d736d10f90 | ||
|
|
50a3725ff2 | ||
|
|
468f5fac6e | ||
|
|
e4100a4435 |
@@ -5,7 +5,7 @@
|
||||
|
||||
<img src="images/kube-bench.png" width="200" alt="kube-bench logo">
|
||||
|
||||
kube-bench is a Go application that checks whether Kubernetes is deployed securely by running the checks documented in the CIS Kubernetes Benchmark.
|
||||
kube-bench is a Go application that checks whether Kubernetes is deployed securely by running the checks documented in the [CIS Kubernetes Benchmark](https://www.cisecurity.org/benchmark/kubernetes/).
|
||||
|
||||
Tests are configured with YAML files, making this tool easy to update as test specifications evolve.
|
||||
|
||||
@@ -28,15 +28,17 @@ You can choose to
|
||||
You can avoid installing kube-bench on the host by running it inside a container using the host PID namespace.
|
||||
|
||||
```
|
||||
docker run --pid=host aquasec/kube-bench:latest <master|node>
|
||||
docker run --pid=host -t aquasec/kube-bench:latest <master|node>
|
||||
```
|
||||
|
||||
You can even use your own configs by mounting them over the default ones in `/opt/kube-bench/cfg/`
|
||||
|
||||
```
|
||||
docker run --pid=host -v path/to/my-config.yaml:/opt/kube-bench/cfg/config.yaml aquasec/kube-bench:latest <master|node>
|
||||
docker run --pid=host -t -v path/to/my-config.yaml:/opt/kube-bench/cfg/config.yaml aquasec/kube-bench:latest <master|node>
|
||||
```
|
||||
|
||||
> Note: the tests require either the kubelet or kubectl binary in the path in order to know the Kubernetes version. You can pass `-v $(which kubectl):/usr/bin/kubectl` to the above invocations to resolve this.
|
||||
|
||||
### Running in a kubernetes cluster
|
||||
Run the master check
|
||||
|
||||
|
||||
@@ -9,21 +9,27 @@
|
||||
|
||||
master:
|
||||
apiserver:
|
||||
confs:
|
||||
- /etc/kubernetes/manifests/kube-apiserver.yaml
|
||||
- /etc/kubernetes/manifests/kube-apiserver.manifest
|
||||
defaultconf: /etc/kubernetes/manifests/kube-apiserver.yaml
|
||||
|
||||
scheduler:
|
||||
confs:
|
||||
- /etc/kubernetes/manifests/kube-scheduler.yaml
|
||||
- /etc/kubernetes/manifests/kube-scheduler.manifest
|
||||
defaultconf: /etc/kubernetes/manifests/kube-scheduler.yaml
|
||||
|
||||
controllermanager:
|
||||
confs:
|
||||
- /etc/kubernetes/manifests/kube-controller-manager.yaml
|
||||
- /etc/kubernetes/manifests/kube-controller-manager.manifest
|
||||
defaultconf: /etc/kubernetes/manifests/kube-controller-manager.yaml
|
||||
|
||||
etcd:
|
||||
confs:
|
||||
- /etc/kubernetes/manifests/etcd.yaml
|
||||
- /etc/kubernetes/manifests/etcd.manifest
|
||||
defaultconf: /etc/kubernetes/manifests/etcd.yaml
|
||||
|
||||
node:
|
||||
|
||||
@@ -942,7 +942,7 @@ groups:
|
||||
|
||||
- id: 1.4.11
|
||||
text: "Ensure that the etcd data directory permissions are set to 700 or more restrictive (Scored)"
|
||||
audit: ps -ef | grep $etcdbin | grep -v grep | sed 's%.*data-dir[= ]\([^ ]*\).*%\1%' | xargs stat -c %a
|
||||
audit: ps -ef | grep $etcdbin | grep -- --data-dir | sed 's%.*data-dir[= ]\([^ ]*\).*%\1%' | xargs stat -c %a
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "700"
|
||||
@@ -960,7 +960,7 @@ groups:
|
||||
|
||||
- id: 1.4.12
|
||||
text: "Ensure that the etcd data directory ownership is set to etcd:etcd (Scored)"
|
||||
audit: ps -ef | grep $etcdbin | grep -v grep | sed 's%.*data-dir[= ]\(\S*\)%\1%' | xargs stat -c %U:%G
|
||||
audit: ps -ef | grep $etcdbin | grep -- --data-dir | sed 's%.*data-dir[= ]\([^ ]*\).*%\1%' | xargs stat -c %U:%G
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "etcd:etcd"
|
||||
|
||||
@@ -368,8 +368,7 @@ groups:
|
||||
scored: true
|
||||
|
||||
- id: 2.2.4
|
||||
text: "Ensure that the kubelet service file permissions are set to 644 or
|
||||
more restrictive (Scored)"
|
||||
text: "2.2.4 Ensure that the kubelet service file ownership is set to root:root (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $kubeletconf; then stat -c %U:%G $kubeletconf; fi'"
|
||||
tests:
|
||||
test_items:
|
||||
|
||||
@@ -60,16 +60,17 @@ func handleError(err error, context string) (errmsg string) {
|
||||
// Check contains information about a recommendation in the
|
||||
// CIS Kubernetes 1.6+ document.
|
||||
type Check struct {
|
||||
ID string `yaml:"id" json:"test_number"`
|
||||
Text string `json:"test_desc"`
|
||||
ID string `yaml:"id" json:"test_number"`
|
||||
Text string `json:"test_desc"`
|
||||
Audit string `json:"omit"`
|
||||
Type string `json:"type"`
|
||||
Commands []*exec.Cmd `json:"omit"`
|
||||
Tests *tests `json:"omit"`
|
||||
Set bool `json:"omit"`
|
||||
Remediation string `json:"-"`
|
||||
TestInfo []string `json:"test_info"`
|
||||
State `json:"status"`
|
||||
Remediation string `json:"-"`
|
||||
TestInfo []string `json:"test_info"`
|
||||
State `json:"status"`
|
||||
ActualValue string `json:"actual_value"`
|
||||
}
|
||||
|
||||
// Run executes the audit commands specified in a check and outputs
|
||||
@@ -157,15 +158,25 @@ func (c *Check) Run() {
|
||||
i++
|
||||
}
|
||||
|
||||
if errmsgs != "" {
|
||||
glog.V(2).Info(errmsgs)
|
||||
finalOutput := c.Tests.execute(out.String())
|
||||
if finalOutput != nil {
|
||||
c.ActualValue = finalOutput.actualResult
|
||||
if finalOutput.testResult {
|
||||
c.State = PASS
|
||||
} else {
|
||||
c.State = FAIL
|
||||
}
|
||||
} else {
|
||||
errmsgs += handleError(
|
||||
fmt.Errorf("final output is nil"),
|
||||
fmt.Sprintf("failed to run: %s\n",
|
||||
c.Audit,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
res := c.Tests.execute(out.String())
|
||||
if res {
|
||||
c.State = PASS
|
||||
} else {
|
||||
c.State = FAIL
|
||||
if errmsgs != "" {
|
||||
glog.V(2).Info(errmsgs)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,9 +23,9 @@ import (
|
||||
|
||||
// Controls holds all controls to check for master nodes.
|
||||
type Controls struct {
|
||||
ID string `yaml:"id" json:"id"`
|
||||
Version string `json:"version"`
|
||||
Text string `json:"text"`
|
||||
ID string `yaml:"id" json:"id"`
|
||||
Version string `json:"version"`
|
||||
Text string `json:"text"`
|
||||
Type NodeType `json:"node_type"`
|
||||
Groups []*Group `json:"tests"`
|
||||
Summary
|
||||
@@ -43,9 +43,9 @@ type Group struct {
|
||||
|
||||
// Summary is a summary of the results of control checks run.
|
||||
type Summary struct {
|
||||
Pass int `json:"total_pass"`
|
||||
Fail int `json:"total_fail"`
|
||||
Warn int `json:"total_warn"`
|
||||
Pass int `json:"total_pass"`
|
||||
Fail int `json:"total_fail"`
|
||||
Warn int `json:"total_warn"`
|
||||
}
|
||||
|
||||
// NewControls instantiates a new master Controls object.
|
||||
|
||||
@@ -17,7 +17,7 @@ groups:
|
||||
- id: 1
|
||||
text: "flag is not set"
|
||||
tests:
|
||||
test_item:
|
||||
test_items:
|
||||
- flag: "--basic-auth"
|
||||
set: false
|
||||
|
||||
|
||||
@@ -49,8 +49,13 @@ type compare struct {
|
||||
Value string
|
||||
}
|
||||
|
||||
func (t *testItem) execute(s string) (result bool) {
|
||||
result = false
|
||||
type testOutput struct {
|
||||
testResult bool
|
||||
actualResult string
|
||||
}
|
||||
|
||||
func (t *testItem) execute(s string) *testOutput {
|
||||
result := &testOutput{}
|
||||
match := strings.Contains(s, t.Flag)
|
||||
|
||||
if t.Set {
|
||||
@@ -78,57 +83,57 @@ func (t *testItem) execute(s string) (result bool) {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
result.actualResult = strings.ToLower(flagVal)
|
||||
switch t.Compare.Op {
|
||||
case "eq":
|
||||
value := strings.ToLower(flagVal)
|
||||
// Do case insensitive comparaison for booleans ...
|
||||
if value == "false" || value == "true" {
|
||||
result = value == t.Compare.Value
|
||||
result.testResult = value == t.Compare.Value
|
||||
} else {
|
||||
result = flagVal == t.Compare.Value
|
||||
result.testResult = flagVal == t.Compare.Value
|
||||
}
|
||||
|
||||
case "noteq":
|
||||
value := strings.ToLower(flagVal)
|
||||
// Do case insensitive comparaison for booleans ...
|
||||
if value == "false" || value == "true" {
|
||||
result = !(value == t.Compare.Value)
|
||||
result.testResult = !(value == t.Compare.Value)
|
||||
} else {
|
||||
result = !(flagVal == t.Compare.Value)
|
||||
result.testResult = !(flagVal == t.Compare.Value)
|
||||
}
|
||||
|
||||
case "gt":
|
||||
a, b := toNumeric(flagVal, t.Compare.Value)
|
||||
result = a > b
|
||||
result.testResult = a > b
|
||||
|
||||
case "gte":
|
||||
a, b := toNumeric(flagVal, t.Compare.Value)
|
||||
result = a >= b
|
||||
result.testResult = a >= b
|
||||
|
||||
case "lt":
|
||||
a, b := toNumeric(flagVal, t.Compare.Value)
|
||||
result = a < b
|
||||
result.testResult = a < b
|
||||
|
||||
case "lte":
|
||||
a, b := toNumeric(flagVal, t.Compare.Value)
|
||||
result = a <= b
|
||||
result.testResult = a <= b
|
||||
|
||||
case "has":
|
||||
result = strings.Contains(flagVal, t.Compare.Value)
|
||||
result.testResult = strings.Contains(flagVal, t.Compare.Value)
|
||||
|
||||
case "nothave":
|
||||
result = !strings.Contains(flagVal, t.Compare.Value)
|
||||
result.testResult = !strings.Contains(flagVal, t.Compare.Value)
|
||||
}
|
||||
} else {
|
||||
result = isset
|
||||
result.testResult = isset
|
||||
}
|
||||
|
||||
} else {
|
||||
notset := !match
|
||||
result = notset
|
||||
result.testResult = notset
|
||||
}
|
||||
|
||||
return
|
||||
return result
|
||||
}
|
||||
|
||||
type tests struct {
|
||||
@@ -136,13 +141,19 @@ type tests struct {
|
||||
BinOp binOp `yaml:"bin_op"`
|
||||
}
|
||||
|
||||
func (ts *tests) execute(s string) (result bool) {
|
||||
res := make([]bool, len(ts.TestItems))
|
||||
func (ts *tests) execute(s string) *testOutput {
|
||||
finalOutput := &testOutput{}
|
||||
|
||||
for i, t := range ts.TestItems {
|
||||
res[i] = t.execute(s)
|
||||
res := make([]testOutput, len(ts.TestItems))
|
||||
if len(res) == 0 {
|
||||
return finalOutput
|
||||
}
|
||||
|
||||
for i, t := range ts.TestItems {
|
||||
res[i] = *(t.execute(s))
|
||||
}
|
||||
|
||||
var result bool
|
||||
// If no binary operation is specified, default to AND
|
||||
switch ts.BinOp {
|
||||
default:
|
||||
@@ -151,16 +162,19 @@ func (ts *tests) execute(s string) (result bool) {
|
||||
case and, "":
|
||||
result = true
|
||||
for i := range res {
|
||||
result = result && res[i]
|
||||
result = result && res[i].testResult
|
||||
}
|
||||
case or:
|
||||
result = false
|
||||
for i := range res {
|
||||
result = result || res[i]
|
||||
result = result || res[i].testResult
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
finalOutput.testResult = result
|
||||
finalOutput.actualResult = res[0].actualResult
|
||||
|
||||
return finalOutput
|
||||
}
|
||||
|
||||
func toNumeric(a, b string) (c, d int) {
|
||||
|
||||
@@ -113,7 +113,7 @@ func TestTestExecute(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
res := c.Tests.execute(c.str)
|
||||
res := c.Tests.execute(c.str).testResult
|
||||
if !res {
|
||||
t.Errorf("%s, expected:%v, got:%v\n", c.Text, true, res)
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package cmd
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/aquasecurity/kube-bench/check"
|
||||
@@ -28,56 +29,54 @@ var (
|
||||
errmsgs string
|
||||
)
|
||||
|
||||
func runChecks(t check.NodeType) {
|
||||
func runChecks(nodetype check.NodeType) {
|
||||
var summary check.Summary
|
||||
var nodetype string
|
||||
var file string
|
||||
var err error
|
||||
var typeConf *viper.Viper
|
||||
|
||||
switch t {
|
||||
switch nodetype {
|
||||
case check.MASTER:
|
||||
file = masterFile
|
||||
nodetype = "master"
|
||||
case check.NODE:
|
||||
file = nodeFile
|
||||
nodetype = "node"
|
||||
case check.FEDERATED:
|
||||
file = federatedFile
|
||||
nodetype = "federated"
|
||||
}
|
||||
|
||||
var ver string
|
||||
if kubeVersion != "" {
|
||||
ver = kubeVersion
|
||||
} else {
|
||||
ver = getKubeVersion()
|
||||
runningVersion, err := getKubeVersion()
|
||||
if err != nil && kubeVersion == "" {
|
||||
exitWithError(fmt.Errorf("Version check failed: %s\nAlternatively, you can specify the version with --version", err))
|
||||
}
|
||||
path, err := getConfigFilePath(kubeVersion, runningVersion, file)
|
||||
if err != nil {
|
||||
exitWithError(fmt.Errorf("can't find %s controls file in %s: %v", nodetype, cfgDir, err))
|
||||
}
|
||||
|
||||
switch ver {
|
||||
case "1.9", "1.10":
|
||||
continueWithError(nil, fmt.Sprintf("No CIS spec for %s - using tests from CIS 1.2.0 spec for Kubernetes 1.8\n", ver))
|
||||
ver = "1.8"
|
||||
}
|
||||
|
||||
path := filepath.Join(cfgDir, ver)
|
||||
def := filepath.Join(path, file)
|
||||
|
||||
in, err := ioutil.ReadFile(def)
|
||||
if err != nil {
|
||||
exitWithError(fmt.Errorf("error opening %s controls file: %v", t, err))
|
||||
exitWithError(fmt.Errorf("error opening %s controls file: %v", nodetype, err))
|
||||
}
|
||||
|
||||
glog.V(1).Info(fmt.Sprintf("Using benchmark file: %s\n", def))
|
||||
|
||||
// Merge kubernetes version specific config if any.
|
||||
viper.SetConfigFile(path + "/config.yaml")
|
||||
err = viper.MergeInConfig()
|
||||
if err != nil {
|
||||
continueWithError(err, fmt.Sprintf("Reading %s specific configuration file", ver))
|
||||
if os.IsNotExist(err) {
|
||||
glog.V(2).Info(fmt.Sprintf("No version-specific config.yaml file in %s", path))
|
||||
} else {
|
||||
exitWithError(fmt.Errorf("couldn't read config file %s: %v", path+"/config.yaml", err))
|
||||
}
|
||||
} else {
|
||||
glog.V(1).Info(fmt.Sprintf("Using config file: %s\n", viper.ConfigFileUsed()))
|
||||
}
|
||||
typeConf = viper.Sub(nodetype)
|
||||
|
||||
// Get the set of exectuables and config files we care about on this type of node. This also
|
||||
// checks that the executables we need for the node type are running.
|
||||
typeConf = viper.Sub(string(nodetype))
|
||||
binmap := getBinaries(typeConf)
|
||||
confmap := getConfigFiles(typeConf)
|
||||
|
||||
@@ -86,12 +85,9 @@ func runChecks(t check.NodeType) {
|
||||
s = makeSubstitutions(s, "bin", binmap)
|
||||
s = makeSubstitutions(s, "conf", confmap)
|
||||
|
||||
glog.V(1).Info(fmt.Sprintf("Using config file: %s\n", viper.ConfigFileUsed()))
|
||||
glog.V(1).Info(fmt.Sprintf("Using benchmark file: %s\n", def))
|
||||
|
||||
controls, err := check.NewControls(t, []byte(s))
|
||||
controls, err := check.NewControls(nodetype, []byte(s))
|
||||
if err != nil {
|
||||
exitWithError(fmt.Errorf("error setting up %s controls: %v", t, err))
|
||||
exitWithError(fmt.Errorf("error setting up %s controls: %v", nodetype, err))
|
||||
}
|
||||
|
||||
if groupList != "" && checkList == "" {
|
||||
|
||||
@@ -46,7 +46,7 @@ var (
|
||||
var RootCmd = &cobra.Command{
|
||||
Use: os.Args[0],
|
||||
Short: "Run CIS Benchmarks checks against a Kubernetes deployment",
|
||||
Long: `This tool runs the CIS Kubernetes Benchmark (http://www.cisecurity.org/benchmark/kubernetes/)`,
|
||||
Long: `This tool runs the CIS Kubernetes Benchmark (https://www.cisecurity.org/benchmark/kubernetes/)`,
|
||||
}
|
||||
|
||||
// Execute adds all child commands to the root command sets flags appropriately.
|
||||
|
||||
65
cmd/util.go
65
cmd/util.go
@@ -4,7 +4,9 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/aquasecurity/kube-bench/check"
|
||||
@@ -116,6 +118,59 @@ func getBinaries(v *viper.Viper) map[string]string {
|
||||
return binmap
|
||||
}
|
||||
|
||||
// getConfigFilePath locates the config files we should be using based on either the specified
|
||||
// version, or the running version of kubernetes if not specified
|
||||
func getConfigFilePath(specifiedVersion string, runningVersion string, filename string) (path string, err error) {
|
||||
var fileVersion string
|
||||
|
||||
if specifiedVersion != "" {
|
||||
fileVersion = specifiedVersion
|
||||
} else {
|
||||
fileVersion = runningVersion
|
||||
}
|
||||
|
||||
glog.V(2).Info(fmt.Sprintf("Looking for config for version %s", fileVersion))
|
||||
|
||||
for {
|
||||
path = filepath.Join(cfgDir, fileVersion)
|
||||
file := filepath.Join(path, string(filename))
|
||||
glog.V(2).Info(fmt.Sprintf("Looking for config file: %s\n", file))
|
||||
|
||||
if _, err = os.Stat(file); !os.IsNotExist(err) {
|
||||
if specifiedVersion == "" && fileVersion != runningVersion {
|
||||
glog.V(1).Info(fmt.Sprintf("No test file found for %s - using tests for Kubernetes %s\n", runningVersion, fileVersion))
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
|
||||
// If we were given an explicit version to look for, don't look for any others
|
||||
if specifiedVersion != "" {
|
||||
return "", err
|
||||
}
|
||||
|
||||
fileVersion = decrementVersion(fileVersion)
|
||||
if fileVersion == "" {
|
||||
return "", fmt.Errorf("no test files found <= runningVersion")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// decrementVersion decrements the version number
|
||||
// We want to decrement individually even through versions where we don't supply test files
|
||||
// just in case someone wants to specify their own test files for that version
|
||||
func decrementVersion(version string) string {
|
||||
split := strings.Split(version, ".")
|
||||
minor, err := strconv.Atoi(split[1])
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
if minor <= 1 {
|
||||
return ""
|
||||
}
|
||||
split[1] = strconv.Itoa(minor - 1)
|
||||
return strings.Join(split, ".")
|
||||
}
|
||||
|
||||
// getConfigFiles finds which of the set of candidate config files exist
|
||||
// accepts a string 't' which indicates the type of config file, conf,
|
||||
// podspec or untifile.
|
||||
@@ -212,19 +267,19 @@ func multiWordReplace(s string, subname string, sub string) string {
|
||||
return strings.Replace(s, subname, sub, -1)
|
||||
}
|
||||
|
||||
func getKubeVersion() string {
|
||||
func getKubeVersion() (string, error) {
|
||||
// These executables might not be on the user's path.
|
||||
_, err := exec.LookPath("kubectl")
|
||||
|
||||
if err != nil {
|
||||
_, err = exec.LookPath("kubelet")
|
||||
if err != nil {
|
||||
exitWithError(fmt.Errorf("Version check failed: need kubectl or kubelet binaries to get kubernetes version.\nAlternately, you can specify the version with --version"))
|
||||
return "", fmt.Errorf("need kubectl or kubelet binaries to get kubernetes version")
|
||||
}
|
||||
return getKubeVersionFromKubelet()
|
||||
return getKubeVersionFromKubelet(), nil
|
||||
}
|
||||
|
||||
return getKubeVersionFromKubectl()
|
||||
return getKubeVersionFromKubectl(), nil
|
||||
}
|
||||
|
||||
func getKubeVersionFromKubectl() string {
|
||||
@@ -275,7 +330,7 @@ func makeSubstitutions(s string, ext string, m map[string]string) string {
|
||||
glog.V(2).Info(fmt.Sprintf("No subsitution for '%s'\n", subst))
|
||||
continue
|
||||
}
|
||||
glog.V(1).Info(fmt.Sprintf("Substituting %s with '%s'\n", subst, v))
|
||||
glog.V(2).Info(fmt.Sprintf("Substituting %s with '%s'\n", subst, v))
|
||||
s = multiWordReplace(s, subst, v)
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
@@ -306,3 +308,45 @@ func TestMakeSubsitutions(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetConfigFilePath(t *testing.T) {
|
||||
var err error
|
||||
cfgDir, err = ioutil.TempDir("", "kube-bench-test")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp directory")
|
||||
}
|
||||
defer os.RemoveAll(cfgDir)
|
||||
d := filepath.Join(cfgDir, "1.8")
|
||||
err = os.Mkdir(d, 0666)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp file")
|
||||
}
|
||||
ioutil.WriteFile(filepath.Join(d, "master.yaml"), []byte("hello world"), 0666)
|
||||
|
||||
cases := []struct {
|
||||
specifiedVersion string
|
||||
runningVersion string
|
||||
succeed bool
|
||||
exp string
|
||||
}{
|
||||
{runningVersion: "1.8", succeed: true, exp: d},
|
||||
{runningVersion: "1.9", succeed: true, exp: d},
|
||||
{runningVersion: "1.10", succeed: true, exp: d},
|
||||
{runningVersion: "1.1", succeed: false},
|
||||
{specifiedVersion: "1.8", succeed: true, exp: d},
|
||||
{specifiedVersion: "1.9", succeed: false},
|
||||
{specifiedVersion: "1.10", succeed: false},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.specifiedVersion+"-"+c.runningVersion, func(t *testing.T) {
|
||||
path, err := getConfigFilePath(c.specifiedVersion, c.runningVersion, "/master.yaml")
|
||||
if err != nil && c.succeed {
|
||||
t.Fatalf("Error %v", err)
|
||||
}
|
||||
if path != c.exp {
|
||||
t.Fatalf("Got %s expected %s", path, c.exp)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user