Compare commits

...

128 Commits

Author SHA1 Message Date
Liz Rice
d30786da4a Merge pull request #258 from aquasecurity/fix-241
Add ":" as a valid flag-value separator for tests
2019-04-11 09:37:39 +01:00
Liz Rice
c03e958311 Merge branch 'master' into fix-241 2019-04-11 09:34:02 +01:00
Liz Rice
241972c659 Merge pull request #249 from aquasecurity/document-output
Document output states
2019-04-11 09:18:34 +01:00
Liz Rice
d93ed0acca Merge branch 'master' into fix-241 2019-04-11 09:05:18 +01:00
Liz Rice
b5f3299e92 Merge branch 'master' into document-output 2019-04-11 09:04:04 +01:00
Liz Rice
588d75d20d Merge pull request #251 from aquasecurity/version-mapping
Add CIS & Kubernetes version mapping to README
2019-04-11 09:03:44 +01:00
Abubakr-Sadik Nii Nai Davis
4b8a7ffbe1 Add ":" as a valid flag-value separator for tests
This is useful for checking values in YAML (possibly JSON) kubernetes config files.
2019-04-10 22:47:26 +00:00
Liz Rice
651b72f7d1 Merge branch 'master' into document-output 2019-04-10 08:45:55 +01:00
Liz Rice
0c40532e76 Merge branch 'master' into version-mapping 2019-04-10 08:31:04 +01:00
Liz Rice
54502c5f75 Merge pull request #247 from aquasecurity/yoavrotems-patch-2
Update master.yaml
2019-03-27 14:24:03 +00:00
Liz Rice
df556c2f42 Add CIS & Kubernetes version mapping to README 2019-03-27 14:21:22 +00:00
Liz Rice
488f5221ef Document output states
Also describe how tests can be omitted by editing the YAML
2019-03-26 10:37:17 +00:00
Liz Rice
b1ce0a9a75 Merge branch 'master' into yoavrotems-patch-2 2019-03-26 09:51:03 +00:00
Liz Rice
0f86bfc060 Merge pull request #246 from aquasecurity/yoavrotems-patch-1
Update master.yaml
2019-03-26 09:41:40 +00:00
yoavrotems
d059196b71 Update master.yaml
Fix 1.1.23 to check *if* --service-account-lookup argument is set and if so then if it's equal to true
2019-03-25 14:41:06 +02:00
yoavrotems
a85e5a7759 Update master.yaml
Fix title of 1.4.21 from 644 to 600 according to cis benchmark
2019-03-25 14:33:52 +02:00
Liz Rice
573136a700 Merge pull request #238 from Kuqd/features/autodetect-nodetype
Adds master node detection - thanks @Kuqd!
2019-03-18 18:43:13 +00:00
Liz Rice
9246be924d Merge branch 'master' into features/autodetect-nodetype 2019-03-13 20:36:19 -07:00
Cyril Tovena
5baf81a70a Adds master node detection and a root command that automatically detect checks to run.
The root command will run node checks and if possible master checks.
I've also added some Makefile targets to improve local testing and improve the documentation.
2019-03-12 19:32:05 -04:00
Liz Rice
c4c0d911d4 Merge pull request #237 from aquasecurity/openshift
Update openshift executable config
2019-03-07 14:53:22 +00:00
Liz Rice
9b3628e76a Update openshift executable config for #236 2019-03-07 11:18:06 +00:00
Liz Rice
8745df170a Merge pull request #233 from aquasecurity/clean-ocp-configs
Clean up OCP benchmark config.
2019-03-07 09:30:18 +00:00
Liz Rice
1ead9e1d71 Merge branch 'master' into clean-ocp-configs 2019-03-07 09:22:47 +00:00
Liz Rice
772d2e26b4 Merge pull request #226 from aquasecurity/add-new-cfg-version1.4
add new config files from the new CIS Kubernetes Benchmark
2019-03-06 13:35:17 +00:00
Abubakr-Sadik Nii Nai Davis
53ed68a0b2 Clean up OCP benchmark config.
The OCP benchmarks uses configs for only binary component variable names.
This commit cleans up the OCP config by removing all configuration
except those component binaries required to run kube-bench on OCP
installations and adds missing ones.
2019-03-06 12:02:58 +00:00
yoavrotems
c6102f0a1b Fix the files
Fix the start from 1.11 to 1.13 and adding changes from pull #227, and pull #228.
2019-03-06 11:26:36 +00:00
yoavrotems
e534392525 Delete node.yaml
replace with the new node.yaml file
2019-03-06 13:24:14 +02:00
yoavrotems
5f09ecef44 Delete master.yaml
replace with the new master.yaml file
2019-03-06 13:23:49 +02:00
yoavrotems
a7d9e06c1b Delete config.yaml
replace with the new config.yaml file
2019-03-06 13:23:18 +02:00
yoavrotems
50f22e7f13 Merge branch 'master' into add-new-cfg-version1.4 2019-03-06 11:16:36 +00:00
Liz Rice
2d4019aabe Merge pull request #228 from aquasecurity/fix-208
Fix issues with checks for kubelet configuration files
2019-03-03 11:10:05 +00:00
Liz Rice
dd8e7ec874 Merge branch 'master' into fix-208 2019-03-03 09:45:16 +00:00
Abubakr-Sadik Nii Nai Davis
d255b49d4b Revert 1.8 config file. 2019-03-02 17:20:46 +00:00
Liz Rice
0a58805cdb Merge pull request #227 from aquasecurity/fix-false-detections
Only find flags on the process we really want
2019-02-28 10:48:23 +08:00
Liz Rice
c18d8a2234 Merge branch 'master' into fix-false-detections 2019-02-28 10:38:41 +08:00
Abubakr-Sadik Nii Nai Davis
a88b0703d8 Add kubeconfig variable substitution for kubelet and proxy.
There are checks for the kubeconfig for both kubelet and proxy which
the current kube-bench implementation does not check for properly.
kube-bench checks the wrong files.

This PR adds support for variable substitution for all the config file
types are that should be checked in the CIS benchmarks.

This PR also fixes a buggy in CIS 1.3.0 check 2.2.9, which checks for
ownership of the kubelet config file /var/lib/kubelet/config.yaml but
recommends changing ownership of kubelet kubeconfig file
/etc/kubernetes/kubelet.conf as remediation.
2019-02-27 22:15:14 +00:00
Abubakr-Sadik Nii Nai Davis
3f98c1def2 Fix wrong reference to kubelet.config in node checks.
This fix applies to only checks for kubernetes versions 1.8 and 1.11.
See https://github.com/aquasecurity/kube-bench/pull/208.
2019-02-27 22:14:19 +00:00
Liz Rice
d712db47a2 Only find flags on the process we really want 2019-02-28 01:33:21 +08:00
yoavrotems
82150fdc63 add new config files from the new CIS Kubernetes Benchmark
there is a new update at CIS_Kubernetes_Benchmark_v1.4.0 for Kubernetes 1.13
2019-02-27 10:39:32 +00:00
Liz Rice
c824daeb15 Merge pull request #222 from nshauli/search_for_kubelet_binary_when_not_in_path
search for the kubelet binary when it is not in the path
2019-02-19 16:07:20 +00:00
nshauli
e93bfc1aac search for the kubelet binary when it is not in the path 2019-02-19 16:38:10 +02:00
Liz Rice
da09e6513a Merge pull request #218 from yoavAqua/bugfix-log-warnings-instead-of-print
Bugfix: Logging warning instead of printing
2019-02-19 13:48:30 +00:00
Liz Rice
7626dc2705 Merge branch 'master' into bugfix-log-warnings-instead-of-print 2019-02-19 13:44:23 +00:00
Yoav Hizkiahou
082e9cf7e9 Bugfix: Logging warning instead of printing
Made all the warnings to be logged and not printed, so when using the json flag the output will be only in json format.

fix #217
2019-02-19 14:39:55 +02:00
Liz Rice
2d4c7e8b42 Merge pull request #212 from aquasecurity/ocp-configs
OCP benchmarks and configs
2019-02-18 09:31:45 +00:00
Liz Rice
cd231106cc Improve comment
Tests could easily be marked "skip" because the user doesn't want to run them in their environment, and in this common case the set of tests will be non-nil
2019-02-18 08:46:26 +00:00
Liz Rice
db962a0ad9 Fix merge of skip check 2019-02-18 08:40:57 +00:00
Abubakr-Sadik Nii Nai Davis
911e9051dc Merge remote-tracking branch 'origin/master' into ocp-configs 2019-02-15 19:48:53 +00:00
Abubakr-Sadik Nii Nai Davis
e899e941f7 Add OCP 3.10 benchmarks. 2019-02-15 19:44:39 +00:00
Weston Steimel
42ed8628de Only get runningVersion if --version has not been provided
Signed-off-by: Weston Steimel <weston.steimel@gmail.com>
2019-02-15 19:43:13 +00:00
Liz Rice
dc8dcfbf8c Merge pull request #211 from yoavAqua/support-skip-flag
Type skip and not scored checks
2019-01-29 23:14:05 +02:00
Yoav Hizkiahou
49f745af8e Support new check type - skip:
If a check is marked with type "skip", it will be marked as Info.

