From 7ca438b61813ee720437c12fa8b63bb535284326 Mon Sep 17 00:00:00 2001 From: Roberto Rojas Date: Tue, 5 Nov 2019 16:31:27 -0500 Subject: [PATCH] Fixes Issue 269 - Numbering to use CIS Versions (#511) * starting benchmark flag * Revert "starting benchmark flag" This reverts commit 58fc948626cb2f99a4f26e9cef3675b4d0938176. * fixes issue #269 * add more unit tests * fix bug * Update cmd/common.go Co-Authored-By: Liz Rice * fixes as per PR review * fixes as per PR review * adds more tests * fixed tests * changes as per PR Review * changes as per PR Review * updated README * Update README.md Co-Authored-By: Liz Rice * Update README.md Co-Authored-By: Liz Rice * Update README.md Co-Authored-By: Liz Rice * Update README.md Co-Authored-By: Liz Rice * changes are per PR review --- README.md | 83 +- cfg/{1.11 => cis-1.3}/config.yaml | 0 cfg/{1.11 => cis-1.3}/master.yaml | 0 cfg/{1.11 => cis-1.3}/node.yaml | 0 cfg/{1.13 => cis-1.4}/config.yaml | 0 cfg/{1.13 => cis-1.4}/master.yaml | 0 cfg/{1.13 => cis-1.4}/node.yaml | 0 cfg/config.yaml | 11 +- cfg/ocp-3.10/master.yaml | 1464 -------------------------- cfg/ocp-3.10/node.yaml | 376 ------- cfg/ocp-3.11/config.yaml | 27 - cfg/{ocp-3.10 => rh-0.7}/config.yaml | 0 cfg/{ocp-3.11 => rh-0.7}/master.yaml | 0 cfg/{ocp-3.11 => rh-0.7}/node.yaml | 0 cmd/common.go | 65 +- cmd/common_test.go | 235 +++++ cmd/root.go | 2 + cmd/util.go | 52 +- cmd/util_test.go | 62 +- 19 files changed, 424 insertions(+), 1953 deletions(-) rename cfg/{1.11 => cis-1.3}/config.yaml (100%) rename cfg/{1.11 => cis-1.3}/master.yaml (100%) rename cfg/{1.11 => cis-1.3}/node.yaml (100%) rename cfg/{1.13 => cis-1.4}/config.yaml (100%) rename cfg/{1.13 => cis-1.4}/master.yaml (100%) rename cfg/{1.13 => cis-1.4}/node.yaml (100%) delete mode 100644 cfg/ocp-3.10/master.yaml delete mode 100644 cfg/ocp-3.10/node.yaml delete mode 100644 cfg/ocp-3.11/config.yaml rename cfg/{ocp-3.10 => rh-0.7}/config.yaml (100%) rename cfg/{ocp-3.11 => rh-0.7}/master.yaml (100%) rename cfg/{ocp-3.11 => rh-0.7}/node.yaml (100%) diff --git a/README.md b/README.md index 8300c32..ff89e53 100644 --- a/README.md +++ b/README.md @@ -19,39 +19,43 @@ Tests are configured with YAML files, making this tool easy to update as test sp Table of Contents ================= -* [CIS Kubernetes Benchmark support](#cis-kubernetes-benchmark-support) -* [Installation](#installation) -* [Running kube-bench](#running-kube-bench) - * [Running inside a container](#running-inside-a-container) - * [Running in a kubernetes cluster](#running-in-a-kubernetes-cluster) - * [Running in an EKS cluster](#running-in-an-eks-cluster) - * [Installing from a container](#installing-from-a-container) - * [Installing from sources](#installing-from-sources) -* [Running on OpenShift](#running-on-openshift) -* [Output](#output) -* [Configuration](#configuration) -* [Test config YAML representation](#test-config-yaml-representation) - * [Omitting checks](#omitting-checks) -* [Roadmap](#roadmap) -* [Testing locally with kind](#testing-locally-with-kind) -* [Contributing](#contributing) - * [Bugs](#bugs) - * [Features](#features) - * [Pull Requests](#pull-requests) +- [Table of Contents](#table-of-contents) + - [CIS Kubernetes Benchmark support](#cis-kubernetes-benchmark-support) + - [Installation](#installation) + - [Running kube-bench](#running-kube-bench) + - [Running inside a container](#running-inside-a-container) + - [Running in a Kubernetes cluster](#running-in-a-kubernetes-cluster) + - [Running in an EKS cluster](#running-in-an-eks-cluster) + - [Installing from a container](#installing-from-a-container) + - [Installing from sources](#installing-from-sources) + - [Running on OpenShift](#running-on-openshift) + - [Output](#output) + - [Configuration](#configuration) + - [Test config YAML representation](#test-config-yaml-representation) + - [Omitting checks](#omitting-checks) + - [Roadmap](#roadmap) + - [Testing locally with kind](#testing-locally-with-kind) + - [Contributing](#contributing) + - [Bugs](#bugs) + - [Features](#features) + - [Pull Requests](#pull-requests) ## CIS Kubernetes Benchmark support -kube-bench supports the tests for Kubernetes as defined in the CIS Benchmarks 1.3.0 to 1.4.0 respectively. +kube-bench supports the tests for Kubernetes as defined in the CIS Benchmarks 1.3.0 to 1.4.1 respectively. | CIS Kubernetes Benchmark | kube-bench config | Kubernetes versions | |---|---|---| -| 1.3.0| 1.11 | 1.11-1.12 | -| 1.4.1| 1.13 | 1.13- | +| 1.3.0| cis-1.3 | 1.11-1.12 | +| 1.4.1| cis-1.4 | 1.13- | + By default kube-bench will determine the test set to run based on the Kubernetes version running on the machine. There is also preliminary support for Red Hat's OpenShift Hardening Guide for 3.10 and 3.11. Please note that kube-bench does not automatically detect OpenShift - see below. + + ## Installation You can choose to @@ -78,16 +82,31 @@ For example, run kube-bench against a master with version auto-detection: kube-bench master ``` -Or run kube-bench against a node with the node `controls` for Kubernetes version 1.13: +Or run kube-bench against a node with the node `controls` for Kubernetes version 1.13: ``` kube-bench node --version 1.13 ``` -`controls` for the various versions of Kubernetes can be found in directories -with same name as the Kubernetes versions under `cfg/`, for example `cfg/1.13`. -`controls` are also organized by distribution under the `cfg` directory for -example `cfg/ocp-3.10`. +`kube-bench` will map the `--version` to the corresponding CIS Benchmark version as indicated by the version mapping table above. + +For example, if you specify: + +``` +kube-bench node --version 1.13 +``` +`kube-bench` will map the `1.13` to CIS Bechmark version `cis-1.14` + +Also, you can specify `--benchmark` to run a specific CIS Benchmark version: + +``` +kube-bench node --benchmark cis-1.4 +``` + +`controls` for the various versions of CIS Benchmark can be found in directories +with same name as the CIS Benchmark versions under `cfg/`, for example `cfg/cis-1.4`. + +**Note:** **`It is an error to specify both --version and --benchmark flags together`** ### Running inside a container @@ -183,7 +202,15 @@ go build -o kube-bench . ## Running on OpenShift -kube-bench includes a set of test files for Red Hat's OpenShift hardening guide for OCP 3.10 and 3.11. To run this you will need to specify `--version ocp-3.10` when you run the `kube-bench` command (either directly or through YAML). This config version is valid for OCP 3.10 and 3.11. +| OpenShift Hardening Guide | kube-bench config | +|---|---|---| +| ocp-3.10| rh-0.7 | +| ocp-3.11| rh-0.7 | + +kube-bench includes a set of test files for Red Hat's OpenShift hardening guide for OCP 3.10 and 3.11. To run this you will need to specify `--benchmark rh-07`, or `--version ocp-3.10` or `--version ocp-3.11` + +when you run the `kube-bench` command (either directly or through YAML). + ## Output diff --git a/cfg/1.11/config.yaml b/cfg/cis-1.3/config.yaml similarity index 100% rename from cfg/1.11/config.yaml rename to cfg/cis-1.3/config.yaml diff --git a/cfg/1.11/master.yaml b/cfg/cis-1.3/master.yaml similarity index 100% rename from cfg/1.11/master.yaml rename to cfg/cis-1.3/master.yaml diff --git a/cfg/1.11/node.yaml b/cfg/cis-1.3/node.yaml similarity index 100% rename from cfg/1.11/node.yaml rename to cfg/cis-1.3/node.yaml diff --git a/cfg/1.13/config.yaml b/cfg/cis-1.4/config.yaml similarity index 100% rename from cfg/1.13/config.yaml rename to cfg/cis-1.4/config.yaml diff --git a/cfg/1.13/master.yaml b/cfg/cis-1.4/master.yaml similarity index 100% rename from cfg/1.13/master.yaml rename to cfg/cis-1.4/master.yaml diff --git a/cfg/1.13/node.yaml b/cfg/cis-1.4/node.yaml similarity index 100% rename from cfg/1.13/node.yaml rename to cfg/cis-1.4/node.yaml diff --git a/cfg/config.yaml b/cfg/config.yaml index 778a1b4..7bd7d92 100644 --- a/cfg/config.yaml +++ b/cfg/config.yaml @@ -139,4 +139,13 @@ node: svc: - "/lib/systemd/system/kube-proxy.service" defaultconf: /etc/kubernetes/addons/kube-proxy-daemonset.yaml - defaultkubeconfig: "/etc/kubernetes/proxy.conf" \ No newline at end of file + defaultkubeconfig: "/etc/kubernetes/proxy.conf" + +version_mapping: + "1.11": "cis-1.3" + "1.12": "cis-1.3" + "1.13": "cis-1.4" + "1.14": "cis-1.4" + "1.15": "cis-1.4" + "ocp-3.10": "rh-0.7" + "ocp-3.11": "rh-0.7" \ No newline at end of file diff --git a/cfg/ocp-3.10/master.yaml b/cfg/ocp-3.10/master.yaml deleted file mode 100644 index 7f82a5d..0000000 --- a/cfg/ocp-3.10/master.yaml +++ /dev/null @@ -1,1464 +0,0 @@ ---- -controls: -version: 3.10 -id: 1 -text: "Securing the OpenShift Master" -type: "master" -groups: - -- id: 1 - text: "Protecting the API Server" - checks: - - id: 1.1 - text: "Maintain default behavior for anonymous access" - type: "skip" - scored: true - - - id: 1.2 - text: "Verify that the basic-auth-file method is not enabled" - audit: "grep -A2 basic-auth-file /etc/origin/master/master-config.yaml" - tests: - test_items: - - flag: "--basic-auth-file" - compare: - op: eq - value: "" - set: false - remediation: | - Edit the kubernetes master config file /etc/origin/master/master-config.yaml and - remove the basic-auth-file entry. - - kubernetesMasterConfig: -  apiServerArguments: -    basic-auth-file: -    - /path/to/any/file - scored: true - - - id: 1.3 - text: "Insecure Tokens" - type: "skip" - scored: true - - - id: 1.4 - text: "Secure communications between the API server and master nodes" - audit: "grep -A4 kubeletClientInfo /etc/origin/master/master-config.yaml" - tests: - bin_op: and - test_items: - - flag: "kubeletClientInfo:" - compare: - op: eq - value: "kubeletClientInfo:" - set: true - - flag: "ca: ca-bundle.crt" - compare: - op: has - value: "ca-bundle.crt" - set: true - - flag: "certFile: master.kubelet-client.crt" - compare: - op: has - value: "master.kubelet-client.crt" - set: true - - flag: "keyFile: master.kubelet-client.key" - compare: - op: has - value: "master.kubelet-client.key" - set: true - - flag: "port: 10250" - compare: - op: eq - value: "port: 10250" - set: true - remediation: | - Edit the kubernetes master config file /etc/origin/master/master-config.yaml - and change it to match the below. - - kubeletClientInfo: -  ca: ca-bundle.crt -  certFile: master.kubelet-client.crt -  keyFile: master.kubelet-client.key -  port: 10250 - scored: true - - - id: 1.5 - text: "Prevent insecure bindings" - audit: "grep -A2 insecure-bind-address /etc/origin/master/master-config.yaml" - tests: - test_items: - - flag: "insecure-bind-address" - set: false - remediation: | - Edit the kubernetes master config file /etc/origin/master/master-config.yaml - and remove the insecure-bind-address entry. - - kubernetesMasterConfig: -  apiServerArguments: -    insecure-bind-address: -    - 127.0.0.1 - scored: true - - - id: 1.6 - text: "Prevent insecure port access" - audit: "grep -A2 insecure-port /etc/origin/master/master-config.yaml" - tests: - test_items: - - flag: "insecure-port" - set: false - remediation: | - Edit the kubernetes master config file /etc/origin/master/master-config.yaml - and remove the insecure-port entry. - - kubernetesMasterConfig: -  apiServerArguments: -   insecure-port: -  - 0 - scored: true - - - id: 1.7 - text: "Use Secure Ports for API Server Traffic" - audit: "grep -A2 secure-port /etc/origin/master/master-config.yaml" - tests: - bin_op: or - test_items: - - flag: "secure-port" - set: false - - flag: "secure-port" - compare: - op: nothave - value: "0" - set: true - remediation: | - Edit the kubernetes master config file /etc/origin/master/master-config.yaml - and either remove the secure-port parameter or set it to a different (non-zero) - desired port. - - kubernetesMasterConfig: -  apiServerArguments: -   secure-port: -  - 8443 - scored: true - - - id: 1.8 - text: "Do not expose API server profiling data" - type: "skip" - scored: true - - - id: 1.9 - text: "Verify repair-malformed-updates argument for API compatibility" - audit: "grep -A2 repair-malformed-updates /etc/origin/master/master-config.yaml" - tests: - bin_op: or - test_items: - - flag: "repair-malformed-updates" - set: false - - flag: "repair-malformed-updates" - compare: - op: has - value: "true" - set: true - remediation: | - Edit the kubernetes master config file /etc/origin/master/master-config.yaml - and remove the repair-malformed-updates entry or set repair-malformed-updates=true. - scored: true - - - id: 1.10 - text: "Verify that the AlwaysAdmit admission controller is disabled" - audit: "grep -A4 AlwaysAdmit /etc/origin/master/master-config.yaml" - tests: - test_items: - - flag: "AlwaysAdmit" - set: false - remediation: | - Edit the kubernetes master config file /etc/origin/master/master-config.yaml - and remove the entry below. - - AlwaysAdmit: - configuration: - kind: DefaultAdmissionConfig - apiVersion: v1 - disable: false - scored: true - - - id: 1.11 - text: "Manage the AlwaysPullImages admission controller" - audit: "grep -A4 AlwaysPullImages /etc/origin/master/master-config.yaml" - tests: - test_items: - - flag: "disable: false" - compare: - op: has - value: "false" - set: true - remediation: | - Edit the kubernetes master config file /etc/origin/master/master-config.yaml - and add the entry below. - - admissionConfig: - pluginConfig: - AlwaysPullImages: - configuration: - kind: DefaultAdmissionConfig - apiVersion: v1 - disable: false - scored: true - - - id: 1.12 - text: "Use Security Context Constraints instead of DenyEscalatingExec admission" - type: "skip" - scored: true - - - id: 1.13 - text: "Use Security Context Constraints instead of the SecurityContextDeny admission controller" - type: "skip" - scored: true - - - id: 1.14 - text: "Manage the NamespaceLifecycle admission controller" - audit: "grep -A4 NamespaceLifecycle /etc/origin/master/master-config.yaml" - tests: - test_items: - - flag: "NamespaceLifecycle" - set: false - remediation: | - Edit the kubernetes master config file /etc/origin/master/master-config.yaml - and remove the following entry. - - NamespaceLifecycle: - configuration: - kind: DefaultAdmissionConfig - apiVersion: v1 - disable: true - scored: true - - - id: 1.15 - text: "Configure API server auditing - audit log file path" - audit: "grep -A5 auditConfig /etc/origin/master/master-config.yaml" - tests: - test_items: - - flag: "enabled: true" - compare: - op: has - value: "true" - set: true - remediation: | - Edit the Openshift master config file /etc/origin/master/master-config.yaml, update the following entry and restart the API server. - - auditConfig: - auditFilePath: ""/etc/origin/master/audit-ocp.log"" - enabled: true - maximumFileRetentionDays: 30 - maximumFileSizeMegabytes: 10 - maximumRetainedFiles: 10 - - Make the same changes in the inventory/ansible variables so the changes are not - lost when an upgrade occurs. - scored: true - - - id: 1.16 - text: "Configure API server auditing - audit log retention" - audit: "grep -A5 auditConfig /etc/origin/master/master-config.yaml" - tests: - test_items: - - flag: "maximumFileRetentionDays: 30" - compare: - op: has - value: "maximumFileRetentionDays" - set: true - remediation: | - Edit the Openshift master config file /etc/origin/master/master-config.yaml, - update the maximumFileRetentionDays entry and restart the API server. - - auditConfig: - auditFilePath: ""/etc/origin/master/audit-ocp.log"" - enabled: true - maximumFileRetentionDays: 30 - maximumFileSizeMegabytes: 10 - maximumRetainedFiles: 10 - - Make the same changes in the inventory/ansible variables so the changes are not - lost when an upgrade occurs. - scored: true - - - id: 1.17 - text: "Configure API server auditing - audit log backup retention" - audit: "grep -A5 auditConfig /etc/origin/master/master-config.yaml" - tests: - test_items: - - flag: "maximumRetainedFiles: 10" - compare: - op: has - value: "maximumRetainedFiles" - set: true - remediation: | - Edit the Openshift master config file /etc/origin/master/master-config.yaml, update the maximumRetainedFiles entry, - set enabled to true and restart the API server. - - auditConfig: - auditFilePath: ""/etc/origin/master/audit-ocp.log"" - enabled: true - maximumFileRetentionDays: 30 - maximumFileSizeMegabytes: 10 - maximumRetainedFiles: 10 - - Make the same changes in the inventory/ansible variables so the changes are not - lost when an upgrade occurs. - scored: true - - - id: 1.18 - text: "Configure audit log file size" - audit: "grep -A5 auditConfig /etc/origin/master/master-config.yaml" - tests: - test_items: - - flag: "maximumFileSizeMegabytes: 30" - compare: - op: has - value: "maximumFileSizeMegabytes" - set: true - remediation: | - Edit the Openshift master config file /etc/origin/master/master-config.yaml, update the maximumFileSizeMegabytes entry, - set enabled to true and restart the API server. - - auditConfig: - auditFilePath: ""/etc/origin/master/audit-ocp.log"" - enabled: true - maximumFileRetentionDays: 30 - maximumFileSizeMegabytes: 10 - maximumRetainedFiles: 10 - - Make the same changes in the inventory/ansible variables so the changes are not - lost when an upgrade occurs. - scored: true - - - id: 1.19 - text: "Verify that authorization-mode is not set to AlwaysAllow" - audit: "grep -A1 authorization-mode /etc/origin/master/master-config.yaml" - tests: - test_items: - - flag: "authorization-mode" - set: false - remediation: | - Edit the Openshift master config file /etc/origin/master/master-config.yaml and remove the authorization-mode - entry. - - kubernetesMasterConfig: -  apiServerArguments: -    authorization-mode: -    - AllowAll - scored: true - - - id: 1.20 - text: "Verify that the token-auth-file flag is not set" - audit: "grep token-auth-file /etc/origin/master/master-config.yaml" - tests: - test_items: - - flag: "token-auth-file" - set: false - remediation: | - Edit the Openshift master config file /etc/origin/master/master-config.yaml and remove the token-auth-file - entry under apiserverArguments section. - - kubernetesMasterConfig: -  apiServerArguments: -    token-auth-file: -    - /path/to/file - scored: true - - - id: 1.21 - text: "Verify the API server certificate authority" - audit: "grep -A1 kubelet-certificate-authority /etc/origin/master/master-config.yaml" - tests: - test_items: - - flag: "kubelet-certificate-authority" - set: false - remediation: | - Edit the Openshift master config file /etc/origin/master/master-config.yaml and remove the following - configuration under apiserverArguments section. - - kubernetesMasterConfig: -  apiServerArguments: -    kubelet-certificat-authority: -    - /path/to/ca - scored: true - - - id: 1.22 - text: "Verify the API server client certificate and client key" - audit: "grep -A4 kubeletClientInfo /etc/origin/master/master-config.yaml" - tests: - bin_op: and - test_items: - - flag: "keyFile: master.kubelet-client.key" - compare: - op: has - value: "keyFile: master.kubelet-client.key" - set: true - - flag: "certFile: master.kubelet-client.crt" - compare: - op: has - value: "certFile: master.kubelet-client.crt" - set: true - remediation: | - Edit the Openshift master config file /etc/origin/master/master-config.yaml and add the following - configuration under kubeletClientInfo - - kubeletClientInfo: -  ca: ca-bundle.crt -  certFile: master.kubelet-client.crt -  keyFile: master.kubelet-client.key - port: 10250 - scored: true - - - id: 1.23 - text: "Verify that the service account lookup flag is not set" - type: "skip" - scored: true - - - id: 1.24 - text: "Verify the PodSecurityPolicy is disabled to ensure use of SecurityContextConstraints" - type: "skip" - scored: true - - - id: 1.25 - text: "Verify that the service account key file argument is not set" - audit: "grep -A9 serviceAccountConfig /etc/origin/master/master-config.yaml" - tests: - bin_op: and - test_items: - - flag: "privateKeyFile: serviceaccounts.private.key" - compare: - op: has - value: "privateKeyFile: serviceaccounts.private.key" - set: true - - flag: "serviceaccounts.public.key" - compare: - op: has - value: "serviceaccounts.public.key" - set: true - remediation: | - OpenShift API server does not use the service-account-key-file argument. - Even if value is set in master-config.yaml, it will not be used to verify - service account tokens, as it is in upstream Kubernetes. The ServiceAccount - token authenticator is configured with serviceAccountConfig.publicKeyFiles in - the master-config.yaml. OpenShift does not reuse the apiserver TLS key. - - Edit the Openshift master config file /etc/origin/master/master-config.yaml and set the privateKeyFile - and publicKeyFile configuration under serviceAccountConfig. - - serviceAccountConfig: -  limitSecretReferences: false -  managedNames: - - default -  - builder -  - deployer -  masterCA: ca-bundle.crt -   privateKeyFile: serviceaccounts.private.key -  publicKeyFiles: -  - serviceaccounts.public.key - - Verify that privateKeyFile and publicKeyFile exist and set. - scored: true - - - id: 1.26 - text: "Verify the certificate and key used for communication with etcd" - audit: "grep -A3 etcdClientInfo /etc/origin/master/master-config.yaml" - tests: - bin_op: and - test_items: - - flag: "certFile: master.etcd-client.crt" - compare: - op: has - value: "certFile: master.etcd-client.crt" - set: true - - flag: "keyFile: master.etcd-client.key" - compare: - op: has - value: "keyFile: master.etcd-client.key" - set: true - remediation: | - Edit the Openshift master config file /etc/origin/master/master-config.yaml and set keyFile and certFile - under etcdClientInfo like below. - - etcdClientInfo: -  ca: master.etcd-ca.crt - certFile: master.etcd-client.crt - keyFile: master.etcd-client.key - scored: true - - - id: 1.27 - text: "Verify that the ServiceAccount admission controller is enabled" - audit: "grep -A4 ServiceAccount /etc/origin/master/master-config.yaml" - tests: - bin_op: or - test_items: - - flag: "ServiceAccount" - set: false - - flag: "disable: false" - compare: - op: has - value: "disable: false" - set: true - remediation: | - Edit the Openshift master config file /etc/origin/master/master-config.yaml and enable ServiceAccount - admission control policy. - - ServiceAccount: - configuration: - kind: DefaultAdmissionConfig - apiVersion: v1 - disable: false - scored: true - - - id: 1.28 - text: "Verify the certificate and key used to encrypt API server traffic" - audit: "grep -A7 servingInfo /etc/origin/master/master-config.yaml" - tests: - bin_op: and - test_items: - - flag: "certFile: master.server.crt" - compare: - op: has - value: "certFile: master.server.crt" - set: true - - flag: "keyFile: master.server.key" - compare: - op: has - value: "keyFile: master.server.key" - set: true - remediation: | - Edit the Openshift master config file /etc/origin/master/master-config.yaml and set keyFile and certFile under servingInfo. - - servingInfo: -  bindAddress: 0.0.0.0:8443 -   bindNetwork: tcp4 - certFile: master.server.crt - clientCA: ca.crt - keyFile: master.server.key - maxRequestsInFlight: 500 - requestTimeoutSeconds: 3600 - scored: true - - - id: 1.29 - text: "Verify that the --client-ca-file argument is not set" - audit: "grep client-ca-file /etc/origin/master/master-config.yaml" - tests: - test_items: - - flag: "clientCA: ca.crt" - set: false - remediation: | - Edit the Openshift master config file /etc/origin/master/master-config.yaml and set clientCA under servingInfo. - - servingInfo: -  bindAddress: 0.0.0.0:8443 -   bindNetwork: tcp4 - certFile: master.server.crt - clientCA: ca.crt - keyFile: master.server.key - maxRequestsInFlight: 500 - requestTimeoutSeconds: 3600 - scored: true - - - id: 1.30 - text: "Verify the CA used for communication with etcd" - audit: "grep -A3 etcdClientInfo /etc/origin/master/master-config.yaml" - tests: - test_items: - - flag: "ca: master.etcd-ca.crt" - compare: - op: has - value: "ca: master.etcd-ca.crt" - set: true - remediation: | - Edit the Openshift master config file /etc/origin/master/master-config.yaml and set ca under etcdClientInfo. - - etcdClientInfo: -   ca: master.etcd-ca.crt - certFile: master.etcd-client.crt - keyFile: master.etcd-client.key - scored: true - - - id: 1.31 - text: "Verify that the authorization-mode argument is not set" - type: "skip" - scored: true - - - id: 1.32 - text: "Verify that the NodeRestriction admission controller is enabled" - audit: "grep -A4 NodeRestriction /etc/origin/master/master-config.yaml" - tests: - bin_op: or - test_items: - - flag: "NodeRestriction" - set: false - - flag: "disable: false" - compare: - op: has - value: "disable: false" - set: true - remediation: | - Edit the Openshift master config file /etc/origin/master/master-config.yaml and enable NodeRestriction ca under etcdClientInfo. - - NodeRestriction: - configuration: - kind: DefaultAdmissionConfig - apiVersion: v1 - disable: false - scored: true - - - id: 1.33 - text: "Configure encryption of data at rest in etcd datastore" - audit: "grep -A1 experimental-encryption-provider-config /etc/origin/master/master-config.yaml" - tests: - test_items: - - flag: "experimental-encryption-provider-config:" - compare: - op: has - value: "experimental-encryption-provider-config:" - set: true - remediation: | - Follow the instructions in the documentation to configure encryption. - https://docs.openshift.com/container-platform/3.10/admin_guide/encrypting_data.html - scored: true - - - id: 1.34 - text: "Set the encryption provider to aescbc for etcd data at rest" - audit: "grep -A1 experimental-encryption-provider-config /etc/origin/master/master-config.yaml | sed -n '2p' | awk '{ print $2 }' | xargs grep -A1 providers" - tests: - test_items: - - flag: "aescbc:" - compare: - op: has - value: "aescbc:" - set: true - remediation: | - Edit the Openshift master config file /etc/origin/master/master-config.yaml and set aescbc as the first provider in encryption provider config. - See https://docs.openshift.com/container-platform/3.10/admin_guide/encrypting_data.html. - scored: true - - - id: 1.35 - text: "Enable the EventRateLimit plugin" - audit: "grep -A4 EventRateLimit /etc/origin/master/master-config.yaml" - tests: - test_items: - - flag: "disable: false" - compare: - op: has - value: "disable: false" - set: true - remediation: | - Follow the documentation to enable the EventRateLimit plugin. - https://docs.openshift.com/container-platform/3.10/architecture/additional_concepts/admission_controllers.html#admission-controllers-general-admission-rules - scored: true - - - id: 1.36 - text: "Configure advanced auditing" - audit: "grep AdvancedAuditing /etc/origin/master/master-config.yaml" - tests: - bin_op: or - test_items: - - flag: "AdvancedAuditing" - compare: - op: eq - value: "true" - set: true - - flag: "AdvancedAuditing" - set: false - remediation: | - Edit the Openshift master config file /etc/origin/master/master-config.yaml and enable AdvancedAuditing, - - kubernetesMasterConfig: -  apiServerArguments: - feature-gates: - - AdvancedAuditing=true - scored: true - - # Review 1.1.37 in Aquasec shared doc, the tests are net zero. - - id: 1.37 - text: "Adjust the request timeout argument for your cluster resources" - audit: "grep request-timeout /etc/origin/master/master-config.yaml" - type: "manual" - remediation: | - [Manual test] - change the request-timeout value in the  /etc/origin/master/master-config.yaml - scored: true - - -- id: 2 - text: "Scheduler" - checks: - - id: 2.1 - text: "Verify that Scheduler profiling is not exposed to the web" - type: "skip" - scored: true - - -- id: 3 - text: "Controller Manager" - checks: - - id: 3.1 - text: "Adjust the terminated-pod-gc-threshold argument as needed" - audit: "grep terminated-pod-gc-threshold -A1 /etc/origin/master/master-config.yaml" - tests: - test_items: - - flag: "terminated-pod-gc-threshold:" - compare: - op: has - value: "12500" - set: true - remediation: | - Edit the Openshift master config file /etc/origin/master/master-config.yaml and enable terminated-pod-gc-threshold. - - kubernetesMasterConfig: -  controllerArguments: -     terminated-pod-gc-threshold: -    - true - - Enabling the "terminated-pod-gc-threshold" settings is optional. - scored: true - - - id: 3.2 - text: "Verify that Controller profiling is not exposed to the web" - type: "skip" - scored: true - - - id: 3.3 - text: "Verify that the --use-service-account-credentials argument is set to true" - audit: "grep -A2 use-service-account-credentials /etc/origin/master/master-config.yaml" - tests: - bin_op: or - test_items: - - flag: "use-service-account-credentials" - set: false - - flag: "true" - compare: - op: has - value: "true" - set: true - remediation: | - Edit the Openshift master config file /etc/origin/master/master-config.yaml and set use-service-account-credentials - to true under controllerArguments section. - - kubernetesMasterConfig: -  controllerArguments: -     use-service-account-credentials: -     - true - scored: true - - # Review 3.4 - - id: 3.4 - text: "Verify that the --service-account-private-key-file argument is set as appropriate" - audit: | - grep -A9 serviceAccountConfig /etc/origin/master/master-config.yaml | grep privateKeyFile; - grep -A2 service-account-private-key-file /etc/origin/master/master-config.yaml - tests: - bin_op: and - test_items: - - flag: "privateKeyFile: serviceaccounts.private.key" - compare: - op: has - value: "privateKeyFile" - - flag: "service-account-private-key-file" - set: false - remediation: - Edit the Openshift master config file /etc/origin/master/master-config.yaml and remove service-account-private-key-file - scored: true - - # Review 3.5 - - id: 3.5 - text: "Verify that the --root-ca-file argument is set as appropriate" - audit: "/bin/sh -c 'grep root-ca-file /etc/origin/master/master-config.yaml; grep -A9 serviceAccountConfig /etc/origin/master/master-config.yaml'" - tests: - bin_op: and - test_items: - - flag: "root-ca-file=/etc/origin/master/ca-bundle.crt" - compare: - op: has - value: "/etc/origin/master/ca-bundle.crt" - set: true - test_items: - - flag: "masterCA: ca-bundle.crt" - compare: - op: has - value: "ca-bundle.crt" - set: true - remediation: - Reset to OpenShift defaults OpenShift starts kube-controller-manager with - root-ca-file=/etc/origin/master/ca-bundle.crt by default.  OpenShift Advanced - Installation creates this certificate authority and configuration without any - configuration required. - - https://docs.openshift.com/container-platform/3.10/admin_guide/service_accounts.html" - scored: true - - - id: 3.6 - text: "Verify that Security Context Constraints are applied to Your Pods and Containers" - type: "skip" - scored: false - - - id: 3.7 - text: "Manage certificate rotation" - audit: "grep -B3 RotateKubeletServerCertificate=true /etc/origin/master/master-config.yaml" - tests: - test_items: - - flag: "RotateKubeletServerCertificate" - compare: - op: eq - value: "true" - set: true - remediation: - If you decide not to enable the RotateKubeletServerCertificate feature, - be sure to use the Ansible playbooks provided with the OpenShift installer to - automate re-deploying certificates. - scored: true - - -- id: 4 - text: "Configuration Files" - checks: - - id: 4.1 - text: "Verify the OpenShift default permissions for the API server pod specification file" - audit: "stat -c %a /etc/origin/node/pods/apiserver.yaml" - tests: - test_items: - - flag: "600" - compare: - op: eq - value: "600" - set: true - remediation: | - Run the below command. - - chmod 600 /etc/origin/node/pods/apiserver.yaml - scored: true - - - id: 4.2 - text: "Verify the OpenShift default file ownership for the API server pod specification file" - audit: "stat -c %U:%G /etc/origin/node/pods/apiserver.yaml" - tests: - test_items: - - flag: "root:root" - compare: - op: eq - value: "root:root" - set: true - remediation: | - Run the below command on the master node. - - chown root:root /etc/origin/node/pods/apiserver.yaml - scored: true - - - id: 4.3 - text: "Verify the OpenShift default file permissions for the controller manager pod specification file" - audit: "stat -c %a /etc/origin/node/pods/controller.yaml" - tests: - test_items: - - flag: "600" - compare: - op: eq - value: "600" - set: true - remediation: | - Run the below command on the master node. - - chmod 600 /etc/origin/node/pods/controller.yaml - scored: true - - - id: 4.4 - text: "Verify the OpenShift default ownership for the controller manager pod specification file" - audit: "stat -c %U:%G /etc/origin/node/pods/controller.yaml" - tests: - test_items: - - flag: "root:root" - compare: - op: eq - value: "root:root" - set: true - remediation: | - Run the below command on the master node. - - chown root:root /etc/origin/node/pods/controller.yaml - scored: true - - - id: 4.5 - text: "Verify the OpenShift default permissions for the scheduler pod specification file" - audit: "stat -c %a /etc/origin/node/pods/controller.yaml" - tests: - test_items: - - flag: "600" - compare: - op: eq - value: "600" - set: true - remediation: | - Run the below command. - - chmod 600 stat -c %a /etc/origin/node/pods/controller.yaml - scored: true - - - id: 4.6 - text: "Verify the scheduler pod specification file ownership set by OpenShift" - audit: "stat -c %u:%g /etc/origin/node/pods/controller.yaml" - tests: - test_items: - - flag: "root:root" - compare: - op: eq - value: "root:root" - set: true - remediation: | - Run the below command on the master node. - - chown root:root /etc/origin/node/pods/controller.yaml - scored: true - - - id: 4.7 - text: "Verify the OpenShift default etcd pod specification file permissions" - audit: "stat -c %a /etc/origin/node/pods/etcd.yaml" - tests: - test_items: - - flag: "600" - compare: - op: eq - value: "600" - set: true - remediation: | - Run the below command. - - chmod 600 /etc/origin/node/pods/etcd.yaml - scored: true - - - id: 4.8 - text: "Verify the OpenShift default etcd pod specification file ownership" - audit: "stat -c %U:%G /etc/origin/node/pods/etcd.yaml" - tests: - test_items: - - flag: "root:root" - compare: - op: eq - value: "root:root" - set: true - remediation: | - Run the below command on the master node. - - chown root:root /etc/origin/node/pods/etcd.yaml - scored: true - - - id: 4.9 - text: "Verify the default OpenShift Container Network Interface file permissions" - audit: "stat -c %a /etc/origin/openvswitch/ /etc/cni/net.d/" - 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. - - chmod 644 -R /etc/origin/openvswitch/ /etc/cni/net.d/ - scored: true - - - id: 4.10 - text: "Verify the default OpenShift Container Network Interface file ownership" - audit: "stat -c %U:%G /etc/origin/openvswitch/ /etc/cni/net.d/" - tests: - test_items: - - flag: "root:root" - compare: - op: eq - value: "root:root" - set: true - remediation: | - Run the below command on the master node. - - chown root:root /etc/origin/openvswitch/ /etc/cni/net.d/ - scored: true - - - id: 4.11 - text: "Verify the default OpenShift etcd data directory permissions" - audit: "stat -c %a /var/lib/etcd" - tests: - test_items: - - flag: "700" - compare: - op: eq - value: "700" - set: true - remediation: | - On the etcd server node, get the etcd data directory, passed as an argument --data-dir , - from the below command: - ps -ef | grep etcd - Run the below command (based on the etcd data directory found above). For example, - chmod 700 /var/lib/etcd - scored: true - - - id: 4.12 - text: "Verify the default OpenShift etcd data directory ownership" - audit: "stat -c %U:%G /var/lib/etcd" - tests: - test_items: - - flag: "etcd:etcd" - compare: - op: eq - value: "etcd:etcd" - set: true - remediation: | - Run the below command on the master node. - - chown etcd:etcd /var/lib/etcd - scored: true - - - id: 4.13 - text: "Verify the default OpenShift admin.conf file permissions" - audit: "stat -c %a /etc/origin/master/admin.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. - - chmod 644 /etc/origin/master/admin.kubeconfig" - scored: true - - - id: 4.14 - text: "Verify the default OpenShift admin.conf file ownership" - audit: "stat -c %U:%G /etc/origin/master/admin.kubeconfig" - tests: - test_items: - - flag: "root:root" - compare: - op: eq - value: "root:root" - set: true - remediation: | - Run the below command on the master node. - - chown root:root /etc/origin/master/admin.kubeconfig - scored: true - - - id: 4.15 - text: "Verify the default OpenShift scheduler.conf file permissions" - audit: "stat -c %a /etc/origin/master/openshift-master.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. - - chmod 644 /etc/origin/master/openshift-master.kubeconfig - scored: true - - - id: 4.16 - text: "Verify the default OpenShift scheduler.conf file ownership" - audit: "stat -c %U:%G /etc/origin/master/openshift-master.kubeconfig" - tests: - test_items: - - flag: "root:root" - compare: - op: eq - value: "root:root" - set: true - remediation: | - Run the below command on the master node. - - chown root:root /etc/origin/master/openshift-master.kubeconfig - scored: true - - - id: 4.17 - text: "Verify the default Openshift controller-manager.conf file permissions" - audit: "stat -c %a /etc/origin/master/openshift-master.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. - - chmod 644 /etc/origin/master/openshift-master.kubeconfig - scored: true - - - id: 4.18 - text: "Ensure that the controller-manager.conf file ownership is set to root:root (Scored)" - audit: "stat -c %U:%G /etc/origin/master/openshift-master.kubeconfig" - tests: - test_items: - - flag: "root:root" - compare: - op: eq - value: "root:root" - set: true - remediation: | - Run the below command on the master node. - - chown root:root /etc/origin/master/openshift-master.kubeconfig - scored: true - - -- id: 5 - text: "Etcd" - checks: - - id: 5.1 - text: "Verify the default OpenShift cert-file and key-file configuration" - audit: "/bin/sh -c '/usr/local/bin/master-exec etcd etcd grep ETCD_CERT_FILE=/etc/etcd/server.crt /proc/1/environ; /usr/local/bin/master-exec etcd etcd grep etcd_key_file=/etc/etcd/server.key /proc/1/environ; grep ETCD_CERT_FILE=/etc/etcd/server.crt /etc/etcd/etcd.conf; grep ETCD_KEY_FILE=/etc/etcd/server.key /etc/etcd/etcd.conf'" - tests: - bin_op: and - test_items: - - flag: "Binary file /proc/1/environ matches" - compare: - op: has - value: "Binary file /proc/1/environ matches" - set: true - - flag: "ETCD_CERT_FILE=/etc/etcd/server.crt" - compare: - op: has - value: "ETCD_CERT_FILE=/etc/etcd/server.crt" - set: true - - flag: "ETCD_KEY_FILE=/etc/etcd/server.key" - compare: - op: has - value: "ETCD_KEY_FILE=/etc/etcd/server.key" - set: true - remediation: | - Reset to the OpenShift default configuration. - scored: true - - - id: 5.2 - text: "Verify the default OpenShift setting for the client-cert-auth argument" - audit: "/bin/sh -c'/usr/local/bin/master-exec etcd etcd grep ETCD_CLIENT_CERT_AUTH=true /proc/1/environ; grep ETCD_CLIENT_CERT_AUTH /etc/etcd/etcd.conf'" - tests: - bin_op: and - test_items: - - flag: "Binary file /proc/1/environ matches" - compare: - op: has - value: "Binary file /proc/1/environ matches" - set: true - - flag: "ETCD_CLIENT_CERT_AUTH=true" - compare: - op: has - value: "ETCD_CLIENT_CERT_AUTH=true" - set: true - remediation: | - Reset to the OpenShift default configuration. - scored: true - - - id: 5.3 - text: "Verify the OpenShift default values for etcd_auto_tls" - audit: "/bin/sh -c '/usr/local/bin/master-exec etcd etcd grep ETCD_AUTO_TLS /proc/1/environ; grep ETCD_AUTO_TLS /etc/etcd/etcd.conf'" - tests: - bin_op: or - test_items: - - flag: "ETCD_AUTO_TLS=false" - compare: - op: has - value: "ETCD_AUTO_TLS=false" - set: true - - flag: "#ETCD_AUTO_TLS" - compare: - op: has - value: "#ETCD_AUTO_TLS" - set: true - remediation: | - Reset to the OpenShift default configuration. - scored: true - - - id: 5.4 - text: "Verify the OpenShift default peer-cert-file and peer-key-file arguments for etcd" - audit: "/bin/sh -c'/usr/local/bin/master-exec etcd etcd grep ETCD_PEER_CERT_FILE=/etc/etcd/peer.crt /proc/1/environ; /usr/local/bin/master-exec etcd etcd grep ETCD_PEER_KEY_FILE=/etc/etcd/peer.key /proc/1/environ; grep ETCD_PEER_CERT_FILE /etc/etcd/etcd.conf; grep ETCD_PEER_KEY_FILE /etc/etcd/etcd.conf'" - tests: - bin_op: and - test_items: - - flag: "Binary file /proc/1/environ matches" - compare: - op: has - value: "Binary file /proc/1/environ matches" - set: true - - flag: "ETCD_PEER_CERT_FILE=/etc/etcd/peer.crt" - compare: - op: has - value: "ETCD_PEER_CERT_FILE=/etc/etcd/peer.crt" - set: true - - flag: "ETCD_PEER_KEY_FILE=/etc/etcd/peer.key" - compare: - op: has - value: "ETCD_PEER_KEY_FILE=/etc/etcd/peer.key" - set: true - remediation: | - Reset to the OpenShift default configuration. - scored: true - - - id: 5.5 - text: "Verify the OpenShift default configuration for the peer-client-cert-auth" - audit: "/bin/sh -c '/usr/local/bin/master-exec etcd etcd grep ETCD_PEER_CLIENT_CERT_AUTH=true /proc/1/environ; grep ETCD_PEER_CLIENT_CERT_AUTH /etc/etcd/etcd.conf'" - tests: - bin_op: and - test_items: - - flag: "Binary file /proc/1/environ matches" - compare: - op: has - value: "Binary file /proc/1/environ matches" - set: true - - flag: "ETCD_PEER_CLIENT_CERT_AUTH=true" - compare: - op: has - value: "ETCD_PEER_CLIENT_CERT_AUTH=true" - set: true - remediation: | - Reset to the OpenShift default configuration. - scored: true - - - id: 5.6 - text: "Verify the OpenShift default configuration for the peer-auto-tls argument" - audit: "/bin/sh -c '/usr/local/bin/master-exec etcd etcd grep ETCD_PEER_AUTO_TLS /proc/1/environ; grep ETCD_PEER_AUTO_TLS /etc/etcd/etcd.conf'" - tests: - bin_op: and - test_items: - - flag: "Binary file /proc/1/environ matches" - compare: - op: has - value: "Binary file /proc/1/environ matches" - set: true - - flag: "#ETCD_PEER_AUTO_TLS=false" - compare: - op: has - value: "#ETCD_PEER_AUTO_TLS=false" - set: true - remediation: | - Reset to the OpenShift default configuration. - scored: true - - - id: 5.7 - text: "Optionally modify the wal-dir argument" - type: "skip" - scored: true - - - id: 5.8 - text: "Optionally modify the max-wals argument" - type: "skip" - scored: true - - - id: 5.9 - text: "Verify the OpenShift default configuration for the etcd Certificate Authority" - audit: "openssl x509 -in /etc/origin/master/master.etcd-ca.crt -subject -issuer -noout | sed 's/@/ /'" - tests: - test_items: - - flag: "issuer= /CN=etcd-signer" - compare: - op: has - value: "issuer= /CN=etcd-signer" - set: true - remediation: | - Reset to the OpenShift default configuration. - scored: false - - -- id: 6 - text: "General Security Primitives" - checks: - - id: 6.1 - text: "Ensure that the cluster-admin role is only used where required" - type: "manual" - remediation: | - [Manual test] - Review users, groups, serviceaccounts bound to cluster-admin: - oc get clusterrolebindings | grep cluster-admin - - Review users and groups bound to cluster-admin and decide whether they require - such access. Consider creating least-privilege roles for users and service accounts - scored: false - - - id: 6.2 - text: "Verify Security Context Constraints as in use" - type: "manual" - remediation: | - [Manual test] - Review Security Context Constraints: - oc get scc - - Use OpenShift's Security Context Constraint feature, which has been contributed - to Kubernetes as Pod Security Policies. PSPs are still beta in Kubernetes 1.10. - OpenShift ships with two SCCs: restricted and privileged. - - The two default SCCs will be created when the master is started. The restricted - SCC is granted to all authenticated users by default. - - https://docs.openshift.com/container-platform/3.10/admin_guide/manage_scc.html" - scored: false - - - id: 6.3 - text: "Use OpenShift projects to maintain boundaries between resources" - type: "manual" - remediation: | - [Manual test] - Review projects: - oc get projects - scored: false - - - id: 6.4 - text: "Create network segmentation using the Multi-tenant plugin or Network Policies" - type: "manual" - remediation: | - [Manual test] - Verify on masters the plugin being used: - grep networkPluginName /etc/origin/master/master-config.yaml - - OpenShift provides multi-tenant networking isolation (using Open vSwich and - vXLAN), to segregate network traffic between containers belonging to different - tenants (users or applications) while running on a shared cluster. Red Hat also - works with 3rd-party SDN vendors to provide the same level of capabilities - integrated with OpenShift. OpenShift SDN is included a part of OpenShift - subscription. - - OpenShift supports Kubernetes NetworkPolicy. Administrator must configure - NetworkPolicies if desired. - - https://docs.openshift.com/container-platform/3.10/architecture/networking/sdn.html#architecture-additional-concepts-sdn - - Ansible Inventory variable: os_sdn_network_plugin_name: - https://docs.openshift.com/container-platform/3.10/install/configuring_inventory_file.html - scored: false - - - id: 6.5 - text: "Enable seccomp and configure custom Security Context Constraints" - type: "manual" - remediation: | - [Manual test] - Verify SCCs that have been configured with seccomp: - oc get scc -ocustom-columns=NAME:.metadata.name,SECCOMP-PROFILES:.seccompProfiles - - OpenShift does not enable seccomp by default. To configure seccomp profiles that - are applied to pods run by the SCC, follow the instructions in the - documentation: - - https://docs.openshift.com/container-platform/3.9/admin_guide/seccomp.html#admin-guide-seccomp - scored: false - - - id: 6.6 - text: "Review Security Context Constraints" - type: "manual" - remediation: | - [Manual test] - Review SCCs: - oc describe scc - - Use OpenShift's Security Context Constraint feature, which has been contributed - to Kubernetes as Pod Security Policies. PSPs are still beta in Kubernetes 1.10. - - OpenShift ships with two SCCs: restricted and privileged. The two default SCCs - will be created when the master is started. The restricted SCC is granted to - all authenticated users by default. - - All pods are run under the restricted SCC by default. Running a pod under any - other SCC requires an account with cluster admin capabilities to grant access - for the service account. - - SecurityContextConstraints limit what securityContext is applied to pods and - containers. - - https://docs.openshift.com/container-platform/3.10/admin_guide/manage_scc.html - scored: false - - - id: 6.7 - text: "Manage Image Provenance using ImagePolicyWebhook admission controller" - type: "manual" - remediation: | - [Manual test] - Review imagePolicyConfig in /etc/origin/master/master-config.yaml. - scored: false - - - id: 6.8 - text: "Configure Network policies as appropriate" - type: "manual" - remediation: | - [Manual test] - If ovs-networkplugin is used, review network policies: - oc get networkpolicies - - OpenShift supports Kubernetes NetworkPolicy via ovs-networkpolicy plugin. - If choosing ovs-multitenant plugin, each namespace is isolated in its own - netnamespace by default. - scored: false - - - id: 6.9 - text: "Use Security Context Constraints as compensating controls for privileged containers" - type: "manual" - remediation: | - [Manual test] - 1) Determine all sccs allowing privileged containers: - oc get scc -ocustom-columns=NAME:.metadata.name,ALLOWS_PRIVILEGED:.allowPrivilegedContainer - 2) Review users and groups assigned to sccs allowing priviliged containers: - oc describe sccs - - Use OpenShift's Security Context Constraint feature, which has been contributed - to Kubernetes as Pod Security Policies. PSPs are still beta in Kubernetes 1.10. - - OpenShift ships with two SCCs: restricted and privileged. The two default SCCs - will be created when the master is started. The restricted SCC is granted to all - authenticated users by default. - - Similar scenarios are documented in the SCC - documentation, which outlines granting SCC access to specific serviceaccounts. - Administrators may create least-restrictive SCCs based on individual container - needs. - - For example, if a container only requires running as the root user, the anyuid - SCC can be used, which will not expose additional access granted by running - privileged containers. - - https://docs.openshift.com/container-platform/3.10/admin_guide/manage_scc.html - scored: false diff --git a/cfg/ocp-3.10/node.yaml b/cfg/ocp-3.10/node.yaml deleted file mode 100644 index cc894c5..0000000 --- a/cfg/ocp-3.10/node.yaml +++ /dev/null @@ -1,376 +0,0 @@ ---- -controls: -id: 2 -text: "Worker Node Security Configuration" -type: "node" -groups: -- id: 7 - text: "Kubelet" - checks: - - id: 7.1 - text: "Use Security Context Constraints to manage privileged containers as needed" - type: "skip" - scored: true - - - id: 7.2 - text: "Ensure anonymous-auth is not disabled" - type: "skip" - scored: true - - - id: 7.3 - text: "Verify that the --authorization-mode argument is set to WebHook" - 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: 7.4 - text: "Verify the OpenShift default for the client-ca-file argument" - 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: 7.5 - text: "Verify the OpenShift default setting for the read-only-port argument" - 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: 7.6 - text: "Adjust the streaming-connection-idle-timeout argument" - 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: "5m" - 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: 7.7 - text: "Verify the OpenShift defaults for the protect-kernel-defaults argument" - type: "skip" - scored: true - - - id: 7.8 - text: "Verify the OpenShift default value of true for the make-iptables-util-chains argument" - 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: 7.9 - text: "Verify that the --keep-terminated-pod-volumes argument is set to false" - 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: 7.10 - text: "Verify the OpenShift defaults for the hostname-override argument" - type: "skip" - scored: true - - - id: 7.11 - text: "Set the --event-qps argument to 0" - 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: 7.12 - text: "Verify the OpenShift cert-dir flag for HTTPS traffic" - 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: 7.13 - text: "Verify the OpenShift default of 0 for the cadvisor-port argument" - 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: 7.14 - text: "Verify that the RotateKubeletClientCertificate argument is set to true" - 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: 7.15 - text: "Verify that the RotateKubeletServerCertificate argument is set to true" - audit: "grep -B1 RotateKubeletServerCertificate=true /etc/origin/node/node-config.yaml" - tests: - 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: 8 - text: "Configuration Files" - checks: - - id: 8.1 - text: "Verify the OpenShift default permissions for the kubelet.conf file" - 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: 8.2 - text: "Verify the kubeconfig file ownership of root:root" - 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: 8.3 - text: "Verify the kubelet service file permissions of 644" - 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: 8.4 - text: "Verify the kubelet service file ownership of root:root" - 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: 8.5 - text: "Verify the OpenShift default permissions for the proxy kubeconfig file" - 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: 8.6 - text: "Verify the proxy kubeconfig file ownership of root:root" - 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: 8.7 - text: "Verify the OpenShift default permissions for the certificate authorities file." - 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: 8.8 - text: "Verify the client certificate authorities file ownership of root:root" - 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 diff --git a/cfg/ocp-3.11/config.yaml b/cfg/ocp-3.11/config.yaml deleted file mode 100644 index df15172..0000000 --- a/cfg/ocp-3.11/config.yaml +++ /dev/null @@ -1,27 +0,0 @@ ---- -## Version-specific settings that override the values in cfg/config.yaml - -master: - apiserver: - bins: - - openshift start master api - - hypershift openshift-kube-apiserver - - scheduler: - bins: - - "openshift start master controllers" - confs: - - /etc/origin/master/scheduler.json - - controllermanager: - bins: - - "openshift start master controllers" - - etcd: - bins: - - openshift start etcd - -node: - proxy: - bins: - - openshift start network diff --git a/cfg/ocp-3.10/config.yaml b/cfg/rh-0.7/config.yaml similarity index 100% rename from cfg/ocp-3.10/config.yaml rename to cfg/rh-0.7/config.yaml diff --git a/cfg/ocp-3.11/master.yaml b/cfg/rh-0.7/master.yaml similarity index 100% rename from cfg/ocp-3.11/master.yaml rename to cfg/rh-0.7/master.yaml diff --git a/cfg/ocp-3.11/node.yaml b/cfg/rh-0.7/node.yaml similarity index 100% rename from cfg/ocp-3.11/node.yaml rename to cfg/rh-0.7/node.yaml diff --git a/cmd/common.go b/cmd/common.go index ed5918b..8e6566f 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -209,15 +209,12 @@ func loadConfig(nodetype check.NodeType) string { file = nodeFile } - runningVersion := "" - if kubeVersion == "" { - runningVersion, err = getKubeVersion() - if err != nil { - exitWithError(fmt.Errorf("Version check failed: \n%s", err)) - } + benchmarkVersion, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, viper.GetViper()) + if err != nil { + exitWithError(err) } - path, err := getConfigFilePath(kubeVersion, runningVersion, file) + path, err := getConfigFilePath(benchmarkVersion, file) if err != nil { exitWithError(fmt.Errorf("can't find %s controls file in %s: %v", nodetype, cfgDir, err)) } @@ -237,6 +234,60 @@ func loadConfig(nodetype check.NodeType) string { return filepath.Join(path, file) } +func mapToBenchmarkVersion(kubeToBenchmarkMap map[string]string, kv string) (string, error) { + cisVersion, found := kubeToBenchmarkMap[kv] + for !found && (kv != defaultKubeVersion && !isEmpty(kv)) { + kv = decrementVersion(kv) + cisVersion, found = kubeToBenchmarkMap[kv] + glog.V(2).Info(fmt.Sprintf("mapToBenchmarkVersion for cisVersion: %q found: %t\n", cisVersion, found)) + } + + if !found { + glog.V(1).Info(fmt.Sprintf("mapToBenchmarkVersion unable to find a match for: %q", kv)) + glog.V(3).Info(fmt.Sprintf("mapToBenchmarkVersion kubeToBenchmarkSMap: %#v", kubeToBenchmarkMap)) + return "", fmt.Errorf("Unable to find a matching Benchmark Version match for kubernetes version: %s", kubeVersion) + } + + return cisVersion, nil +} + +func loadVersionMapping(v *viper.Viper) (map[string]string, error) { + kubeToBenchmarkMap := v.GetStringMapString("version_mapping") + if kubeToBenchmarkMap == nil || (len(kubeToBenchmarkMap) == 0) { + return nil, fmt.Errorf("config file is missing 'version_mapping' section") + } + + return kubeToBenchmarkMap, nil +} + +func getBenchmarkVersion(kubeVersion, benchmarkVersion string, v *viper.Viper) (bv string, err error) { + if !isEmpty(kubeVersion) && !isEmpty(benchmarkVersion) { + return "", fmt.Errorf("It is an error to specify both --version and --benchmark flags") + } + + if isEmpty(benchmarkVersion) { + if isEmpty(kubeVersion) { + kubeVersion, err = getKubeVersion() + if err != nil { + return "", fmt.Errorf("Version check failed: %s\nAlternatively, you can specify the version with --version", err) + } + } + + kubeToBenchmarkMap, err := loadVersionMapping(v) + if err != nil { + return "", err + } + + benchmarkVersion, err = mapToBenchmarkVersion(kubeToBenchmarkMap, kubeVersion) + if err != nil { + return "", err + } + + glog.V(2).Info(fmt.Sprintf("Mapped Kubernetes version: %s to Benchmark version: %s", kubeVersion, benchmarkVersion)) + } + return benchmarkVersion, nil +} + // isMaster verify if master components are running on the node. func isMaster() bool { glog.V(2).Info("Checking if the current node is running master components") diff --git a/cmd/common_test.go b/cmd/common_test.go index 722a73e..68bc36b 100644 --- a/cmd/common_test.go +++ b/cmd/common_test.go @@ -16,6 +16,10 @@ package cmd import ( "errors" + "fmt" + "io/ioutil" + "os" + "path/filepath" "testing" "github.com/aquasecurity/kube-bench/check" @@ -166,3 +170,234 @@ func TestIsMaster(t *testing.T) { assert.Equal(t, tc.isMaster, isMaster(), tc.name) } } + +func TestMapToCISVersion(t *testing.T) { + + viperWithData, err := loadConfigForTest() + if err != nil { + t.Fatalf("Unable to load config file %v", err) + } + kubeToBenchmarkMap, err := loadVersionMapping(viperWithData) + if err != nil { + t.Fatalf("Unable to load config file %v", err) + } + + cases := []struct { + kubeVersion string + succeed bool + exp string + }{ + {kubeVersion: "1.9", succeed: false, exp: ""}, + {kubeVersion: "1.11", succeed: true, exp: "cis-1.3"}, + {kubeVersion: "1.12", succeed: true, exp: "cis-1.3"}, + {kubeVersion: "1.13", succeed: true, exp: "cis-1.4"}, + {kubeVersion: "1.16", succeed: true, exp: "cis-1.4"}, + {kubeVersion: "ocp-3.10", succeed: true, exp: "rh-0.7"}, + {kubeVersion: "ocp-3.11", succeed: true, exp: "rh-0.7"}, + {kubeVersion: "unknown", succeed: false, exp: ""}, + } + for _, c := range cases { + rv, err := mapToBenchmarkVersion(kubeToBenchmarkMap, c.kubeVersion) + if c.succeed { + if err != nil { + t.Errorf("[%q]-Unexpected error: %v", c.kubeVersion, err) + } + + if len(rv) == 0 { + t.Errorf("[%q]-missing return value", c.kubeVersion) + } + + if c.exp != rv { + t.Errorf("[%q]- expected %q but Got %q", c.kubeVersion, c.exp, rv) + } + } else { + if c.exp != rv { + t.Errorf("mapToBenchmarkVersion kubeversion: %q Got %q expected %s", c.kubeVersion, rv, c.exp) + } + } + } +} + +func TestLoadVersionMapping(t *testing.T) { + setDefault := func(v *viper.Viper, key string, value interface{}) *viper.Viper { + v.SetDefault(key, value) + return v + } + + viperWithData, err := loadConfigForTest() + if err != nil { + t.Fatalf("Unable to load config file %v", err) + } + + cases := []struct { + n string + v *viper.Viper + succeed bool + }{ + {n: "empty", v: viper.New(), succeed: false}, + { + n: "novals", + v: setDefault(viper.New(), "version_mapping", "novals"), + succeed: false, + }, + { + n: "good", + v: viperWithData, + succeed: true, + }, + } + for _, c := range cases { + rv, err := loadVersionMapping(c.v) + if c.succeed { + if err != nil { + t.Errorf("[%q]-Unexpected error: %v", c.n, err) + } + + if len(rv) == 0 { + t.Errorf("[%q]-missing mapping value", c.n) + } + } else { + if err == nil { + t.Errorf("[%q]-Expected error but got none", c.n) + } + } + } +} + +func TestGetBenchmarkVersion(t *testing.T) { + viperWithData, err := loadConfigForTest() + if err != nil { + t.Fatalf("Unable to load config file %v", err) + } + + type getBenchmarkVersionFnToTest func(kubeVersion, benchmarkVersion string, v *viper.Viper) (string, error) + + withFakeKubectl := func(kubeVersion, benchmarkVersion string, v *viper.Viper, fn getBenchmarkVersionFnToTest) (string, error) { + execCode := `#!/bin/sh + echo "Server Version: v1.13.10" + ` + restore, err := fakeExecutableInPath("kubectl", execCode) + if err != nil { + t.Fatal("Failed when calling fakeExecutableInPath ", err) + } + defer restore() + + return fn(kubeVersion, benchmarkVersion, v) + } + + withNoPath := func(kubeVersion, benchmarkVersion string, v *viper.Viper, fn getBenchmarkVersionFnToTest) (string, error) { + restore, err := prunePath() + if err != nil { + t.Fatal("Failed when calling prunePath ", err) + } + defer restore() + + return fn(kubeVersion, benchmarkVersion, v) + } + + type getBenchmarkVersionFn func(string, string, *viper.Viper, getBenchmarkVersionFnToTest) (string, error) + cases := []struct { + n string + kubeVersion string + benchmarkVersion string + v *viper.Viper + callFn getBenchmarkVersionFn + exp string + succeed bool + }{ + {n: "both versions", kubeVersion: "1.11", benchmarkVersion: "cis-1.3", exp: "cis-1.3", callFn: withNoPath, v: viper.New(), succeed: false}, + {n: "no version-missing-kubectl", kubeVersion: "", benchmarkVersion: "", v: viperWithData, exp: "", callFn: withNoPath, succeed: false}, + {n: "no version-fakeKubectl", kubeVersion: "", benchmarkVersion: "", v: viperWithData, exp: "cis-1.4", callFn: withFakeKubectl, succeed: true}, + {n: "kubeVersion", kubeVersion: "1.11", benchmarkVersion: "", v: viperWithData, exp: "cis-1.3", callFn: withNoPath, succeed: true}, + {n: "ocpVersion310", kubeVersion: "ocp-3.10", benchmarkVersion: "", v: viperWithData, exp: "rh-0.7", callFn: withNoPath, succeed: true}, + {n: "ocpVersion311", kubeVersion: "ocp-3.11", benchmarkVersion: "", v: viperWithData, exp: "rh-0.7", callFn: withNoPath, succeed: true}, + } + for _, c := range cases { + rv, err := c.callFn(c.kubeVersion, c.benchmarkVersion, c.v, getBenchmarkVersion) + if c.succeed { + if err != nil { + t.Errorf("[%q]-Unexpected error: %v", c.n, err) + } + + if len(rv) == 0 { + t.Errorf("[%q]-missing return value", c.n) + } + + if c.exp != rv { + t.Errorf("[%q]- expected %q but Got %q", c.n, c.exp, rv) + } + } else { + if err == nil { + t.Errorf("[%q]-Expected error but got none", c.n) + } + } + } +} + +func loadConfigForTest() (*viper.Viper, error) { + viperWithData := viper.New() + viperWithData.SetConfigFile(filepath.Join("..", cfgDir, "config.yaml")) + if err := viperWithData.ReadInConfig(); err != nil { + return nil, err + } + + return viperWithData, nil +} + +type restoreFn func() + +func fakeExecutableInPath(execFile, execCode string) (restoreFn, error) { + pathenv := os.Getenv("PATH") + tmp, err := ioutil.TempDir("", "TestfakeExecutableInPath") + if err != nil { + return nil, err + } + + wd, err := os.Getwd() + if err != nil { + return nil, err + } + + err = os.Chdir(tmp) + if err != nil { + return nil, err + } + + if len(execCode) > 0 { + ioutil.WriteFile(filepath.Join(tmp, execFile), []byte(execCode), 0700) + } else { + f, err := os.OpenFile(execFile, os.O_CREATE|os.O_EXCL, 0700) + if err != nil { + return nil, err + } + err = f.Close() + if err != nil { + return nil, err + } + } + + err = os.Setenv("PATH", fmt.Sprintf("%s:%s", tmp, pathenv)) + if err != nil { + return nil, err + } + + restorePath := func() { + os.RemoveAll(tmp) + os.Chdir(wd) + os.Setenv("PATH", pathenv) + } + + return restorePath, nil +} + +func prunePath() (restoreFn, error) { + pathenv := os.Getenv("PATH") + err := os.Setenv("PATH", "") + if err != nil { + return nil, err + } + restorePath := func() { + os.Setenv("PATH", pathenv) + } + return restorePath, nil +} diff --git a/cmd/root.go b/cmd/root.go index 57711e5..e277996 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -36,6 +36,7 @@ var ( envVarsPrefix = "KUBE_BENCH" defaultKubeVersion = "1.11" kubeVersion string + benchmarkVersion string cfgFile string cfgDir string jsonFmt bool @@ -113,6 +114,7 @@ func init() { RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is ./cfg/config.yaml)") RootCmd.PersistentFlags().StringVarP(&cfgDir, "config-dir", "D", "./cfg/", "config directory") RootCmd.PersistentFlags().StringVar(&kubeVersion, "version", "", "Manually specify Kubernetes version, automatically detected if unset") + RootCmd.PersistentFlags().StringVar(&benchmarkVersion, "benchmark", "", "Manually specify CIS benchmark version. It would be an error to specify both --version and --benchmark flags") goflag.CommandLine.VisitAll(func(goflag *goflag.Flag) { RootCmd.PersistentFlags().AddGoFlag(goflag) diff --git a/cmd/util.go b/cmd/util.go index 4d439d9..c55e753 100644 --- a/cmd/util.go +++ b/cmd/util.go @@ -121,41 +121,19 @@ func getBinaries(v *viper.Viper, nodetype check.NodeType) (map[string]string, er return binmap, nil } -// getConfigFilePath locates the config files we should be using based on either the specified -// version, or the running version of kubernetes if not specified -func getConfigFilePath(specifiedVersion string, runningVersion string, filename string) (path string, err error) { - var fileVersion string +// getConfigFilePath locates the config files we should be using CIS version +func getConfigFilePath(benchmarkVersion string, filename string) (path string, err error) { + glog.V(2).Info(fmt.Sprintf("Looking for config specific CIS version %q", benchmarkVersion)) - if specifiedVersion != "" { - fileVersion = specifiedVersion - } else { - 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)) - glog.V(2).Info(fmt.Sprintf("Looking for config file: %s\n", file)) - - if _, err = os.Stat(file); !os.IsNotExist(err) { - if specifiedVersion == "" && fileVersion != runningVersion { - glog.V(1).Info(fmt.Sprintf("No test file found for %s - using tests for Kubernetes %s\n", runningVersion, fileVersion)) - } - return path, nil - } - - // If we were given an explicit version to look for, don't look for any others - if specifiedVersion != "" { - return "", err - } - - fileVersion = decrementVersion(fileVersion) - if fileVersion == "" { - return "", fmt.Errorf("no test files found <= runningVersion") - } + path = filepath.Join(cfgDir, benchmarkVersion) + file := filepath.Join(path, string(filename)) + glog.V(2).Info(fmt.Sprintf("Looking for config file: %s", file)) + + if _, err = os.Stat(file); os.IsNotExist(err) { + glog.V(2).Infof("error accessing config file: %q error: %v\n", file, err) + return "", fmt.Errorf("no test files found <= benchmark version: %s", benchmarkVersion) } + return path, nil } // decrementVersion decrements the version number @@ -163,6 +141,9 @@ func getConfigFilePath(specifiedVersion string, runningVersion string, filename // just in case someone wants to specify their own test files for that version func decrementVersion(version string) string { split := strings.Split(version, ".") + if len(split) < 2 { + return "" + } minor, err := strconv.Atoi(split[1]) if err != nil { return "" @@ -367,6 +348,11 @@ func makeSubstitutions(s string, ext string, m map[string]string) string { return s } +func isEmpty(str string) bool { + return len(strings.TrimSpace(str)) == 0 + +} + func buildComponentMissingErrorMessage(nodetype check.NodeType, component string, bins []string) string { errMessageTemplate := ` diff --git a/cmd/util_test.go b/cmd/util_test.go index 6fb6901..3e327c1 100644 --- a/cmd/util_test.go +++ b/cmd/util_test.go @@ -409,7 +409,7 @@ func TestGetConfigFilePath(t *testing.T) { t.Fatalf("Failed to create temp directory") } defer os.RemoveAll(cfgDir) - d := filepath.Join(cfgDir, "1.8") + d := filepath.Join(cfgDir, "cis-1.4") err = os.Mkdir(d, 0666) if err != nil { t.Fatalf("Failed to create temp file") @@ -417,29 +417,57 @@ func TestGetConfigFilePath(t *testing.T) { ioutil.WriteFile(filepath.Join(d, "master.yaml"), []byte("hello world"), 0666) cases := []struct { - specifiedVersion string - runningVersion string + benchmarkVersion string succeed bool exp string }{ - {runningVersion: "1.8", succeed: true, exp: d}, - {runningVersion: "1.9", succeed: true, exp: d}, - {runningVersion: "1.10", succeed: true, exp: d}, - {runningVersion: "1.1", succeed: false}, - {specifiedVersion: "1.8", succeed: true, exp: d}, - {specifiedVersion: "1.9", succeed: false}, - {specifiedVersion: "1.10", succeed: false}, + {benchmarkVersion: "cis-1.4", succeed: true, exp: d}, + {benchmarkVersion: "cis-1.5", succeed: false, exp: ""}, + {benchmarkVersion: "1.1", succeed: false, exp: ""}, } for _, c := range cases { - t.Run(c.specifiedVersion+"-"+c.runningVersion, func(t *testing.T) { - path, err := getConfigFilePath(c.specifiedVersion, c.runningVersion, "/master.yaml") - if err != nil && c.succeed { - t.Fatalf("Error %v", err) - } - if path != c.exp { - t.Fatalf("Got %s expected %s", path, c.exp) + t.Run(c.benchmarkVersion, func(t *testing.T) { + path, err := getConfigFilePath(c.benchmarkVersion, "/master.yaml") + if c.succeed { + if err != nil { + t.Fatalf("Error %v", err) + } + if path != c.exp { + t.Fatalf("Got %s expected %s", path, c.exp) + } + } else { + if err == nil { + t.Fatalf("Expected Error, but none") + } } }) } } + +func TestDecrementVersion(t *testing.T) { + + cases := []struct { + kubeVersion string + succeed bool + exp string + }{ + {kubeVersion: "1.13", succeed: true, exp: "1.12"}, + {kubeVersion: "1.15", succeed: true, exp: "1.14"}, + {kubeVersion: "1.11", succeed: true, exp: "1.10"}, + {kubeVersion: "1.1", succeed: true, exp: ""}, + {kubeVersion: "invalid", succeed: false, exp: ""}, + } + for _, c := range cases { + rv := decrementVersion(c.kubeVersion) + if c.succeed { + if c.exp != rv { + t.Fatalf("decrementVersion(%q) - Got %q expected %s", c.kubeVersion, rv, c.exp) + } + } else { + if len(rv) > 0 { + t.Fatalf("decrementVersion(%q) - Expected empty string but Got %s", c.kubeVersion, rv) + } + } + } +}