1
0
mirror of https://github.com/aquasecurity/kube-bench.git synced 2024-12-18 12:48:08 +00:00

Merge branch 'master' into feature/json-config

This commit is contained in:
Liz Rice 2019-04-11 10:03:07 +01:00 committed by GitHub
commit c887794807
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 76 additions and 20 deletions

View File

@ -13,7 +13,17 @@ Tests are configured with YAML files, making this tool easy to update as test sp
## CIS Kubernetes Benchmark support ## CIS Kubernetes Benchmark support
kube-bench supports the tests for multiple versions of Kubernetes (1.6, 1.7, 1.8, and 1.11) as defined in the CIS Benchmarks 1.0.0, 1.1.0, 1.2.0, and 1.3.0 respectively. It will determine the test set to run based on the Kubernetes version running on the machine. kube-bench supports the tests for Kubernetes as defined in the CIS Benchmarks 1.0.0 to 1.4.0 respectively.
| CIS Kubernetes Benchmark | kube-bench config | Kubernetes versions |
|---|---|---|
| 1.0.0| 1.6 | 1.6 |
| 1.1.0| 1.7 | 1.7 |
| 1.2.0| 1.8 | 1.8-1.10 |
| 1.3.0| 1.11 | 1.11-1.12 |
| 1.4.0| 1.13 | 1.13- |
By default kube-bench will determine the test set to run based on the Kubernetes version running on the machine.
## Installation ## Installation
@ -114,6 +124,13 @@ For each type of node (*master*, *node* or *federated*) there is a list of compo
* **confs** - If one of the listed config files is found, this will be considered for the test. Tests can continue even if no config file is found. If no file is found at any of the listed locations, and a *defaultconf* location is given for the component, the test will give remediation advice using the *defaultconf* location. * **confs** - If one of the listed config files is found, this will be considered for the test. Tests can continue even if no config file is found. If no file is found at any of the listed locations, and a *defaultconf* location is given for the component, the test will give remediation advice using the *defaultconf* location.
* **unitfiles** - From version 1.2.0 of the benchmark (tests for Kubernetes 1.8), the remediation instructions were updated to assume that kubelet configuration is defined in a service file, and this setting defines where to look for that configuration. * **unitfiles** - From version 1.2.0 of the benchmark (tests for Kubernetes 1.8), the remediation instructions were updated to assume that kubelet configuration is defined in a service file, and this setting defines where to look for that configuration.
## Output
There are three output states
- [PASS] and [FAIL] indicate that a test was run successfully, and it either passed or failed
- [WARN] means this test needs further attention, for example it is a test that needs to be run manually
- [INFO] is informational output that needs no further action.
## Test config YAML representation ## Test config YAML representation
The tests are represented as YAML documents (installed by default into ./cfg). The tests are represented as YAML documents (installed by default into ./cfg).
@ -146,6 +163,20 @@ Recommendations (called `checks` in this document) can run on Kubernetes Master,
Checks are organized into `groups` which share similar controls (things to check for) and are grouped together in the section of the CIS Kubernetes document. Checks are organized into `groups` which share similar controls (things to check for) and are grouped together in the section of the CIS Kubernetes document.
These groups are further organized under `controls` which can be of the type `master`, `node` or `federated apiserver` to reflect the various Kubernetes node types. These groups are further organized under `controls` which can be of the type `master`, `node` or `federated apiserver` to reflect the various Kubernetes node types.
### Omitting checks
If you decide that a recommendation is not appropriate for your environment, you can choose to omit it by editing the test YAML file to give it the check type `skip` as in this example:
```yaml
checks:
- id: 2.1.1
text: "Ensure that the --allow-privileged argument is set to false (Scored)"
type: "skip"
scored: true
```
No tests will be run for this check and the output will be marked [INFO].
## Tests ## Tests
Tests are the items we actually look for to determine if a check is successful or not. Checks can have multiple tests, which must all be successful for the check to pass. Tests are the items we actually look for to determine if a check is successful or not. Checks can have multiple tests, which must all be successful for the check to pass.

View File

@ -366,7 +366,10 @@ groups:
text: "Ensure that the --service-account-lookup argument is set to true (Scored)" text: "Ensure that the --service-account-lookup argument is set to true (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: "--service-account-lookup"
set: false
- flag: "--service-account-lookup" - flag: "--service-account-lookup"
compare: compare:
op: eq op: eq
@ -1213,7 +1216,7 @@ groups:
scored: true scored: true
- id: 1.4.21 - id: 1.4.21
text: "Ensure that the Kubernetes PKI certificate file permissions are set to 644 or more restrictive (Scored)" text: "Ensure that the Kubernetes PKI certificate file permissions are set to 600 or more restrictive (Scored)"
audit: "stat -c %n\ %a /etc/kubernetes/pki/*.key" audit: "stat -c %n\ %a /etc/kubernetes/pki/*.key"
type: "manual" type: "manual"
tests: tests:

View File

