1
0
mirror of https://github.com/aquasecurity/kube-bench.git synced 2024-11-29 11:28:14 +00:00

Simplify verifying binaries and config files

This commit is contained in:
Liz Rice 2017-08-15 16:44:40 +01:00
parent 86d49b1b1a
commit 34f8b8e980
3 changed files with 82 additions and 56 deletions

View File

@ -17,6 +17,7 @@ package cmd
import ( import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os"
"strings" "strings"
"github.com/aquasecurity/kube-bench/check" "github.com/aquasecurity/kube-bench/check"
@ -150,15 +151,35 @@ func runChecks(t check.NodeType) {
// verifyNodeType checks the executables and config files are as expected // verifyNodeType checks the executables and config files are as expected
// for the specified tests (master, node or federated). // for the specified tests (master, node or federated).
func verifyNodeType(t check.NodeType) { func verifyNodeType(t check.NodeType) {
var bins []string
var confs []string
switch t { switch t {
case check.MASTER: case check.MASTER:
verifyBin(apiserverBin, schedulerBin, controllerManagerBin) bins = []string{apiserverBin, schedulerBin, controllerManagerBin}
verifyConf(apiserverConf, schedulerConf, controllerManagerConf) confs = []string{apiserverConf, schedulerConf, controllerManagerConf}
case check.NODE: case check.NODE:
verifyBin(kubeletBin, proxyBin) bins = []string{kubeletBin, proxyBin}
verifyConf(kubeletConf, proxyConf) confs = []string{kubeletConf, proxyConf}
case check.FEDERATED: case check.FEDERATED:
verifyBin(fedApiserverBin, fedControllerManagerBin) bins = []string{fedApiserverBin, fedControllerManagerBin}
}
for _, bin := range bins {
if !verifyBin(bin, ps) {
printlnWarn(fmt.Sprintf("%s is not running", bin))
}
}
for _, conf := range confs {
_, err := os.Stat(conf)
if err != nil {
if os.IsNotExist(err) {
printlnWarn(fmt.Sprintf("Missing kubernetes config file: %s", conf))
} else {
exitWithError(fmt.Errorf("error looking for file %s: %v", conf, err))
}
}
} }
} }

View File

@ -64,59 +64,30 @@ func cleanIDs(list string) []string {
return ids return ids
} }
func verifyConf(confPath ...string) { // ps execs out to the ps command; it's separated into a function so we can write tests
var missing string func ps(proc string) string {
cmd := exec.Command("ps", "-C", proc, "-o", "cmd", "--no-headers")
for _, c := range confPath {
if _, err := os.Stat(c); err != nil && os.IsNotExist(err) {
continueWithError(err, "")
missing += c + ", "
}
}
if len(missing) > 0 {
missing = strings.Trim(missing, ", ")
printlnWarn(fmt.Sprintf("Missing kubernetes config files: %s", missing))
}
}
func verifyBin(binPath ...string) {
var binSlice []string
var bin string
var missing string
var notRunning string
// Construct proc name for ps(1)
for _, b := range binPath {
_, err := exec.LookPath(b)
bin = bin + "," + b
binSlice = append(binSlice, b)
if err != nil {
missing += b + ", "
continueWithError(err, "")
}
}
bin = strings.Trim(bin, ",")
cmd := exec.Command("ps", "-C", bin, "-o", "cmd", "--no-headers")
out, err := cmd.Output() out, err := cmd.Output()
if err != nil { if err != nil {
continueWithError(fmt.Errorf("%s: %s", cmd.Args, err), "") continueWithError(fmt.Errorf("%s: %s", cmd.Args, err), "")
} }
for _, b := range binSlice { return string(out)
matched := strings.Contains(string(out), b) }
if !matched { // verifyBin checks that the binary specified is running
notRunning += b + ", " func verifyBin(bin string, psFunc func(string) string) bool {
}
}
if len(notRunning) > 0 { // Strip any quotes
notRunning = strings.Trim(notRunning, ", ") bin = strings.Trim(bin, "'\"")
printlnWarn(fmt.Sprintf("Kubernetes binaries not running: %s", notRunning))
} // bin could consist of more than one word
// We'll search for running processes with the first word, and then check the whole
// proc as supplied is included in the results
proc := strings.Fields(bin)[0]
out := psFunc(proc)
return strings.Contains(out, bin)
} }
func verifyKubeVersion(major string, minor string) { func verifyKubeVersion(major string, minor string) {
@ -133,8 +104,10 @@ func verifyKubeVersion(major string, minor string) {
if err != nil { if err != nil {
s := fmt.Sprintf("Kubernetes version check skipped with error %v", err) s := fmt.Sprintf("Kubernetes version check skipped with error %v", err)
continueWithError(err, sprintlnWarn(s)) continueWithError(err, sprintlnWarn(s))
if len(out) == 0 {
return return
} }
}
msg := checkVersion("Client", string(out), major, minor) msg := checkVersion("Client", string(out), major, minor)
if msg != "" { if msg != "" {

View File

@ -16,6 +16,7 @@ package cmd
import ( import (
"regexp" "regexp"
"strconv"
"testing" "testing"
) )
@ -36,8 +37,8 @@ func TestCheckVersion(t *testing.T) {
{t: "Server", s: "something unexpected", major: "2", minor: "0", exp: "Couldn't find Server version from kubectl output 'something unexpected'"}, {t: "Server", s: "something unexpected", major: "2", minor: "0", exp: "Couldn't find Server version from kubectl output 'something unexpected'"},
} }
for _, c := range cases { for id, c := range cases {
t.Run("", func(t *testing.T) { t.Run(strconv.Itoa(id), func(t *testing.T) {
m := checkVersion(c.t, c.s, c.major, c.minor) m := checkVersion(c.t, c.s, c.major, c.minor)
if m != c.exp { if m != c.exp {
t.Fatalf("Got: %s, expected: %s", m, c.exp) t.Fatalf("Got: %s, expected: %s", m, c.exp)
@ -66,8 +67,8 @@ func TestVersionMatch(t *testing.T) {
{r: minor}, // Checking that we don't fall over if the string is empty {r: minor}, // Checking that we don't fall over if the string is empty
} }
for _, c := range cases { for id, c := range cases {
t.Run("", func(t *testing.T) { t.Run(strconv.Itoa(id), func(t *testing.T) {
m := versionMatch(c.r, c.s) m := versionMatch(c.r, c.s)
if m != c.exp { if m != c.exp {
t.Fatalf("Got %s expected %s", m, c.exp) t.Fatalf("Got %s expected %s", m, c.exp)
@ -75,3 +76,34 @@ func TestVersionMatch(t *testing.T) {
}) })
} }
} }
var g string
func fakeps(proc string) string {
return g
}
func TestVerifyBin(t *testing.T) {
cases := []struct {
proc string
psOut string
exp bool
}{
{proc: "single", psOut: "single", exp: true},
{proc: "single", psOut: "", exp: false},
{proc: "two words", psOut: "two words", exp: true},
{proc: "two words", psOut: "", exp: false},
{proc: "cmd", psOut: "cmd param1 param2", exp: true},
{proc: "cmd param", psOut: "cmd param1 param2", exp: true},
{proc: "cmd param", psOut: "cmd", exp: false},
}
for id, c := range cases {
t.Run(strconv.Itoa(id), func(t *testing.T) {
g = c.psOut
v := verifyBin(c.proc, fakeps)
if v != c.exp {
t.Fatalf("Expected %v got %v", c.exp, v)
}
})
}
}