mirror of
https://github.com/aquasecurity/kube-bench.git
synced 2025-07-05 14:22:37 +00:00
Allow for environment variables to be checked in tests (#755)
* Initial commit for checking environment variables for etcd * Revert config changes * Remove redundant struct data * Fix issues with failing tests * Initial changes based on code review * Add option to disable envTesting + Update docs * Initial tests * Finished testing * Fix broken tests
This commit is contained in:
parent
28192bb7ab
commit
a19b65127e
@ -15,7 +15,9 @@ groups:
|
|||||||
bin_op: and
|
bin_op: and
|
||||||
test_items:
|
test_items:
|
||||||
- flag: "--cert-file"
|
- flag: "--cert-file"
|
||||||
|
env: "ETCD_CERT_FILE"
|
||||||
- flag: "--key-file"
|
- flag: "--key-file"
|
||||||
|
env: "ETCD_KEY_FILE"
|
||||||
remediation: |
|
remediation: |
|
||||||
Follow the etcd service documentation and configure TLS encryption.
|
Follow the etcd service documentation and configure TLS encryption.
|
||||||
Then, edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml
|
Then, edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml
|
||||||
@ -30,6 +32,7 @@ groups:
|
|||||||
tests:
|
tests:
|
||||||
test_items:
|
test_items:
|
||||||
- flag: "--client-cert-auth"
|
- flag: "--client-cert-auth"
|
||||||
|
env: "ETCD_CLIENT_CERT_AUTH"
|
||||||
compare:
|
compare:
|
||||||
op: eq
|
op: eq
|
||||||
value: true
|
value: true
|
||||||
@ -46,8 +49,10 @@ groups:
|
|||||||
bin_op: or
|
bin_op: or
|
||||||
test_items:
|
test_items:
|
||||||
- flag: "--auto-tls"
|
- flag: "--auto-tls"
|
||||||
|
env: "ETCD_AUTO_TLS"
|
||||||
set: false
|
set: false
|
||||||
- flag: "--auto-tls"
|
- flag: "--auto-tls"
|
||||||
|
env: "ETCD_AUTO_TLS"
|
||||||
compare:
|
compare:
|
||||||
op: eq
|
op: eq
|
||||||
value: false
|
value: false
|
||||||
@ -65,7 +70,9 @@ groups:
|
|||||||
bin_op: and
|
bin_op: and
|
||||||
test_items:
|
test_items:
|
||||||
- flag: "--peer-cert-file"
|
- flag: "--peer-cert-file"
|
||||||
|
env: "ETCD_PEER_CERT_FILE"
|
||||||
- flag: "--peer-key-file"
|
- flag: "--peer-key-file"
|
||||||
|
env: "ETCD_PEER_KEY_FILE"
|
||||||
remediation: |
|
remediation: |
|
||||||
Follow the etcd service documentation and configure peer TLS encryption as appropriate
|
Follow the etcd service documentation and configure peer TLS encryption as appropriate
|
||||||
for your etcd cluster.
|
for your etcd cluster.
|
||||||
@ -81,6 +88,7 @@ groups:
|
|||||||
tests:
|
tests:
|
||||||
test_items:
|
test_items:
|
||||||
- flag: "--peer-client-cert-auth"
|
- flag: "--peer-client-cert-auth"
|
||||||
|
env: "ETCD_PEER_CLIENT_CERT_AUTH"
|
||||||
compare:
|
compare:
|
||||||
op: eq
|
op: eq
|
||||||
value: true
|
value: true
|
||||||
@ -97,8 +105,10 @@ groups:
|
|||||||
bin_op: or
|
bin_op: or
|
||||||
test_items:
|
test_items:
|
||||||
- flag: "--peer-auto-tls"
|
- flag: "--peer-auto-tls"
|
||||||
|
env: "ETCD_PEER_AUTO_TLS"
|
||||||
set: false
|
set: false
|
||||||
- flag: "--peer-auto-tls"
|
- flag: "--peer-auto-tls"
|
||||||
|
env: "ETCD_PEER_AUTO_TLS"
|
||||||
compare:
|
compare:
|
||||||
op: eq
|
op: eq
|
||||||
value: false
|
value: false
|
||||||
@ -114,6 +124,7 @@ groups:
|
|||||||
tests:
|
tests:
|
||||||
test_items:
|
test_items:
|
||||||
- flag: "--trusted-ca-file"
|
- flag: "--trusted-ca-file"
|
||||||
|
env: "ETCD_TRUSTED_CA_FILE"
|
||||||
remediation: |
|
remediation: |
|
||||||
[Manual test]
|
[Manual test]
|
||||||
Follow the etcd documentation and create a dedicated certificate authority setup for the
|
Follow the etcd documentation and create a dedicated certificate authority setup for the
|
||||||
|
@ -68,6 +68,7 @@ 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:"audit"`
|
Audit string `json:"audit"`
|
||||||
|
AuditEnv string `yaml:"audit_env"`
|
||||||
AuditConfig string `yaml:"audit_config"`
|
AuditConfig string `yaml:"audit_config"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Tests *tests `json:"-"`
|
Tests *tests `json:"-"`
|
||||||
@ -81,7 +82,9 @@ type Check struct {
|
|||||||
ExpectedResult string `json:"expected_result"`
|
ExpectedResult string `json:"expected_result"`
|
||||||
Reason string `json:"reason,omitempty"`
|
Reason string `json:"reason,omitempty"`
|
||||||
AuditOutput string `json:"-"`
|
AuditOutput string `json:"-"`
|
||||||
|
AuditEnvOutput string `json:"-"`
|
||||||
AuditConfigOutput string `json:"-"`
|
AuditConfigOutput string `json:"-"`
|
||||||
|
DisableEnvTesting bool `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Runner wraps the basic Run method.
|
// Runner wraps the basic Run method.
|
||||||
@ -184,6 +187,14 @@ func (c *Check) run() State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Check) runAuditCommands() (lastCommand string, err error) {
|
func (c *Check) runAuditCommands() (lastCommand string, err error) {
|
||||||
|
// Always run auditEnvOutput if needed
|
||||||
|
if c.AuditEnv != "" {
|
||||||
|
c.AuditEnvOutput, err = runAudit(c.AuditEnv)
|
||||||
|
if err != nil {
|
||||||
|
return c.AuditEnv, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Run the audit command and auditConfig commands, if present
|
// Run the audit command and auditConfig commands, if present
|
||||||
c.AuditOutput, err = runAudit(c.Audit)
|
c.AuditOutput, err = runAudit(c.Audit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -207,11 +218,15 @@ func (c *Check) execute() (finalOutput *testOutput, err error) {
|
|||||||
t.isMultipleOutput = c.IsMultiple
|
t.isMultipleOutput = c.IsMultiple
|
||||||
|
|
||||||
// Try with the auditOutput first, and if that's not found, try the auditConfigOutput
|
// Try with the auditOutput first, and if that's not found, try the auditConfigOutput
|
||||||
t.isConfigSetting = false
|
t.auditUsed = AuditCommand
|
||||||
result := *(t.execute(c.AuditOutput))
|
result := *(t.execute(c.AuditOutput))
|
||||||
if !result.flagFound {
|
if !result.found {
|
||||||
t.isConfigSetting = true
|
t.auditUsed = AuditConfig
|
||||||
result = *(t.execute(c.AuditConfigOutput))
|
result = *(t.execute(c.AuditConfigOutput))
|
||||||
|
if !result.found && t.Env != "" {
|
||||||
|
t.auditUsed = AuditEnv
|
||||||
|
result = *(t.execute(c.AuditEnvOutput))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
res[i] = result
|
res[i] = result
|
||||||
expectedResultArr[i] = res[i].ExpectedResult
|
expectedResultArr[i] = res[i].ExpectedResult
|
||||||
|
@ -81,6 +81,39 @@ func TestCheck_Run(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCheckAuditEnv(t *testing.T){
|
||||||
|
passingCases := []*Check{
|
||||||
|
controls.Groups[2].Checks[0],
|
||||||
|
controls.Groups[2].Checks[2],
|
||||||
|
controls.Groups[2].Checks[3],
|
||||||
|
controls.Groups[2].Checks[4],
|
||||||
|
}
|
||||||
|
|
||||||
|
failingCases := []*Check{
|
||||||
|
controls.Groups[2].Checks[1],
|
||||||
|
controls.Groups[2].Checks[5],
|
||||||
|
controls.Groups[2].Checks[6],
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range passingCases {
|
||||||
|
t.Run(c.Text, func(t *testing.T) {
|
||||||
|
c.run()
|
||||||
|
if c.State != "PASS" {
|
||||||
|
t.Errorf("Should PASS, got: %v", c.State)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range failingCases {
|
||||||
|
t.Run(c.Text, func(t *testing.T) {
|
||||||
|
c.run()
|
||||||
|
if c.State != "FAIL" {
|
||||||
|
t.Errorf("Should FAIL, got: %v", c.State)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCheckAuditConfig(t *testing.T) {
|
func TestCheckAuditConfig(t *testing.T) {
|
||||||
|
|
||||||
passingCases := []*Check{
|
passingCases := []*Check{
|
||||||
|
@ -256,7 +256,7 @@ func TestControls_JUnitIncludesJSON(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expect: []byte(`<testsuite name="" tests="0" failures="0" errors="0" time="0">
|
expect: []byte(`<testsuite name="" tests="0" failures="0" errors="0" time="0">
|
||||||
<testcase name="check1id check1text" classname="" time="0">
|
<testcase name="check1id check1text" classname="" time="0">
|
||||||
<system-out>{"test_number":"check1id","test_desc":"check1text","audit":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"PASS","actual_value":"","scored":false,"IsMultiple":false,"expected_result":""}</system-out>
|
<system-out>{"test_number":"check1id","test_desc":"check1text","audit":"","AuditEnv":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"PASS","actual_value":"","scored":false,"IsMultiple":false,"expected_result":""}</system-out>
|
||||||
</testcase>
|
</testcase>
|
||||||
</testsuite>`),
|
</testsuite>`),
|
||||||
}, {
|
}, {
|
||||||
@ -279,7 +279,7 @@ func TestControls_JUnitIncludesJSON(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expect: []byte(`<testsuite name="" tests="402" failures="99" errors="0" time="0">
|
expect: []byte(`<testsuite name="" tests="402" failures="99" errors="0" time="0">
|
||||||
<testcase name="check1id check1text" classname="" time="0">
|
<testcase name="check1id check1text" classname="" time="0">
|
||||||
<system-out>{"test_number":"check1id","test_desc":"check1text","audit":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"PASS","actual_value":"","scored":false,"IsMultiple":false,"expected_result":""}</system-out>
|
<system-out>{"test_number":"check1id","test_desc":"check1text","audit":"","AuditEnv":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"PASS","actual_value":"","scored":false,"IsMultiple":false,"expected_result":""}</system-out>
|
||||||
</testcase>
|
</testcase>
|
||||||
</testsuite>`),
|
</testsuite>`),
|
||||||
}, {
|
}, {
|
||||||
@ -299,19 +299,19 @@ func TestControls_JUnitIncludesJSON(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expect: []byte(`<testsuite name="" tests="0" failures="0" errors="0" time="0">
|
expect: []byte(`<testsuite name="" tests="0" failures="0" errors="0" time="0">
|
||||||
<testcase name="check1id check1text" classname="" time="0">
|
<testcase name="check1id check1text" classname="" time="0">
|
||||||
<system-out>{"test_number":"check1id","test_desc":"check1text","audit":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"PASS","actual_value":"","scored":false,"IsMultiple":false,"expected_result":""}</system-out>
|
<system-out>{"test_number":"check1id","test_desc":"check1text","audit":"","AuditEnv":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"PASS","actual_value":"","scored":false,"IsMultiple":false,"expected_result":""}</system-out>
|
||||||
</testcase>
|
</testcase>
|
||||||
<testcase name="check2id check2text" classname="" time="0">
|
<testcase name="check2id check2text" classname="" time="0">
|
||||||
<skipped></skipped>
|
<skipped></skipped>
|
||||||
<system-out>{"test_number":"check2id","test_desc":"check2text","audit":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"INFO","actual_value":"","scored":false,"IsMultiple":false,"expected_result":""}</system-out>
|
<system-out>{"test_number":"check2id","test_desc":"check2text","audit":"","AuditEnv":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"INFO","actual_value":"","scored":false,"IsMultiple":false,"expected_result":""}</system-out>
|
||||||
</testcase>
|
</testcase>
|
||||||
<testcase name="check3id check3text" classname="" time="0">
|
<testcase name="check3id check3text" classname="" time="0">
|
||||||
<skipped></skipped>
|
<skipped></skipped>
|
||||||
<system-out>{"test_number":"check3id","test_desc":"check3text","audit":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"WARN","actual_value":"","scored":false,"IsMultiple":false,"expected_result":""}</system-out>
|
<system-out>{"test_number":"check3id","test_desc":"check3text","audit":"","AuditEnv":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"WARN","actual_value":"","scored":false,"IsMultiple":false,"expected_result":""}</system-out>
|
||||||
</testcase>
|
</testcase>
|
||||||
<testcase name="check4id check4text" classname="" time="0">
|
<testcase name="check4id check4text" classname="" time="0">
|
||||||
<failure type=""></failure>
|
<failure type=""></failure>
|
||||||
<system-out>{"test_number":"check4id","test_desc":"check4text","audit":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"FAIL","actual_value":"","scored":false,"IsMultiple":false,"expected_result":""}</system-out>
|
<system-out>{"test_number":"check4id","test_desc":"check4text","audit":"","AuditEnv":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"FAIL","actual_value":"","scored":false,"IsMultiple":false,"expected_result":""}</system-out>
|
||||||
</testcase>
|
</testcase>
|
||||||
</testsuite>`),
|
</testsuite>`),
|
||||||
},
|
},
|
||||||
|
148
check/data
148
check/data
@ -327,6 +327,53 @@ groups:
|
|||||||
op: eq
|
op: eq
|
||||||
value: false
|
value: false
|
||||||
set: true
|
set: true
|
||||||
|
- id: 29
|
||||||
|
text: "flag is set (via env)"
|
||||||
|
tests:
|
||||||
|
test_items:
|
||||||
|
- flag: "--allow-privileged"
|
||||||
|
env: "ALLOW_PRIVILEGED"
|
||||||
|
set: true
|
||||||
|
|
||||||
|
- id: 30
|
||||||
|
text: "flag is not set (via env)"
|
||||||
|
tests:
|
||||||
|
test_items:
|
||||||
|
- flag: "--basic-auth"
|
||||||
|
env: "BASIC_AUTH"
|
||||||
|
set: false
|
||||||
|
|
||||||
|
- id: 31
|
||||||
|
text: "flag value is set to some value (via env)"
|
||||||
|
tests:
|
||||||
|
test_items:
|
||||||
|
- flag: "--insecure-port"
|
||||||
|
env: "INSECURE_PORT"
|
||||||
|
compare:
|
||||||
|
op: eq
|
||||||
|
value: 0
|
||||||
|
set: true
|
||||||
|
|
||||||
|
- id: 32
|
||||||
|
text: "flag value is greater than or equal some number (via env)"
|
||||||
|
tests:
|
||||||
|
test_items:
|
||||||
|
- flag: "--audit-log-maxage"
|
||||||
|
env: "AUDIT_LOG_MAXAGE"
|
||||||
|
compare:
|
||||||
|
op: gte
|
||||||
|
value: 30
|
||||||
|
set: true
|
||||||
|
|
||||||
|
- id: 33
|
||||||
|
text: "flag value is less than some number (via env)"
|
||||||
|
tests:
|
||||||
|
test_items:
|
||||||
|
- env: "MAX_BACKLOG"
|
||||||
|
compare:
|
||||||
|
op: lt
|
||||||
|
value: 30
|
||||||
|
set: true
|
||||||
|
|
||||||
- id: 2.1
|
- id: 2.1
|
||||||
text: "audit and audit_config commands"
|
text: "audit and audit_config commands"
|
||||||
@ -557,3 +604,104 @@ groups:
|
|||||||
path: '{.readOnlyPort}'
|
path: '{.readOnlyPort}'
|
||||||
set: false
|
set: false
|
||||||
scored: true
|
scored: true
|
||||||
|
|
||||||
|
- id: 3.1
|
||||||
|
text: "audit_env commands"
|
||||||
|
checks:
|
||||||
|
- id: 0
|
||||||
|
text: "audit fails to find flag, audit_env finds flag -> pass"
|
||||||
|
audit: "echo in=incorrect"
|
||||||
|
audit_env: "echo flag=correct"
|
||||||
|
tests:
|
||||||
|
test_items:
|
||||||
|
- flag: "flag"
|
||||||
|
env: "flag"
|
||||||
|
compare:
|
||||||
|
op: eq
|
||||||
|
value: "correct"
|
||||||
|
set: true
|
||||||
|
scored: true
|
||||||
|
- id: 1
|
||||||
|
text: "audit fails to find flag, audit_env finds flag and fails -> fail"
|
||||||
|
audit: "echo in=wrong"
|
||||||
|
audit_env: "echo flag=wrong"
|
||||||
|
tests:
|
||||||
|
test_items:
|
||||||
|
- flag: "flag"
|
||||||
|
env: "flag"
|
||||||
|
compare:
|
||||||
|
op: eq
|
||||||
|
value: "correct"
|
||||||
|
set: true
|
||||||
|
scored: true
|
||||||
|
- id: 2
|
||||||
|
text: "audit finds correct flag, audit_env is incorrect -> pass"
|
||||||
|
audit: "echo flag=correct"
|
||||||
|
audit_env: "echo flag=incorrect"
|
||||||
|
tests:
|
||||||
|
test_items:
|
||||||
|
- flag: "flag"
|
||||||
|
env: "flag"
|
||||||
|
compare:
|
||||||
|
op: eq
|
||||||
|
value: "correct"
|
||||||
|
set: true
|
||||||
|
scored: true
|
||||||
|
- id: 3
|
||||||
|
text: "audit doesn't flag flag, audit_config finds it and passes, audit_env is not present -> pass"
|
||||||
|
audit: "echo in=correct"
|
||||||
|
audit_config: "echo 'flag: correct'"
|
||||||
|
tests:
|
||||||
|
test_items:
|
||||||
|
- flag: "flag"
|
||||||
|
path: "{.flag}"
|
||||||
|
compare:
|
||||||
|
op: eq
|
||||||
|
value: "correct"
|
||||||
|
set: true
|
||||||
|
scored: true
|
||||||
|
- id: 4
|
||||||
|
text: "audit doesn't flag flag, audit_config doesn't find flag, audit_env finds and passes -> pass"
|
||||||
|
audit: "echo in=correct"
|
||||||
|
audit_config: "echo 'in: correct'"
|
||||||
|
audit_env: "echo flag=correct"
|
||||||
|
tests:
|
||||||
|
test_items:
|
||||||
|
- flag: "flag"
|
||||||
|
path: "{.flag}"
|
||||||
|
env: "flag"
|
||||||
|
compare:
|
||||||
|
op: eq
|
||||||
|
value: "correct"
|
||||||
|
set: true
|
||||||
|
scored: true
|
||||||
|
- id: 5
|
||||||
|
text: "audit doesn't find flag, audit_config doesn't find flag, audit_env finds and fails -> fails"
|
||||||
|
audit: "echo in=correct"
|
||||||
|
audit_config: "echo 'in: correct'"
|
||||||
|
audit_env: "echo flag=incorrect"
|
||||||
|
tests:
|
||||||
|
test_items:
|
||||||
|
- flag: "flag"
|
||||||
|
path: "{.flag}"
|
||||||
|
env: "flag"
|
||||||
|
compare:
|
||||||
|
op: eq
|
||||||
|
value: "correct"
|
||||||
|
set: true
|
||||||
|
scored: true
|
||||||
|
- id: 6
|
||||||
|
text: "audit finds flag and fails, audit_config finds flag and fails, audit_env finds and passes -> fails"
|
||||||
|
audit: "echo flag=incorrect"
|
||||||
|
audit_config: "echo 'flag: incorrect'"
|
||||||
|
audit_env: "echo flag=correct"
|
||||||
|
tests:
|
||||||
|
test_items:
|
||||||
|
- flag: "flag"
|
||||||
|
path: "{.flag}"
|
||||||
|
env: "flag"
|
||||||
|
compare:
|
||||||
|
op: eq
|
||||||
|
value: "correct"
|
||||||
|
set: true
|
||||||
|
scored: true
|
||||||
|
@ -48,17 +48,27 @@ type tests struct {
|
|||||||
BinOp binOp `yaml:"bin_op"`
|
BinOp binOp `yaml:"bin_op"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AuditUsed string
|
||||||
|
|
||||||
|
const (
|
||||||
|
AuditCommand AuditUsed = "auditCommand"
|
||||||
|
AuditConfig AuditUsed = "auditConfig"
|
||||||
|
AuditEnv AuditUsed = "auditEnv"
|
||||||
|
)
|
||||||
|
|
||||||
type testItem struct {
|
type testItem struct {
|
||||||
Flag string
|
Flag string
|
||||||
|
Env string
|
||||||
Path string
|
Path string
|
||||||
Output string
|
Output string
|
||||||
Value string
|
Value string
|
||||||
Set bool
|
Set bool
|
||||||
Compare compare
|
Compare compare
|
||||||
isMultipleOutput bool
|
isMultipleOutput bool
|
||||||
isConfigSetting bool
|
auditUsed AuditUsed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type envTestItem testItem
|
||||||
type pathTestItem testItem
|
type pathTestItem testItem
|
||||||
type flagTestItem testItem
|
type flagTestItem testItem
|
||||||
|
|
||||||
@ -69,7 +79,7 @@ type compare struct {
|
|||||||
|
|
||||||
type testOutput struct {
|
type testOutput struct {
|
||||||
testResult bool
|
testResult bool
|
||||||
flagFound bool
|
found bool
|
||||||
actualResult string
|
actualResult string
|
||||||
ExpectedResult string
|
ExpectedResult string
|
||||||
}
|
}
|
||||||
@ -78,16 +88,25 @@ func failTestItem(s string) *testOutput {
|
|||||||
return &testOutput{testResult: false, actualResult: s}
|
return &testOutput{testResult: false, actualResult: s}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t testItem) flagValue() string {
|
func (t testItem) value() string {
|
||||||
if t.isConfigSetting {
|
if t.auditUsed == AuditConfig {
|
||||||
return t.Path
|
return t.Path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if t.auditUsed == AuditEnv {
|
||||||
|
return t.Env
|
||||||
|
}
|
||||||
|
|
||||||
return t.Flag
|
return t.Flag
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t testItem) findValue(s string) (match bool, value string, err error) {
|
func (t testItem) findValue(s string) (match bool, value string, err error) {
|
||||||
if t.isConfigSetting {
|
if t.auditUsed == AuditEnv {
|
||||||
|
et := envTestItem(t)
|
||||||
|
return et.findValue(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.auditUsed == AuditConfig {
|
||||||
pt := pathTestItem(t)
|
pt := pathTestItem(t)
|
||||||
return pt.findValue(s)
|
return pt.findValue(s)
|
||||||
}
|
}
|
||||||
@ -145,10 +164,28 @@ func (t pathTestItem) findValue(s string) (match bool, value string, err error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
glog.V(3).Infof("In pathTestItem.findValue %s", value)
|
glog.V(3).Infof("In pathTestItem.findValue %s", value)
|
||||||
match = (value != "")
|
match = value != ""
|
||||||
return match, value, err
|
return match, value, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t envTestItem) findValue(s string) (match bool, value string, err error) {
|
||||||
|
if s != "" && t.Env != "" {
|
||||||
|
r, _ := regexp.Compile(fmt.Sprintf("%s=.*(?:$|\\n)", t.Env))
|
||||||
|
out := r.FindString(s)
|
||||||
|
out = strings.Replace(out, "\n", "", 1)
|
||||||
|
out = strings.Replace(out, fmt.Sprintf("%s=", t.Env), "", 1)
|
||||||
|
|
||||||
|
if len(out) > 0 {
|
||||||
|
match = true
|
||||||
|
value = out
|
||||||
|
}else{
|
||||||
|
match = false
|
||||||
|
value = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return match, value, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (t testItem) execute(s string) *testOutput {
|
func (t testItem) execute(s string) *testOutput {
|
||||||
result := &testOutput{}
|
result := &testOutput{}
|
||||||
s = strings.TrimRight(s, " \n")
|
s = strings.TrimRight(s, " \n")
|
||||||
@ -186,16 +223,16 @@ func (t testItem) evaluate(s string) *testOutput {
|
|||||||
if match && t.Compare.Op != "" {
|
if match && t.Compare.Op != "" {
|
||||||
result.ExpectedResult, result.testResult = compareOp(t.Compare.Op, value, t.Compare.Value)
|
result.ExpectedResult, result.testResult = compareOp(t.Compare.Op, value, t.Compare.Value)
|
||||||
} else {
|
} else {
|
||||||
result.ExpectedResult = fmt.Sprintf("'%s' is present", t.flagValue())
|
result.ExpectedResult = fmt.Sprintf("'%s' is present", t.value())
|
||||||
result.testResult = match
|
result.testResult = match
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result.ExpectedResult = fmt.Sprintf("'%s' is not present", t.flagValue())
|
result.ExpectedResult = fmt.Sprintf("'%s' is not present", t.value())
|
||||||
result.testResult = !match
|
result.testResult = !match
|
||||||
}
|
}
|
||||||
|
|
||||||
result.flagFound = match
|
result.found = match
|
||||||
glog.V(3).Info(fmt.Sprintf("flagFound %v", result.flagFound))
|
glog.V(3).Info(fmt.Sprintf("found %v", result.found))
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
@ -51,168 +51,231 @@ func TestTestExecute(t *testing.T) {
|
|||||||
*Check
|
*Check
|
||||||
str string
|
str string
|
||||||
strConfig string
|
strConfig string
|
||||||
|
strEnv string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[0],
|
controls.Groups[0].Checks[0],
|
||||||
"2:45 ../kubernetes/kube-apiserver --allow-privileged=false --option1=20,30,40",
|
"2:45 ../kubernetes/kube-apiserver --allow-privileged=false --option1=20,30,40",
|
||||||
"",
|
"",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[1],
|
controls.Groups[0].Checks[1],
|
||||||
"2:45 ../kubernetes/kube-apiserver --allow-privileged=false",
|
"2:45 ../kubernetes/kube-apiserver --allow-privileged=false",
|
||||||
"",
|
"",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[2],
|
controls.Groups[0].Checks[2],
|
||||||
"niinai 13617 2635 99 19:26 pts/20 00:03:08 ./kube-apiserver --insecure-port=0 --anonymous-auth",
|
"niinai 13617 2635 99 19:26 pts/20 00:03:08 ./kube-apiserver --insecure-port=0 --anonymous-auth",
|
||||||
"",
|
"",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[3],
|
controls.Groups[0].Checks[3],
|
||||||
"2:45 ../kubernetes/kube-apiserver --secure-port=0 --audit-log-maxage=40 --option",
|
"2:45 ../kubernetes/kube-apiserver --secure-port=0 --audit-log-maxage=40 --option",
|
||||||
"",
|
"",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[4],
|
controls.Groups[0].Checks[4],
|
||||||
"2:45 ../kubernetes/kube-apiserver --max-backlog=20 --secure-port=0 --audit-log-maxage=40 --option",
|
"2:45 ../kubernetes/kube-apiserver --max-backlog=20 --secure-port=0 --audit-log-maxage=40 --option",
|
||||||
"",
|
"",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[5],
|
controls.Groups[0].Checks[5],
|
||||||
"2:45 ../kubernetes/kube-apiserver --option --admission-control=WebHook,RBAC ---audit-log-maxage=40",
|
"2:45 ../kubernetes/kube-apiserver --option --admission-control=WebHook,RBAC ---audit-log-maxage=40",
|
||||||
"",
|
"",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[6],
|
controls.Groups[0].Checks[6],
|
||||||
"2:45 .. --kubelet-clientkey=foo --kubelet-client-certificate=bar --admission-control=Webhook,RBAC",
|
"2:45 .. --kubelet-clientkey=foo --kubelet-client-certificate=bar --admission-control=Webhook,RBAC",
|
||||||
"",
|
"",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[7],
|
controls.Groups[0].Checks[7],
|
||||||
"2:45 .. --secure-port=0 --kubelet-client-certificate=bar --admission-control=Webhook,RBAC",
|
"2:45 .. --secure-port=0 --kubelet-client-certificate=bar --admission-control=Webhook,RBAC",
|
||||||
"",
|
"",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[8],
|
controls.Groups[0].Checks[8],
|
||||||
"644",
|
"644",
|
||||||
"",
|
"",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[9],
|
controls.Groups[0].Checks[9],
|
||||||
"640",
|
"640",
|
||||||
"",
|
"",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[9],
|
controls.Groups[0].Checks[9],
|
||||||
"600",
|
"600",
|
||||||
"",
|
"",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[10],
|
controls.Groups[0].Checks[10],
|
||||||
"2:45 ../kubernetes/kube-apiserver --option --admission-control=WebHook,RBAC ---audit-log-maxage=40",
|
"2:45 ../kubernetes/kube-apiserver --option --admission-control=WebHook,RBAC ---audit-log-maxage=40",
|
||||||
"",
|
"",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[11],
|
controls.Groups[0].Checks[11],
|
||||||
"2:45 ../kubernetes/kube-apiserver --option --admission-control=WebHook,RBAC ---audit-log-maxage=40",
|
"2:45 ../kubernetes/kube-apiserver --option --admission-control=WebHook,RBAC ---audit-log-maxage=40",
|
||||||
"",
|
"",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[12],
|
controls.Groups[0].Checks[12],
|
||||||
"2:45 ../kubernetes/kube-apiserver --option --admission-control=WebHook,Something,RBAC ---audit-log-maxage=40",
|
"2:45 ../kubernetes/kube-apiserver --option --admission-control=WebHook,Something,RBAC ---audit-log-maxage=40",
|
||||||
"",
|
"",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[13],
|
controls.Groups[0].Checks[13],
|
||||||
"2:45 ../kubernetes/kube-apiserver --option --admission-control=Something ---audit-log-maxage=40",
|
"2:45 ../kubernetes/kube-apiserver --option --admission-control=Something ---audit-log-maxage=40",
|
||||||
"",
|
"",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// check for ':' as argument-value separator, with space between arg and val
|
// check for ':' as argument-value separator, with space between arg and val
|
||||||
controls.Groups[0].Checks[14],
|
controls.Groups[0].Checks[14],
|
||||||
"2:45 kube-apiserver some-arg: some-val --admission-control=Something ---audit-log-maxage=40",
|
"2:45 kube-apiserver some-arg: some-val --admission-control=Something ---audit-log-maxage=40",
|
||||||
"",
|
"",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// check for ':' as argument-value separator, with no space between arg and val
|
// check for ':' as argument-value separator, with no space between arg and val
|
||||||
controls.Groups[0].Checks[14],
|
controls.Groups[0].Checks[14],
|
||||||
"2:45 kube-apiserver some-arg:some-val --admission-control=Something ---audit-log-maxage=40",
|
"2:45 kube-apiserver some-arg:some-val --admission-control=Something ---audit-log-maxage=40",
|
||||||
"",
|
"",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[15],
|
controls.Groups[0].Checks[15],
|
||||||
"",
|
"",
|
||||||
"{\"readOnlyPort\": 15000}",
|
"{\"readOnlyPort\": 15000}",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[16],
|
controls.Groups[0].Checks[16],
|
||||||
"",
|
"",
|
||||||
"{\"stringValue\": \"WebHook,Something,RBAC\"}",
|
"{\"stringValue\": \"WebHook,Something,RBAC\"}",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[17],
|
controls.Groups[0].Checks[17],
|
||||||
"",
|
"",
|
||||||
"{\"trueValue\": true}",
|
"{\"trueValue\": true}",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[18],
|
controls.Groups[0].Checks[18],
|
||||||
"",
|
"",
|
||||||
"{\"readOnlyPort\": 15000}",
|
"{\"readOnlyPort\": 15000}",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[19],
|
controls.Groups[0].Checks[19],
|
||||||
"",
|
"",
|
||||||
"{\"authentication\": { \"anonymous\": {\"enabled\": false}}}",
|
"{\"authentication\": { \"anonymous\": {\"enabled\": false}}}",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[20],
|
controls.Groups[0].Checks[20],
|
||||||
"",
|
"",
|
||||||
"readOnlyPort: 15000",
|
"readOnlyPort: 15000",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[21],
|
controls.Groups[0].Checks[21],
|
||||||
"",
|
"",
|
||||||
"readOnlyPort: 15000",
|
"readOnlyPort: 15000",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[22],
|
controls.Groups[0].Checks[22],
|
||||||
"",
|
"",
|
||||||
"authentication:\n anonymous:\n enabled: false",
|
"authentication:\n anonymous:\n enabled: false",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[26],
|
controls.Groups[0].Checks[26],
|
||||||
"",
|
"",
|
||||||
"currentMasterVersion: 1.12.7",
|
"currentMasterVersion: 1.12.7",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[27],
|
controls.Groups[0].Checks[27],
|
||||||
"--peer-client-cert-auth",
|
"--peer-client-cert-auth",
|
||||||
"",
|
"",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[27],
|
controls.Groups[0].Checks[27],
|
||||||
"--abc=true --peer-client-cert-auth --efg=false",
|
"--abc=true --peer-client-cert-auth --efg=false",
|
||||||
"",
|
"",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[27],
|
controls.Groups[0].Checks[27],
|
||||||
"--abc --peer-client-cert-auth --efg",
|
"--abc --peer-client-cert-auth --efg",
|
||||||
"",
|
"",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[27],
|
controls.Groups[0].Checks[27],
|
||||||
"--peer-client-cert-auth=true",
|
"--peer-client-cert-auth=true",
|
||||||
"",
|
"",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[27],
|
controls.Groups[0].Checks[27],
|
||||||
"--abc --peer-client-cert-auth=true --efg",
|
"--abc --peer-client-cert-auth=true --efg",
|
||||||
"",
|
"",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
controls.Groups[0].Checks[28],
|
controls.Groups[0].Checks[28],
|
||||||
"--abc --peer-client-cert-auth=false --efg",
|
"--abc --peer-client-cert-auth=false --efg",
|
||||||
"",
|
"",
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
controls.Groups[0].Checks[29],
|
||||||
|
"2:45 ../kubernetes/kube-apiserver --option1=20,30,40",
|
||||||
|
"",
|
||||||
|
"SOME_OTHER_ENV=true\nALLOW_PRIVILEGED=false",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
controls.Groups[0].Checks[30],
|
||||||
|
"2:45 ../kubernetes/kube-apiserver --option1=20,30,40",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
controls.Groups[0].Checks[31],
|
||||||
|
"2:45 ../kubernetes/kube-apiserver --option1=20,30,40",
|
||||||
|
"",
|
||||||
|
"INSECURE_PORT=0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
controls.Groups[0].Checks[32],
|
||||||
|
"2:45 ../kubernetes/kube-apiserver --option1=20,30,40",
|
||||||
|
"",
|
||||||
|
"AUDIT_LOG_MAXAGE=40",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
controls.Groups[0].Checks[33],
|
||||||
|
"2:45 ../kubernetes/kube-apiserver --option1=20,30,40",
|
||||||
|
"",
|
||||||
|
"MAX_BACKLOG=20",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,6 +283,7 @@ func TestTestExecute(t *testing.T) {
|
|||||||
t.Run(c.Text, func(t *testing.T) {
|
t.Run(c.Text, func(t *testing.T) {
|
||||||
c.Check.AuditOutput = c.str
|
c.Check.AuditOutput = c.str
|
||||||
c.Check.AuditConfigOutput = c.strConfig
|
c.Check.AuditConfigOutput = c.strConfig
|
||||||
|
c.Check.AuditEnvOutput = c.strEnv
|
||||||
res, err := c.Check.execute()
|
res, err := c.Check.execute()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf(err.Error())
|
t.Errorf(err.Error())
|
||||||
|
@ -100,11 +100,11 @@ func runChecks(nodetype check.NodeType, testYamlFile string) {
|
|||||||
|
|
||||||
// Variable substitutions. Replace all occurrences of variables in controls files.
|
// Variable substitutions. Replace all occurrences of variables in controls files.
|
||||||
s := string(in)
|
s := string(in)
|
||||||
s = makeSubstitutions(s, "bin", binmap)
|
s, binSubs := makeSubstitutions(s, "bin", binmap)
|
||||||
s = makeSubstitutions(s, "conf", confmap)
|
s, _ = makeSubstitutions(s, "conf", confmap)
|
||||||
s = makeSubstitutions(s, "svc", svcmap)
|
s, _ = makeSubstitutions(s, "svc", svcmap)
|
||||||
s = makeSubstitutions(s, "kubeconfig", kubeconfmap)
|
s, _ = makeSubstitutions(s, "kubeconfig", kubeconfmap)
|
||||||
s = makeSubstitutions(s, "cafile", cafilemap)
|
s, _ = makeSubstitutions(s, "cafile", cafilemap)
|
||||||
|
|
||||||
controls, err := check.NewControls(nodetype, []byte(s))
|
controls, err := check.NewControls(nodetype, []byte(s))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -117,10 +117,36 @@ func runChecks(nodetype check.NodeType, testYamlFile string) {
|
|||||||
exitWithError(fmt.Errorf("error setting up run filter: %v", err))
|
exitWithError(fmt.Errorf("error setting up run filter: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
generateDefaultEnvAudit(controls, binSubs)
|
||||||
|
|
||||||
controls.RunChecks(runner, filter, parseSkipIds(skipIds))
|
controls.RunChecks(runner, filter, parseSkipIds(skipIds))
|
||||||
controlsCollection = append(controlsCollection, controls)
|
controlsCollection = append(controlsCollection, controls)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func generateDefaultEnvAudit(controls *check.Controls, binSubs []string){
|
||||||
|
for _, group := range controls.Groups {
|
||||||
|
for _, checkItem := range group.Checks {
|
||||||
|
if checkItem.Tests != nil && !checkItem.DisableEnvTesting {
|
||||||
|
for _, test := range checkItem.Tests.TestItems {
|
||||||
|
if test.Env != "" && checkItem.AuditEnv == "" {
|
||||||
|
binPath := ""
|
||||||
|
|
||||||
|
if len(binSubs) == 1 {
|
||||||
|
binPath = binSubs[0]
|
||||||
|
} else {
|
||||||
|
fmt.Printf("AuditEnv not explicit for check (%s), where bin path cannot be determined\n", checkItem.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if test.Env != "" && checkItem.AuditEnv == "" {
|
||||||
|
checkItem.AuditEnv = fmt.Sprintf("cat \"/proc/$(/bin/ps -C %s -o pid= | tr -d ' ')/environ\" | tr '\\0' '\\n'", binPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func parseSkipIds(skipIds string) map[string]bool {
|
func parseSkipIds(skipIds string) map[string]bool {
|
||||||
var skipIdMap = make(map[string]bool, 0)
|
var skipIdMap = make(map[string]bool, 0)
|
||||||
if skipIds != "" {
|
if skipIds != "" {
|
||||||
|
@ -559,6 +559,41 @@ func TestExitCodeSelection(t *testing.T){
|
|||||||
assert.Equal(t, 10, exitCodeFailure)
|
assert.Equal(t, 10, exitCodeFailure)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGenerationDefaultEnvAudit(t *testing.T) {
|
||||||
|
input := []byte(`
|
||||||
|
---
|
||||||
|
type: "master"
|
||||||
|
groups:
|
||||||
|
- id: G1
|
||||||
|
checks:
|
||||||
|
- id: G1/C1
|
||||||
|
- id: G2
|
||||||
|
checks:
|
||||||
|
- id: G2/C1
|
||||||
|
text: "Verify that the SomeSampleFlag argument is set to true"
|
||||||
|
audit: "grep -B1 SomeSampleFlag=true /this/is/a/file/path"
|
||||||
|
tests:
|
||||||
|
test_items:
|
||||||
|
- flag: "SomeSampleFlag=true"
|
||||||
|
env: "SOME_SAMPLE_FLAG"
|
||||||
|
compare:
|
||||||
|
op: has
|
||||||
|
value: "true"
|
||||||
|
set: true
|
||||||
|
remediation: |
|
||||||
|
Edit the config file /this/is/a/file/path and set SomeSampleFlag to true.
|
||||||
|
scored: true
|
||||||
|
`)
|
||||||
|
controls, err := check.NewControls(check.MASTER, input)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
binSubs := []string {"TestBinPath"}
|
||||||
|
generateDefaultEnvAudit(controls, binSubs)
|
||||||
|
|
||||||
|
expectedAuditEnv := fmt.Sprintf("cat \"/proc/$(/bin/ps -C %s -o pid= | tr -d ' ')/environ\" | tr '\\0' '\\n'", binSubs[0])
|
||||||
|
assert.Equal(t, expectedAuditEnv, controls.Groups[1].Checks[0].AuditEnv)
|
||||||
|
}
|
||||||
|
|
||||||
func parseControlsJsonFile(filepath string) ([]*check.Controls, error) {
|
func parseControlsJsonFile(filepath string) ([]*check.Controls, error) {
|
||||||
var result []*check.Controls
|
var result []*check.Controls
|
||||||
|
|
||||||
|
@ -353,7 +353,8 @@ func getVersionFromKubeletOutput(s string) string {
|
|||||||
return subs[1]
|
return subs[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeSubstitutions(s string, ext string, m map[string]string) string {
|
func makeSubstitutions(s string, ext string, m map[string]string) (string, []string) {
|
||||||
|
substitutions := make([]string, 0)
|
||||||
for k, v := range m {
|
for k, v := range m {
|
||||||
subst := "$" + k + ext
|
subst := "$" + k + ext
|
||||||
if v == "" {
|
if v == "" {
|
||||||
@ -361,10 +362,14 @@ func makeSubstitutions(s string, ext string, m map[string]string) string {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
glog.V(2).Info(fmt.Sprintf("Substituting %s with '%s'\n", subst, v))
|
glog.V(2).Info(fmt.Sprintf("Substituting %s with '%s'\n", subst, v))
|
||||||
|
beforeS := s
|
||||||
s = multiWordReplace(s, subst, v)
|
s = multiWordReplace(s, subst, v)
|
||||||
|
if beforeS != s {
|
||||||
|
substitutions = append(substitutions, v)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return s
|
return s, substitutions
|
||||||
}
|
}
|
||||||
|
|
||||||
func isEmpty(str string) bool {
|
func isEmpty(str string) bool {
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/magiconair/properties/assert"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -387,17 +388,19 @@ func TestMakeSubsitutions(t *testing.T) {
|
|||||||
input string
|
input string
|
||||||
subst map[string]string
|
subst map[string]string
|
||||||
exp string
|
exp string
|
||||||
|
expectedSubs []string
|
||||||
}{
|
}{
|
||||||
{input: "Replace $thisbin", subst: map[string]string{"this": "that"}, exp: "Replace that"},
|
{input: "Replace $thisbin", subst: map[string]string{"this": "that"}, exp: "Replace that", expectedSubs: []string{"that"}},
|
||||||
{input: "Replace $thisbin", subst: map[string]string{"this": "that", "here": "there"}, exp: "Replace that"},
|
{input: "Replace $thisbin", subst: map[string]string{"this": "that", "here": "there"}, exp: "Replace that", expectedSubs: []string{"that"}},
|
||||||
{input: "Replace $thisbin and $herebin", subst: map[string]string{"this": "that", "here": "there"}, exp: "Replace that and there"},
|
{input: "Replace $thisbin and $herebin", subst: map[string]string{"this": "that", "here": "there"}, exp: "Replace that and there", expectedSubs: []string{"that", "there"}},
|
||||||
}
|
}
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
t.Run(c.input, func(t *testing.T) {
|
t.Run(c.input, func(t *testing.T) {
|
||||||
s := makeSubstitutions(c.input, "bin", c.subst)
|
s, subs := makeSubstitutions(c.input, "bin", c.subst)
|
||||||
if s != c.exp {
|
if s != c.exp {
|
||||||
t.Fatalf("Got %s expected %s", s, c.exp)
|
t.Fatalf("Got %s expected %s", s, c.exp)
|
||||||
}
|
}
|
||||||
|
assert.Equal(t, c.expectedSubs, subs)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,8 +150,8 @@ pass a check. This criteria is made up of keywords extracted from the output of
|
|||||||
the `audit` command and operations that compare these keywords against
|
the `audit` command and operations that compare these keywords against
|
||||||
values expected by the CIS Kubernetes Benchmark.
|
values expected by the CIS Kubernetes Benchmark.
|
||||||
|
|
||||||
There are two ways to extract keywords from the output of the `audit` command,
|
There are three ways to extract keywords from the output of the `audit` command,
|
||||||
`flag` and `path`.
|
`flag`, `path`, `env`.
|
||||||
|
|
||||||
`flag` is used when the keyword is a command-line flag. The associated `audit`
|
`flag` is used when the keyword is a command-line flag. The associated `audit`
|
||||||
command is usually a `ps` command and a `grep` for the binary whose flag we are
|
command is usually a `ps` command and a `grep` for the binary whose flag we are
|
||||||
@ -186,6 +186,23 @@ tests:
|
|||||||
# ...
|
# ...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`env` is used to check if the value is present within a specified environment variable. The presence of `env` is treated as an OR operation, if both `flag` and `env` are supplied it will use either to attempt pass the check.
|
||||||
|
The command used for checking the environment variables of a process **is generated by default**.
|
||||||
|
|
||||||
|
If the command being generated is causing errors, you can override the command used by setting `auditEnv` on the check.
|
||||||
|
Similarly, if you don't want the environment checking command to be generated or run at all, specify `disableEnvTesting` as true on the check.
|
||||||
|
|
||||||
|
The example below will check if the flag `--auto-tls` is equal to false *OR* `ETCD_AUTO_TLS` is equal to false
|
||||||
|
|
||||||
|
```yml
|
||||||
|
test_items:
|
||||||
|
- flag: "--auto-tls"
|
||||||
|
env: "ETCD_AUTO_TLS"
|
||||||
|
compare:
|
||||||
|
op: eq
|
||||||
|
value: false
|
||||||
|
```
|
||||||
|
|
||||||
`test_item` compares the output of the audit command and keywords using the
|
`test_item` compares the output of the audit command and keywords using the
|
||||||
`set` and `compare` fields.
|
`set` and `compare` fields.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user