@ -166,6 +166,8 @@ func (c *Check) Run() {
i++ i++
} }
glog.V(3).Info(out.String())
finalOutput := c.Tests.execute(out.String()) finalOutput := c.Tests.execute(out.String())
if finalOutput != nil { if finalOutput != nil {
c.ActualValue = finalOutput.actualResult c.ActualValue = finalOutput.actualResult

View File

@ -158,6 +158,16 @@ groups:
set: true set: true
- id: 14 - id: 14
text: "check that flag some-arg is set to some-val with ':' separator"
tests:
test_items:
- flag: "some-arg"
compare:
op: eq
value: some-val
set: true
- id: 15
text: "jsonpath correct value on field" text: "jsonpath correct value on field"
tests: tests:
test_items: test_items:
@ -177,7 +187,7 @@ groups:
value: 15000 value: 15000
set: true set: true
- id: 15 - id: 16
text: "jsonpath correct case-sensitive value on string field" text: "jsonpath correct case-sensitive value on string field"
tests: tests:
test_items: test_items:
@ -197,7 +207,7 @@ groups:
value: "WebHook,Something,RBAC" value: "WebHook,Something,RBAC"
set: true set: true
- id: 16 - id: 17
text: "jsonpath correct value on boolean field" text: "jsonpath correct value on boolean field"
tests: tests:
test_items: test_items:
@ -217,14 +227,14 @@ groups:
value: true value: true
set: true set: true
- id: 17 - id: 18
text: "jsonpath field absent" text: "jsonpath field absent"
tests: tests:
test_items: test_items:
- jsonpath: "{.notARealField}" - jsonpath: "{.notARealField}"
set: false set: false
- id: 18 - id: 19
text: "jsonpath correct value on nested field" text: "jsonpath correct value on nested field"
tests: tests:
test_items: test_items:
@ -234,7 +244,7 @@ groups:
value: "false" value: "false"
set: true set: true
- id: 19 - id: 20
text: "yamlpath correct value on field" text: "yamlpath correct value on field"
tests: tests:
test_items: test_items:
@ -244,14 +254,14 @@ groups:
value: 14999 value: 14999
set: true set: true
- id: 20 - id: 21
text: "yamlpath field absent" text: "yamlpath field absent"
tests: tests:
test_items: test_items:
- yamlpath: "{.fieldThatIsUnset}" - yamlpath: "{.fieldThatIsUnset}"
set: false set: false
- id: 21 - id: 22
text: "yamlpath correct value on nested field" text: "yamlpath correct value on nested field"
tests: tests:
test_items: test_items:
@ -261,7 +271,7 @@ groups:
value: "false" value: "false"
set: true set: true
- id: 22 - id: 23
text: "jsonpath on invalid json" text: "jsonpath on invalid json"
tests: tests:
test_items: test_items:
@ -271,14 +281,14 @@ groups:
value: "false" value: "false"
set: true set: true
- id: 23 - id: 24
text: "jsonpath with broken expression" text: "jsonpath with broken expression"
tests: tests:
test_items: test_items:
- jsonpath: "{.missingClosingBrace" - jsonpath: "{.missingClosingBrace"
set: true set: true
- id: 24 - id: 25
text: "yamlpath on invalid yaml" text: "yamlpath on invalid yaml"
tests: tests:
test_items: test_items:

View File

@ -123,10 +123,10 @@ func (t *testItem) execute(s string) *testOutput {
if t.Flag != "" { if t.Flag != "" {
// Expects flags in the form; // Expects flags in the form;
// --flag=somevalue // --flag=somevalue
// flag: somevalue
// --flag // --flag
// somevalue // somevalue
//pttn := `(` + t.Flag + `)(=)*([^\s,]*) *` pttn := `(` + t.Flag + `)(=|: *)*([^\s]*) *`
pttn := `(` + t.Flag + `)(=)*([^\s]*) *`
flagRe := regexp.MustCompile(pttn) flagRe := regexp.MustCompile(pttn)
vals := flagRe.FindStringSubmatch(s) vals := flagRe.FindStringSubmatch(s)

View File

@ -111,28 +111,34 @@ func TestTestExecute(t *testing.T) {
"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
controls.Groups[0].Checks[14], controls.Groups[0].Checks[14],
"{\"readOnlyPort\": 15000}", "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
controls.Groups[0].Checks[14],
"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],
"{\"stringValue\": \"WebHook,Something,RBAC\"}",
},
{
controls.Groups[0].Checks[16],
"{\"trueValue\": true}",
},
{
controls.Groups[0].Checks[17],
"{\"readOnlyPort\": 15000}", "{\"readOnlyPort\": 15000}",
}, },
{
controls.Groups[0].Checks[16],
"{\"stringValue\": \"WebHook,Something,RBAC\"}",
},
{
controls.Groups[0].Checks[17],
"{\"trueValue\": true}",
},
{ {
controls.Groups[0].Checks[18], controls.Groups[0].Checks[18],
"{\"authentication\": { \"anonymous\": {\"enabled\": false}}}", "{\"readOnlyPort\": 15000}",
}, },
{ {
controls.Groups[0].Checks[19], controls.Groups[0].Checks[19],
"readOnlyPort: 15000", "{\"authentication\": { \"anonymous\": {\"enabled\": false}}}",
}, },
{ {
controls.Groups[0].Checks[20], controls.Groups[0].Checks[20],
@ -140,6 +146,10 @@ func TestTestExecute(t *testing.T) {
}, },
{ {
controls.Groups[0].Checks[21], controls.Groups[0].Checks[21],
"readOnlyPort: 15000",
},
{
controls.Groups[0].Checks[22],
"authentication:\n anonymous:\n enabled: false", "authentication:\n anonymous:\n enabled: false",
}, },
} }