mirror of
https://github.com/aquasecurity/kube-bench.git
synced 2026-03-01 17:20:28 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b649588f46 | ||
|
|
cb3d876ced | ||
|
|
d43cdfdf01 | ||
|
|
3926ba3977 | ||
|
|
d127512ab9 | ||
|
|
336ca84998 | ||
|
|
d8528a1ec8 | ||
|
|
a0bed18054 | ||
|
|
25b2c5da5a | ||
|
|
08097d2211 | ||
|
|
9a900db021 |
@@ -1,8 +1,9 @@
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
builds:
|
||||
- main: main.go
|
||||
binary: kube-bench
|
||||
goos:
|
||||
- darwin
|
||||
- linux
|
||||
goarch:
|
||||
- amd64
|
||||
|
||||
16
README.md
16
README.md
@@ -39,19 +39,23 @@ You can choose to
|
||||
|
||||
### Running inside a container
|
||||
|
||||
You can avoid installing kube-bench on the host by running it inside a container using the host PID namespace and mounting the `/etc` and `/var` directories where the configuration and other files are located on the host, so that kube-bench can check their existence and permissions.
|
||||
You can avoid installing kube-bench on the host by running it inside a container using the host PID namespace and mounting the `/etc` and `/var` directories where the configuration and other files are located on the host, so that kube-bench can check their existence and permissions.
|
||||
|
||||
```
|
||||
docker run --pid=host -v /etc:/etc:ro -v /var:/var:ro -t aquasec/kube-bench:latest [master|node]
|
||||
docker run --pid=host -v /etc:/etc:ro -v /var:/var:ro -t aquasec/kube-bench:latest [master|node] --version 1.13
|
||||
```
|
||||
|
||||
You can even use your own configs by mounting them over the default ones in `/opt/kube-bench/cfg/`
|
||||
> Note: the tests require either the kubelet or kubectl binary in the path in order to auto-detect the Kubernetes version. You can pass `-v $(which kubectl):/usr/bin/kubectl` to resolve this. You will also need to pass in kubeconfig credentials. For example:
|
||||
|
||||
```
|
||||
docker run --pid=host -v /etc:/etc:ro -v /var:/var:ro -t -v path/to/my-config.yaml:/opt/kube-bench/cfg/config.yaml aquasec/kube-bench:latest [master|node]
|
||||
docker run --pid=host -v /etc:/etc:ro -v /var:/var:ro -v $(which kubectl):/usr/bin/kubectl -v ~/.kube:/.kube -e KUBECONFIG=/.kube/config -t aquasec/kube-bench:latest [master|node]
|
||||
```
|
||||
|
||||
> Note: the tests require either the kubelet or kubectl binary in the path in order to auto-detect the Kubernetes version. You can pass `-v $(which kubectl):/usr/bin/kubectl` to the above invocations to resolve this.
|
||||
You can use your own configs by mounting them over the default ones in `/opt/kube-bench/cfg/`
|
||||
|
||||
```
|
||||
docker run --pid=host -v /etc:/etc:ro -v /var:/var:ro -t -v path/to/my-config.yaml:/opt/kube-bench/cfg/config.yam -v $(which kubectl):/usr/bin/kubectl -v ~/.kube:/.kube -e KUBECONFIG=/.kube/config aquasec/kube-bench:latest [master|node]
|
||||
```
|
||||
|
||||
### Running in a kubernetes cluster
|
||||
|
||||
@@ -284,6 +288,6 @@ We welcome pull requests!
|
||||
- Your PR is more likely to be accepted if it focuses on just one change.
|
||||
- Please include a comment with the results before and after your change.
|
||||
- Your PR is more likely to be accepted if it includes tests. (We have not historically been very strict about tests, but we would like to improve this!).
|
||||
- You're welcome to submit a **WIP** *(work in progress)* PR if you would like early feedback on an idea or an approach.
|
||||
- You're welcome to submit a draft PR if you would like early feedback on an idea or an approach.
|
||||
- Happy coding!
|
||||
|
||||
|
||||
@@ -10,6 +10,9 @@ groups:
|
||||
checks:
|
||||
- id: 2.1.1
|
||||
text: "Ensure that the --allow-privileged argument is set to false (Scored)"
|
||||
# This is one of those properties that can only be set as a command line argument.
|
||||
# To check if the property is set as expected, we need to parse the kubelet command
|
||||
# instead reading the Kubelet Configuration file.
|
||||
audit: "ps -fC $kubeletbin"
|
||||
tests:
|
||||
test_items:
|
||||
@@ -462,8 +465,14 @@ groups:
|
||||
|
||||
- id: 2.2.8
|
||||
text: "Ensure that the client certificate authorities file ownership is set to root:root (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $ca-file; then stat -c %U:%G $ca-file; fi'"
|
||||
type: manual
|
||||
audit: "/bin/sh -c 'if test -e $kubeletcafile; then stat -c %U:%G $kubeletcafile; fi'"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "root:root"
|
||||
compare:
|
||||
op: eq
|
||||
value: root:root
|
||||
set: true
|
||||
remediation: |
|
||||
Run the following command to modify the ownership of the --client-ca-file .
|
||||
chown root:root <filename>
|
||||
|
||||
@@ -453,8 +453,14 @@ groups:
|
||||
|
||||
- id: 2.2.8
|
||||
text: "Ensure that the client certificate authorities file ownership is set to root:root (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $ca-file; then stat -c %U:%G $ca-file; fi'"
|
||||
type: manual
|
||||
audit: "/bin/sh -c 'if test -e $kubeletcafile; then stat -c %U:%G $kubeletcafile; fi'"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "root:root"
|
||||
compare:
|
||||
op: eq
|
||||
value: root:root
|
||||
set: true
|
||||
remediation: |
|
||||
Run the following command to modify the ownership of the --client-ca-file .
|
||||
chown root:root <filename>
|
||||
|
||||
16
cfg/1.13-json/config.yaml
Normal file
16
cfg/1.13-json/config.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
# Config file for systems such as EKS where config is in JSON files
|
||||
# Master nodes are controlled by EKS and not user-accessible
|
||||
node:
|
||||
kubernetes:
|
||||
confs:
|
||||
- "/var/lib/kubelet/kubeconfig"
|
||||
kubeconfig:
|
||||
- "/var/lib/kubelet/kubeconfig"
|
||||
|
||||
kubelet:
|
||||
defaultsvc: "/etc/systemd/system/kubelet.service"
|
||||
defaultkubeconfig: "/var/lib/kubelet/kubeconfig"
|
||||
|
||||
proxy:
|
||||
defaultkubeconfig: "/var/lib/kubelet/kubeconfig"
|
||||
492
cfg/1.13-json/node.yaml
Normal file
492
cfg/1.13-json/node.yaml
Normal file
@@ -0,0 +1,492 @@
|
||||
---
|
||||
controls:
|
||||
version: 1.13
|
||||
id: 2
|
||||
text: "Worker Node Security Configuration"
|
||||
type: "node"
|
||||
groups:
|
||||
- id: 2.1
|
||||
text: "Kubelet"
|
||||
checks:
|
||||
- id: 2.1.1
|
||||
text: "Ensure that the --anonymous-auth argument is set to false (Scored)"
|
||||
audit: "cat $kubeletconf"
|
||||
tests:
|
||||
test_items:
|
||||
- path: "{.authentication.anonymous.enabled}"
|
||||
compare:
|
||||
op: eq
|
||||
value: false
|
||||
set: true
|
||||
remediation: |
|
||||
If using a Kubelet config file, edit the file to set authentication: anonymous: enabled to
|
||||
false .
|
||||
If using executable arguments, edit the kubelet service file
|
||||
$kubeletsvc on each worker node and
|
||||
set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
|
||||
--anonymous-auth=false
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
systemctl daemon-reload
|
||||
systemctl restart kubelet.service
|
||||
scored: true
|
||||
|
||||
- id: 2.1.2
|
||||
text: "Ensure that the --authorization-mode argument is not set to AlwaysAllow (Scored)"
|
||||
audit: "cat $kubeletconf"
|
||||
tests:
|
||||
test_items:
|
||||
- path: "{.authorization.mode}"
|
||||
compare:
|
||||
op: nothave
|
||||
value: "AlwaysAllow"
|
||||
set: true
|
||||
remediation: |
|
||||
If using a Kubelet config file, edit the file to set authorization: mode to Webhook.
|
||||
If using executable arguments, edit the kubelet service file
|
||||
$kubeletsvc on each worker node and
|
||||
set the below parameter in KUBELET_AUTHZ_ARGS variable.
|
||||
--authorization-mode=Webhook
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
systemctl daemon-reload
|
||||
systemctl restart kubelet.service
|
||||
scored: true
|
||||
|
||||
- id: 2.1.3
|
||||
text: "Ensure that the --client-ca-file argument is set as appropriate (Scored)"
|
||||
audit: "cat $kubeletconf"
|
||||
tests:
|
||||
test_items:
|
||||
- path: "{.authentication.x509.clientCAFile}"
|
||||
set: true
|
||||
remediation: |
|
||||
If using a Kubelet config file, edit the file to set authentication: x509: clientCAFile to
|
||||
the location of the client CA file.
|
||||
If using command line arguments, edit the kubelet service file
|
||||
$kubeletsvc on each worker node and
|
||||
set the below parameter in KUBELET_AUTHZ_ARGS variable.
|
||||
--client-ca-file=<path/to/client-ca-file>
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
systemctl daemon-reload
|
||||
systemctl restart kubelet.service
|
||||
scored: true
|
||||
|
||||
- id: 2.1.4
|
||||
text: "Ensure that the --read-only-port argument is set to 0 (Scored)"
|
||||
audit: "cat $kubeletconf"
|
||||
tests:
|
||||
test_items:
|
||||
- path: "{.readOnlyPort}"
|
||||
compare:
|
||||
op: eq
|
||||
value: 0
|
||||
set: true
|
||||
remediation: |
|
||||
If using a Kubelet config file, edit the file to set readOnlyPort to 0 .
|
||||
If using command line arguments, edit the kubelet service file
|
||||
$kubeletsvc on each worker node and
|
||||
set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
|
||||
--read-only-port=0
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
systemctl daemon-reload
|
||||
systemctl restart kubelet.service
|
||||
scored: true
|
||||
|
||||
- id: 2.1.5
|
||||
text: "Ensure that the --streaming-connection-idle-timeout argument is not set to 0 (Scored)"
|
||||
audit: "cat $kubeletconf"
|
||||
tests:
|
||||
test_items:
|
||||
- path: "{.streamingConnectionIdleTimeout}"
|
||||
compare:
|
||||
op: noteq
|
||||
value: 0
|
||||
set: true
|
||||
remediation: |
|
||||
If using a Kubelet config file, edit the file to set streamingConnectionIdleTimeout to a
|
||||
value other than 0.
|
||||
If using command line arguments, edit the kubelet service file
|
||||
$kubeletsvc on each worker node and
|
||||
set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
|
||||
--streaming-connection-idle-timeout=5m
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
systemctl daemon-reload
|
||||
systemctl restart kubelet.service
|
||||
scored: true
|
||||
|
||||
- id: 2.1.6
|
||||
text: "Ensure that the --protect-kernel-defaults argument is set to true (Scored)"
|
||||
audit: "cat $kubeletconf"
|
||||
tests:
|
||||
test_items:
|
||||
- path: "{.protectKernelDefaults}"
|
||||
compare:
|
||||
op: eq
|
||||
value: true
|
||||
set: true
|
||||
remediation: |
|
||||
If using a Kubelet config file, edit the file to set protectKernelDefaults: true .
|
||||
If using command line arguments, edit the kubelet service file
|
||||
$kubeletsvc on each worker node and
|
||||
set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
|
||||
--protect-kernel-defaults=true
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
systemctl daemon-reload
|
||||
systemctl restart kubelet.service
|
||||
scored: true
|
||||
|
||||
- id: 2.1.7
|
||||
text: "Ensure that the --make-iptables-util-chains argument is set to true (Scored)"
|
||||
audit: "cat $kubeletconf"
|
||||
tests:
|
||||
bin_op: or
|
||||
test_items:
|
||||
- path: "{.makeIPTablesUtilChains}"
|
||||
compare:
|
||||
op: eq
|
||||
value: true
|
||||
set: true
|
||||
- path: "{.makeIPTablesUtilChains}"
|
||||
set: false
|
||||
remediation: |
|
||||
If using a Kubelet config file, edit the file to set makeIPTablesUtilChains: true .
|
||||
If using command line arguments, edit the kubelet service file
|
||||
$kubeletsvc on each worker node and
|
||||
remove the --make-iptables-util-chains argument from the
|
||||
KUBELET_SYSTEM_PODS_ARGS variable.
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
systemctl daemon-reload
|
||||
systemctl restart kubelet.service
|
||||
scored: true
|
||||
|
||||
- id: 2.1.8
|
||||
text: "Ensure that the --hostname-override argument is not set (Scored)"
|
||||
# This is one of those properties that can only be set as a command line argument.
|
||||
# To check if the property is set as expected, we need to parse the kubelet command
|
||||
# instead reading the Kubelet Configuration file.
|
||||
audit: "ps -fC $kubeletbin"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "--hostname-override"
|
||||
set: false
|
||||
remediation: |
|
||||
Edit the kubelet service file $kubeletsvc
|
||||
on each worker node and remove the --hostname-override argument from the
|
||||
KUBELET_SYSTEM_PODS_ARGS variable.
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
systemctl daemon-reload
|
||||
systemctl restart kubelet.service
|
||||
scored: true
|
||||
|
||||
- id: 2.1.9
|
||||
text: "Ensure that the --event-qps argument is set to 0 (Scored)"
|
||||
audit: "cat $kubeletconf"
|
||||
tests:
|
||||
test_items:
|
||||
- path: "{.eventRecordQPS}"
|
||||
compare:
|
||||
op: eq
|
||||
value: 0
|
||||
set: true
|
||||
remediation: |
|
||||
If using a Kubelet config file, edit the file to set eventRecordQPS: 0 .
|
||||
If using command line arguments, edit the kubelet service file
|
||||
$kubeletsvc on each worker node and
|
||||
set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
|
||||
--event-qps=0
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
systemctl daemon-reload
|
||||
systemctl restart kubelet.service
|
||||
scored: true
|
||||
|
||||
- id: 2.1.10
|
||||
text: "Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate (Scored)"
|
||||
audit: "cat $kubeletconf"
|
||||
tests:
|
||||
bin_op: and
|
||||
test_items:
|
||||
- path: "{.tlsCertFile}"
|
||||
set: true
|
||||
- path: "{.tlsPrivateKeyFile}"
|
||||
set: true
|
||||
remediation: |
|
||||
If using a Kubelet config file, edit the file to set tlsCertFile to the location of the certificate
|
||||
file to use to identify this Kubelet, and tlsPrivateKeyFile to the location of the
|
||||
corresponding private key file.
|
||||
If using command line arguments, edit the kubelet service file
|
||||
$kubeletsvc on each worker node and
|
||||
set the below parameters in KUBELET_CERTIFICATE_ARGS variable.
|
||||
--tls-cert-file=<path/to/tls-certificate-file>
|
||||
file=<path/to/tls-key-file>
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
systemctl daemon-reload
|
||||
systemctl restart kubelet.service
|
||||
scored: true
|
||||
|
||||
- id: 2.1.11
|
||||
text: "Ensure that the --cadvisor-port argument is set to 0 (Scored)"
|
||||
# This is one of those properties that can only be set as a command line argument.
|
||||
# To check if the property is set as expected, we need to parse the kubelet command
|
||||
# instead reading the Kubelet Configuration file.
|
||||
audit: "ps -fC $kubeletbin"
|
||||
tests:
|
||||
bin_op: or
|
||||
test_items:
|
||||
- flag: "--cadvisor-port"
|
||||
compare:
|
||||
op: eq
|
||||
value: 0
|
||||
set: true
|
||||
- flag: "--cadvisor-port"
|
||||
set: false
|
||||
remediation: |
|
||||
Edit the kubelet service file $kubeletsvc
|
||||
on each worker node and set the below parameter in KUBELET_CADVISOR_ARGS variable.
|
||||
--cadvisor-port=0
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
systemctl daemon-reload
|
||||
systemctl restart kubelet.service
|
||||
scored: true
|
||||
|
||||
- id: 2.1.12
|
||||
text: "Ensure that the --rotate-certificates argument is not set to false (Scored)"
|
||||
audit: "cat $kubeletconf"
|
||||
tests:
|
||||
test_items:
|
||||
- path: "{.rotateCertificates}"
|
||||
compare:
|
||||
op: eq
|
||||
value: true
|
||||
set: true
|
||||
remediation: |
|
||||
If using a Kubelet config file, edit the file to add the line rotateCertificates: true.
|
||||
If using command line arguments, edit the kubelet service file $kubeletsvc
|
||||
on each worker node and add --rotate-certificates=true argument to the KUBELET_CERTIFICATE_ARGS variable.
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
systemctl daemon-reload
|
||||
systemctl restart kubelet.service
|
||||
scored: true
|
||||
|
||||
- id: 2.1.13
|
||||
text: "Ensure that the RotateKubeletServerCertificate argument is set to true (Scored)"
|
||||
audit: "cat $kubeletconf"
|
||||
tests:
|
||||
test_items:
|
||||
- path: "{.RotateKubeletServerCertificate}"
|
||||
compare:
|
||||
op: eq
|
||||
value: true
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the kubelet service file $kubeletsvc
|
||||
on each worker node and set the below parameter in KUBELET_CERTIFICATE_ARGS variable.
|
||||
--feature-gates=RotateKubeletServerCertificate=true
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
systemctl daemon-reload
|
||||
systemctl restart kubelet.service
|
||||
scored: true
|
||||
|
||||
- id: 2.1.14
|
||||
text: "Ensure that the Kubelet only makes use of Strong Cryptographic Ciphers (Not Scored)"
|
||||
audit: "cat $kubeletconf"
|
||||
tests:
|
||||
test_items:
|
||||
- path: "{.tlsCipherSuites}"
|
||||
compare:
|
||||
op: eq
|
||||
value: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256"
|
||||
set: true
|
||||
remediation: |
|
||||
If using a Kubelet config file, edit the file to set TLSCipherSuites: to TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256
|
||||
If using executable arguments, edit the kubelet service file $kubeletconf on each worker node and set the below parameter.
|
||||
--tls-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256
|
||||
scored: false
|
||||
|
||||
- id: 2.2
|
||||
text: "Configuration Files"
|
||||
checks:
|
||||
- id: 2.2.1
|
||||
text: "Ensure that the kubelet.conf file permissions are set to 644 or
|
||||
more restrictive (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $kubeletkubeconfig; then stat -c %a $kubeletkubeconfig; fi'"
|
||||
tests:
|
||||
bin_op: or
|
||||
test_items:
|
||||
- flag: "644"
|
||||
compare:
|
||||
op: eq
|
||||
value: "644"
|
||||
set: true
|
||||
- flag: "640"
|
||||
compare:
|
||||
op: eq
|
||||
value: "640"
|
||||
set: true
|
||||
- flag: "600"
|
||||
compare:
|
||||
op: eq
|
||||
value: "600"
|
||||
set: true
|
||||
remediation: |
|
||||
Run the below command (based on the file location on your system) on the each worker
|
||||
node. For example,
|
||||
chmod 644 $kubeletkubeconfig
|
||||
scored: true
|
||||
|
||||
- id: 2.2.2
|
||||
text: "Ensure that the kubelet.conf file ownership is set to root:root (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $kubeletkubeconfig; then stat -c %U:%G $kubeletkubeconfig; fi'"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "root:root"
|
||||
compare:
|
||||
op: eq
|
||||
value: root:root
|
||||
set: true
|
||||
remediation: |
|
||||
Run the below command (based on the file location on your system) on the each worker
|
||||
node. For example,
|
||||
chown root:root $kubeletkubeconfig
|
||||
scored: true
|
||||
|
||||
- id: 2.2.3
|
||||
text: "Ensure that the kubelet service file permissions are set to 644 or
|
||||
more restrictive (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $kubeletsvc; then stat -c %a $kubeletsvc; fi'"
|
||||
tests:
|
||||
bin_op: or
|
||||
test_items:
|
||||
- flag: "644"
|
||||
compare:
|
||||
op: eq
|
||||
value: 644
|
||||
set: true
|
||||
- flag: "640"
|
||||
compare:
|
||||
op: eq
|
||||
value: "640"
|
||||
set: true
|
||||
- flag: "600"
|
||||
compare:
|
||||
op: eq
|
||||
value: "600"
|
||||
set: true
|
||||
remediation: |
|
||||
Run the below command (based on the file location on your system) on the each worker
|
||||
node. For example,
|
||||
chmod 755 $kubeletsvc
|
||||
scored: true
|
||||
|
||||
- id: 2.2.4
|
||||
text: "Ensure that the kubelet service file ownership is set to root:root (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $kubeletsvc; then stat -c %U:%G $kubeletsvc; fi'"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "root:root"
|
||||
set: true
|
||||
remediation: |
|
||||
Run the below command (based on the file location on your system) on the each worker
|
||||
node. For example,
|
||||
chown root:root $kubeletsvc
|
||||
scored: true
|
||||
|
||||
- id: 2.2.5
|
||||
text: "Ensure that the proxy kubeconfig file permissions are set to 644 or more restrictive (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $proxykubeconfig; then stat -c %a $proxykubeconfig; fi'"
|
||||
tests:
|
||||
bin_op: or
|
||||
test_items:
|
||||
- flag: "644"
|
||||
compare:
|
||||
op: eq
|
||||
value: "644"
|
||||
set: true
|
||||
- flag: "640"
|
||||
compare:
|
||||
op: eq
|
||||
value: "640"
|
||||
set: true
|
||||
- flag: "600"
|
||||
compare:
|
||||
op: eq
|
||||
value: "600"
|
||||
set: true
|
||||
remediation: |
|
||||
Run the below command (based on the file location on your system) on the each worker
|
||||
node. For example,
|
||||
chmod 644 $proxykubeconfig
|
||||
scored: true
|
||||
|
||||
- id: 2.2.6
|
||||
text: "Ensure that the proxy kubeconfig file ownership is set to root:root (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $proxykubeconfig; then stat -c %U:%G $proxykubeconfig; fi'"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "root:root"
|
||||
set: true
|
||||
remediation: |
|
||||
Run the below command (based on the file location on your system) on the each worker
|
||||
node. For example,
|
||||
chown root:root $proxykubeconfig
|
||||
scored: true
|
||||
|
||||
- id: 2.2.7
|
||||
text: "Ensure that the certificate authorities file permissions are set to
|
||||
644 or more restrictive (Scored)"
|
||||
type: manual
|
||||
remediation: |
|
||||
Run the following command to modify the file permissions of the --client-ca-file
|
||||
chmod 644 <filename>
|
||||
scored: true
|
||||
|
||||
- id: 2.2.8
|
||||
text: "Ensure that the client certificate authorities file ownership is set to root:root (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $kubeletcafile; then stat -c %U:%G $kubeletcafile; fi'"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "root:root"
|
||||
compare:
|
||||
op: eq
|
||||
value: root:root
|
||||
set: true
|
||||
remediation: |
|
||||
Run the following command to modify the ownership of the --client-ca-file .
|
||||
chown root:root <filename>
|
||||
scored: true
|
||||
|
||||
- id: 2.2.9
|
||||
text: "Ensure that the kubelet configuration file ownership is set to root:root (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $kubeletconf; then stat -c %U:%G $kubeletconf; fi'"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "root:root"
|
||||
set: true
|
||||
remediation: |
|
||||
Run the following command (using the config file location identied in the Audit step)
|
||||
chown root:root $kubeletconf
|
||||
scored: true
|
||||
|
||||
- id: 2.2.10
|
||||
text: "Ensure that the kubelet configuration file has permissions set to 644 or more restrictive (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $kubeletconf; then stat -c %a $kubeletconf; fi'"
|
||||
tests:
|
||||
bin_op: or
|
||||
test_items:
|
||||
- flag: "644"
|
||||
compare:
|
||||
op: eq
|
||||
value: "644"
|
||||
set: true
|
||||
- flag: "640"
|
||||
compare:
|
||||
op: eq
|
||||
value: "640"
|
||||
set: true
|
||||
- flag: "600"
|
||||
compare:
|
||||
op: eq
|
||||
value: "600"
|
||||
set: true
|
||||
remediation: |
|
||||
Run the following command (using the config file location identied in the Audit step)
|
||||
chmod 644 $kubeletconf
|
||||
scored: true
|
||||
@@ -22,7 +22,7 @@ groups:
|
||||
If using a Kubelet config file, edit the file to set authentication: anonymous: enabled to
|
||||
false .
|
||||
If using executable arguments, edit the kubelet service file
|
||||
$kubeletconf on each worker node and
|
||||
$kubeletsvc on each worker node and
|
||||
set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
|
||||
--anonymous-auth=false
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
@@ -434,8 +434,14 @@ groups:
|
||||
|
||||
- id: 2.2.8
|
||||
text: "Ensure that the client certificate authorities file ownership is set to root:root (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $ca-file; then stat -c %U:%G $ca-file; fi'"
|
||||
type: manual
|
||||
audit: "/bin/sh -c 'if test -e $kubeletcafile; then stat -c %U:%G $kubeletcafile; fi'"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "root:root"
|
||||
compare:
|
||||
op: eq
|
||||
value: root:root
|
||||
set: true
|
||||
remediation: |
|
||||
Run the following command to modify the ownership of the --client-ca-file .
|
||||
chown root:root <filename>
|
||||
|
||||
@@ -430,9 +430,15 @@ groups:
|
||||
scored: true
|
||||
|
||||
- id: 2.2.8
|
||||
text: "Ensure that the client certificate authorities file ownership is set to root:root"
|
||||
audit: "/bin/sh -c 'if test -e $ca-file; then stat -c %U:%G $ca-file; fi'"
|
||||
type: manual
|
||||
text: "Ensure that the client certificate authorities file ownership is set to root:root (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $kubeletcafile; then stat -c %U:%G $kubeletcafile; fi'"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "root:root"
|
||||
compare:
|
||||
op: eq
|
||||
value: root:root
|
||||
set: true
|
||||
remediation: |
|
||||
Run the following command to modify the ownership of the --client-ca-file .
|
||||
chown root:root <filename>
|
||||
|
||||
@@ -81,6 +81,8 @@ node:
|
||||
defaultconf: /etc/kubernetes/config
|
||||
|
||||
kubelet:
|
||||
cafile:
|
||||
- "/etc/kubernetes/pki/ca.crt"
|
||||
bins:
|
||||
- "hyperkube kubelet"
|
||||
- "kubelet"
|
||||
@@ -91,6 +93,7 @@ node:
|
||||
defaultconf: "/var/lib/kubelet/config.yaml"
|
||||
defaultsvc: "/etc/systemd/system/kubelet.service.d/10-kubeadm.conf"
|
||||
defaultkubeconfig: "/etc/kubernetes/kubelet.conf"
|
||||
defaultcafile: "/etc/kubernetes/pki/ca.crt"
|
||||
|
||||
proxy:
|
||||
bins:
|
||||
|
||||
@@ -56,8 +56,8 @@ type compare struct {
|
||||
}
|
||||
|
||||
type testOutput struct {
|
||||
testResult bool
|
||||
actualResult string
|
||||
testResult bool
|
||||
actualResult string
|
||||
ExpectedResult string
|
||||
}
|
||||
|
||||
@@ -76,36 +76,22 @@ func (t *testItem) execute(s string) *testOutput {
|
||||
} else {
|
||||
// Path != "" - we don't know whether it's YAML or JSON but
|
||||
// we can just try one then the other
|
||||
buf := new(bytes.Buffer)
|
||||
var jsonInterface interface{}
|
||||
|
||||
if t.Path != "" {
|
||||
err := json.Unmarshal([]byte(s), &jsonInterface)
|
||||
err := unmarshal(s, &jsonInterface)
|
||||
if err != nil {
|
||||
err := yaml.Unmarshal([]byte(s), &jsonInterface)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to load YAML or JSON from provided input \"%s\": %v\n", s, err)
|
||||
return failTestItem("failed to load YAML or JSON")
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "failed to load YAML or JSON from provided input \"%s\": %v\n", s, err)
|
||||
return failTestItem("failed to load YAML or JSON")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Parse the jsonpath/yamlpath expression...
|
||||
j := jsonpath.New("jsonpath")
|
||||
j.AllowMissingKeys(true)
|
||||
err := j.Parse(t.Path)
|
||||
jsonpathResult, err := executeJSONPath(t.Path, &jsonInterface)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "unable to parse path expression \"%s\": %v\n", t.Path, err)
|
||||
return failTestItem("unable to parse path expression")
|
||||
}
|
||||
|
||||
err = j.Execute(buf, jsonInterface)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error executing path expression \"%s\": %v\n", t.Path, err)
|
||||
return failTestItem("error executing path expression")
|
||||
}
|
||||
|
||||
jsonpathResult := fmt.Sprintf("%s", buf)
|
||||
match = (jsonpathResult != "")
|
||||
flagVal = jsonpathResult
|
||||
}
|
||||
@@ -205,6 +191,35 @@ func (t *testItem) execute(s string) *testOutput {
|
||||
return result
|
||||
}
|
||||
|
||||
func unmarshal(s string, jsonInterface *interface{}) error {
|
||||
data := []byte(s)
|
||||
err := json.Unmarshal(data, jsonInterface)
|
||||
if err != nil {
|
||||
err := yaml.Unmarshal(data, jsonInterface)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func executeJSONPath(path string, jsonInterface interface{}) (string, error) {
|
||||
j := jsonpath.New("jsonpath")
|
||||
j.AllowMissingKeys(true)
|
||||
err := j.Parse(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
err = j.Execute(buf, jsonInterface)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
jsonpathResult := fmt.Sprintf("%s", buf)
|
||||
return jsonpathResult, nil
|
||||
}
|
||||
|
||||
type tests struct {
|
||||
TestItems []*testItem `yaml:"test_items"`
|
||||
BinOp binOp `yaml:"bin_op"`
|
||||
|
||||
@@ -201,3 +201,124 @@ func TestTestExecuteExceptions(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTestUnmarshal(t *testing.T) {
|
||||
type kubeletConfig struct {
|
||||
Kind string
|
||||
ApiVersion string
|
||||
Address string
|
||||
}
|
||||
cases := []struct {
|
||||
content string
|
||||
jsonInterface interface{}
|
||||
expectedToFail bool
|
||||
}{
|
||||
{
|
||||
`{
|
||||
"kind": "KubeletConfiguration",
|
||||
"apiVersion": "kubelet.config.k8s.io/v1beta1",
|
||||
"address": "0.0.0.0"
|
||||
}
|
||||
`,
|
||||
kubeletConfig{},
|
||||
false,
|
||||
}, {
|
||||
`
|
||||
kind: KubeletConfiguration
|
||||
address: 0.0.0.0
|
||||
apiVersion: kubelet.config.k8s.io/v1beta1
|
||||
authentication:
|
||||
anonymous:
|
||||
enabled: false
|
||||
webhook:
|
||||
cacheTTL: 2m0s
|
||||
enabled: true
|
||||
x509:
|
||||
clientCAFile: /etc/kubernetes/pki/ca.crt
|
||||
tlsCipherSuites:
|
||||
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
`,
|
||||
kubeletConfig{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
`
|
||||
kind: ddress: 0.0.0.0
|
||||
apiVersion: kubelet.config.k8s.io/v1beta
|
||||
`,
|
||||
kubeletConfig{},
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
err := unmarshal(c.content, &c.jsonInterface)
|
||||
if err != nil {
|
||||
if !c.expectedToFail {
|
||||
t.Errorf("%s, expectedToFail:%v, got:%v\n", c.content, c.expectedToFail, err)
|
||||
}
|
||||
} else {
|
||||
if c.expectedToFail {
|
||||
t.Errorf("%s, expectedToFail:%v, got:Did not fail\n", c.content, c.expectedToFail)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecuteJSONPath(t *testing.T) {
|
||||
type kubeletConfig struct {
|
||||
Kind string
|
||||
ApiVersion string
|
||||
Address string
|
||||
}
|
||||
cases := []struct {
|
||||
jsonPath string
|
||||
jsonInterface kubeletConfig
|
||||
expectedResult string
|
||||
expectedToFail bool
|
||||
}{
|
||||
{
|
||||
// JSONPath parse works, results don't match
|
||||
"{.Kind}",
|
||||
kubeletConfig{
|
||||
Kind: "KubeletConfiguration",
|
||||
ApiVersion: "kubelet.config.k8s.io/v1beta1",
|
||||
Address: "127.0.0.0",
|
||||
},
|
||||
"blah",
|
||||
true,
|
||||
},
|
||||
{
|
||||
// JSONPath parse works, results match
|
||||
"{.Kind}",
|
||||
kubeletConfig{
|
||||
Kind: "KubeletConfiguration",
|
||||
ApiVersion: "kubelet.config.k8s.io/v1beta1",
|
||||
Address: "127.0.0.0",
|
||||
},
|
||||
"KubeletConfiguration",
|
||||
false,
|
||||
},
|
||||
{
|
||||
// JSONPath parse fails
|
||||
"{.ApiVersion",
|
||||
kubeletConfig{
|
||||
Kind: "KubeletConfiguration",
|
||||
ApiVersion: "kubelet.config.k8s.io/v1beta1",
|
||||
Address: "127.0.0.0",
|
||||
},
|
||||
"",
|
||||
true,
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
result, err := executeJSONPath(c.jsonPath, c.jsonInterface)
|
||||
if err != nil && !c.expectedToFail {
|
||||
t.Fatalf("jsonPath:%q, expectedResult:%q got:%v\n", c.jsonPath, c.expectedResult, err)
|
||||
}
|
||||
if c.expectedResult != result && !c.expectedToFail {
|
||||
t.Errorf("jsonPath:%q, expectedResult:%q got:%q\n", c.jsonPath, c.expectedResult, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +85,7 @@ func runChecks(nodetype check.NodeType) {
|
||||
confmap := getConfigFiles(typeConf)
|
||||
svcmap := getServiceFiles(typeConf)
|
||||
kubeconfmap := getKubeConfigFiles(typeConf)
|
||||
cafilemap := getCaFile(typeConf)
|
||||
|
||||
// Variable substitutions. Replace all occurrences of variables in controls files.
|
||||
s := string(in)
|
||||
@@ -92,6 +93,7 @@ func runChecks(nodetype check.NodeType) {
|
||||
s = makeSubstitutions(s, "conf", confmap)
|
||||
s = makeSubstitutions(s, "svc", svcmap)
|
||||
s = makeSubstitutions(s, "kubeconfig", kubeconfmap)
|
||||
s = makeSubstitutions(s, "cafile", cafilemap)
|
||||
|
||||
controls, err := check.NewControls(nodetype, []byte(s))
|
||||
if err != nil {
|
||||
|
||||
31
cmd/util.go
31
cmd/util.go
@@ -68,6 +68,8 @@ func cleanIDs(list string) map[string]bool {
|
||||
|
||||
// ps execs out to the ps command; it's separated into a function so we can write tests
|
||||
func ps(proc string) string {
|
||||
// TODO: truncate proc to 15 chars
|
||||
// See https://github.com/aquasecurity/kube-bench/issues/328#issuecomment-506813344
|
||||
cmd := exec.Command("ps", "-C", proc, "-o", "cmd", "--no-headers")
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
@@ -256,6 +258,35 @@ func getKubeConfigFiles(v *viper.Viper) map[string]string {
|
||||
return kubeconfigmap
|
||||
}
|
||||
|
||||
// getCaFile finds which of the set of client certificate authorities files exist
|
||||
func getCaFile(v *viper.Viper) map[string]string {
|
||||
cafilemap := make(map[string]string)
|
||||
|
||||
for _, component := range v.GetStringSlice("components") {
|
||||
s := v.Sub(component)
|
||||
if s == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
cafile := findConfigFile(s.GetStringSlice("cafile"))
|
||||
if cafile == "" {
|
||||
if s.IsSet("defaultcafile") {
|
||||
cafile = s.GetString("defaultcafile")
|
||||
glog.V(2).Info(fmt.Sprintf("Using default client CA file name '%s' for component %s", cafile, component))
|
||||
} else {
|
||||
glog.V(2).Info(fmt.Sprintf("Missing client CA file for %s", component))
|
||||
cafile = component
|
||||
}
|
||||
} else {
|
||||
glog.V(2).Info(fmt.Sprintf("Component %s uses client CA file '%s'", component, cafile))
|
||||
}
|
||||
|
||||
cafilemap[component] = cafile
|
||||
}
|
||||
|
||||
return cafilemap
|
||||
}
|
||||
|
||||
// verifyBin checks that the binary specified is running
|
||||
func verifyBin(bin string) bool {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user