From 08d987af812ef0edcf35ddc135c7a185dbce44e4 Mon Sep 17 00:00:00 2001 From: Oren Zohar <85433724+oren-zohar@users.noreply.github.com> Date: Mon, 22 Nov 2021 19:44:12 +0200 Subject: [PATCH] [Security Policies] [New Rule] Api server first automated rule (1.2.2) (#11) --- compliance/cis_k8s/rules/cis_1_2_2/rule.rego | 26 ++++++++++++++++++ compliance/cis_k8s/rules/cis_1_2_2/test.rego | 18 ++++++++++++ compliance/cis_k8s/test_data.rego | 6 ++++ compliance/lib/common.rego | 29 ++++++++++++++++++++ compliance/lib/data_adapter.rego | 10 +++++++ 5 files changed, 89 insertions(+) create mode 100644 compliance/cis_k8s/rules/cis_1_2_2/rule.rego create mode 100644 compliance/cis_k8s/rules/cis_1_2_2/test.rego diff --git a/compliance/cis_k8s/rules/cis_1_2_2/rule.rego b/compliance/cis_k8s/rules/cis_1_2_2/rule.rego new file mode 100644 index 00000000..cd464bac --- /dev/null +++ b/compliance/cis_k8s/rules/cis_1_2_2/rule.rego @@ -0,0 +1,26 @@ +package compliance.cis_k8s.rules.cis_1_2_2 + +import data.compliance.cis_k8s +import data.compliance.lib.common +import data.compliance.lib.data_adapter + +# Ensure that the --basic-auth-file argument is not set (Automated) +finding = result { + command_args := data_adapter.command_args + rule_evaluation := common.array_contains(command_args, "--basic-auth-file") == false + + # set result + result := { + "evaluation": common.calculate_result(rule_evaluation), + "evidence": {"command_args": command_args}, + } +} + +metadata = { + "name": "Ensure that the --basic-auth-file argument is not set", + "description": "Basic authentication uses plaintext credentials for authentication. Currently, the basic authentication credentials last indefinitely, and the password cannot be changed without restarting the API server. The basic authentication is currently supported for convenience. Hence, basic authentication should not be used.", + "impact": "You will have to configure and use alternate authentication mechanisms such as tokens and certificates. Username and password for basic authentication could no longer be used.", + "tags": array.concat(cis_k8s.default_tags, ["CIS 1.2.2", "API Server"]), + "benchmark": cis_k8s.benchmark_name, + "remediation": "Follow the documentation and configure alternate mechanisms for authentication. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and remove the --basic-auth-file= parameter.", +} diff --git a/compliance/cis_k8s/rules/cis_1_2_2/test.rego b/compliance/cis_k8s/rules/cis_1_2_2/test.rego new file mode 100644 index 00000000..60568bec --- /dev/null +++ b/compliance/cis_k8s/rules/cis_1_2_2/test.rego @@ -0,0 +1,18 @@ +package compliance.cis_k8s.rules.cis_1_2_2 + +import data.cis_k8s.test_data +import data.lib.test + +test_violation { + test.assert_fail(finding) with input as rule_input("api_server", "--basic-auth-file") +} + +test_pass { + test.assert_pass(finding) with input as rule_input("api_server", "") +} + +test_not_evaluated { + not finding with input as rule_input("some_process", "") +} + +rule_input(process_type, argument) = test_data.api_server_input(process_type, [argument]) diff --git a/compliance/cis_k8s/test_data.rego b/compliance/cis_k8s/test_data.rego index 51c4d531..a49190f2 100644 --- a/compliance/cis_k8s/test_data.rego +++ b/compliance/cis_k8s/test_data.rego @@ -9,3 +9,9 @@ filesystem_input(filename, mode, uid, gid) = { "uid": uid, "gid": gid, } + +# Recivies an array of arguments representing the API Server command +api_server_input(process_type, arguments) = { + "type": process_type, + "command": concat(" ", array.concat(["kube-apiserver"], arguments)), +} diff --git a/compliance/lib/common.rego b/compliance/lib/common.rego index ab1fd176..5006bf25 100644 --- a/compliance/lib/common.rego +++ b/compliance/lib/common.rego @@ -22,6 +22,35 @@ file_permission_match(filemode, user, group, other) { true } +array_contains(array, key) { + contains(array[_], key) +} else = false { + true +} + +# gets argument's value +get_arg_value(arguments, key) = value { + contains(arguments[i], key) + argument := arguments[i] + [_, value] := split(argument, "=") +} + +# checks if argument contains value (argument format is csv) +arg_values_contains(arguments, key, value) { + argument := get_arg_value(arguments, key) + values := split(argument, ",") + value = values[_] +} else = false { + true +} + +# checks if a argument is set to greater value then minimum +arg_at_least(arguments, key, minimum) { + value := get_arg_value(arguments, key) + to_number(value) >= minimum +} else = false { + true + # check if file is in path file_in_path(path, file_path) { closed_path := concat("", [file_path, "/"]) # make sure last dir name is closed by "/" diff --git a/compliance/lib/data_adapter.rego b/compliance/lib/data_adapter.rego index 4e06c4db..417384b7 100644 --- a/compliance/lib/data_adapter.rego +++ b/compliance/lib/data_adapter.rego @@ -28,3 +28,13 @@ owner_group_id = gid { is_filesystem gid = input.gid } + +is_process { + input.type == "api_server" +} + +# split the process args string into an array +command_args = args { + is_process + args = split(input.command, " ") +}