mirror of
https://github.com/aquasecurity/kube-bench.git
synced 2024-12-24 07:28:06 +00:00
Merge branch 'master' into bugfix-no-actual-result
This commit is contained in:
commit
31019c44da
2
.gitignore
vendored
2
.gitignore
vendored
@ -4,3 +4,5 @@ vendor
|
|||||||
dist
|
dist
|
||||||
.vscode/
|
.vscode/
|
||||||
hack/kind.test.yaml
|
hack/kind.test.yaml
|
||||||
|
|
||||||
|
.idea/
|
38
Gopkg.lock
generated
38
Gopkg.lock
generated
@ -1,6 +1,14 @@
|
|||||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||||
|
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec"
|
||||||
|
name = "github.com/davecgh/go-spew"
|
||||||
|
packages = ["spew"]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73"
|
||||||
|
version = "v1.1.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:938a2672d6ebbb7f7bc63eee3e4b9464c16ffcf77ec8913d3edbf32b4e3984dd"
|
digest = "1:938a2672d6ebbb7f7bc63eee3e4b9464c16ffcf77ec8913d3edbf32b4e3984dd"
|
||||||
name = "github.com/fatih/color"
|
name = "github.com/fatih/color"
|
||||||
@ -113,6 +121,14 @@
|
|||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "0131db6d737cfbbfb678f8b7d92e55e27ce46224"
|
revision = "0131db6d737cfbbfb678f8b7d92e55e27ce46224"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe"
|
||||||
|
name = "github.com/pmezard/go-difflib"
|
||||||
|
packages = ["difflib"]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:1fccaaeae58b2a2f1af4dbf7eee92ff14f222e161d143bfd20082ef664f91216"
|
digest = "1:1fccaaeae58b2a2f1af4dbf7eee92ff14f222e161d143bfd20082ef664f91216"
|
||||||
name = "github.com/spf13/afero"
|
name = "github.com/spf13/afero"
|
||||||
@ -161,6 +177,25 @@
|
|||||||
revision = "25b30aa063fc18e48662b86996252eabdcf2f0c7"
|
revision = "25b30aa063fc18e48662b86996252eabdcf2f0c7"
|
||||||
version = "v1.0.0"
|
version = "v1.0.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:ac83cf90d08b63ad5f7e020ef480d319ae890c208f8524622a2f3136e2686b02"
|
||||||
|
name = "github.com/stretchr/objx"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "477a77ecc69700c7cdeb1fa9e129548e1c1c393c"
|
||||||
|
version = "v0.1.1"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:0bcc464dabcfad5393daf87c3f8142911d0f6c52569b837e91a1c15e890265f3"
|
||||||
|
name = "github.com/stretchr/testify"
|
||||||
|
packages = [
|
||||||
|
"assert",
|
||||||
|
"mock",
|
||||||
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "ffdc059bfe9ce6a4e144ba849dbedead332c6053"
|
||||||
|
version = "v1.3.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:c9c0ba9ea00233c41b91e441cfd490f34b129bbfebcb1858979623bd8de07f72"
|
digest = "1:c9c0ba9ea00233c41b91e441cfd490f34b129bbfebcb1858979623bd8de07f72"
|
||||||
name = "golang.org/x/sys"
|
name = "golang.org/x/sys"
|
||||||
@ -210,7 +245,10 @@
|
|||||||
"github.com/jinzhu/gorm/dialects/postgres",
|
"github.com/jinzhu/gorm/dialects/postgres",
|
||||||
"github.com/spf13/cobra",
|
"github.com/spf13/cobra",
|
||||||
"github.com/spf13/viper",
|
"github.com/spf13/viper",
|
||||||
|
"github.com/stretchr/testify/assert",
|
||||||
|
"github.com/stretchr/testify/mock",
|
||||||
"gopkg.in/yaml.v2",
|
"gopkg.in/yaml.v2",
|
||||||
|
"k8s.io/client-go/util/jsonpath",
|
||||||
]
|
]
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
@ -18,6 +18,10 @@
|
|||||||
name = "github.com/spf13/viper"
|
name = "github.com/spf13/viper"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/stretchr/testify"
|
||||||
|
version = "1.3.0"
|
||||||
|
|
||||||
[prune]
|
[prune]
|
||||||
go-tests = true
|
go-tests = true
|
||||||
unused-packages = true
|
unused-packages = true
|
||||||
|
@ -9,10 +9,6 @@ node:
|
|||||||
- "/var/lib/kubelet/kubeconfig"
|
- "/var/lib/kubelet/kubeconfig"
|
||||||
|
|
||||||
kubelet:
|
kubelet:
|
||||||
bins:
|
|
||||||
- "hyperkube kubelet"
|
|
||||||
- "kubelet"
|
|
||||||
defaultconf: "/etc/kubernetes/kubelet/kubelet-config.json"
|
|
||||||
defaultsvc: "/etc/systemd/system/kubelet.service"
|
defaultsvc: "/etc/systemd/system/kubelet.service"
|
||||||
defaultkubeconfig: "/var/lib/kubelet/kubeconfig"
|
defaultkubeconfig: "/var/lib/kubelet/kubeconfig"
|
||||||
|
|
||||||
|
@ -9,21 +9,25 @@
|
|||||||
|
|
||||||
master:
|
master:
|
||||||
apiserver:
|
apiserver:
|
||||||
|
confs:
|
||||||
|
- /etc/kubernetes/manifests/kube-apiserver.yaml
|
||||||
|
- /etc/kubernetes/manifests/kube-apiserver.manifest
|
||||||
defaultconf: /etc/kubernetes/manifests/kube-apiserver.yaml
|
defaultconf: /etc/kubernetes/manifests/kube-apiserver.yaml
|
||||||
|
|
||||||
scheduler:
|
scheduler:
|
||||||
|
confs:
|
||||||
|
- /etc/kubernetes/manifests/kube-scheduler.yaml
|
||||||
|
- /etc/kubernetes/manifests/kube-scheduler.manifest
|
||||||
defaultconf: /etc/kubernetes/manifests/kube-scheduler.yaml
|
defaultconf: /etc/kubernetes/manifests/kube-scheduler.yaml
|
||||||
|
|
||||||
controllermanager:
|
controllermanager:
|
||||||
|
confs:
|
||||||
|
- /etc/kubernetes/manifests/kube-controller-manager.yaml
|
||||||
|
- /etc/kubernetes/manifests/kube-controller-manager.manifest
|
||||||
defaultconf: /etc/kubernetes/manifests/kube-controller-manager.yaml
|
defaultconf: /etc/kubernetes/manifests/kube-controller-manager.yaml
|
||||||
|
|
||||||
etcd:
|
etcd:
|
||||||
|
confs:
|
||||||
|
- /etc/kubernetes/manifests/etcd.yaml
|
||||||
|
- /etc/kubernetes/manifests/etcd.manifest
|
||||||
defaultconf: /etc/kubernetes/manifests/etcd.yaml
|
defaultconf: /etc/kubernetes/manifests/etcd.yaml
|
||||||
|
|
||||||
node:
|
|
||||||
kubelet:
|
|
||||||
defaultconf: /etc/kubernetes/kubelet.conf
|
|
||||||
defaultsvc: /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
|
|
||||||
|
|
||||||
proxy:
|
|
||||||
defaultconf: /etc/kubernetes/addons/kube-proxy-daemonset.yaml
|
|
||||||
|
@ -9,21 +9,25 @@
|
|||||||
|
|
||||||
master:
|
master:
|
||||||
apiserver:
|
apiserver:
|
||||||
|
confs:
|
||||||
|
- /etc/kubernetes/manifests/kube-apiserver.yaml
|
||||||
|
- /etc/kubernetes/manifests/kube-apiserver.manifest
|
||||||
defaultconf: /etc/kubernetes/manifests/kube-apiserver.yaml
|
defaultconf: /etc/kubernetes/manifests/kube-apiserver.yaml
|
||||||
|
|
||||||
scheduler:
|
scheduler:
|
||||||
|
confs:
|
||||||
|
- /etc/kubernetes/manifests/kube-scheduler.yaml
|
||||||
|
- /etc/kubernetes/manifests/kube-scheduler.manifest
|
||||||
defaultconf: /etc/kubernetes/manifests/kube-scheduler.yaml
|
defaultconf: /etc/kubernetes/manifests/kube-scheduler.yaml
|
||||||
|
|
||||||
controllermanager:
|
controllermanager:
|
||||||
|
confs:
|
||||||
|
- /etc/kubernetes/manifests/kube-controller-manager.yaml
|
||||||
|
- /etc/kubernetes/manifests/kube-controller-manager.manifest
|
||||||
defaultconf: /etc/kubernetes/manifests/kube-controller-manager.yaml
|
defaultconf: /etc/kubernetes/manifests/kube-controller-manager.yaml
|
||||||
|
|
||||||
etcd:
|
etcd:
|
||||||
|
confs:
|
||||||
|
- /etc/kubernetes/manifests/etcd.yaml
|
||||||
|
- /etc/kubernetes/manifests/etcd.manifest
|
||||||
defaultconf: /etc/kubernetes/manifests/etcd.yaml
|
defaultconf: /etc/kubernetes/manifests/etcd.yaml
|
||||||
|
|
||||||
node:
|
|
||||||
kubelet:
|
|
||||||
defaultconf: /etc/kubernetes/kubelet.conf
|
|
||||||
defaultsvc: /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
|
|
||||||
|
|
||||||
proxy:
|
|
||||||
defaultconf: /etc/kubernetes/addons/kube-proxy-daemonset.yaml
|
|
||||||
|
@ -220,12 +220,15 @@ groups:
|
|||||||
text: "Ensure that the admission control plugin NamespaceLifecycle is set (Scored)"
|
text: "Ensure that the admission control plugin NamespaceLifecycle is set (Scored)"
|
||||||
audit: "ps -ef | grep $apiserverbin | grep -v grep"
|
audit: "ps -ef | grep $apiserverbin | grep -v grep"
|
||||||
tests:
|
tests:
|
||||||
|
bin_op: or
|
||||||
test_items:
|
test_items:
|
||||||
- flag: "--disable-admission-plugins"
|
- flag: "--disable-admission-plugins"
|
||||||
compare:
|
compare:
|
||||||
op: nothave
|
op: nothave
|
||||||
value: "NamespaceLifecycle"
|
value: "NamespaceLifecycle"
|
||||||
set: true
|
set: true
|
||||||
|
- flag: "--disable-admission-plugins"
|
||||||
|
set: false
|
||||||
remediation: |
|
remediation: |
|
||||||
Edit the API server pod specification file $apiserverconf
|
Edit the API server pod specification file $apiserverconf
|
||||||
on the master node and set the --disable-admission-plugins parameter to
|
on the master node and set the --disable-admission-plugins parameter to
|
||||||
|
@ -31,12 +31,3 @@ master:
|
|||||||
- /etc/kubernetes/manifests/etcd.yaml
|
- /etc/kubernetes/manifests/etcd.yaml
|
||||||
- /etc/kubernetes/manifests/etcd.manifest
|
- /etc/kubernetes/manifests/etcd.manifest
|
||||||
defaultconf: /etc/kubernetes/manifests/etcd.yaml
|
defaultconf: /etc/kubernetes/manifests/etcd.yaml
|
||||||
|
|
||||||
node:
|
|
||||||
kubelet:
|
|
||||||
defaultconf: /var/lib/kubelet/config.yaml
|
|
||||||
defaultsvc: /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
|
|
||||||
defaultkubeconfig: /etc/kubernetes/kubelet.conf
|
|
||||||
|
|
||||||
proxy:
|
|
||||||
defaultconf: /etc/kubernetes/addons/kube-proxy-daemonset.yaml
|
|
||||||
|
@ -81,6 +81,9 @@ node:
|
|||||||
bins:
|
bins:
|
||||||
- "hyperkube kubelet"
|
- "hyperkube kubelet"
|
||||||
- "kubelet"
|
- "kubelet"
|
||||||
|
confs:
|
||||||
|
- "/var/lib/kubelet/config.yaml"
|
||||||
|
- "/etc/kubernetes/kubelet/kubelet-config.json"
|
||||||
defaultconf: "/var/lib/kubelet/config.yaml"
|
defaultconf: "/var/lib/kubelet/config.yaml"
|
||||||
defaultsvc: "/etc/systemd/system/kubelet.service.d/10-kubeadm.conf"
|
defaultsvc: "/etc/systemd/system/kubelet.service.d/10-kubeadm.conf"
|
||||||
defaultkubeconfig: "/etc/kubernetes/kubelet.conf"
|
defaultkubeconfig: "/etc/kubernetes/kubelet.conf"
|
||||||
@ -93,6 +96,7 @@ node:
|
|||||||
confs:
|
confs:
|
||||||
- /etc/kubernetes/proxy
|
- /etc/kubernetes/proxy
|
||||||
- /etc/kubernetes/addons/kube-proxy-daemonset.yaml
|
- /etc/kubernetes/addons/kube-proxy-daemonset.yaml
|
||||||
|
defaultconf: /etc/kubernetes/addons/kube-proxy-daemonset.yaml
|
||||||
defaultkubeconfig: "/etc/kubernetes/proxy.conf"
|
defaultkubeconfig: "/etc/kubernetes/proxy.conf"
|
||||||
|
|
||||||
federated:
|
federated:
|
||||||
|
@ -36,11 +36,11 @@ const (
|
|||||||
// PASS check passed.
|
// PASS check passed.
|
||||||
PASS State = "PASS"
|
PASS State = "PASS"
|
||||||
// FAIL check failed.
|
// FAIL check failed.
|
||||||
FAIL = "FAIL"
|
FAIL State = "FAIL"
|
||||||
// WARN could not carry out check.
|
// WARN could not carry out check.
|
||||||
WARN = "WARN"
|
WARN State = "WARN"
|
||||||
// INFO informational message
|
// INFO informational message
|
||||||
INFO = "INFO"
|
INFO State = "INFO"
|
||||||
|
|
||||||
// MASTER a master node
|
// MASTER a master node
|
||||||
MASTER NodeType = "master"
|
MASTER NodeType = "master"
|
||||||
@ -62,32 +62,49 @@ func handleError(err error, context string) (errmsg string) {
|
|||||||
type Check struct {
|
type Check struct {
|
||||||
ID string `yaml:"id" json:"test_number"`
|
ID string `yaml:"id" json:"test_number"`
|
||||||
Text string `json:"test_desc"`
|
Text string `json:"test_desc"`
|
||||||
Audit string `json:"omit"`
|
Audit string `json:"audit"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Commands []*exec.Cmd `json:"omit"`
|
Commands []*exec.Cmd `json:"omit"`
|
||||||
Tests *tests `json:"omit"`
|
Tests *tests `json:"omit"`
|
||||||
Set bool `json:"omit"`
|
Set bool `json:"omit"`
|
||||||
Remediation string `json:"-"`
|
Remediation string `json:"remediation"`
|
||||||
TestInfo []string `json:"test_info"`
|
TestInfo []string `json:"test_info"`
|
||||||
State `json:"status"`
|
State `json:"status"`
|
||||||
ActualValue string `json:"actual_value"`
|
ActualValue string `json:"actual_value"`
|
||||||
Scored bool `json:"scored"`
|
Scored bool `json:"scored"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Runner wraps the basic Run method.
|
||||||
|
type Runner interface {
|
||||||
|
// Run runs a given check and returns the execution state.
|
||||||
|
Run(c *Check) State
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRunner constructs a default Runner.
|
||||||
|
func NewRunner() Runner {
|
||||||
|
return &defaultRunner{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type defaultRunner struct{}
|
||||||
|
|
||||||
|
func (r *defaultRunner) Run(c *Check) State {
|
||||||
|
return c.run()
|
||||||
|
}
|
||||||
|
|
||||||
// Run executes the audit commands specified in a check and outputs
|
// Run executes the audit commands specified in a check and outputs
|
||||||
// the results.
|
// the results.
|
||||||
func (c *Check) Run() {
|
func (c *Check) run() State {
|
||||||
|
|
||||||
// If check type is skip, force result to INFO
|
// If check type is skip, force result to INFO
|
||||||
if c.Type == "skip" {
|
if c.Type == "skip" {
|
||||||
c.State = INFO
|
c.State = INFO
|
||||||
return
|
return c.State
|
||||||
}
|
}
|
||||||
|
|
||||||
// If check type is manual or the check is not scored, force result to WARN
|
// If check type is manual or the check is not scored, force result to WARN
|
||||||
if c.Type == "manual" || !c.Scored {
|
if c.Type == "manual" || !c.Scored {
|
||||||
c.State = WARN
|
c.State = WARN
|
||||||
return
|
return c.State
|
||||||
}
|
}
|
||||||
|
|
||||||
var out bytes.Buffer
|
var out bytes.Buffer
|
||||||
@ -97,7 +114,7 @@ func (c *Check) Run() {
|
|||||||
for _, cmd := range c.Commands {
|
for _, cmd := range c.Commands {
|
||||||
if !isShellCommand(cmd.Path) {
|
if !isShellCommand(cmd.Path) {
|
||||||
c.State = WARN
|
c.State = WARN
|
||||||
return
|
return c.State
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +123,7 @@ func (c *Check) Run() {
|
|||||||
if n == 0 {
|
if n == 0 {
|
||||||
// Likely a warning message.
|
// Likely a warning message.
|
||||||
c.State = WARN
|
c.State = WARN
|
||||||
return
|
return c.State
|
||||||
}
|
}
|
||||||
|
|
||||||
// Each command runs,
|
// Each command runs,
|
||||||
@ -188,6 +205,7 @@ func (c *Check) Run() {
|
|||||||
if errmsgs != "" {
|
if errmsgs != "" {
|
||||||
glog.V(2).Info(errmsgs)
|
glog.V(2).Info(errmsgs)
|
||||||
}
|
}
|
||||||
|
return c.State
|
||||||
}
|
}
|
||||||
|
|
||||||
// textToCommand transforms an input text representation of commands to be
|
// textToCommand transforms an input text representation of commands to be
|
||||||
|
@ -1,3 +1,17 @@
|
|||||||
|
// Copyright © 2017-2019 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
|
package check
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -21,7 +35,7 @@ func TestCheck_Run(t *testing.T) {
|
|||||||
|
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
|
|
||||||
testCase.check.Run()
|
testCase.check.run()
|
||||||
|
|
||||||
if testCase.check.State != testCase.Expected {
|
if testCase.check.State != testCase.Expected {
|
||||||
t.Errorf("test failed, expected %s, actual %s\n", testCase.Expected, testCase.check.State)
|
t.Errorf("test failed, expected %s, actual %s\n", testCase.Expected, testCase.check.State)
|
||||||
|
@ -17,8 +17,8 @@ package check
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/golang/glog"
|
||||||
yaml "gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Controls holds all controls to check for master nodes.
|
// Controls holds all controls to check for master nodes.
|
||||||
@ -50,6 +50,9 @@ type Summary struct {
|
|||||||
Info int `json:"total_info"`
|
Info int `json:"total_info"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Predicate a predicate on the given Group and Check arguments.
|
||||||
|
type Predicate func(group *Group, check *Check) bool
|
||||||
|
|
||||||
// NewControls instantiates a new master Controls object.
|
// NewControls instantiates a new master Controls object.
|
||||||
func NewControls(t NodeType, in []byte) (*Controls, error) {
|
func NewControls(t NodeType, in []byte) (*Controls, error) {
|
||||||
c := new(Controls)
|
c := new(Controls)
|
||||||
@ -73,54 +76,21 @@ func NewControls(t NodeType, in []byte) (*Controls, error) {
|
|||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunGroup runs all checks in a group.
|
// RunChecks runs the checks with the given Runner. Only checks for which the filter Predicate returns `true` will run.
|
||||||
func (controls *Controls) RunGroup(gids ...string) Summary {
|
func (controls *Controls) RunChecks(runner Runner, filter Predicate) Summary {
|
||||||
g := []*Group{}
|
var g []*Group
|
||||||
controls.Summary.Pass, controls.Summary.Fail, controls.Summary.Warn, controls.Info = 0, 0, 0, 0
|
|
||||||
|
|
||||||
// If no groupid is passed run all group checks.
|
|
||||||
if len(gids) == 0 {
|
|
||||||
gids = controls.getAllGroupIDs()
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, group := range controls.Groups {
|
|
||||||
|
|
||||||
for _, gid := range gids {
|
|
||||||
if gid == group.ID {
|
|
||||||
for _, check := range group.Checks {
|
|
||||||
check.Run()
|
|
||||||
check.TestInfo = append(check.TestInfo, check.Remediation)
|
|
||||||
summarize(controls, check)
|
|
||||||
summarizeGroup(group, check)
|
|
||||||
}
|
|
||||||
|
|
||||||
g = append(g, group)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
controls.Groups = g
|
|
||||||
return controls.Summary
|
|
||||||
}
|
|
||||||
|
|
||||||
// RunChecks runs the checks with the supplied IDs.
|
|
||||||
func (controls *Controls) RunChecks(ids ...string) Summary {
|
|
||||||
g := []*Group{}
|
|
||||||
m := make(map[string]*Group)
|
m := make(map[string]*Group)
|
||||||
controls.Summary.Pass, controls.Summary.Fail, controls.Summary.Warn, controls.Info = 0, 0, 0, 0
|
controls.Summary.Pass, controls.Summary.Fail, controls.Summary.Warn, controls.Info = 0, 0, 0, 0
|
||||||
|
|
||||||
// If no groupid is passed run all group checks.
|
|
||||||
if len(ids) == 0 {
|
|
||||||
ids = controls.getAllCheckIDs()
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, group := range controls.Groups {
|
for _, group := range controls.Groups {
|
||||||
for _, check := range group.Checks {
|
for _, check := range group.Checks {
|
||||||
for _, id := range ids {
|
|
||||||
if id == check.ID {
|
if !filter(group, check) {
|
||||||
check.Run()
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
state := runner.Run(check)
|
||||||
check.TestInfo = append(check.TestInfo, check.Remediation)
|
check.TestInfo = append(check.TestInfo, check.Remediation)
|
||||||
summarize(controls, check)
|
|
||||||
|
|
||||||
// Check if we have already added this checks group.
|
// Check if we have already added this checks group.
|
||||||
if v, ok := m[group.ID]; !ok {
|
if v, ok := m[group.ID]; !ok {
|
||||||
@ -133,16 +103,17 @@ func (controls *Controls) RunChecks(ids ...string) Summary {
|
|||||||
|
|
||||||
// Add this check to the new group
|
// Add this check to the new group
|
||||||
w.Checks = append(w.Checks, check)
|
w.Checks = append(w.Checks, check)
|
||||||
|
summarizeGroup(w, state)
|
||||||
|
|
||||||
// Add to groups we have visited.
|
// Add to groups we have visited.
|
||||||
m[w.ID] = w
|
m[w.ID] = w
|
||||||
g = append(g, w)
|
g = append(g, w)
|
||||||
} else {
|
} else {
|
||||||
v.Checks = append(v.Checks, check)
|
v.Checks = append(v.Checks, check)
|
||||||
|
summarizeGroup(v, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
summarize(controls, state)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,29 +126,8 @@ func (controls *Controls) JSON() ([]byte, error) {
|
|||||||
return json.Marshal(controls)
|
return json.Marshal(controls)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (controls *Controls) getAllGroupIDs() []string {
|
func summarize(controls *Controls, state State) {
|
||||||
var ids []string
|
switch state {
|
||||||
|
|
||||||
for _, group := range controls.Groups {
|
|
||||||
ids = append(ids, group.ID)
|
|
||||||
}
|
|
||||||
return ids
|
|
||||||
}
|
|
||||||
|
|
||||||
func (controls *Controls) getAllCheckIDs() []string {
|
|
||||||
var ids []string
|
|
||||||
|
|
||||||
for _, group := range controls.Groups {
|
|
||||||
for _, check := range group.Checks {
|
|
||||||
ids = append(ids, check.ID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ids
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func summarize(controls *Controls, check *Check) {
|
|
||||||
switch check.State {
|
|
||||||
case PASS:
|
case PASS:
|
||||||
controls.Summary.Pass++
|
controls.Summary.Pass++
|
||||||
case FAIL:
|
case FAIL:
|
||||||
@ -186,11 +136,13 @@ func summarize(controls *Controls, check *Check) {
|
|||||||
controls.Summary.Warn++
|
controls.Summary.Warn++
|
||||||
case INFO:
|
case INFO:
|
||||||
controls.Summary.Info++
|
controls.Summary.Info++
|
||||||
|
default:
|
||||||
|
glog.Warningf("Unrecognized state %s", state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func summarizeGroup(group *Group, check *Check) {
|
func summarizeGroup(group *Group, state State) {
|
||||||
switch check.State {
|
switch state {
|
||||||
case PASS:
|
case PASS:
|
||||||
group.Pass++
|
group.Pass++
|
||||||
case FAIL:
|
case FAIL:
|
||||||
@ -199,5 +151,7 @@ func summarizeGroup(group *Group, check *Check) {
|
|||||||
group.Warn++
|
group.Warn++
|
||||||
case INFO:
|
case INFO:
|
||||||
group.Info++
|
group.Info++
|
||||||
|
default:
|
||||||
|
glog.Warningf("Unrecognized state %s", state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,17 @@
|
|||||||
|
// Copyright © 2017-2019 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
|
package check
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -6,11 +20,22 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
yaml "gopkg.in/yaml.v2"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/mock"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
const cfgDir = "../cfg/"
|
const cfgDir = "../cfg/"
|
||||||
|
|
||||||
|
type mockRunner struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockRunner) Run(c *Check) State {
|
||||||
|
args := m.Called(c)
|
||||||
|
return args.Get(0).(State)
|
||||||
|
}
|
||||||
|
|
||||||
// validate that the files we're shipping are valid YAML
|
// validate that the files we're shipping are valid YAML
|
||||||
func TestYamlFiles(t *testing.T) {
|
func TestYamlFiles(t *testing.T) {
|
||||||
err := filepath.Walk(cfgDir, func(path string, info os.FileInfo, err error) error {
|
err := filepath.Walk(cfgDir, func(path string, info os.FileInfo, err error) error {
|
||||||
@ -38,3 +63,89 @@ func TestYamlFiles(t *testing.T) {
|
|||||||
t.Fatalf("failure walking cfg dir: %v\n", err)
|
t.Fatalf("failure walking cfg dir: %v\n", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNewControls(t *testing.T) {
|
||||||
|
|
||||||
|
t.Run("Should return error when node type is not specified", func(t *testing.T) {
|
||||||
|
// given
|
||||||
|
in := []byte(`
|
||||||
|
---
|
||||||
|
controls:
|
||||||
|
type: # not specified
|
||||||
|
groups:
|
||||||
|
`)
|
||||||
|
// when
|
||||||
|
_, err := NewControls(MASTER, in)
|
||||||
|
// then
|
||||||
|
assert.EqualError(t, err, "non-master controls file specified")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should return error when input YAML is invalid", func(t *testing.T) {
|
||||||
|
// given
|
||||||
|
in := []byte("BOOM")
|
||||||
|
// when
|
||||||
|
_, err := NewControls(MASTER, in)
|
||||||
|
// then
|
||||||
|
assert.EqualError(t, err, "failed to unmarshal YAML: yaml: unmarshal errors:\n line 1: cannot unmarshal !!str `BOOM` into check.Controls")
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestControls_RunChecks(t *testing.T) {
|
||||||
|
|
||||||
|
t.Run("Should run checks matching the filter and update summaries", func(t *testing.T) {
|
||||||
|
// given
|
||||||
|
runner := new(mockRunner)
|
||||||
|
// and
|
||||||
|
in := []byte(`
|
||||||
|
---
|
||||||
|
type: "master"
|
||||||
|
groups:
|
||||||
|
- id: G1
|
||||||
|
checks:
|
||||||
|
- id: G1/C1
|
||||||
|
- id: G2
|
||||||
|
checks:
|
||||||
|
- id: G2/C1
|
||||||
|
`)
|
||||||
|
// and
|
||||||
|
controls, _ := NewControls(MASTER, in)
|
||||||
|
// and
|
||||||
|
runner.On("Run", controls.Groups[0].Checks[0]).Return(PASS)
|
||||||
|
runner.On("Run", controls.Groups[1].Checks[0]).Return(FAIL)
|
||||||
|
// and
|
||||||
|
var runAll Predicate = func(group *Group, c *Check) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// when
|
||||||
|
controls.RunChecks(runner, runAll)
|
||||||
|
// then
|
||||||
|
assert.Equal(t, 2, len(controls.Groups))
|
||||||
|
// and
|
||||||
|
G1 := controls.Groups[0]
|
||||||
|
assert.Equal(t, "G1", G1.ID)
|
||||||
|
assert.Equal(t, "G1/C1", G1.Checks[0].ID)
|
||||||
|
assertEqualGroupSummary(t, 1, 0, 0, 0, G1)
|
||||||
|
// and
|
||||||
|
G2 := controls.Groups[1]
|
||||||
|
assert.Equal(t, "G2", G2.ID)
|
||||||
|
assert.Equal(t, "G2/C1", G2.Checks[0].ID)
|
||||||
|
assertEqualGroupSummary(t, 0, 1, 0, 0, G2)
|
||||||
|
// and
|
||||||
|
assert.Equal(t, 1, controls.Summary.Pass)
|
||||||
|
assert.Equal(t, 1, controls.Summary.Fail)
|
||||||
|
assert.Equal(t, 0, controls.Summary.Info)
|
||||||
|
assert.Equal(t, 0, controls.Summary.Warn)
|
||||||
|
// and
|
||||||
|
runner.AssertExpectations(t)
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertEqualGroupSummary(t *testing.T, pass, fail, info, warn int, actual *Group) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, pass, actual.Pass)
|
||||||
|
assert.Equal(t, fail, actual.Fail)
|
||||||
|
assert.Equal(t, info, actual.Info)
|
||||||
|
assert.Equal(t, warn, actual.Warn)
|
||||||
|
}
|
||||||
|
@ -19,15 +19,47 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/aquasecurity/kube-bench/check"
|
"github.com/aquasecurity/kube-bench/check"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
// NewRunFilter constructs a Predicate based on FilterOpts which determines whether tested Checks should be run or not.
|
||||||
errmsgs string
|
func NewRunFilter(opts FilterOpts) (check.Predicate, error) {
|
||||||
)
|
|
||||||
|
if opts.CheckList != "" && opts.GroupList != "" {
|
||||||
|
return nil, fmt.Errorf("group option and check option can't be used together")
|
||||||
|
}
|
||||||
|
|
||||||
|
var groupIDs map[string]bool
|
||||||
|
if opts.GroupList != "" {
|
||||||
|
groupIDs = cleanIDs(opts.GroupList)
|
||||||
|
}
|
||||||
|
|
||||||
|
var checkIDs map[string]bool
|
||||||
|
if opts.CheckList != "" {
|
||||||
|
checkIDs = cleanIDs(opts.CheckList)
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(g *check.Group, c *check.Check) bool {
|
||||||
|
var test = true
|
||||||
|
if len(groupIDs) > 0 {
|
||||||
|
_, ok := groupIDs[g.ID]
|
||||||
|
test = test && ok
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(checkIDs) > 0 {
|
||||||
|
_, ok := checkIDs[c.ID]
|
||||||
|
test = test && ok
|
||||||
|
}
|
||||||
|
|
||||||
|
test = test && (opts.Scored && c.Scored || opts.Unscored && !c.Scored)
|
||||||
|
|
||||||
|
return test
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func runChecks(nodetype check.NodeType) {
|
func runChecks(nodetype check.NodeType) {
|
||||||
var summary check.Summary
|
var summary check.Summary
|
||||||
@ -40,7 +72,7 @@ func runChecks(nodetype check.NodeType) {
|
|||||||
|
|
||||||
glog.V(1).Info(fmt.Sprintf("Using benchmark file: %s\n", def))
|
glog.V(1).Info(fmt.Sprintf("Using benchmark file: %s\n", def))
|
||||||
|
|
||||||
// Get the set of exectuables and config files we care about on this type of node.
|
// Get the set of executables and config files we care about on this type of node.
|
||||||
typeConf := viper.Sub(string(nodetype))
|
typeConf := viper.Sub(string(nodetype))
|
||||||
binmap, err := getBinaries(typeConf)
|
binmap, err := getBinaries(typeConf)
|
||||||
|
|
||||||
@ -65,18 +97,14 @@ func runChecks(nodetype check.NodeType) {
|
|||||||
exitWithError(fmt.Errorf("error setting up %s controls: %v", nodetype, err))
|
exitWithError(fmt.Errorf("error setting up %s controls: %v", nodetype, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if groupList != "" && checkList == "" {
|
runner := check.NewRunner()
|
||||||
ids := cleanIDs(groupList)
|
filter, err := NewRunFilter(filterOpts)
|
||||||
summary = controls.RunGroup(ids...)
|
if err != nil {
|
||||||
} else if checkList != "" && groupList == "" {
|
exitWithError(fmt.Errorf("error setting up run filter: %v", err))
|
||||||
ids := cleanIDs(checkList)
|
|
||||||
summary = controls.RunChecks(ids...)
|
|
||||||
} else if checkList != "" && groupList != "" {
|
|
||||||
exitWithError(fmt.Errorf("group option and check option can't be used together"))
|
|
||||||
} else {
|
|
||||||
summary = controls.RunGroup()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
summary = controls.RunChecks(runner, filter)
|
||||||
|
|
||||||
// if we successfully ran some tests and it's json format, ignore the warnings
|
// if we successfully ran some tests and it's json format, ignore the warnings
|
||||||
if (summary.Fail > 0 || summary.Warn > 0 || summary.Pass > 0 || summary.Info > 0) && jsonFmt {
|
if (summary.Fail > 0 || summary.Warn > 0 || summary.Pass > 0 || summary.Info > 0) && jsonFmt {
|
||||||
out, err := controls.JSON()
|
out, err := controls.JSON()
|
||||||
@ -115,6 +143,10 @@ func prettyPrint(r *check.Controls, summary check.Summary) {
|
|||||||
colorPrint(check.INFO, fmt.Sprintf("%s %s\n", g.ID, g.Text))
|
colorPrint(check.INFO, fmt.Sprintf("%s %s\n", g.ID, g.Text))
|
||||||
for _, c := range g.Checks {
|
for _, c := range g.Checks {
|
||||||
colorPrint(c.State, fmt.Sprintf("%s %s\n", c.ID, c.Text))
|
colorPrint(c.State, fmt.Sprintf("%s %s\n", c.ID, c.Text))
|
||||||
|
|
||||||
|
if includeTestOutput && c.State == check.FAIL && len(c.ActualValue) > 0 {
|
||||||
|
printRawOutput(c.ActualValue)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,3 +245,9 @@ func isMaster() bool {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printRawOutput(output string) {
|
||||||
|
for _, row := range strings.Split(output, "\n") {
|
||||||
|
fmt.Println(fmt.Sprintf("\t %s", row))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
112
cmd/common_test.go
Normal file
112
cmd/common_test.go
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
// Copyright © 2017-2019 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 (
|
||||||
|
"github.com/aquasecurity/kube-bench/check"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewRunFilter(t *testing.T) {
|
||||||
|
|
||||||
|
type TestCase struct {
|
||||||
|
Name string
|
||||||
|
FilterOpts FilterOpts
|
||||||
|
Group *check.Group
|
||||||
|
Check *check.Check
|
||||||
|
|
||||||
|
Expected bool
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []TestCase{
|
||||||
|
{
|
||||||
|
Name: "Should return true when scored flag is enabled and check is scored",
|
||||||
|
FilterOpts: FilterOpts{Scored: true, Unscored: false},
|
||||||
|
Group: &check.Group{},
|
||||||
|
Check: &check.Check{Scored: true},
|
||||||
|
Expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Should return false when scored flag is enabled and check is not scored",
|
||||||
|
FilterOpts: FilterOpts{Scored: true, Unscored: false},
|
||||||
|
Group: &check.Group{},
|
||||||
|
Check: &check.Check{Scored: false},
|
||||||
|
Expected: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
Name: "Should return true when unscored flag is enabled and check is not scored",
|
||||||
|
FilterOpts: FilterOpts{Scored: false, Unscored: true},
|
||||||
|
Group: &check.Group{},
|
||||||
|
Check: &check.Check{Scored: false},
|
||||||
|
Expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Should return false when unscored flag is enabled and check is scored",
|
||||||
|
FilterOpts: FilterOpts{Scored: false, Unscored: true},
|
||||||
|
Group: &check.Group{},
|
||||||
|
Check: &check.Check{Scored: true},
|
||||||
|
Expected: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
Name: "Should return true when group flag contains group's ID",
|
||||||
|
FilterOpts: FilterOpts{Scored: true, Unscored: true, GroupList: "G1,G2,G3"},
|
||||||
|
Group: &check.Group{ID: "G2"},
|
||||||
|
Check: &check.Check{},
|
||||||
|
Expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Should return false when group flag doesn't contain group's ID",
|
||||||
|
FilterOpts: FilterOpts{GroupList: "G1,G3"},
|
||||||
|
Group: &check.Group{ID: "G2"},
|
||||||
|
Check: &check.Check{},
|
||||||
|
Expected: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
Name: "Should return true when check flag contains check's ID",
|
||||||
|
FilterOpts: FilterOpts{Scored: true, Unscored: true, CheckList: "C1,C2,C3"},
|
||||||
|
Group: &check.Group{},
|
||||||
|
Check: &check.Check{ID: "C2"},
|
||||||
|
Expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Should return false when check flag doesn't contain check's ID",
|
||||||
|
FilterOpts: FilterOpts{CheckList: "C1,C3"},
|
||||||
|
Group: &check.Group{},
|
||||||
|
Check: &check.Check{ID: "C2"},
|
||||||
|
Expected: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
t.Run(testCase.Name, func(t *testing.T) {
|
||||||
|
filter, _ := NewRunFilter(testCase.FilterOpts)
|
||||||
|
assert.Equal(t, testCase.Expected, filter(testCase.Group, testCase.Check))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("Should return error when both group and check flags are used", func(t *testing.T) {
|
||||||
|
// given
|
||||||
|
opts := FilterOpts{GroupList: "G1", CheckList: "C1"}
|
||||||
|
// when
|
||||||
|
_, err := NewRunFilter(opts)
|
||||||
|
// then
|
||||||
|
assert.EqualError(t, err, "group option and check option can't be used together")
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
18
cmd/root.go
18
cmd/root.go
@ -25,6 +25,13 @@ import (
|
|||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type FilterOpts struct {
|
||||||
|
CheckList string
|
||||||
|
GroupList string
|
||||||
|
Scored bool
|
||||||
|
Unscored bool
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
envVarsPrefix = "KUBE_BENCH"
|
envVarsPrefix = "KUBE_BENCH"
|
||||||
defaultKubeVersion = "1.6"
|
defaultKubeVersion = "1.6"
|
||||||
@ -33,14 +40,14 @@ var (
|
|||||||
cfgDir string
|
cfgDir string
|
||||||
jsonFmt bool
|
jsonFmt bool
|
||||||
pgSQL bool
|
pgSQL bool
|
||||||
checkList string
|
|
||||||
groupList string
|
|
||||||
masterFile = "master.yaml"
|
masterFile = "master.yaml"
|
||||||
nodeFile = "node.yaml"
|
nodeFile = "node.yaml"
|
||||||
federatedFile string
|
federatedFile string
|
||||||
noResults bool
|
noResults bool
|
||||||
noSummary bool
|
noSummary bool
|
||||||
noRemediations bool
|
noRemediations bool
|
||||||
|
filterOpts FilterOpts
|
||||||
|
includeTestOutput bool
|
||||||
)
|
)
|
||||||
|
|
||||||
// RootCmd represents the base command when called without any subcommands
|
// RootCmd represents the base command when called without any subcommands
|
||||||
@ -79,16 +86,19 @@ func init() {
|
|||||||
RootCmd.PersistentFlags().BoolVar(&noRemediations, "noremediations", false, "Disable printing of remediations section")
|
RootCmd.PersistentFlags().BoolVar(&noRemediations, "noremediations", false, "Disable printing of remediations section")
|
||||||
RootCmd.PersistentFlags().BoolVar(&jsonFmt, "json", false, "Prints the results as JSON")
|
RootCmd.PersistentFlags().BoolVar(&jsonFmt, "json", false, "Prints the results as JSON")
|
||||||
RootCmd.PersistentFlags().BoolVar(&pgSQL, "pgsql", false, "Save the results to PostgreSQL")
|
RootCmd.PersistentFlags().BoolVar(&pgSQL, "pgsql", false, "Save the results to PostgreSQL")
|
||||||
|
RootCmd.PersistentFlags().BoolVar(&filterOpts.Scored, "scored", true, "Run the scored CIS checks")
|
||||||
|
RootCmd.PersistentFlags().BoolVar(&filterOpts.Unscored, "unscored", true, "Run the unscored CIS checks")
|
||||||
|
RootCmd.PersistentFlags().BoolVar(&includeTestOutput, "include-test-output", false, "Prints the actual result when test fails")
|
||||||
|
|
||||||
RootCmd.PersistentFlags().StringVarP(
|
RootCmd.PersistentFlags().StringVarP(
|
||||||
&checkList,
|
&filterOpts.CheckList,
|
||||||
"check",
|
"check",
|
||||||
"c",
|
"c",
|
||||||
"",
|
"",
|
||||||
`A comma-delimited list of checks to run as specified in CIS document. Example --check="1.1.1,1.1.2"`,
|
`A comma-delimited list of checks to run as specified in CIS document. Example --check="1.1.1,1.1.2"`,
|
||||||
)
|
)
|
||||||
RootCmd.PersistentFlags().StringVarP(
|
RootCmd.PersistentFlags().StringVarP(
|
||||||
&groupList,
|
&filterOpts.GroupList,
|
||||||
"group",
|
"group",
|
||||||
"g",
|
"g",
|
||||||
"",
|
"",
|
||||||
|
@ -50,15 +50,18 @@ func continueWithError(err error, msg string) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanIDs(list string) []string {
|
func cleanIDs(list string) map[string]bool {
|
||||||
list = strings.Trim(list, ",")
|
list = strings.Trim(list, ",")
|
||||||
ids := strings.Split(list, ",")
|
ids := strings.Split(list, ",")
|
||||||
|
|
||||||
|
set := make(map[string]bool)
|
||||||
|
|
||||||
for _, id := range ids {
|
for _, id := range ids {
|
||||||
id = strings.Trim(id, " ")
|
id = strings.Trim(id, " ")
|
||||||
|
set[id] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return ids
|
return set
|
||||||
}
|
}
|
||||||
|
|
||||||
// ps execs out to the ps command; it's separated into a function so we can write tests
|
// ps execs out to the ps command; it's separated into a function so we can write tests
|
||||||
|
Loading…
Reference in New Issue
Block a user