1
0
mirror of https://github.com/aquasecurity/kube-bench.git synced 2024-11-15 12:29:04 +00:00
kube-bench/check/test.go
Abubakr-Sadik Nii Nai Davis d2fa9d35b6 Rewrite audit commands in the check definition that contain shell builtins
and modify text to command function to support this.

Shell builtins fail the binary command lookup test which result in a
WARN. Audit commands which include shell builtins must use the form:

   "/bin/sh -c 'sh-builtin arg'"

So they are executed properly. Additionally Go will fail to execute
commands involving shell builtins if they are not in the above format.
2017-08-12 18:41:41 +00:00

168 lines
3.2 KiB
Go

// 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 check
import (
"fmt"
"os"
"regexp"
"strconv"
"strings"
)
// test:
// flag: OPTION
// set: (true|false)
// compare:
// op: (eq|gt|gte|lt|lte|has)
// value: val
type binOp string
const (
and binOp = "and"
or = "or"
)
type testItem struct {
Flag string
Output string
Value string
Set bool
Compare compare
}
type compare struct {
Op string
Value string
}
func (t *testItem) execute(s string) (result bool) {
result = false
match := strings.Contains(s, t.Flag)
if t.Set {
var flagVal string
isset := match
if isset && t.Compare.Op != "" {
// Expects flags in the form;
// --flag=somevalue
// --flag
// somevalue
pttn := `(` + t.Flag + `)(=)*([^\s,]*) *`
flagRe := regexp.MustCompile(pttn)
vals := flagRe.FindStringSubmatch(s)
if len(vals) > 0 {
if vals[3] != "" {
flagVal = vals[3]
} else {
flagVal = vals[1]
}
} else {
fmt.Fprintf(os.Stderr, "invalid flag in testitem definition")
os.Exit(1)
}
switch t.Compare.Op {
case "eq":
result = flagVal == t.Compare.Value
case "noteq":
result = !(flagVal == t.Compare.Value)
case "gt":
a, b := toNumeric(flagVal, t.Compare.Value)
result = a > b
case "gte":
a, b := toNumeric(flagVal, t.Compare.Value)
result = a >= b
case "lt":
a, b := toNumeric(flagVal, t.Compare.Value)
result = a < b
case "lte":
a, b := toNumeric(flagVal, t.Compare.Value)
result = a <= b
case "has":
result = strings.Contains(flagVal, t.Compare.Value)
case "nothave":
result = !strings.Contains(flagVal, t.Compare.Value)
}
} else {
result = isset
}
} else {
notset := !match
result = notset
}
return
}
type tests struct {
TestItems []*testItem `yaml:"test_items"`
BinOp binOp `yaml:"bin_op"`
}
func (ts *tests) execute(s string) (result bool) {
res := make([]bool, len(ts.TestItems))
for i, t := range ts.TestItems {
res[i] = t.execute(s)
}
// If no binary operation is specified, default to AND
switch ts.BinOp {
default:
fmt.Fprintf(os.Stderr, "unknown binary operator for tests %s\n", ts.BinOp)
os.Exit(1)
case and, "":
result = true
for i := range res {
result = result && res[i]
}
case or:
result = false
for i := range res {
result = result || res[i]
}
}
return
}
func toNumeric(a, b string) (c, d int) {
var err error
c, err = strconv.Atoi(a)
if err != nil {
fmt.Fprintf(os.Stderr, "error converting %s: %s\n", a, err)
os.Exit(1)
}
d, err = strconv.Atoi(b)
if err != nil {
fmt.Fprintf(os.Stderr, "error converting %s: %s\n", b, err)
os.Exit(1)
}
return c, d
}