Support scored property:
If a check is not scored and is not marked with type skip, it will be marked as Warn.
2019-01-29 19:05:12 +02:00
Liz Rice
ba437d500a Merge pull request #206 from westonsteimel/no_runningversion_if_version_set
Only get runningVersion if --version has not been provided
2019-01-24 12:00:59 +01:00
Weston Steimel
42f4152058 Only get runningVersion if --version has not been provided
Signed-off-by: Weston Steimel <weston.steimel@gmail.com>
2019-01-24 00:34:09 +00:00
Liz Rice
8dabb7dc37 Merge pull request #201 from aquasecurity/yam-comment
Comment why we mount /usr/bin
2019-01-22 09:49:25 +01:00
Liz Rice
f2062e81a1 Comment why /usr/bin is mounted 2019-01-17 11:36:25 +00:00
Liz Rice
528bcfbffe Update job-node.yaml 2019-01-17 11:34:26 +00:00
Liz Rice
3422b9102f Add comment for why /usr/bin is mounted 2019-01-17 11:33:35 +00:00
Liz Rice
86b126ad2b Create NOTICE (#199)
* Create NOTICE

* Update NOTICE
2019-01-16 10:53:07 +02:00
Liz Rice
827945f7fb Merge pull request #200 from spuder/patch-1
warn osx limitation
2019-01-15 11:11:57 +00:00
Liz Rice
79427e185e Merge branch 'master' into patch-1 2019-01-15 11:05:27 +00:00
Liz Rice
6b9ceae9d4 True for Windows too 2019-01-15 11:05:04 +00:00
Liz Rice
fbd6eb8ff5 Merge pull request #198 from aquasecurity/mount-volumes
For #197 - create job YAML files that mount host volumes as needed
2019-01-15 11:03:06 +00:00
Spencer Owen
2a9a02f25b warn osx limitation 2019-01-14 10:41:19 -07:00
Liz Rice
8021610e46 For #197 - create job YAML files that mount host volumes as needed 2019-01-11 18:44:13 +00:00
Liz Rice
2eef3e8ad2 Merge pull request #193 from maxbischoff/patch-1
Changed 1.1.14 to not fail when flag is not set
2019-01-09 10:21:27 +00:00
Maximilian Bischoff
791fbba9e7 Changed 1.1.14 to not fail when flag is not set
Added another test item that checks whether --disable-admission-plugins is not set and an "or" bin_op. 
This causes check 1.1.14 to be successful when the flag is not set, while still failing when the flag is set and includes the value NamespaceLifecycle
2019-01-08 13:58:41 +01:00
Liz Rice
f6cab11357 Merge pull request #187 from martinmosegaard/doc-kubectl-host-pid
Document limitation of running with kubectl
2019-01-02 11:05:32 +00:00
Liz Rice
9f2899027e Merge branch 'master' into doc-kubectl-host-pid 2019-01-02 10:59:19 +00:00
Liz Rice
313fe038f6 Merge pull request #188 from martinmosegaard/rm-space-tls-cipher
Remove spaces in remediation command for tls-cipher-suites
2019-01-02 10:59:07 +00:00
Liz Rice
2d721ed4ad Merge branch 'master' into rm-space-tls-cipher 2019-01-02 10:53:29 +00:00
Liz Rice
799b928054 Merge pull request #189 from Congelli501/patch-1
Typo: trailing whitespace for rule text
2019-01-02 10:53:16 +00:00
Liz Rice
3a662b3ff6 Merge branch 'master' into doc-kubectl-host-pid 2019-01-02 10:53:04 +00:00
Liz Rice
f902b30110 Merge branch 'master' into rm-space-tls-cipher 2019-01-02 10:31:34 +00:00
Liz Rice
b52a88214f Merge branch 'master' into patch-1 2019-01-02 10:30:33 +00:00
Liz Rice
bfdd921f3d Merge pull request #190 from Congelli501/patch-2
Advise the use to mount /etc & /var read only for docker usage
2019-01-02 10:29:58 +00:00
Colin GILLE
af7ad90477 Advise the use to mount /etc & /var read only for docker usage 2018-12-31 16:39:31 +01:00
Colin GILLE
ffe7ffb3d3 Type: trailing whitespace for rule text 2018-12-31 16:36:15 +01:00
Martin Mosegaard Amdisen
fd120d0adf Remove spaces in remediation command for tls-cipher-suites
Makes it easier to copy-paste the remediation. Matches the other occurences
of tls-cipher-suites in the configuration.
2018-12-27 14:48:21 +01:00
Martin Mosegaard Amdisen
ba03d8f64b Document limitation of running with kubectl
Once the master node recommended check:

1.1.12 Ensure that the admission control plugin DenyEscalatingExec is set

has been followed, it is no longer possible to run kube-bench itself using kubectl.
2018-12-27 13:10:00 +01:00
Liz Rice
21f7902288 Merge pull request #183 from s1lv3r40/master
Fixing Node Check - 2.1.15 typos
2018-12-21 11:31:43 +00:00
Liz Rice
26e28b8897 Merge branch 'master' into master 2018-12-21 11:26:53 +00:00
Liz Rice
ae1812b4db Merge pull request #185 from maxbischoff/patch-1
Added missing "=" to master.yaml
2018-12-21 11:26:40 +00:00
Liz Rice
1534a4aea8 Merge branch 'master' into patch-1 2018-12-21 11:20:13 +00:00
Liz Rice
28a57ff1a3 Merge branch 'master' into master 2018-12-21 11:18:26 +00:00
Liz Rice
41fe066039 Merge pull request #186 from seslattery/seslattery-patch-1
Fix typo on README.md
2018-12-21 11:17:31 +00:00
Sean Slattery
5ca498cd50 Fix typo on README.md 2018-12-20 11:19:44 -08:00
Maximilian Bischoff
e81b785bf8 Added missing "=" to master.yaml
In the remediation of 1.1.11 the flag --enable-admission-plugins was missing a =
2018-12-19 18:20:23 +01:00
Vladimir Dimov
645d23e1ec fixing typos 2.1.15 2018-11-28 13:14:49 +02:00
Liz Rice
52d6ac717d Merge pull request #181 from aquasecurity/config-file-location-mount
read config files from host /etc
2018-11-20 19:49:37 +00:00
Liz Rice
bdbbe41b69 Also /var 2018-11-20 13:22:36 +00:00
Liz Rice
ba9985047c read config files from host /etc
I don't see how kube-bench can check the permissions on files unless it has access to them on the host, so I think we need to be mounting the /etc directory from the host
2018-11-20 10:18:06 +00:00
Liz Rice
5fe702edbe Merge pull request #175 from aquasecurity/fix-2.1.8
Fix node check 2.1.8
2018-11-08 12:22:17 +00:00
Liz Rice
6e80b6477a Merge branch 'master' into fix-2.1.8 2018-11-08 11:41:54 +00:00
Liz Rice
e1f5bb1ace Merge pull request #173 from aquasecurity/fix-1.1.37
Fix check 1.1.37.
2018-11-08 11:40:06 +00:00
Liz Rice
6d8788071f Merge branch 'master' into fix-2.1.8 2018-11-08 11:38:34 +00:00
Liz Rice
f42243e9b5 Merge branch 'master' into fix-1.1.37 2018-11-08 11:35:58 +00:00
Liz Rice
d004acdbba Merge pull request #174 from johscheuer/correct-readme
Correct readme for 1.11 example
2018-11-08 11:33:50 +00:00
Abubakr-Sadik Nii Nai Davis
0a5358665e By default --make-iptables-util-chain is true, so PASS if this flag is not set. 2018-11-07 23:57:38 +00:00
Abubakr-Sadik Nii Nai Davis
4f40a11e84 Change binary op from and to or. 2018-11-07 23:54:41 +00:00
Johannes M. Scheuermann
b3b3cb819a Correct readme for 1.11 example
Signed-off-by: Johannes M. Scheuermann <joh.scheuer@gmail.com>
2018-11-07 21:51:52 +01:00
Abubakr-Sadik Nii Nai Davis
c0f56e966a Fix check 1.1.37. 2018-11-06 14:35:45 +00:00
Liz Rice
ed7f6cf3fc Merge pull request #171 from nickperry/master
Fixes https://github.com/aquasecurity/kube-bench/issues/170
2018-11-01 09:57:14 +00:00
Nick Perry
e083c8f0a3 Fixes https://github.com/aquasecurity/kube-bench/issues/170
Correcting the logic of 1.1.14 for Kubernetes 1.11.
2018-10-30 23:40:41 +00:00
Liz Rice
77481e8739 Merge pull request #169 from mikekim/fix-1.3.7
Fixing 1.3.7 on 1.11 master.
2018-10-29 12:12:39 +00:00
Liz Rice
48489637c5 Merge branch 'master' into fix-1.3.7 2018-10-29 12:08:22 +00:00
Liz Rice
15537cb42b Merge pull request #168 from mikekim/fix-dollar-in-paths
Fixing checks 2.2.9 and 2.2.10 on 1.11 nodes.
2018-10-27 09:31:55 +01:00
Michal Jankowski
9988503223 Fixing 1.3.7 on 1.11 master.
With multiple test items operator defaults to "and". In case of 1.3.7
the tests check whether --address flag is either set to 127.0.0.1 or not
set at all. Those conditions cannot be met at the same time.
2018-10-25 15:32:41 -07:00
Michal Jankowski
5f254de415 Fixing checks 2.2.9 and 2.2.10 on 1.11 nodes.
Path to kubelet configuration was accidentally prefixed with a dollar
symbol (probably as a result of copying some other test that used
variable name).
After removing the dollar sign from paths both checks pass on conforming
deployment.
2018-10-24 17:06:21 -07:00
Liz Rice
64f4f638e9 Merge pull request #167 from aquasecurity/fix-issue-with-kubelet-config-and-unitfile-checks
Fix issue with kubelet config and unitfile checks
2018-10-23 14:45:19 +01:00
Abubakr-Sadik Nii Nai Davis
97623aea05 Update kubernetes node benchmark to check kubelet systemd unitfile.
Also clean up the config file for 1.11 a bit.
2018-10-23 02:30:08 +00:00
Abubakr-Sadik Nii Nai Davis
ed21839464 Add getServiceFiles function.
The CIS benchmark check for node checks 2 config files for kubelet:
  - kubelet config file (kubelet.conf)
  - kubelet systemd unitfile (10-kubeadm.conf)

The getServiceFiles function gets candidates for kubelet systemd
unitfile and returns valid untifiles.
2018-10-23 02:26:38 +00:00
Liz Rice
277ec9c823 Merge pull request #163 from noqcks/master
Update tests for Kubernetes 1.11 - thank you @noqcks!
2018-10-13 22:09:24 +01:00
Abubakr-Sadik Nii Nai Davis
b1369832bc A few corrections to node tests. (#2)
* Add a few corrections.

* Add a few corrections to node test file.
2018-10-13 15:48:50 -04:00
Abubakr-Sadik Nii Nai Davis
934b4aef96 Add a few corrections. (#1) 2018-10-12 10:22:08 -04:00
noqcks
e85de9e8af fix simple errors 2018-10-09 19:16:08 -04:00
noqcks
ded5aff482 update README 2018-10-09 18:58:30 -04:00
noqcks
b3a115963b adding 1.11 config and node checks 2018-10-09 18:57:37 -04:00
noqcks
e5c05a97f7 updating README with 1.11 updates 2018-10-09 18:56:48 -04:00
noqcks
ba5ec8d4be adding 1.11 master configuration 2018-10-09 18:34:52 -04:00
Liz Rice
d56afd4104 Merge pull request #159 from lukebond/master
Update README.md
2018-09-04 08:37:04 +01:00
Luke Bond
8894b1dc4f Update README.md
Specify `-t` to get colour in the Docker output.
Added a note about mounting kubectl or kubelet to get the version.
2018-09-03 23:05:48 +01:00
Liz Rice
ff59938f94 Merge pull request #155 from bvwells/cis-benchmark-link
Add link to CIS kubernetes benchmark
2018-08-20 09:14:37 +01:00
bvwells
cc43fcbb7e Add link to CIS kubernetes benchmark 2018-08-10 20:55:02 +01:00
Liz Rice
2f4f55a363 Merge pull request #149 from aquasecurity/itai_cis_results
Support actual result in json output.
2018-07-31 18:18:51 +01:00
Itai Ben-Natan
e9076233dd Support actual result in json output.
This commit adds the actual value of the result
of the value which was returned by the test.
2018-07-30 14:19:18 +00:00
Liz Rice
b1e41d345f Merge pull request #147 from aquasecurity/version-fix
Shouldn't need kubelet or kubectl if version specified
2018-07-28 14:53:56 +01:00
Liz Rice
ccc2b6c9ae Shouldn't need kubelet or kubectl if version specified 2018-07-26 12:03:09 +01:00
34 changed files with 6913 additions and 220 deletions

2
.gitignore vendored
View File

@@ -2,3 +2,5 @@ kube-bench
*.swp
vendor
dist
.vscode/
hack/kind.test.yaml

64
Gopkg.lock generated
View File

@@ -2,23 +2,30 @@
[[projects]]
digest = "1:938a2672d6ebbb7f7bc63eee3e4b9464c16ffcf77ec8913d3edbf32b4e3984dd"
name = "github.com/fatih/color"
packages = ["."]
pruneopts = "UT"
revision = "570b54cabe6b8eb0bc2dfce68d964677d63b5260"
version = "v1.5.0"
[[projects]]
digest = "1:38c783cf85b9454cc02a1a8319239800ed0af6c1c864adf19cea0539e134adad"
name = "github.com/fsnotify/fsnotify"
packages = ["."]
pruneopts = "UT"
revision = "4da3e2cfbabc9f751898f250b49f2439785783a1"
[[projects]]
branch = "master"
digest = "1:1ba1d79f2810270045c328ae5d674321db34e3aae468eb4233883b473c5c0467"
name = "github.com/golang/glog"
packages = ["."]
pruneopts = "UT"
revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998"
[[projects]]
digest = "1:145eff5207977eb95c3649a27cdc2e467d8a1c104810bc12b6a53745a91d823a"
name = "github.com/hashicorp/hcl"
packages = [
".",
@@ -29,106 +36,140 @@
"hcl/token",
"json/parser",
"json/scanner",
"json/token"
"json/token",
]
pruneopts = "UT"
revision = "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8"
[[projects]]
digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be"
name = "github.com/inconshreveable/mousetrap"
packages = ["."]
pruneopts = "UT"
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
version = "v1.0"
[[projects]]
digest = "1:510a2b056950ed12b4f3ac704ee1b34fd1920cb5b26f60f98d069de89c60adb7"
name = "github.com/jinzhu/gorm"
packages = [
".",
"dialects/postgres"
"dialects/postgres",
]
pruneopts = "UT"
revision = "5174cc5c242a728b435ea2be8a2f7f998e15429b"
version = "v1.0"
[[projects]]
digest = "1:2cf1e05311b662e68d938f6655c6c5a44ae0e6b3995e390c75fcd8224afa48df"
name = "github.com/jinzhu/inflection"
packages = ["."]
pruneopts = "UT"
revision = "1c35d901db3da928c72a72d8458480cc9ade058f"
[[projects]]
digest = "1:38dd5cee5306173bfe78f8c401edec1e08f772551bee95a85617b4e39347e366"
name = "github.com/lib/pq"
packages = [
".",
"hstore",
"oid"
"oid",
]
pruneopts = "UT"
revision = "83612a56d3dd153a94a629cd64925371c9adad78"
[[projects]]
digest = "1:9cbfcfd1ec741817698b844d17b523f54682a5f7c8683b1ec62b6b6542143240"
name = "github.com/magiconair/properties"
packages = ["."]
pruneopts = "UT"
revision = "49d762b9817ba1c2e9d0c69183c2b4a8b8f1d934"
[[projects]]
digest = "1:31fcf8f5f8f6cc36ef11182c0a0f63ba464e1a7ad9f0e92a7cf46f38bfc0adfd"
name = "github.com/mattn/go-colorable"
packages = ["."]
pruneopts = "UT"
revision = "5411d3eea5978e6cdc258b30de592b60df6aba96"
[[projects]]
digest = "1:fa610f9fe6a93f4a75e64c83673dfff9bf1a34bbb21e6102021b6bc7850834a3"
name = "github.com/mattn/go-isatty"
packages = ["."]
pruneopts = "UT"
revision = "57fdcb988a5c543893cc61bce354a6e24ab70022"
[[projects]]
digest = "1:56a0bd1a1f3809171d1abe0bfd389558be0cd672e858e1f831b88f806aa8764f"
name = "github.com/mitchellh/mapstructure"
packages = ["."]
pruneopts = "UT"
revision = "06020f85339e21b2478f756a78e295255ffa4d6a"
[[projects]]
digest = "1:128af710970a788bb2348dbcdde6b86fa41f92086297f909d659b6d3affc2902"
name = "github.com/pelletier/go-toml"
packages = ["."]
pruneopts = "UT"
revision = "0131db6d737cfbbfb678f8b7d92e55e27ce46224"
[[projects]]
digest = "1:1fccaaeae58b2a2f1af4dbf7eee92ff14f222e161d143bfd20082ef664f91216"
name = "github.com/spf13/afero"
packages = [
".",
"mem"
"mem",
]
pruneopts = "UT"
revision = "57afd63c68602b63ed976de00dd066ccb3c319db"
[[projects]]
digest = "1:9b28ee2984c69d78afe2ce52b1650ba91a6381f355ff08c1d0e53d9e66bd62fe"
name = "github.com/spf13/cast"
packages = ["."]
pruneopts = "UT"
revision = "acbeb36b902d72a7a4c18e8f3241075e7ab763e4"
version = "v1.1.0"
[[projects]]
digest = "1:7ffc0983035bc7e297da3688d9fe19d60a420e9c38bef23f845c53788ed6a05e"
name = "github.com/spf13/cobra"
packages = ["."]
pruneopts = "UT"
revision = "7b2c5ac9fc04fc5efafb60700713d4fa609b777b"
version = "v0.0.1"
[[projects]]
digest = "1:9f28b7e326b8cd1db556678b7ce679cf9bf888647e40922f91d9d40f451f942b"
name = "github.com/spf13/jwalterweatherman"
packages = ["."]
pruneopts = "UT"
revision = "12bd96e66386c1960ab0f74ced1362f66f552f7b"
[[projects]]
digest = "1:772bf4d1907ccb275aaa532ec6cb0d85fc61bd05648af28551590af3ea4e2d53"
name = "github.com/spf13/pflag"
packages = ["."]
pruneopts = "UT"
revision = "4c012f6dcd9546820e378d0bdda4d8fc772cdfea"
[[projects]]
digest = "1:f8e1a678a2571e265f4bf91a3e5e32aa6b1474a55cb0ea849750cc177b664d96"
name = "github.com/spf13/viper"
packages = ["."]
pruneopts = "UT"
revision = "25b30aa063fc18e48662b86996252eabdcf2f0c7"
version = "v1.0.0"
[[projects]]
digest = "1:c9c0ba9ea00233c41b91e441cfd490f34b129bbfebcb1858979623bd8de07f72"
name = "golang.org/x/sys"
packages = ["unix"]
pruneopts = "UT"
revision = "e24f485414aeafb646f6fca458b0bf869c0880a1"
[[projects]]
digest = "1:8029e9743749d4be5bc9f7d42ea1659471767860f0cdc34d37c3111bd308a295"
name = "golang.org/x/text"
packages = [
"internal/gen",
@@ -136,18 +177,29 @@
"internal/ucd",
"transform",
"unicode/cldr",
"unicode/norm"
"unicode/norm",
]
pruneopts = "UT"
revision = "e19ae1496984b1c655b8044a65c0300a3c878dd3"
[[projects]]
digest = "1:cb130999076da4717267c51235d62b63228c330ad86160255cbe3276de4c9892"
name = "gopkg.in/yaml.v2"
packages = ["."]
pruneopts = "UT"
revision = "c95af922eae69f190717a0b7148960af8c55a072"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "8d9a1b665b338530deef434f168913ba1184f835aa5bfed3a213a14c613bc17e"
input-imports = [
"github.com/fatih/color",
"github.com/golang/glog",
"github.com/jinzhu/gorm",
"github.com/jinzhu/gorm/dialects/postgres",
"github.com/spf13/cobra",
"github.com/spf13/viper",
"gopkg.in/yaml.v2",
]
solver-name = "gps-cdcl"
solver-version = 1

5
NOTICE Normal file
View File

@@ -0,0 +1,5 @@
kube-bench
Copyright 2017-2019 Aqua Security Software Ltd.
This product includes software developed by Aqua Security (https://aquasec.com).

123
README.md
View File

@@ -5,59 +5,94 @@
<img src="images/kube-bench.png" width="200" alt="kube-bench logo">
kube-bench is a Go application that checks whether Kubernetes is deployed securely by running the checks documented in the CIS Kubernetes Benchmark.
kube-bench is a Go application that checks whether Kubernetes is deployed securely by running the checks documented in the [CIS Kubernetes Benchmark](https://www.cisecurity.org/benchmark/kubernetes/).
Tests are configured with YAML files, making this tool easy to update as test specifications evolve.
Tests are configured with YAML files, making this tool easy to update as test specifications evolve.
![Kubernetes Bench for Security](https://raw.githubusercontent.com/aquasecurity/kube-bench/master/images/output.png "Kubernetes Bench for Security")
## CIS Kubernetes Benchmark support
kube-bench supports the tests for multiple versions of Kubernetes (1.6, 1.7 and 1.8) as defined in the CIS Benchmarks 1.0.0, 1.1.0 and 1.2.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
You can choose to
You can choose to
* run kube-bench from inside a container (sharing PID namespace with the host)
* run a container that installs kube-bench on the host, and then run kube-bench directly on the host
* install the latest binaries from the [Releases page](https://github.com/aquasecurity/kube-bench/releases),
* install the latest binaries from the [Releases page](https://github.com/aquasecurity/kube-bench/releases),
* compile it from source.
### Running inside a container
You can avoid installing kube-bench on the host by running it inside a container using the host PID namespace.
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 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]
```
You can even use your own configs by mounting them over the default ones in `/opt/kube-bench/cfg/`
```
docker run --pid=host -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 -t -v path/to/my-config.yaml:/opt/kube-bench/cfg/config.yaml aquasec/kube-bench:latest [master|node]
```
> Note: the tests require either the kubelet or kubectl binary in the path in order to know the Kubernetes version. You can pass `-v $(which kubectl):/usr/bin/kubectl` to the above invocations to resolve this.
### Running in a kubernetes cluster
Run the master check
```
kubectl run --rm -i -t kube-bench-master --image=aquasec/kube-bench:latest --restart=Never --overrides="{ \"apiVersion\": \"v1\", \"spec\": { \"hostPID\": true, \"nodeSelector\": { \"kubernetes.io/role\": \"master\" }, \"tolerations\": [ { \"key\": \"node-role.kubernetes.io/master\", \"operator\": \"Exists\", \"effect\": \"NoSchedule\" } ] } }" -- master --version 1.8
You can run kube-bench inside a pod, but it will need access to the host's PID namespace in order to check the running processes, as well as access to some directories on the host where config files and other files are stored.
Master nodes are automatically detected by kube-bench and will run master checks when possible.
The detection is done by verifying that mandatory components for master are running. (see [config file](#configuration).
The supplied `job.yaml` file can be applied to run the tests as a job. For example:
```bash
$ kubectl apply -f job.yaml
job.batch/kube-bench created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
kube-bench-j76s9 0/1 ContainerCreating 0 3s
# Wait for a few seconds for the job to complete
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
kube-bench-j76s9 0/1 Completed 0 11s
# The results are held in the pod's logs
k logs kube-bench-j76s9
[INFO] 1 Master Node Security Configuration
[INFO] 1.1 API Server
...
```
Run the node check
You can still force to run specific master or node checks using respectively `job-master.yaml` and `job-node.yaml`.
```
kubectl run --rm -i -t kube-bench-node --image=aquasec/kube-bench:latest --restart=Never --overrides="{ \"apiVersion\": \"v1\", \"spec\": { \"hostPID\": true } }" -- node --version 1.8
```
To run the tests on the master node, the pod needs to be scheduled on that node. This involves setting a nodeSelector and tolerations in the pod spec.
The default labels applied to master nodes has changed since Kubernetes 1.11, so if you are using an older version you may need to modify the nodeSelector and tolerations to run the job on the master node.
### Installing from a container
This command copies the kube-bench binary and configuration files to your host from the Docker container:
** binaries compiled for linux-x86-64 only (so they won't run on OSX or Windows) **
```
docker run --rm -v `pwd`:/host aquasec/kube-bench:latest install
```
You can then run `./kube-bench <master|node>`.
You can then run `./kube-bench [master|node]`.
### Installing from sources
@@ -73,21 +108,29 @@ go build -o kube-bench .
# See all supported options
./kube-bench --help
# Run the all checks on a master node
./kube-bench master
# Run the all checks
./kube-bench
```
## Configuration
Kubernetes config and binary file locations and names can vary from installation to installation, so these are configurable in the `cfg/config.yaml` file.
For each type of node (*master*, *node* or *federated*) there is a list of components, and for each component there is a set of binaries (*bins*) and config files (*confs*) that kube-bench will look for (in the order they are listed). If your installation uses a different binary name or config file location for a Kubernetes component, you can add it to `cfg/config.yaml`.
Kubernetes config and binary file locations and names can vary from installation to installation, so these are configurable in the `cfg/config.yaml` file.
* **bins** - If there is a *bins* list for a component, at least one of these binaries must be running. The tests will consider the parameters for the first binary in the list found to be running.
* **podspecs** - From version 1.2.0 of the benchmark (tests for Kubernetes 1.8), the remediation instructions were updated to assume that the configuration for several kubernetes components is defined in a pod YAML file, and podspec settings define where to look for that configuration.
* **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.
For each type of node (*master*, *node* or *federated*) there is a list of components, and for each component there is a set of binaries (*bins*) and config files (*confs*) that kube-bench will look for (in the order they are listed). If your installation uses a different binary name or config file location for a Kubernetes component, you can add it to `cfg/config.yaml`.
* **bins** - If there is a *bins* list for a component, at least one of these binaries must be running. The tests will consider the parameters for the first binary in the list found to be running.
* **podspecs** - From version 1.2.0 of the benchmark (tests for Kubernetes 1.8), the remediation instructions were updated to assume that the configuration for several kubernetes components is defined in a pod YAML file, and podspec settings define where to look for that configuration.
* **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.
## 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
The tests are represented as YAML documents (installed by default into ./cfg).
@@ -120,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.
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 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.
@@ -145,7 +202,21 @@ These operations are:
- `has`: tests if the flag value contains the compared value.
- `nothave`: tests if the flag value does not contain the compared value.
# Roadmap
Going forward we plan to release updates to kube-bench to add support for new releases of the Benchmark, which in turn we can anticipate being made for each new Kubernetes release.
# Roadmap
Going forward we plan to release updates to kube-bench to add support for new releases of the Benchmark, which in turn we can anticipate being made for each new Kubernetes release.
We welcome PRs and issue reports.
We welcome PRs and issue reports.
# Testing locally with kind
Our makefile contains targets to test your current version of kube-bench inside a [Kind](https://kind.sigs.k8s.io/) cluster. This can be very handy if you don't want to run a real kubernetes cluster for development purpose.
First you'll need to create the cluster using `make kind-test-cluster` this will create a new cluster if it cannot be found on your machine. By default the cluster is named `kube-bench` but you can change the name by using the environment variable `KIND_PROFILE`.
*If kind cannot be found on your system the target will try to install it using `go get`*
Next you'll have to build the kube-bench docker image using `make build-docker`, then we will be able to push the docker image to the cluster using `make kind-push`.
Finally we can use the `make kind-run` target to run the current version of kube-bench in the cluster and follow the logs of pods created. (Ctrl+C to exit)
Everytime you want to test a change, you'll need to rebuild the docker image and push it to cluster before running it again. ( `make build-docker kind-push kind-run` )

29
cfg/1.11/config.yaml Normal file
View File

@@ -0,0 +1,29 @@
---
## Controls Files.
# These are YAML files that hold all the details for running checks.
#
## Uncomment to use different control file paths.
# masterControls: ./cfg/master.yaml
# nodeControls: ./cfg/node.yaml
# federatedControls: ./cfg/federated.yaml
master:
apiserver:
defaultconf: /etc/kubernetes/manifests/kube-apiserver.yaml
scheduler:
defaultconf: /etc/kubernetes/manifests/kube-scheduler.yaml
controllermanager:
defaultconf: /etc/kubernetes/manifests/kube-controller-manager.yaml
etcd:
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

1446
cfg/1.11/master.yaml Normal file

File diff suppressed because it is too large Load Diff

499
cfg/1.11/node.yaml Normal file
View File

@@ -0,0 +1,499 @@
---
controls:
version: 1.11
id: 2
text: "Worker Node Security Configuration"
type: "node"
groups:
- id: 2.1
text: "Kubelet"
checks:
- id: 2.1.1
text: "Ensure that the --allow-privileged argument is set to false (Scored)"
audit: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--allow-privileged"
compare:
op: eq
value: false
set: true
remediation: |
Edit the kubelet service file $kubeletsvc
on each worker node and set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
--allow-privileged=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 --anonymous-auth argument is set to false (Scored)"
audit: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--anonymous-auth"
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.3
text: "Ensure that the --authorization-mode argument is not set to AlwaysAllow (Scored)"
audit: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--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.4
text: "Ensure that the --client-ca-file argument is set as appropriate (Scored)"
audit: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--client-ca-file"
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.5
text: "Ensure that the --read-only-port argument is set to 0 (Scored)"
audit: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--read-only-port"
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.6
text: "Ensure that the --streaming-connection-idle-timeout argument is not set to 0 (Scored)"
audit: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--streaming-connection-idle-timeout"
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.7
text: "Ensure that the --protect-kernel-defaults argument is set to true (Scored)"
audit: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--protect-kernel-defaults"
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.8
text: "Ensure that the --make-iptables-util-chains argument is set to true (Scored)"
audit: "ps -fC $kubeletbin"
tests:
bin_op: or
test_items:
- flag: "--make-iptables-util-chains"
compare:
op: eq
value: true
set: true
- flag: "--make-iptables-util-chains"
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.9
text: "Ensure that the --hostname-override argument is not set (Scored)"
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.10
text: "Ensure that the --event-qps argument is set to 0 (Scored)"
audit: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--event-qps"
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.11
text: "Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate (Scored)"
audit: "ps -fC $kubeletbin"
tests:
bin_op: and
test_items:
- flag: "--tls-cert-file"
set: true
- flag: "--tls-private-key-file"
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.12
text: "Ensure that the --cadvisor-port argument is set to 0 (Scored)"
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.13
text: "Ensure that the --rotate-certificates argument is not set to false (Scored)"
audit: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--rotate-certificates"
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.14
text: "Ensure that the RotateKubeletServerCertificate argument is set to true (Scored)"
audit: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "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.15
text: "Ensure that the Kubelet only makes use of Strong Cryptographic Ciphers (Not Scored)"
audit: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--tls-cipher-suites"
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 $ca-file; then stat -c %U:%G $ca-file; fi'"
type: manual
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

29
cfg/1.13/config.yaml Normal file
View File

@@ -0,0 +1,29 @@
---
## Controls Files.
# These are YAML files that hold all the details for running checks.
#
## Uncomment to use different control file paths.
# masterControls: ./cfg/master.yaml
# nodeControls: ./cfg/node.yaml
# federatedControls: ./cfg/federated.yaml
master:
apiserver:
defaultconf: /etc/kubernetes/manifests/kube-apiserver.yaml
scheduler:
defaultconf: /etc/kubernetes/manifests/kube-scheduler.yaml
controllermanager:
defaultconf: /etc/kubernetes/manifests/kube-controller-manager.yaml
etcd:
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

1503
cfg/1.13/master.yaml Normal file

File diff suppressed because it is too large Load Diff

480
cfg/1.13/node.yaml Normal file
View File

@@ -0,0 +1,480 @@
---
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: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--anonymous-auth"
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
$kubeletconf 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: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--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: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--client-ca-file"
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: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--read-only-port"
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: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--streaming-connection-idle-timeout"
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: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--protect-kernel-defaults"
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: "ps -fC $kubeletbin"
tests:
bin_op: or
test_items:
- flag: "--make-iptables-util-chains"
compare:
op: eq
value: true
set: true
- flag: "--make-iptables-util-chains"
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)"
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: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--event-qps"
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: "ps -fC $kubeletbin"
tests:
bin_op: and
test_items:
- flag: "--tls-cert-file"
set: true
- flag: "--tls-private-key-file"
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)"
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: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--rotate-certificates"
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: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "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: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--tls-cipher-suites"
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 $ca-file; then stat -c %U:%G $ca-file; fi'"
type: manual
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

View File

@@ -34,11 +34,9 @@ master:
node:
kubelet:
confs:
- /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
defaultconf: /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
defaultconf: /var/lib/kubelet/config.yaml
defaultsvc: /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
defaultkubeconfig: /etc/kubernetes/kubelet.conf
proxy:
confs:
- /etc/kubernetes/addons/kube-proxy-daemonset.yaml
defaultconf: /etc/kubernetes/addons/kube-proxy-daemonset.yaml

View File

@@ -10,7 +10,7 @@ groups:
checks:
- id: 2.1.1
text: "Ensure that the --allow-privileged argument is set to false (Scored)"
audit: "ps -ef | grep $kubeletbin | grep -v grep"
audit: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--allow-privileged"
@@ -19,7 +19,7 @@ groups:
value: false
set: true
remediation: |
Edit the kubelet service file $kubeletconf
Edit the kubelet service file $kubeletsvc
on each worker node and set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
--allow-privileged=false
Based on your system, restart the kubelet service. For example:
@@ -29,7 +29,7 @@ groups:
- id: 2.1.2
text: "Ensure that the --anonymous-auth argument is set to false (Scored)"
audit: "ps -ef | grep $kubeletbin | grep -v grep"
audit: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--anonymous-auth"
@@ -38,7 +38,7 @@ groups:
value: false
set: true
remediation: |
Edit the kubelet service file $kubeletconf
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:
@@ -48,7 +48,7 @@ groups:
- id: 2.1.3
text: "Ensure that the --authorization-mode argument is not set to AlwaysAllow (Scored)"
audit: "ps -ef | grep $kubeletbin | grep -v grep"
audit: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--authorization-mode"
@@ -57,7 +57,7 @@ groups:
value: "AlwaysAllow"
set: true
remediation: |
Edit the kubelet service file $kubeletconf
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:
@@ -67,13 +67,13 @@ groups:
- id: 2.1.4
text: "Ensure that the --client-ca-file argument is set as appropriate (Scored)"
audit: "ps -ef | grep $kubeletbin | grep -v grep"
audit: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--client-ca-file"
set: true
remediation: |
Edit the kubelet service file $kubeletconf
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:
@@ -83,7 +83,7 @@ groups:
- id: 2.1.5
text: "Ensure that the --read-only-port argument is set to 0 (Scored)"
audit: "ps -ef | grep $kubeletbin | grep -v grep"
audit: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--read-only-port"
@@ -92,7 +92,7 @@ groups:
value: 0
set: true
remediation: |
Edit the kubelet service file $kubeletconf
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:
@@ -102,7 +102,7 @@ groups:
- id: 2.1.6
text: "Ensure that the --streaming-connection-idle-timeout argument is not set to 0 (Scored)"
audit: "ps -ef | grep $kubeletbin | grep -v grep"
audit: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--streaming-connection-idle-timeout"
@@ -111,7 +111,7 @@ groups:
value: 0
set: true
remediation: |
Edit the kubelet service file $kubeletconf
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:
@@ -121,7 +121,7 @@ groups:
- id: 2.1.7
text: "Ensure that the --protect-kernel-defaults argument is set to true (Scored)"
audit: "ps -ef | grep $kubeletbin | grep -v grep"
audit: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--protect-kernel-defaults"
@@ -130,7 +130,7 @@ groups:
value: true
set: true
remediation: |
Edit the kubelet service file $kubeletconf
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:
@@ -140,7 +140,7 @@ groups:
- id: 2.1.8
text: "Ensure that the --make-iptables-util-chains argument is set to true (Scored)"
audit: "ps -ef | grep $kubeletbin | grep -v grep"
audit: "ps -fC $kubeletbin"
tests:
bin_op: or
test_items:
@@ -150,7 +150,7 @@ groups:
value: true
set: true
remediation: |
Edit the kubelet service file $kubeletconf
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:
@@ -160,7 +160,7 @@ groups:
- id: 2.1.9
text: "Ensure that the --keep-terminated-pod-volumes argument is set to false (Scored)"
audit: "ps -ef | grep $kubeletbin | grep -v grep"
audit: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--keep-terminated-pod-volumes"
@@ -169,7 +169,7 @@ groups:
value: false
set: true
remediation: |
Edit the kubelet service file $kubeletconf
Edit the kubelet service file $kubeletsvc
on each worker node and set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
--keep-terminated-pod-volumes=false
Based on your system, restart the kubelet service. For example:
@@ -179,13 +179,13 @@ groups:
- id: 2.1.10
text: "Ensure that the --hostname-override argument is not set (Scored)"
audit: "ps -ef | grep $kubeletbin | grep -v grep"
audit: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--hostname-override"
set: false
remediation: |
Edit the kubelet service file $kubeletconf
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:
@@ -195,7 +195,7 @@ groups:
- id: 2.1.11
text: "Ensure that the --event-qps argument is set to 0 (Scored)"
audit: "ps -ef | grep $kubeletbin | grep -v grep"
audit: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--event-qps"
@@ -204,7 +204,7 @@ groups:
value: 0
set: true
remediation: |
Edit the kubelet service file $kubeletconf
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:
@@ -214,7 +214,7 @@ groups:
- id: 2.1.12
text: "Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate (Scored)"
audit: "ps -ef | grep $kubeletbin | grep -v grep"
audit: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--tls-cert-file"
@@ -223,8 +223,7 @@ groups:
set: true
remediation: |
Follow the Kubernetes documentation and set up the TLS connection on the Kubelet.
Then edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-
kubeadm.conf on each worker node and set the below parameters in
Then 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>
@@ -236,7 +235,7 @@ groups:
- id: 2.1.13
text: "Ensure that the --cadvisor-port argument is set to 0 (Scored)"
audit: "ps -ef | grep $kubeletbin | grep -v grep"
audit: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "--cadvisor-port"
@@ -245,7 +244,7 @@ groups:
value: 0
set: true
remediation: |
Edit the kubelet service file $kubeletconf
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:
@@ -255,7 +254,7 @@ groups:
- id: 2.1.14
text: "Ensure that the RotateKubeletClientCertificate argument is set to true"
audit: "ps -ef | grep $kubeletbin | grep -v grep"
audit: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "RotateKubeletClientCertificate"
@@ -264,7 +263,7 @@ groups:
value: true
set: true
remediation: |
Edit the kubelet service file $kubeletconf
Edit the kubelet service file $kubeletsvc
on each worker node and remove the --feature-
gates=RotateKubeletClientCertificate=false argument from the
KUBELET_CERTIFICATE_ARGS variable.
@@ -275,7 +274,7 @@ groups:
- id: 2.1.15
text: "Ensure that the RotateKubeletServerCertificate argument is set to true"
audit: "ps -ef | grep $kubeletbin | grep -v grep"
audit: "ps -fC $kubeletbin"
tests:
test_items:
- flag: "RotateKubeletServerCertificate"
@@ -284,7 +283,7 @@ groups:
value: true
set: true
remediation: |
Edit the kubelet service file $kubeletconf
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:
@@ -298,7 +297,7 @@ groups:
- 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 $kubeletconf; then stat -c %a $kubeletconf; fi'"
audit: "/bin/sh -c 'if test -e $kubeletkubeconfig; then stat -c %a $kubeletkubeconfig; fi'"
tests:
bin_op: or
test_items:
@@ -320,12 +319,12 @@ groups:
remediation: |
Run the below command (based on the file location on your system) on the each worker
node. For example,
chmod 644 $kubeletconf
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 $kubeletconf; then stat -c %U:%G $kubeletconf; fi'"
audit: "/bin/sh -c 'if test -e $kubeletkubeconfig; then stat -c %U:%G $kubeletkubeconfig; fi'"
tests:
test_items:
- flag: "root:root"
@@ -336,13 +335,13 @@ groups:
remediation: |
Run the below command (based on the file location on your system) on the each worker
node. For example,
chown root:root /etc/kubernetes/kubelet.conf
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 $kubeletconf; then stat -c %a $kubeletconf; fi'"
audit: "/bin/sh -c 'if test -e $kubeletsvc; then stat -c %a $kubeletsvc; fi'"
tests:
bin_op: or
test_items:
@@ -364,12 +363,12 @@ groups:
remediation: |
Run the below command (based on the file location on your system) on the each worker
node. For example,
chmod 755 $kubeletconf
chmod 755 $kubeletsvc
scored: true
- id: 2.2.4
text: "2.2.4 Ensure that the kubelet service file ownership is set to root:root (Scored)"
audit: "/bin/sh -c 'if test -e $kubeletconf; then stat -c %U:%G $kubeletconf; fi'"
audit: "/bin/sh -c 'if test -e $kubeletsvc; then stat -c %U:%G $kubeletsvc; fi'"
tests:
test_items:
- flag: "root:root"
@@ -377,13 +376,13 @@ groups:
remediation: |
Run the below command (based on the file location on your system) on the each worker
node. For example,
chown root:root $kubeletconf
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 $proxyconf; then stat -c %a $proxyconf; fi'"
audit: "/bin/sh -c 'if test -e $proxykubeconfig; then stat -c %a $proxykubeconfig; fi'"
tests:
bin_op: or
test_items:
@@ -405,12 +404,12 @@ groups:
remediation: |
Run the below command (based on the file location on your system) on the each worker
node. For example,
chmod 644 $proxyconf
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 $proxyconf; then stat -c %U:%G $proxyconf; fi'"
audit: "/bin/sh -c 'if test -e $proxykubeconfig; then stat -c %U:%G $proxykubeconfig; fi'"
tests:
test_items:
- flag: "root:root"
@@ -418,7 +417,7 @@ groups:
remediation: |
Run the below command (based on the file location on your system) on the each worker
node. For example,
chown root:root $proxyconf
chown root:root $proxykubeconfig
scored: true
- id: 2.2.7

View File

@@ -24,6 +24,7 @@ master:
bins:
- "kube-apiserver"
- "hyperkube apiserver"
- "hyperkube kube-apiserver"
- "apiserver"
confs:
- /etc/kubernetes/apiserver.conf
@@ -34,6 +35,7 @@ master:
bins:
- "kube-scheduler"
- "hyperkube scheduler"
- "hyperkube kube-scheduler"
- "scheduler"
confs:
- /etc/kubernetes/scheduler.conf
@@ -44,6 +46,7 @@ master:
bins:
- "kube-controller-manager"
- "hyperkube controller-manager"
- "hyperkube kube-controller-manager"
- "controller-manager"
confs:
- /etc/kubernetes/controller-manager.conf
@@ -78,10 +81,9 @@ node:
bins:
- "hyperkube kubelet"
- "kubelet"
confs:
- /etc/kubernetes/kubelet.conf
- /etc/kubernetes/kubelet
defaultconf: "/etc/kubernetes/kubelet.conf"
defaultconf: "/var/lib/kubelet/config.yaml"
defaultsvc: "/etc/systemd/system/kubelet.service.d/10-kubeadm.conf"
defaultkubeconfig: "/etc/kubernetes/kubelet.conf"
proxy:
bins:
@@ -89,9 +91,9 @@ node:
- "hyperkube proxy"
- "proxy"
confs:
- /etc/kubernetes/proxy.conf
- /etc/kubernetes/proxy
- /etc/kubernetes/addons/kube-proxy-daemonset.yaml
defaultkubeconfig: "/etc/kubernetes/proxy.conf"
federated:
components:

22
cfg/ocp-3.10/config.yaml Normal file
View File

@@ -0,0 +1,22 @@
---
## Controls Files.
# These are YAML files that hold all the details for running checks.
#
## Uncomment to use different control file paths.
# masterControls: ./cfg/master.yaml
# nodeControls: ./cfg/node.yaml
# federatedControls: ./cfg/federated.yaml
master:
apiserver:
bins:
- hypershift openshift-kube-apiserver
etcd:
bins:
- openshift start etcd
node:
proxy:
bins:
- openshift start network

113
cfg/ocp-3.10/federated.yaml Normal file
View File

@@ -0,0 +1,113 @@
---
controls:
id: 3
text: "Federated Deployments"
type: "federated"
groups:
- id: 3.1
text: "Federated API Server"
checks:
- id: 3.1.1
text: "Ensure that the --anonymous-auth argument is set to false (Scored)"
type: "skip"
scored: true
- id: 3.1.2
text: "Ensure that the --basic-auth-file argument is not set (Scored)"
type: "skip"
scored: true
- id: 3.1.3
text: "Ensure that the --insecure-allow-any-token argument is not set (Scored)"
type: "skip"
scored: true
- id: 3.1.4
text: "Ensure that the --insecure-bind-address argument is not set (Scored)"
type: "skip"
scored: true
- id: 3.1.5
text: "Ensure that the --insecure-port argument is set to 0 (Scored)"
type: "skip"
scored: true
- id: 3.1.6
text: "Ensure that the --secure-port argument is not set to 0 (Scored)"
type: "skip"
scored: true
- id: 3.1.7
text: "Ensure that the --profiling argument is set to false (Scored)"
type: "skip"
scored: true
- id: 3.1.8
text: "Ensure that the admission control policy is not set to AlwaysAdmit (Scored)"
type: "skip"
scored: true
- id: 3.1.9
text: "Ensure that the admission control policy is set to NamespaceLifecycle (Scored)"
type: "skip"
scored: true
- id: 3.1.10
text: "Ensure that the --audit-log-path argument is set as appropriate (Scored)"
type: "skip"
scored: true
- id: 3.1.11
text: "Ensure that the --audit-log-maxage argument is set to 30 or as appropriate (Scored)"
type: "skip"
scored: true
- id: 3.1.12
text: "Ensure that the --audit-log-maxbackup argument is set to 10 or as appropriate (Scored)"
type: "skip"
scored: true
- id: 3.1.13
text: "Ensure that the --audit-log-maxsize argument is set to 100 or as appropriate (Scored)"
type: "skip"
scored: true
- id: 3.1.14
text: "Ensure that the --authorization-mode argument is not set to AlwaysAllow (Scored)"
type: "skip"
scored: true
- id: 3.1.15
text: "Ensure that the --token-auth-file parameter is not set (Scored)"
type: "skip"
scored: true
- id: 3.1.16
text: "Ensure that the --service-account-lookup argument is set to true (Scored)"
type: "skip"
scored: true
- id: 3.1.17
text: "Ensure that the --service-account-key-file argument is set as appropriate (Scored)"
type: "skip"
scored: true
- id: 3.1.18
text: "Ensure that the --etcd-certfile and --etcd-keyfile arguments are set as appropriate (Scored)"
type: "skip"
scored: true
- id: 3.1.19
text: "Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate (Scored)"
type: "skip"
scored: true
- id: 3.2
text: "Federation Controller Manager"
checks:
- id: 3.2.1
text: "Ensure that the --profiling argument is set to false (Scored)"
type: "skip"
scored: true

1500
cfg/ocp-3.10/master.yaml Normal file

File diff suppressed because it is too large Load Diff

376
cfg/ocp-3.10/node.yaml Normal file
View File

@@ -0,0 +1,376 @@
---
controls:
id: 2
text: "Worker Node Security Configuration"
type: "node"
groups:
- id: 2.1
text: "Kubelet"
checks:
- id: 2.1.1
text: "Ensure that the --allow-privileged argument is set to false (Scored)"
type: "skip"
scored: true
- id: 2.1.2
text: "Ensure that the --anonymous-auth argument is set to false (Scored)"
type: "skip"
scored: true
- id: 2.1.3
text: "Ensure that the --authorization-mode argument is not set to AlwaysAllow (Scored)"
audit: "grep -A1 authorization-mode /etc/origin/node/node-config.yaml"
tests:
bin_op: or
test_items:
- flag: "authorization-mode"
set: false
- flag: "authorization-mode: Webhook"
compare:
op: has
value: "Webhook"
set: true
remediation: |
Edit the Openshift node config file /etc/origin/node/node-config.yaml and remove authorization-mode under
kubeletArguments in /etc/origin/node/node-config.yaml or set it to "Webhook".
scored: true
- id: 2.1.4
text: "Ensure that the --client-ca-file argument is set as appropriate (Scored)"
audit: "grep -A1 client-ca-file /etc/origin/node/node-config.yaml"
tests:
test_items:
- flag: "client-ca-file"
set: false
remediation: |
Edit the Openshift node config file /etc/origin/node/node-config.yaml and remove any configuration returned by the following:
grep -A1 client-ca-file /etc/origin/node/node-config.yaml
Reset to the OpenShift default.
See https://github.com/openshift/openshift-ansible/blob/release-3.10/roles/openshift_node_group/templates/node-config.yaml.j2#L65
The config file does not have this defined in kubeletArgument, but in PodManifestConfig.
scored: true
- id: 2.1.5
text: "Ensure that the --read-only-port argument is set to 0 (Scored)"
audit: "grep -A1 read-only-port /etc/origin/node/node-config.yaml"
tests:
bin_op: or
test_items:
- flag: "read-only-port"
set: false
- flag: "read-only-port: 0"
compare:
op: has
value: "0"
set: true
remediation: |
Edit the Openshift node config file /etc/origin/node/node-config.yaml and removed so that the OpenShift default is applied.
scored: true
- id: 2.1.6
text: "Ensure that the --streaming-connection-idle-timeout argument is not set to 0 (Scored)"
audit: "grep -A1 streaming-connection-idle-timeout /etc/origin/node/node-config.yaml"
tests:
bin_op: or
test_items:
- flag: "streaming-connection-idle-timeout"
set: false
- flag: "0"
set: false
remediation: |
Edit the Openshift node config file /etc/origin/node/node-config.yaml and set the streaming-connection-timeout
value like the following in node-config.yaml.
kubeletArguments:
 streaming-connection-idle-timeout:
   - "5m"
scored: true
- id: 2.1.7
text: "Ensure that the --protect-kernel-defaults argument is set to true (Scored)"
type: "skip"
scored: true
- id: 2.1.8
text: "Ensure that the --make-iptables-util-chains argument is set to true (Scored)"
audit: "grep -A1 make-iptables-util-chains /etc/origin/node/node-config.yaml"
tests:
bin_op: or
test_items:
- flag: "make-iptables-util-chains"
set: false
- flag: "make-iptables-util-chains: true"
compare:
op: has
value: "true"
set: true
remediation: |
Edit the Openshift node config file /etc/origin/node/node-config.yaml and reset make-iptables-util-chains to the OpenShift
default value of true.
scored: true
id: 2.1.9
text: "Ensure that the --keep-terminated-pod-volumeskeep-terminated-pod-volumes argument is set to false (Scored)"
audit: "grep -A1 keep-terminated-pod-volumes /etc/origin/node/node-config.yaml"
tests:
test_items:
- flag: "keep-terminated-pod-volumes: false"
compare:
op: has
value: "false"
set: true
remediation: |
Reset to the OpenShift defaults
scored: true
- id: 2.1.10
text: "Ensure that the --hostname-override argument is not set (Scored)"
type: "skip"
scored: true
- id: 2.1.11
text: "Ensure that the --event-qps argument is set to 0 (Scored)"
audit: "grep -A1 event-qps /etc/origin/node/node-config.yaml"
tests:
bin_op: or
test_items:
- flag: "event-qps"
set: false
- flag: "event-qps: 0"
compare:
op: has
value: "0"
set: true
remediation: |
Edit the Openshift node config file /etc/origin/node/node-config.yaml set the event-qps argument to 0 in
the kubeletArguments section of.
scored: true
- id: 2.1.12
text: "Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate (Scored)"
audit: "grep -A1 cert-dir /etc/origin/node/node-config.yaml"
tests:
test_items:
- flag: "/etc/origin/node/certificates"
compare:
op: has
value: "/etc/origin/node/certificates"
set: true
remediation: |
Reset to the OpenShift default values.
scored: true
- id: 2.1.13
text: "Ensure that the --cadvisor-port argument is set to 0 (Scored)"
audit: "grep -A1 cadvisor-port /etc/origin/node/node-config.yaml"
tests:
bin_op: or
test_items:
- flag: "cadvisor-port"
set: false
- flag: "cadvisor-port: 0"
compare:
op: has
value: "0"
set: true
remediation: |
Edit the Openshift node config file /etc/origin/node/node-config.yaml and remove the cadvisor-port flag
if it is set in the kubeletArguments section.
scored: true
- id: 2.1.14
text: "Ensure that the RotateKubeletClientCertificate argument is not set to false (Scored)"
audit: "grep -B1 RotateKubeletClientCertificate=true /etc/origin/node/node-config.yaml"
tests:
test_items:
- flag: "RotateKubeletClientCertificate=true"
compare:
op: has
value: "true"
set: true
remediation: |
Edit the Openshift node config file /etc/origin/node/node-config.yaml and set RotateKubeletClientCertificate to true.
scored: true
- id: 2.1.15
text: "Ensure that the RotateKubeletServerCertificate argument is set to true (Scored)"
audit: "grep -B1 RotateKubeletServerCertificate=true /etc/origin/node/node-config.yaml"
test:
test_items:
- flag: "RotateKubeletServerCertificate=true"
compare:
op: has
value: "true"
set: true
remediation: |
Edit the Openshift node config file /etc/origin/node/node-config.yaml and set RotateKubeletServerCertificate to true.
scored: true
- 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: "stat -c %a /etc/origin/node/node.kubeconfig"
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 on each worker node.
chmod 644 /etc/origin/node/node.kubeconfig
scored: true
- id: 2.2.2
text: "Ensure that the kubelet.conf file ownership is set to root:root (Scored)"
audit: "stat -c %U:%G /etc/origin/node/node.kubeconfig"
tests:
test_items:
- flag: "root:root"
compare:
op: eq
value: root:root
set: true
remediation: |
Run the below command on each worker node.
chown root:root /etc/origin/node/node.kubeconfig
scored: true
- id: 2.2.3
text: "Ensure that the kubelet service file permissions are set to 644 or more restrictive (Scored)"
audit: "stat -c %a /etc/systemd/system/atomic-openshift-node.service"
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 on each worker node.
chmod 644 /etc/systemd/system/atomic-openshift-node.service
scored: true
- id: 2.2.4
text: "Ensure that the kubelet service file ownership is set to root:root (Scored)"
audit: "stat -c %U:%G /etc/systemd/system/atomic-openshift-node.service"
tests:
test_items:
- flag: "root:root"
compare:
op: eq
value: root:root
set: true
remediation: |
Run the below command on each worker node.
chown root:root /etc/systemd/system/atomic-openshift-node.service
scored: true
- id: 2.2.5
text: "Ensure that the proxy kubeconfig file permissions are set to 644 or more restrictive (Scored)"
audit: "stat -c %a /etc/origin/node/node.kubeconfig"
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 on each worker node.
chmod 644 /etc/origin/node/node.kubeconfig
scored: true
- id: 2.2.6
text: "Ensure that the proxy kubeconfig file ownership is set to root:root (Scored)"
audit: "stat -c %U:%G /etc/origin/node/node.kubeconfig"
tests:
test_items:
- flag: "root:root"
compare:
op: eq
value: root:root
set: true
remediation: |
Run the below command on each worker node.
chown root:root /etc/origin/node/node.kubeconfig
scored: true
- id: 2.2.7
text: "Ensure that the certificate authorities file permissions are set to 644 or more restrictive (Scored)"
audit: "stat -c %a /etc/origin/node/client-ca.crt"
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 on each worker node.
chmod 644 /etc/origin/node/client-ca.crt
scored: true
- id: 2.2.8
text: "Ensure that the client certificate authorities file ownership is set to root:root (Scored)"
audit: "stat -c %U:%G /etc/origin/node/client-ca.crt"
tests:
test_items:
- flag: "root:root"
compare:
op: eq
value: root:root
set: true
remediation: |
Run the below command on each worker node.
chown root:root /etc/origin/node/client-ca.crt
scored: true

View File

@@ -60,23 +60,32 @@ func handleError(err error, context string) (errmsg string) {
// Check contains information about a recommendation in the
// CIS Kubernetes 1.6+ document.
type Check struct {
ID string `yaml:"id" json:"test_number"`
Text string `json:"test_desc"`
ID string `yaml:"id" json:"test_number"`
Text string `json:"test_desc"`
Audit string `json:"omit"`
Type string `json:"type"`
Commands []*exec.Cmd `json:"omit"`
Tests *tests `json:"omit"`
Set bool `json:"omit"`
Remediation string `json:"-"`
TestInfo []string `json:"test_info"`
State `json:"status"`
Remediation string `json:"-"`
TestInfo []string `json:"test_info"`
State `json:"status"`
ActualValue string `json:"actual_value"`
Scored bool `json:"scored"`
}
// Run executes the audit commands specified in a check and outputs
// the results.
func (c *Check) Run() {
// If check type is manual, force result to WARN.
if c.Type == "manual" {
// If check type is skip, force result to INFO
if c.Type == "skip" {
c.State = INFO
return
}
// If check type is manual or the check is not scored, force result to WARN
if c.Type == "manual" || !c.Scored {
c.State = WARN
return
}
@@ -157,15 +166,27 @@ func (c *Check) Run() {
i++
}
if errmsgs != "" {
glog.V(2).Info(errmsgs)
glog.V(3).Info(out.String())
finalOutput := c.Tests.execute(out.String())
if finalOutput != nil {
c.ActualValue = finalOutput.actualResult
if finalOutput.testResult {
c.State = PASS
} else {
c.State = FAIL
}
} else {
errmsgs += handleError(
fmt.Errorf("final output is nil"),
fmt.Sprintf("failed to run: %s\n",
c.Audit,
),
)
}
res := c.Tests.execute(out.String())
if res {
c.State = PASS
} else {
c.State = FAIL
if errmsgs != "" {
glog.V(2).Info(errmsgs)
}
}

30
check/check_test.go Normal file
View File

@@ -0,0 +1,30 @@
package check
import (
"testing"
)
func TestCheck_Run(t *testing.T) {
type TestCase struct {
check Check
Expected State
}
testCases := []TestCase{
{check: Check{Type: "manual"}, Expected: WARN},
{check: Check{Type: "skip"}, Expected: INFO},
{check: Check{Type: "", Scored: false}, Expected: WARN}, // Not scored checks with no type should be marked warn
{check: Check{Type: "", Scored: true}, Expected: WARN}, // If there are no tests in the check, warn
{check: Check{Type: "manual", Scored: false}, Expected: WARN},
{check: Check{Type: "skip", Scored: false}, Expected: INFO},
}
for _, testCase := range testCases {
testCase.check.Run()
if testCase.check.State != testCase.Expected {
t.Errorf("test failed, expected %s, actual %s\n", testCase.Expected, testCase.check.State)
}
}
}

View File

@@ -23,9 +23,9 @@ import (
// Controls holds all controls to check for master nodes.
type Controls struct {
ID string `yaml:"id" json:"id"`
Version string `json:"version"`
Text string `json:"text"`
ID string `yaml:"id" json:"id"`
Version string `json:"version"`
Text string `json:"text"`
Type NodeType `json:"node_type"`
Groups []*Group `json:"tests"`
Summary
@@ -37,15 +37,17 @@ type Group struct {
Pass int `json:"pass"`
Fail int `json:"fail"`
Warn int `json:"warn"`
Info int `json:"info"`
Text string `json:"desc"`
Checks []*Check `json:"results"`
}
// Summary is a summary of the results of control checks run.
type Summary struct {
Pass int `json:"total_pass"`
Fail int `json:"total_fail"`
Warn int `json:"total_warn"`
Pass int `json:"total_pass"`
Fail int `json:"total_fail"`
Warn int `json:"total_warn"`
Info int `json:"total_info"`
}
// NewControls instantiates a new master Controls object.
@@ -74,7 +76,7 @@ func NewControls(t NodeType, in []byte) (*Controls, error) {
// RunGroup runs all checks in a group.
func (controls *Controls) RunGroup(gids ...string) Summary {
g := []*Group{}
controls.Summary.Pass, controls.Summary.Fail, controls.Summary.Warn = 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(gids) == 0 {
@@ -105,7 +107,7 @@ func (controls *Controls) RunGroup(gids ...string) Summary {
func (controls *Controls) RunChecks(ids ...string) Summary {
g := []*Group{}
m := make(map[string]*Group)
controls.Summary.Pass, controls.Summary.Fail, controls.Summary.Warn = 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 {
@@ -182,6 +184,8 @@ func summarize(controls *Controls, check *Check) {
controls.Summary.Fail++
case WARN:
controls.Summary.Warn++
case INFO:
controls.Summary.Info++
}
}
@@ -193,5 +197,7 @@ func summarizeGroup(group *Group, check *Check) {
group.Fail++
case WARN:
group.Warn++
case INFO:
group.Info++
}
}

View File

@@ -17,7 +17,7 @@ groups:
- id: 1
text: "flag is not set"
tests:
test_item:
test_items:
- flag: "--basic-auth"
set: false
@@ -158,3 +158,12 @@ groups:
set: true
- 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

View File

@@ -49,8 +49,13 @@ type compare struct {
Value string
}
func (t *testItem) execute(s string) (result bool) {
result = false
type testOutput struct {
testResult bool
actualResult string
}
func (t *testItem) execute(s string) *testOutput {
result := &testOutput{}
match := strings.Contains(s, t.Flag)
if t.Set {
@@ -63,7 +68,7 @@ func (t *testItem) execute(s string) (result bool) {
// --flag
// somevalue
//pttn := `(` + t.Flag + `)(=)*([^\s,]*) *`
pttn := `(` + t.Flag + `)(=)*([^\s]*) *`
pttn := `(` + t.Flag + `)(=|: *)*([^\s]*) *`
flagRe := regexp.MustCompile(pttn)
vals := flagRe.FindStringSubmatch(s)
@@ -78,57 +83,57 @@ func (t *testItem) execute(s string) (result bool) {
os.Exit(1)
}
result.actualResult = strings.ToLower(flagVal)
switch t.Compare.Op {
case "eq":
value := strings.ToLower(flagVal)
// Do case insensitive comparaison for booleans ...
if value == "false" || value == "true" {
result = value == t.Compare.Value
result.testResult = value == t.Compare.Value
} else {
result = flagVal == t.Compare.Value
result.testResult = flagVal == t.Compare.Value
}
case "noteq":
value := strings.ToLower(flagVal)
// Do case insensitive comparaison for booleans ...
if value == "false" || value == "true" {
result = !(value == t.Compare.Value)
result.testResult = !(value == t.Compare.Value)
} else {
result = !(flagVal == t.Compare.Value)
result.testResult = !(flagVal == t.Compare.Value)
}
case "gt":
a, b := toNumeric(flagVal, t.Compare.Value)
result = a > b
result.testResult = a > b
case "gte":
a, b := toNumeric(flagVal, t.Compare.Value)
result = a >= b
result.testResult = a >= b
case "lt":
a, b := toNumeric(flagVal, t.Compare.Value)
result = a < b
result.testResult = a < b
case "lte":
a, b := toNumeric(flagVal, t.Compare.Value)
result = a <= b
result.testResult = a <= b
case "has":
result = strings.Contains(flagVal, t.Compare.Value)
result.testResult = strings.Contains(flagVal, t.Compare.Value)
case "nothave":
result = !strings.Contains(flagVal, t.Compare.Value)
result.testResult = !strings.Contains(flagVal, t.Compare.Value)
}
} else {
result = isset
result.testResult = isset
}
} else {
notset := !match
result = notset
result.testResult = notset
}
return
return result
}
type tests struct {
@@ -136,13 +141,25 @@ type tests struct {
BinOp binOp `yaml:"bin_op"`
}
func (ts *tests) execute(s string) (result bool) {
res := make([]bool, len(ts.TestItems))
func (ts *tests) execute(s string) *testOutput {
finalOutput := &testOutput{}
for i, t := range ts.TestItems {
res[i] = t.execute(s)
// If no tests are defined return with empty finalOutput.
// This may be the case for checks of type: "skip".
if ts == nil {
return finalOutput
}
res := make([]testOutput, len(ts.TestItems))
if len(res) == 0 {
return finalOutput
}
for i, t := range ts.TestItems {
res[i] = *(t.execute(s))
}
var result bool
// If no binary operation is specified, default to AND
switch ts.BinOp {
default:
@@ -151,16 +168,19 @@ func (ts *tests) execute(s string) (result bool) {
case and, "":
result = true
for i := range res {
result = result && res[i]
result = result && res[i].testResult
}
case or:
result = false
for i := range res {
result = result || res[i]
result = result || res[i].testResult
}
}
return
finalOutput.testResult = result
finalOutput.actualResult = res[0].actualResult
return finalOutput
}
func toNumeric(a, b string) (c, d int) {

View File

@@ -110,10 +110,20 @@ func TestTestExecute(t *testing.T) {
controls.Groups[0].Checks[13],
"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],
"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",
},
}
for _, c := range cases {
res := c.Tests.execute(c.str)
res := c.Tests.execute(c.str).testResult
if !res {
t.Errorf("%s, expected:%v, got:%v\n", c.Text, true, res)
}

View File

@@ -31,25 +31,8 @@ var (
func runChecks(nodetype check.NodeType) {
var summary check.Summary
var file string
var err error
var typeConf *viper.Viper
switch nodetype {
case check.MASTER:
file = masterFile
case check.NODE:
file = nodeFile
case check.FEDERATED:
file = federatedFile
}
path, err := getConfigFilePath(kubeVersion, getKubeVersion(), file)
if err != nil {
exitWithError(fmt.Errorf("can't find %s controls file in %s: %v", nodetype, cfgDir, err))
}
def := filepath.Join(path, file)
def := loadConfig(nodetype)
in, err := ioutil.ReadFile(def)
if err != nil {
exitWithError(fmt.Errorf("error opening %s controls file: %v", nodetype, err))
@@ -57,29 +40,25 @@ func runChecks(nodetype check.NodeType) {
glog.V(1).Info(fmt.Sprintf("Using benchmark file: %s\n", def))
// Merge kubernetes version specific config if any.
viper.SetConfigFile(path + "/config.yaml")
err = viper.MergeInConfig()
// Get the set of exectuables and config files we care about on this type of node.
typeConf := viper.Sub(string(nodetype))
binmap, err := getBinaries(typeConf)
// Checks that the executables we need for the node type are running.
if err != nil {
if os.IsNotExist(err) {
glog.V(2).Info(fmt.Sprintf("No version-specific config.yaml file in %s", path))
} else {
exitWithError(fmt.Errorf("couldn't read config file %s: %v", path+"/config.yaml", err))
}
} else {
glog.V(1).Info(fmt.Sprintf("Using config file: %s\n", viper.ConfigFileUsed()))
exitWithError(err)
}
// Get the set of exectuables and config files we care about on this type of node. This also
// checks that the executables we need for the node type are running.
typeConf = viper.Sub(string(nodetype))
binmap := getBinaries(typeConf)
confmap := getConfigFiles(typeConf)
svcmap := getServiceFiles(typeConf)
kubeconfmap := getKubeConfigFiles(typeConf)
// Variable substitutions. Replace all occurrences of variables in controls files.
s := string(in)
s = makeSubstitutions(s, "bin", binmap)
s = makeSubstitutions(s, "conf", confmap)
s = makeSubstitutions(s, "svc", svcmap)
s = makeSubstitutions(s, "kubeconfig", kubeconfmap)
controls, err := check.NewControls(nodetype, []byte(s))
if err != nil {
@@ -99,7 +78,7 @@ func runChecks(nodetype check.NodeType) {
}
// if we successfully ran some tests and it's json format, ignore the warnings
if (summary.Fail > 0 || summary.Warn > 0 || summary.Pass > 0) && jsonFmt {
if (summary.Fail > 0 || summary.Warn > 0 || summary.Pass > 0 || summary.Info > 0) && jsonFmt {
out, err := controls.JSON()
if err != nil {
exitWithError(fmt.Errorf("failed to output in JSON format: %v", err))
@@ -108,7 +87,7 @@ func runChecks(nodetype check.NodeType) {
fmt.Println(string(out))
} else {
// if we want to store in PostgreSQL, convert to JSON and save it
if (summary.Fail > 0 || summary.Warn > 0 || summary.Pass > 0) && pgSQL {
if (summary.Fail > 0 || summary.Warn > 0 || summary.Pass > 0 || summary.Info > 0) && pgSQL {
out, err := controls.JSON()
if err != nil {
exitWithError(fmt.Errorf("failed to output in JSON format: %v", err))
@@ -148,7 +127,7 @@ func prettyPrint(r *check.Controls, summary check.Summary) {
colors[check.WARN].Printf("== Remediations ==\n")
for _, g := range r.Groups {
for _, c := range g.Checks {
if c.State != check.PASS {
if c.State == check.FAIL || c.State == check.WARN {
fmt.Printf("%s %s\n", c.ID, c.Remediation)
}
}
@@ -169,8 +148,63 @@ func prettyPrint(r *check.Controls, summary check.Summary) {
}
colors[res].Printf("== Summary ==\n")
fmt.Printf("%d checks PASS\n%d checks FAIL\n%d checks WARN\n",
summary.Pass, summary.Fail, summary.Warn,
fmt.Printf("%d checks PASS\n%d checks FAIL\n%d checks WARN\n%d checks INFO\n",
summary.Pass, summary.Fail, summary.Warn, summary.Info,
)
}
}
// loadConfig finds the correct config dir based on the kubernetes version,
// merges any specific config.yaml file found with the main config
// and returns the benchmark file to use.
func loadConfig(nodetype check.NodeType) string {
var file string
var err error
switch nodetype {
case check.MASTER:
file = masterFile
case check.NODE:
file = nodeFile
case check.FEDERATED:
file = federatedFile
}
runningVersion := ""
if kubeVersion == "" {
runningVersion, err = getKubeVersion()
if err != nil {
exitWithError(fmt.Errorf("Version check failed: %s\nAlternatively, you can specify the version with --version", err))
}
}
path, err := getConfigFilePath(kubeVersion, runningVersion, file)
if err != nil {
exitWithError(fmt.Errorf("can't find %s controls file in %s: %v", nodetype, cfgDir, err))
}
// Merge kubernetes version specific config if any.
viper.SetConfigFile(path + "/config.yaml")
err = viper.MergeInConfig()
if err != nil {
if os.IsNotExist(err) {
glog.V(2).Info(fmt.Sprintf("No version-specific config.yaml file in %s", path))
} else {
exitWithError(fmt.Errorf("couldn't read config file %s: %v", path+"/config.yaml", err))
}
} else {
glog.V(1).Info(fmt.Sprintf("Using config file: %s\n", viper.ConfigFileUsed()))
}
return filepath.Join(path, file)
}
// isMaster verify if master components are running on the node.
func isMaster() bool {
_ = loadConfig(check.MASTER)
glog.V(2).Info("Checking if the current node is running master components")
masterConf := viper.Sub(string(check.MASTER))
if _, err := getBinaries(masterConf); err != nil {
glog.V(2).Info(err)
return false
}
return true
}

View File

@@ -20,6 +20,7 @@ import (
"os"
"github.com/aquasecurity/kube-bench/check"
"github.com/golang/glog"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
@@ -34,8 +35,8 @@ var (
pgSQL bool
checkList string
groupList string
masterFile string
nodeFile string
masterFile = "master.yaml"
nodeFile = "node.yaml"
federatedFile string
noResults bool
noSummary bool
@@ -46,7 +47,15 @@ var (
var RootCmd = &cobra.Command{
Use: os.Args[0],
Short: "Run CIS Benchmarks checks against a Kubernetes deployment",
Long: `This tool runs the CIS Kubernetes Benchmark (http://www.cisecurity.org/benchmark/kubernetes/)`,
Long: `This tool runs the CIS Kubernetes Benchmark (https://www.cisecurity.org/benchmark/kubernetes/)`,
Run: func(cmd *cobra.Command, args []string) {
if isMaster() {
glog.V(1).Info("== Running master checks ==\n")
runChecks(check.MASTER)
}
glog.V(1).Info("== Running node checks ==\n")
runChecks(check.NODE)
},
}
// Execute adds all child commands to the root command sets flags appropriately.

View File

@@ -33,20 +33,6 @@ func init() {
statFunc = os.Stat
}
func printlnWarn(msg string) {
fmt.Fprintf(os.Stderr, "[%s] %s\n",
colors[check.WARN].Sprintf("%s", check.WARN),
msg,
)
}
func sprintlnWarn(msg string) string {
return fmt.Sprintf("[%s] %s",
colors[check.WARN].Sprintf("%s", check.WARN),
msg,
)
}
func exitWithError(err error) {
fmt.Fprintf(os.Stderr, "\n%v\n", err)
os.Exit(1)
@@ -86,8 +72,9 @@ func ps(proc string) string {
return string(out)
}
// getBinaries finds which of the set of candidate executables are running
func getBinaries(v *viper.Viper) map[string]string {
// getBinaries finds which of the set of candidate executables are running.
// It returns an error if one mandatory executable is not running.
func getBinaries(v *viper.Viper) (map[string]string, error) {
binmap := make(map[string]string)
for _, component := range v.GetStringSlice("components") {
@@ -101,7 +88,7 @@ func getBinaries(v *viper.Viper) map[string]string {
if len(bins) > 0 {
bin, err := findExecutable(bins)
if err != nil && !optional {
exitWithError(fmt.Errorf("need %s executable but none of the candidates are running", component))
return nil, fmt.Errorf("need %s executable but none of the candidates are running", component)
}
// Default the executable name that we'll substitute to the name of the component
@@ -115,7 +102,7 @@ func getBinaries(v *viper.Viper) map[string]string {
}
}
return binmap
return binmap, nil
}
// getConfigFilePath locates the config files we should be using based on either the specified
@@ -129,6 +116,8 @@ func getConfigFilePath(specifiedVersion string, runningVersion string, filename
fileVersion = runningVersion
}
glog.V(2).Info(fmt.Sprintf("Looking for config for version %s", fileVersion))
for {
path = filepath.Join(cfgDir, fileVersion)
file := filepath.Join(path, string(filename))
@@ -170,8 +159,6 @@ func decrementVersion(version string) string {
}
// getConfigFiles finds which of the set of candidate config files exist
// accepts a string 't' which indicates the type of config file, conf,
// podspec or untifile.
func getConfigFiles(v *viper.Viper) map[string]string {
confmap := make(map[string]string)
@@ -202,6 +189,68 @@ func getConfigFiles(v *viper.Viper) map[string]string {
return confmap
}
// getServiceFiles finds which of the set of candidate service files exist
func getServiceFiles(v *viper.Viper) map[string]string {
svcmap := make(map[string]string)
for _, component := range v.GetStringSlice("components") {
s := v.Sub(component)
if s == nil {
continue
}
// See if any of the candidate config files exist
svc := findConfigFile(s.GetStringSlice("svc"))
if svc == "" {
if s.IsSet("defaultsvc") {
svc = s.GetString("defaultsvc")
glog.V(2).Info(fmt.Sprintf("Using default service file name '%s' for component %s", svc, component))
} else {
// Default the service file name that we'll substitute to the name of the component
glog.V(2).Info(fmt.Sprintf("Missing service file for %s", component))
svc = component
}
} else {
glog.V(2).Info(fmt.Sprintf("Component %s uses service file '%s'", component, svc))
}
svcmap[component] = svc
}
return svcmap
}
// getKubeConfigFiles finds which of the set of candidate kubeconfig files exist
func getKubeConfigFiles(v *viper.Viper) map[string]string {
kubeconfigmap := make(map[string]string)
for _, component := range v.GetStringSlice("components") {
s := v.Sub(component)
if s == nil {
continue
}
// See if any of the candidate config files exist
kubeconfig := findConfigFile(s.GetStringSlice("kubeconfig"))
if kubeconfig == "" {
if s.IsSet("defaultkubeconfig") {
kubeconfig = s.GetString("defaultkubeconfig")
glog.V(2).Info(fmt.Sprintf("Using default kubeconfig file name '%s' for component %s", kubeconfig, component))
} else {
// Default the service file name that we'll substitute to the name of the component
glog.V(2).Info(fmt.Sprintf("Missing service file for %s", component))
kubeconfig = component
}
} else {
glog.V(2).Info(fmt.Sprintf("Component %s uses service file '%s'", component, kubeconfig))
}
kubeconfigmap[component] = kubeconfig
}
return kubeconfigmap
}
// verifyBin checks that the binary specified is running
func verifyBin(bin string) bool {
@@ -265,19 +314,25 @@ func multiWordReplace(s string, subname string, sub string) string {
return strings.Replace(s, subname, sub, -1)
}
func getKubeVersion() string {
func getKubeVersion() (string, error) {
// These executables might not be on the user's path.
_, err := exec.LookPath("kubectl")
if err != nil {
_, err = exec.LookPath("kubelet")
if err != nil {
exitWithError(fmt.Errorf("Version check failed: need kubectl or kubelet binaries to get kubernetes version.\nAlternately, you can specify the version with --version"))
// Search for the kubelet binary all over the filesystem and run the first match to get the kubernetes version
cmd := exec.Command("/bin/sh", "-c", "`find / -type f -executable -name kubelet 2>/dev/null | grep -m1 .` --version")
out, err := cmd.CombinedOutput()
if err == nil {
return getVersionFromKubeletOutput(string(out)), nil
}
return "", fmt.Errorf("need kubectl or kubelet binaries to get kubernetes version")
}
return getKubeVersionFromKubelet()
return getKubeVersionFromKubelet(), nil
}
return getKubeVersionFromKubectl()
return getKubeVersionFromKubectl(), nil
}
func getKubeVersionFromKubectl() string {
@@ -305,7 +360,7 @@ func getVersionFromKubectlOutput(s string) string {
serverVersionRe := regexp.MustCompile(`Server Version: v(\d+.\d+)`)
subs := serverVersionRe.FindStringSubmatch(s)
if len(subs) < 2 {
printlnWarn(fmt.Sprintf("Unable to get kubectl version, using default version: %s", defaultKubeVersion))
glog.V(1).Info(fmt.Sprintf("Unable to get Kubernetes version from kubectl, using default version: %s", defaultKubeVersion))
return defaultKubeVersion
}
return subs[1]
@@ -315,7 +370,7 @@ func getVersionFromKubeletOutput(s string) string {
serverVersionRe := regexp.MustCompile(`Kubernetes v(\d+.\d+)`)
subs := serverVersionRe.FindStringSubmatch(s)
if len(subs) < 2 {
printlnWarn(fmt.Sprintf("Unable to get kubelet version, using default version: %s", defaultKubeVersion))
glog.V(1).Info(fmt.Sprintf("Unable to get Kubernetes version from kubelet, using default version: %s", defaultKubeVersion))
return defaultKubeVersion
}
return subs[1]

View File

@@ -109,38 +109,51 @@ func TestFindExecutable(t *testing.T) {
func TestGetBinaries(t *testing.T) {
cases := []struct {
config map[string]interface{}
psOut string
exp map[string]string
config map[string]interface{}
psOut string
exp map[string]string
expectErr bool
}{
{
config: map[string]interface{}{"components": []string{"apiserver"}, "apiserver": map[string]interface{}{"bins": []string{"apiserver", "kube-apiserver"}}},
psOut: "kube-apiserver",
exp: map[string]string{"apiserver": "kube-apiserver"},
config: map[string]interface{}{"components": []string{"apiserver"}, "apiserver": map[string]interface{}{"bins": []string{"apiserver", "kube-apiserver"}}},
psOut: "kube-apiserver",
exp: map[string]string{"apiserver": "kube-apiserver"},
expectErr: false,
},
{
// "thing" is not in the list of components
config: map[string]interface{}{"components": []string{"apiserver"}, "apiserver": map[string]interface{}{"bins": []string{"apiserver", "kube-apiserver"}}, "thing": map[string]interface{}{"bins": []string{"something else", "thing"}}},
psOut: "kube-apiserver thing",
exp: map[string]string{"apiserver": "kube-apiserver"},
config: map[string]interface{}{"components": []string{"apiserver"}, "apiserver": map[string]interface{}{"bins": []string{"apiserver", "kube-apiserver"}}, "thing": map[string]interface{}{"bins": []string{"something else", "thing"}}},
psOut: "kube-apiserver thing",
exp: map[string]string{"apiserver": "kube-apiserver"},
expectErr: false,
},
{
// "anotherthing" in list of components but doesn't have a defintion
config: map[string]interface{}{"components": []string{"apiserver", "anotherthing"}, "apiserver": map[string]interface{}{"bins": []string{"apiserver", "kube-apiserver"}}, "thing": map[string]interface{}{"bins": []string{"something else", "thing"}}},
psOut: "kube-apiserver thing",
exp: map[string]string{"apiserver": "kube-apiserver"},
config: map[string]interface{}{"components": []string{"apiserver", "anotherthing"}, "apiserver": map[string]interface{}{"bins": []string{"apiserver", "kube-apiserver"}}, "thing": map[string]interface{}{"bins": []string{"something else", "thing"}}},
psOut: "kube-apiserver thing",
exp: map[string]string{"apiserver": "kube-apiserver"},
expectErr: false,
},
{
// more than one component
config: map[string]interface{}{"components": []string{"apiserver", "thing"}, "apiserver": map[string]interface{}{"bins": []string{"apiserver", "kube-apiserver"}}, "thing": map[string]interface{}{"bins": []string{"something else", "thing"}}},
psOut: "kube-apiserver \nthing",
exp: map[string]string{"apiserver": "kube-apiserver", "thing": "thing"},
config: map[string]interface{}{"components": []string{"apiserver", "thing"}, "apiserver": map[string]interface{}{"bins": []string{"apiserver", "kube-apiserver"}}, "thing": map[string]interface{}{"bins": []string{"something else", "thing"}}},
psOut: "kube-apiserver \nthing",
exp: map[string]string{"apiserver": "kube-apiserver", "thing": "thing"},
expectErr: false,
},
{
// default binary to component name
config: map[string]interface{}{"components": []string{"apiserver", "thing"}, "apiserver": map[string]interface{}{"bins": []string{"apiserver", "kube-apiserver"}}, "thing": map[string]interface{}{"bins": []string{"something else", "thing"}, "optional": true}},
psOut: "kube-apiserver \notherthing some params",
exp: map[string]string{"apiserver": "kube-apiserver", "thing": "thing"},
config: map[string]interface{}{"components": []string{"apiserver", "thing"}, "apiserver": map[string]interface{}{"bins": []string{"apiserver", "kube-apiserver"}}, "thing": map[string]interface{}{"bins": []string{"something else", "thing"}, "optional": true}},
psOut: "kube-apiserver \notherthing some params",
exp: map[string]string{"apiserver": "kube-apiserver", "thing": "thing"},
expectErr: false,
},
{
// missing mandatory component
config: map[string]interface{}{"components": []string{"apiserver", "thing"}, "apiserver": map[string]interface{}{"bins": []string{"apiserver", "kube-apiserver"}}, "thing": map[string]interface{}{"bins": []string{"something else", "thing"}, "optional": true}},
psOut: "otherthing some params",
exp: map[string]string{"apiserver": "kube-apiserver", "thing": "thing"},
expectErr: true,
},
}
@@ -153,8 +166,12 @@ func TestGetBinaries(t *testing.T) {
for k, val := range c.config {
v.Set(k, val)
}
m := getBinaries(v)
if !reflect.DeepEqual(m, c.exp) {
m, err := getBinaries(v)
if c.expectErr {
if err == nil {
t.Fatal("Got nil Expected error")
}
} else if !reflect.DeepEqual(m, c.exp) {
t.Fatalf("Got %v\nExpected %v", m, c.exp)
}
})
@@ -289,6 +306,81 @@ func TestGetConfigFiles(t *testing.T) {
}
}
func TestGetServiceFiles(t *testing.T) {
cases := []struct {
config map[string]interface{}
exp map[string]string
statResults []error
}{
{
config: map[string]interface{}{
"components": []string{"kubelet"},
"kubelet": map[string]interface{}{"svc": []string{"kubelet", "10-kubeadm.conf"}},
},
statResults: []error{os.ErrNotExist, nil},
exp: map[string]string{"kubelet": "10-kubeadm.conf"},
},
{
// Component "thing" isn't included in the list of components
config: map[string]interface{}{
"components": []string{"kubelet"},
"kubelet": map[string]interface{}{"svc": []string{"kubelet", "10-kubeadm.conf"}},
"thing": map[string]interface{}{"svc": []string{"/my/file/thing"}},
},
statResults: []error{os.ErrNotExist, nil},
exp: map[string]string{"kubelet": "10-kubeadm.conf"},
},
{
// More than one component
config: map[string]interface{}{
"components": []string{"kubelet", "thing"},
"kubelet": map[string]interface{}{"svc": []string{"kubelet", "10-kubeadm.conf"}},
"thing": map[string]interface{}{"svc": []string{"/my/file/thing"}},
},
statResults: []error{os.ErrNotExist, nil, nil},
exp: map[string]string{"kubelet": "10-kubeadm.conf", "thing": "/my/file/thing"},
},
{
// Default thing to specified default service
config: map[string]interface{}{
"components": []string{"kubelet", "thing"},
"kubelet": map[string]interface{}{"svc": []string{"kubelet", "10-kubeadm.conf"}},
"thing": map[string]interface{}{"svc": []string{"/my/file/thing"}, "defaultsvc": "another/thing"},
},
statResults: []error{os.ErrNotExist, nil, os.ErrNotExist},
exp: map[string]string{"kubelet": "10-kubeadm.conf", "thing": "another/thing"},
},
{
// Default thing to component name
config: map[string]interface{}{
"components": []string{"kubelet", "thing"},
"kubelet": map[string]interface{}{"svc": []string{"kubelet", "10-kubeadm.conf"}},
"thing": map[string]interface{}{"svc": []string{"/my/file/thing"}},
},
statResults: []error{os.ErrNotExist, nil, os.ErrNotExist},
exp: map[string]string{"kubelet": "10-kubeadm.conf", "thing": "thing"},
},
}
v := viper.New()
statFunc = fakestat
for id, c := range cases {
t.Run(strconv.Itoa(id), func(t *testing.T) {
for k, val := range c.config {
v.Set(k, val)
}
e = c.statResults
eIndex = 0
m := getServiceFiles(v)
if !reflect.DeepEqual(m, c.exp) {
t.Fatalf("Got %v\nExpected %v", m, c.exp)
}
})
}
}
func TestMakeSubsitutions(t *testing.T) {
cases := []struct {
input string

46
hack/debug.yaml Normal file
View File

@@ -0,0 +1,46 @@
# use this pod with: kubectl run ubuntu -it --pid=host -- /bin/bash
# this allows you to debug what is running on the host.
apiVersion: v1
kind: Pod
metadata:
name: ubuntu
spec:
hostPID: true
containers:
- name: ubuntu
image: ubuntu
command: [ "/bin/bash", "-c", "--" ]
args: [ "while true; do sleep 30; done;" ]
volumeMounts:
- name: var-lib-kubelet
mountPath: /var/lib/kubelet
- name: etc-systemd
mountPath: /etc/systemd
- name: etc-kubernetes
mountPath: /etc/kubernetes
# /usr/bin is mounted to access kubectl / kubelet, for auto-detecting the Kubernetes version.
# You can omit this mount if you specify --version as part of the command.
- name: usr-bin
mountPath: /usr/bin
- name: kind-bin
mountPath: /kind/bin
resources:
limits:
memory: "128Mi"
cpu: "500m"
volumes:
- name: var-lib-kubelet
hostPath:
path: "/var/lib/kubelet"
- name: etc-systemd
hostPath:
path: "/etc/systemd"
- name: etc-kubernetes
hostPath:
path: "/etc/kubernetes"
- name: usr-bin
hostPath:
path: "/usr/bin"
- name: kind-bin
hostPath:
path: "/kind/bin"

50
hack/kind.yaml Normal file
View File

@@ -0,0 +1,50 @@
apiVersion: batch/v1
kind: Job
metadata:
name: kube-bench
spec:
template:
metadata:
labels:
app: kube-bench
spec:
hostPID: true
containers:
- name: kube-bench
image: aquasec/kube-bench:${VERSION}
command: ["kube-bench"]
volumeMounts:
- name: var-lib-etcd
mountPath: /var/lib/etcd
- name: var-lib-kubelet
mountPath: /var/lib/kubelet
- name: etc-systemd
mountPath: /etc/systemd
- name: etc-kubernetes
mountPath: /etc/kubernetes
# /usr/bin is mounted to access kubectl / kubelet, for auto-detecting the Kubernetes version.
# You can omit this mount if you specify --version as part of the command.
- name: usr-bin
mountPath: /usr/bin
- name: kind-bin
mountPath: /kind/bin
restartPolicy: Never
volumes:
- name: var-lib-etcd
hostPath:
path: "/var/lib/etcd"
- name: var-lib-kubelet
hostPath:
path: "/var/lib/kubelet"
- name: etc-systemd
hostPath:
path: "/etc/systemd"
- name: etc-kubernetes
hostPath:
path: "/etc/kubernetes"
- name: usr-bin
hostPath:
path: "/usr/bin"
- name: kind-bin
hostPath:
path: "/kind/bin"

38
job-master.yaml Normal file
View File

@@ -0,0 +1,38 @@
apiVersion: batch/v1
kind: Job
metadata:
name: kube-bench-master
spec:
template:
spec:
hostPID: true
nodeSelector:
node-role.kubernetes.io/master: ""
tolerations:
- key: node-role.kubernetes.io/master
operator: Exists
effect: NoSchedule
containers:
- name: kube-bench
image: aquasec/kube-bench:latest
command: ["kube-bench","master"]
volumeMounts:
- name: var-lib-etcd
mountPath: /var/lib/etcd
- name: etc-kubernetes
mountPath: /etc/kubernetes
# /usr/bin is mounted to access kubectl / kubelet, for auto-detecting the Kubernetes version.
# You can omit this mount if you specify --version as part of the command.
- name: usr-bin
mountPath: /usr/bin
restartPolicy: Never
volumes:
- name: var-lib-etcd
hostPath:
path: "/var/lib/etcd"
- name: etc-kubernetes
hostPath:
path: "/etc/kubernetes"
- name: usr-bin
hostPath:
path: "/usr/bin"

37
job-node.yaml Normal file
View File

@@ -0,0 +1,37 @@
apiVersion: batch/v1
kind: Job
metadata:
name: kube-bench-node
spec:
template:
spec:
hostPID: true
containers:
- name: kube-bench
image: aquasec/kube-bench:latest
command: ["kube-bench","node"]
volumeMounts:
- name: var-lib-kubelet
mountPath: /var/lib/kubelet
- name: etc-systemd
mountPath: /etc/systemd
- name: etc-kubernetes
mountPath: /etc/kubernetes
# /usr/bin is mounted to access kubectl / kubelet, for auto-detecting the Kubernetes version.
# You can omit this mount if you specify --version as part of the command.
- name: usr-bin
mountPath: /usr/bin
restartPolicy: Never
volumes:
- name: var-lib-kubelet
hostPath:
path: "/var/lib/kubelet"
- name: etc-systemd
hostPath:
path: "/etc/systemd"
- name: etc-kubernetes
hostPath:
path: "/etc/kubernetes"
- name: usr-bin
hostPath:
path: "/usr/bin"

45
job.yaml Normal file
View File

@@ -0,0 +1,45 @@
apiVersion: batch/v1
kind: Job
metadata:
name: kube-bench
spec:
template:
metadata:
labels:
app: kube-bench
spec:
hostPID: true
containers:
- name: kube-bench
image: aquasec/kube-bench:latest
command: ["kube-bench"]
volumeMounts:
- name: var-lib-etcd
mountPath: /var/lib/etcd
- name: var-lib-kubelet
mountPath: /var/lib/kubelet
- name: etc-systemd
mountPath: /etc/systemd
- name: etc-kubernetes
mountPath: /etc/kubernetes
# /usr/bin is mounted to access kubectl / kubelet, for auto-detecting the Kubernetes version.
# You can omit this mount if you specify --version as part of the command.
- name: usr-bin
mountPath: /usr/bin
restartPolicy: Never
volumes:
- name: var-lib-etcd
hostPath:
path: "/var/lib/etcd"
- name: var-lib-kubelet
hostPath:
path: "/var/lib/kubelet"
- name: etc-systemd
hostPath:
path: "/etc/systemd"
- name: etc-kubernetes
hostPath:
path: "/etc/kubernetes"
- name: usr-bin
hostPath:
path: "/usr/bin"

BIN
kb Executable file

Binary file not shown.

View File

@@ -1,7 +1,72 @@
SOURCES := $(shell find . -name '*.go')
TARGET_OS := linux
BINARY := kube-bench
DOCKER_REGISTRY ?= aquasec
VERSION ?= $(shell git rev-parse --short=7 HEAD)
IMAGE_NAME ?= $(DOCKER_REGISTRY)/$(BINARY):$(VERSION)
TARGET_OS := linux
BUILD_OS := linux
uname := $(shell uname -s)
ifneq ($(findstring Microsoft,$(shell uname -r)),)
BUILD_OS := windows
else ifeq ($(uname),Linux)
BUILD_OS := linux
else ifeq ($(uname),Darwin)
BUILD_OS := darwin
endif
# kind cluster name to use
KIND_PROFILE ?= kube-bench
KIND_CONTAINER_NAME=$(KIND_PROFILE)-control-plane
build: kube-bench
$(BINARY): $(SOURCES)
GOOS=$(TARGET_OS) go build -o $(BINARY) .
# builds the current dev docker version
build-docker:
docker build --build-arg BUILD_DATE=$(shell date -u +"%Y-%m-%dT%H:%M:%SZ") \
--build-arg VCS_REF=$(shell git rev-parse --short HEAD) \
-t $(IMAGE_NAME) .
tests:
go test -race -timeout 30s -cover ./cmd ./check
# creates a kind cluster to be used for development.
HAS_KIND := $(shell command -v kind;)
kind-test-cluster:
ifndef HAS_KIND
go get -u sigs.k8s.io/kind
endif
@if [ -z $$(kind get clusters | grep $(KIND_PROFILE)) ]; then\
echo "Could not find $(KIND_PROFILE) cluster. Creating...";\
kind create cluster --name $(KIND_PROFILE) --image kindest/node:v1.11.3 --wait 5m;\
fi
# pushses the current dev version to the kind cluster.
kind-push:
docker save $(IMAGE_NAME) -o kube-bench.tar.gz; \
docker cp kube-bench.tar.gz $(KIND_CONTAINER_NAME):/kube-bench.tar.gz; \
docker exec $(KIND_CONTAINER_NAME) docker load -i /kube-bench.tar.gz;
-rm -f kube-bench.tar.gz
# runs the current version on kind using a job and follow logs
kind-run: KUBECONFIG = "$(shell kind get kubeconfig-path --name="$(KIND_PROFILE)")"
kind-run: ensure-stern
sed "s/\$${VERSION}/$(VERSION)/" ./hack/kind.yaml > ./hack/kind.test.yaml
-KUBECONFIG=$(KUBECONFIG) \
kubectl delete job kube-bench
KUBECONFIG=$(KUBECONFIG) \
kubectl apply -f ./hack/kind.test.yaml
KUBECONFIG=$(KUBECONFIG) \
stern -l app=kube-bench --container kube-bench
# ensures that stern is installed
HAS_STERN := $(shell command -v stern;)
ensure-stern:
ifndef HAS_STERN
curl -LO https://github.com/wercker/stern/releases/download/1.10.0/stern_$(BUILD_OS)_amd64 && \
chmod +rx ./stern_$(BUILD_OS)_amd64 && \
mv ./stern_$(BUILD_OS)_amd64 /usr/local/bin/stern
endif