github.com/khulnasoft-lab/kube-bench@v0.2.1-0.20240330183753-9df52345ae58/docs/controls.md (about) 1 # Test and config files 2 3 `kube-bench` runs checks specified in `controls` files that are a YAML 4 representation of the CIS Kubernetes Benchmark checks (or other distribution-specific hardening guides). 5 6 ## Controls 7 8 `controls` is a YAML document that contains checks that must be run against a 9 specific Kubernetes node type, master or node and version. 10 11 `controls` is the fundamental input to `kube-bench`. The following is an example 12 of a basic `controls`: 13 14 ```yml 15 --- 16 controls: 17 id: 1 18 text: "Master Node Security Configuration" 19 type: "master" 20 groups: 21 - id: 1.1 22 text: API Server 23 checks: 24 - id: 1.1.1 25 text: "Ensure that the --allow-privileged argument is set (Scored)" 26 audit: "ps -ef | grep kube-apiserver | grep -v grep" 27 tests: 28 bin_op: or 29 test_items: 30 - flag: "--allow-privileged" 31 set: true 32 - flag: "--some-other-flag" 33 set: false 34 remediation: "Edit the /etc/kubernetes/config file on the master node and 35 set the KUBE_ALLOW_PRIV parameter to '--allow-privileged=false'" 36 scored: true 37 - id: 1.2 38 text: Scheduler 39 checks: 40 - id: 1.2.1 41 text: "Ensure that the --profiling argument is set to false (Scored)" 42 audit: "ps -ef | grep kube-scheduler | grep -v grep" 43 tests: 44 bin_op: and 45 test_items: 46 - flag: "--profiling" 47 set: true 48 - flag: "--some-other-flag" 49 set: false 50 remediation: "Edit the /etc/kubernetes/config file on the master node and 51 set the KUBE_ALLOW_PRIV parameter to '--allow-privileged=false'" 52 scored: true 53 ``` 54 55 `controls` is composed of a hierarchy of groups, sub-groups and checks. Each of 56 the `controls` components have an id and a text description which are displayed 57 in the `kube-bench` output. 58 59 `type` specifies what kubernetes node type a `controls` is for. Possible values 60 for `type` are `master` and `node`. 61 62 ## Groups 63 64 `groups` is a list of subgroups that test the various Kubernetes components 65 that run on the node type specified in the `controls`. 66 67 For example, one subgroup checks parameters passed to the API server binary, while 68 another subgroup checks parameters passed to the controller-manager binary. 69 70 ```yml 71 groups: 72 - id: 1.1 73 text: API Server 74 # ... 75 - id: 1.2 76 text: Scheduler 77 # ... 78 ``` 79 80 These subgroups have `id`, `text` fields which serve the same purposes described 81 in the previous paragraphs. The most important part of the subgroup is the 82 `checks` field which is the collection of actual `check`s that form the subgroup. 83 84 This is an example of a subgroup and checks in the subgroup. 85 86 ```yml 87 id: 1.1 88 text: API Server 89 checks: 90 - id: 1.1.1 91 text: "Ensure that the --allow-privileged argument is set (Scored)" 92 audit: "ps -ef | grep kube-apiserver | grep -v grep" 93 tests: 94 # ... 95 - id: 1.1.2 96 text: "Ensure that the --anonymous-auth argument is set to false (Not Scored)" 97 audit: "ps -ef | grep kube-apiserver | grep -v grep" 98 tests: 99 # ... 100 ``` 101 102 `kube-bench` supports running a subgroup by specifying the subgroup `id` on the 103 command line, with the flag `--group` or `-g`. 104 105 ## Check 106 107 The CIS Kubernetes Benchmark recommends configurations to harden Kubernetes components. These recommendations are usually configuration options and can be 108 specified by flags to Kubernetes binaries, or in configuration files. 109 110 The Benchmark also provides commands to audit a Kubernetes installation, identify 111 places where the cluster security can be improved, and steps to remediate these 112 identified problems. 113 114 In `kube-bench`, `check` objects embody these recommendations. This an example 115 `check` object: 116 117 ```yml 118 id: 1.1.1 119 text: "Ensure that the --anonymous-auth argument is set to false (Not Scored)" 120 audit: "ps -ef | grep kube-apiserver | grep -v grep" 121 tests: 122 test_items: 123 - flag: "--anonymous-auth" 124 compare: 125 op: eq 126 value: false 127 set: true 128 remediation: | 129 Edit the API server pod specification file kube-apiserver 130 on the master node and set the below parameter. 131 --anonymous-auth=false 132 scored: false 133 ``` 134 135 A `check` object has an `id`, a `text`, an `audit`, a `tests`, `remediation` 136 and `scored` fields. 137 138 `kube-bench` supports running individual checks by specifying the check's `id` 139 as a comma-delimited list on the command line with the `--check` flag. 140 141 The `audit` field specifies the command to run for a check. The output of this 142 command is then evaluated for conformance with the CIS Kubernetes Benchmark 143 recommendation. 144 145 The audit is evaluated against criteria specified by the `tests` 146 object. `tests` contain `bin_op` and `test_items`. 147 148 `test_items` specify the criteria(s) the `audit` command's output should meet to 149 pass a check. This criteria is made up of keywords extracted from the output of 150 the `audit` command and operations that compare these keywords against 151 values expected by the CIS Kubernetes Benchmark. 152 153 There are three ways to run and extract keywords from the output of the command used, 154 | Command | Output var | 155 |---|---| 156 | `audit` | `flag` | 157 | `audit_config` | `path` | 158 | `audit_env` | `env` | 159 160 `flag` is used when the keyword is a command-line flag. The associated `audit` command could 161 be any binaries available on the system like `ps` command and a `grep` for the binary whose flag we are 162 checking: 163 164 ```sh 165 ps -ef | grep somebinary | grep -v grep 166 ``` 167 168 Here is an example usage of the `flag` option: 169 170 ```yml 171 # ... 172 audit: "ps -ef | grep kube-apiserver | grep -v grep" 173 tests: 174 test_items: 175 - flag: "--anonymous-auth" 176 # ... 177 ``` 178 179 `path` is used when the keyword is an option set in a JSON or YAML config file. 180 The associated `audit_command` command is usually `cat /path/to/config-yaml-or-json`. 181 For example: 182 183 ```yml 184 # ... 185 text: "Ensure that the --anonymous-auth argument is set to false (Not Scored)" 186 audit: "cat /path/to/some/config" 187 tests: 188 test_items: 189 - path: "{.someoption.value}" 190 # ... 191 ``` 192 193 `env` is used to check if the value is present within a specified environment variable. The presence of `env` is treated as an OR operation, if both `flag` and `env` are supplied it will use either to attempt pass the check. 194 The command used for checking the environment variables of a process **is generated by default**. 195 196 If the command being generated is causing errors, you can override the command used by setting `audit_env` on the check. 197 Similarly, if you don't want the environment checking command to be generated or run at all, specify `disableEnvTesting` as true on the check. 198 199 The example below will check if the flag `--auto-tls` is equal to false *OR* `ETCD_AUTO_TLS` is equal to false 200 201 ```yml 202 test_items: 203 - flag: "--auto-tls" 204 env: "ETCD_AUTO_TLS" 205 compare: 206 op: eq 207 value: false 208 ``` 209 **Note:** flag, path and env will act as OR if more then one present. 210 211 `test_item` compares the output of the audit command and keywords using the 212 `set` and `compare` fields. 213 214 ```yml 215 test_items: 216 - flag: "--anonymous-auth" 217 compare: 218 op: eq 219 value: false 220 set: true 221 ``` 222 223 `set` checks if a keyword is present in the output of the audit command or a config file. The possible values for `set` are true and false. 224 225 If `set` is true, the check passes only if the keyword is present in the output 226 of the audit command, or config file. If `set` is false, the check passes only 227 if the keyword is not present in the output of the audit command, or config file. 228 `set` is true by default. 229 230 `compare` has two fields `op` and `value` to compare keywords with expected 231 value. `op` specifies which operation is used for the comparison, and `value` 232 specifies the value to compare against. 233 234 > To use `compare`, `set` must true. The comparison will be ignored if `set` is 235 > false 236 237 The `op` (operations) currently supported in `kube-bench` are: 238 - `eq`: tests if the keyword is equal to the compared value. 239 - `noteq`: tests if the keyword is unequal to the compared value. 240 - `gt`: tests if the keyword is greater than the compared value. 241 - `gte`: tests if the keyword is greater than or equal to the compared value. 242 - `lt`: tests if the keyword is less than the compared value. 243 - `lte`: tests if the keyword is less than or equal to the compared value. 244 - `has`: tests if the keyword contains the compared value. 245 - `nothave`: tests if the keyword does not contain the compared value. 246 - `regex`: tests if the flag value matches the compared value regular expression. 247 When defining regular expressions in YAML it is generally easier to wrap them in 248 single quotes, for example `'^[abc]$'`, to avoid issues with string escaping. 249 - `bitmask` : tests if keyward is bitmasked with the compared value, common usege is for 250 comparing file permissions in linux. 251 252 ## Omitting checks 253 254 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: 255 256 ```yaml 257 checks: 258 - id: 2.1.1 259 text: "Ensure that the --allow-privileged argument is set to false (Scored)" 260 type: "skip" 261 scored: true 262 ``` 263 264 No tests will be run for this check and the output will be marked [INFO]. 265 266 ## Configuration and Variables 267 268 Kubernetes component configuration and binary file locations and names 269 vary based on cluster deployment methods and Kubernetes distribution used. 270 For this reason, the locations of these binaries and config files are configurable 271 by editing the `cfg/config.yaml` file and these binaries and files can be 272 referenced in a `controls` file via variables. 273 274 The `cfg/config.yaml` file is a global configuration file. Configuration files 275 can be created for specific Kubernetes versions (distributions). Values in the 276 version-specific config overwrite similar values in `cfg/config.yaml`. 277 278 For example, the kube-apiserver in Red Hat OCP distribution is run as 279 `hypershift openshift-kube-apiserver` instead of the default `kube-apiserver`. 280 This difference can be specified by editing the `master.apiserver.defaultbin` 281 entry `cfg/rh-0.7/config.yaml`. 282 283 Below is the structure of `cfg/config.yaml`: 284 285 ``` 286 nodetype 287 |-- components 288 |-- component1 289 |-- component1 290 |-- bins 291 |-- defaultbin (optional) 292 |-- confs 293 |-- defaultconf (optional) 294 |-- svcs 295 |-- defaultsvc (optional) 296 |-- kubeconfig 297 |-- defaultkubeconfig (optional) 298 ``` 299 300 Every node type has a subsection that specifies the main configuration items. 301 302 - `components`: A list of components for the node type. For example master 303 will have an entry for **apiserver**, **scheduler** and **controllermanager**. 304 305 Each component has the following entries: 306 307 - `bins`: A list of candidate binaries for a component. `kube-bench` checks this 308 list and selects the **first** binary that is running on the node. 309 310 If none of the binaries in `bins` list is running, `kube-bench` checks if the 311 binary specified by `defaultbin` is running and terminates if none of the 312 binaries in both `bins` and `defaultbin` is running. 313 314 The selected binary for a component can be referenced in `controls` using a 315 variable in the form `$<component>bin`. In the example below, we reference 316 the selected API server binary with the variable `$apiserverbin` in an `audit` 317 command. 318 319 ```yml 320 id: 1.1.1 321 text: "Ensure that the --anonymous-auth argument is set to false (Scored)" 322 audit: "ps -ef | grep $apiserverbin | grep -v grep" 323 # ... 324 ``` 325 326 - `confs`: A list of candidate configuration files for a component. `kube-bench` 327 checks this list and selects the **first** config file that is found on the node. 328 If none of the config files exists, `kube-bench` defaults conf to the value 329 of `defaultconf`. 330 331 The selected config for a component can be referenced in `controls` using a 332 variable in the form `$<component>conf`. In the example below, we reference the 333 selected API server config file with the variable `$apiserverconf` in an `audit` 334 command. 335 336 ```yml 337 id: 1.4.1 338 text: "Ensure that the API server pod specification file permissions are 339 set to 644 or more restrictive (Scored)" 340 audit: "/bin/sh -c 'if test -e $apiserverconf; then stat -c %a $apiserverconf; fi'" 341 ``` 342 343 - `svcs`: A list of candidate unitfiles for a component. `kube-bench` checks this 344 list and selects the **first** unitfile that is found on the node. If none of the 345 unitfiles exists, `kube-bench` defaults unitfile to the value of `defaultsvc`. 346 347 The selected unitfile for a component can be referenced in `controls` via a 348 variable in the form `$<component>svc`. In the example below, the selected 349 kubelet unitfile is referenced with `$kubeletsvc` in the `remediation` of the 350 `check`. 351 352 ```yml 353 id: 2.1.1 354 # ... 355 remediation: | 356 Edit the kubelet service file $kubeletsvc 357 on each worker node and set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable. 358 --allow-privileged=false 359 Based on your system, restart the kubelet service. For example: 360 systemctl daemon-reload 361 systemctl restart kubelet.service 362 # ... 363 ``` 364 365 - `kubeconfig`: A list of candidate kubeconfig files for a component. `kube-bench` 366 checks this list and selects the **first** file that is found on the node. If none 367 of the files exists, `kube-bench` defaults kubeconfig to the value of 368 `defaultkubeconfig`. 369 370 The selected kubeconfig for a component can be referenced in `controls` with a variable in the form `$<component>kubeconfig`. In the example below, the 371 selected kubelet kubeconfig is referenced with `$kubeletkubeconfig` in the 372 `audit` command. 373 374 ```yml 375 id: 2.2.1 376 text: "Ensure that the kubelet.conf file permissions are set to 644 or 377 more restrictive (Scored)" 378 audit: "/bin/sh -c 'if test -e $kubeletkubeconfig; then stat -c %a $kubeletkubeconfig; fi'" 379 # ... 380 ```