diff --git a/.gitignore b/.gitignore index 524090b7..c4228841 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ -data.json +output.json +data.yaml input.json \ No newline at end of file diff --git a/compliance/cis.rego b/compliance/cis.rego deleted file mode 100644 index 0714b9c4..00000000 --- a/compliance/cis.rego +++ /dev/null @@ -1,13 +0,0 @@ -package compliance.cis - -# CIS 1.1.1 -findings[x] { - data.rules.cis_1_1_1 - x = data.compliance.cis.rules.cis_1_1_1.finding -} - -# CIS 1.2.2 -findings[x] { - data.rules.cis_1_2_2 - x = data.compliance.cis.rules.cis_1_2_2.finding -} \ No newline at end of file diff --git a/compliance/cis_k8s.rego b/compliance/cis_k8s.rego new file mode 100644 index 00000000..e054d10d --- /dev/null +++ b/compliance/cis_k8s.rego @@ -0,0 +1,11 @@ +package compliance.cis_k8s + +import data.compliance.cis.rules + +default_tags := ["CIS", "CIS v1.6.0", "Kubernetes"] + +findings[finding] { + some rule_id + data.activated_rules.cis_k8s[rule_id] + finding = rules[rule_id].finding +} diff --git a/compliance/lib/common.rego b/compliance/lib/common.rego new file mode 100644 index 00000000..bd6d9a17 --- /dev/null +++ b/compliance/lib/common.rego @@ -0,0 +1,17 @@ +package compliance.lib.common + +# set the rule result +calculate_result(evaluation) = "passed" { + evaluation +} else = "violation" + +file_ownership_match(uid, gid, requierd_uid, requierd_gid) { + uid == requierd_uid + gid == requierd_gid +} else = false + +# todo: compare performance of regex alternatives +file_permission_match(filemode, user, group, other) { + pattern = sprintf("0?[0-%d][0-%d][0-%d]", [user, group, other]) + regex.match(pattern, filemode) +} else = false \ No newline at end of file diff --git a/compliance/lib/data_adapter.rego b/compliance/lib/data_adapter.rego new file mode 100644 index 00000000..90c722d2 --- /dev/null +++ b/compliance/lib/data_adapter.rego @@ -0,0 +1,30 @@ +package compliance.lib.data_adapter + +is_osquery { + input.osquery +} + +is_file { + is_osquery + input.osquery.filename +} + +filename = file_name { + is_file + file_name = input.osquery.filename +} + +filemode = file_mode { + is_file + file_mode = input.osquery.mode +} + +owner_user_id = uid { + is_file + uid = input.osquery.uid +} + +owner_group_id = gid { + is_file + gid = input.osquery.gid +} diff --git a/compliance/lib/osquery.rego b/compliance/lib/osquery.rego deleted file mode 100644 index 0488a6a3..00000000 --- a/compliance/lib/osquery.rego +++ /dev/null @@ -1,21 +0,0 @@ -package compliance.lib.osquery - -is_osquery { - input.osquery -} - - -is_file { - is_osquery - input.osquery.filename -} - -filename = x { - is_file - x = input.osquery.filename -} - -filemode = x { - is_file - x = input.osquery.mode -} \ No newline at end of file diff --git a/compliance/lib/test.rego b/compliance/lib/test.rego new file mode 100644 index 00000000..5fb73d30 --- /dev/null +++ b/compliance/lib/test.rego @@ -0,0 +1,9 @@ +package lib.test + +rule_pass(finding) { + finding.evaluation == "passed" +} + +rule_violation(finding) { + finding.evaluation == "violation" +} diff --git a/compliance/rules/cis_1_1_1/cis_1_1_1.rego b/compliance/rules/cis_1_1_1/cis_1_1_1.rego deleted file mode 100644 index a44f1d03..00000000 --- a/compliance/rules/cis_1_1_1/cis_1_1_1.rego +++ /dev/null @@ -1,17 +0,0 @@ -package compliance.cis.rules.cis_1_1_1 - -import data.compliance.lib.osquery - -finding = {"message": msg, "tags": tags, "result": result} { - osquery.filename == "kube-apiserver.yaml" - filemode := osquery.filemode - pattern := "0?(0|1|2|3|4|5|6)(0|1|2|3|4)(0|1|2|3|4)" - # not regex.match(pattern, filemode) - result := calculate_result(false) - msg := "Ensure that the API server pod specification file permissions are set to 644 or more restrictive (Automated)" - tags := ["cis", "cis 1.1.1", "kubernetes"] -} - -calculate_result(passed) = "passed" { - passed -} else = "violation" \ No newline at end of file diff --git a/compliance/rules/cis_1_1_1/rule.rego b/compliance/rules/cis_1_1_1/rule.rego new file mode 100644 index 00000000..d9f98ac4 --- /dev/null +++ b/compliance/rules/cis_1_1_1/rule.rego @@ -0,0 +1,20 @@ +package compliance.cis.rules.cis_1_1_1 + +import data.compliance.lib.data_adapter +import data.compliance.lib.common +import data.compliance.cis_k8s + +# Ensure that the API server pod specification file permissions are set to 644 or more restrictive +finding = result { + data_adapter.filename == "kube-apiserver.yaml" + filemode := data_adapter.filemode + rule_evaluation := common.file_permission_match(filemode, 6, 4, 4) + + # set result + result := { + "evaluation" : common.calculate_result(rule_evaluation), + "evidence" : { "filemode" : filemode }, + "rule_name" : "Ensure that the API server pod specification file permissions are set to 644 or more restrictive", + "tags" : array.concat(cis_k8s.default_tags, ["CIS 1.1.1"]) + } +} \ No newline at end of file diff --git a/compliance/rules/cis_1_1_1/test.rego b/compliance/rules/cis_1_1_1/test.rego new file mode 100644 index 00000000..54511b18 --- /dev/null +++ b/compliance/rules/cis_1_1_1/test.rego @@ -0,0 +1,21 @@ +package compliance.cis.rules.cis_1_1_1 + +import data.lib.test + +test_violation { + test.rule_violation(finding) with input as rule_input("0700") +} + +test_pass { + test.rule_pass(finding) with input as rule_input("0644") +} + +rule_input(filemode) = { + "osquery": { + "mode": filemode, + "path": "/hostfs/etc/kubernetes/manifests/kube-apiserver.yaml", + "uid": "root", + "filename": "kube-apiserver.yaml", + "gid": "root" + } +} \ No newline at end of file diff --git a/compliance/rules/cis_1_1_2/rule.rego b/compliance/rules/cis_1_1_2/rule.rego new file mode 100644 index 00000000..692fe1d0 --- /dev/null +++ b/compliance/rules/cis_1_1_2/rule.rego @@ -0,0 +1,22 @@ +package compliance.cis.rules.cis_1_1_2 + +import data.compliance.lib.data_adapter +import data.compliance.lib.common +import data.compliance.cis_k8s + + +# Ensure that the API server pod specification file ownership is set to root:root +finding = result { + data_adapter.filename == "kube-apiserver.yaml" + uid = data_adapter.owner_user_id + gid = data_adapter.owner_group_id + rule_evaluation := common.file_ownership_match(uid, gid, "root", "root") + + # set result + result := { + "evaluation" : common.calculate_result(rule_evaluation), + "evidence" : {"uid" : uid, "gid" : gid}, + "rule_name" : "Ensure that the API server pod specification file ownership is set to root:root", + "tags" : array.concat(cis_k8s.default_tags, ["CIS 1.1.2"]) + } +} \ No newline at end of file diff --git a/compliance/rules/cis_1_1_2/test.rego b/compliance/rules/cis_1_1_2/test.rego new file mode 100644 index 00000000..08cc835a --- /dev/null +++ b/compliance/rules/cis_1_1_2/test.rego @@ -0,0 +1,23 @@ +package compliance.cis.rules.cis_1_1_2 + +import data.lib.test + +test_violation { + test.rule_violation(finding) with input as rule_input("root", "user") + test.rule_violation(finding) with input as rule_input("user", "root") + test.rule_violation(finding) with input as rule_input("user", "user") +} + +test_pass { + test.rule_pass(finding) with input as rule_input("root", "root") +} + +rule_input(uid, gid) = { + "osquery": { + "mode": "0644", + "path": "/hostfs/etc/kubernetes/manifests/kube-apiserver.yaml", + "uid": uid, + "filename": "kube-apiserver.yaml", + "gid": gid + } +} \ No newline at end of file diff --git a/data.json b/data.json deleted file mode 100644 index ab562902..00000000 --- a/data.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "rules": { - "cis_1_2_1": true - } -} \ No newline at end of file diff --git a/input.json b/input.json deleted file mode 100644 index f2ca1e8b..00000000 --- a/input.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "agent": { - "hostname": "kind-1w-1c-control-plane", - "name": "kind-1w-1c-control-plane", - "id": "5997e578-56af-464a-af29-925d564724c4", - "ephemeral_id": "483a0204-fd4f-4fa6-9031-87676e3be5f1", - "type": "osquerybeat", - "version": "7.14.0" - }, - "osquery": { - "gid": 0, - "atime": 1633537471, - "type": "regular", - "mtime": 1633278242, - "directory": "/hostfs/etc/kubernetes/manifests", - "inode": 2502045, - "mode": "0600", - "uid": 0, - "path": "/hostfs/etc/kubernetes/manifests/kube-apiserver.yaml", - "filename": "kube-apiserver.yaml", - "size": 3826, - "btime": 0, - "symlink": 0, - "ctime": 1633278242, - "block_size": 4096, - "device": 0, - "hard_links": 1 - }, - "elastic_agent": { - "id": "5997e578-56af-464a-af29-925d564724c4", - "version": "7.14.0", - "snapshot": false - }, - "type": "kind-1w-1c-control-plane", - "action_data": { - "query": "SELECT * FROM file WHERE path LIKE \"/hostfs/etc/kubernetes/manifests/%\";", - "id": "520f1027-4d26-4746-8b2b-efe6a84ff958" - }, - "@timestamp": "2021-10-07T11:54:50.409Z", - "ecs": { - "version": "1.10.0" - }, - "action_id": "fd14a9bd-f885-4e85-98a4-59b5a25cf81c", - "host": { - "hostname": "kind-1w-1c-control-plane", - "os": { - "kernel": "5.10.25-linuxkit", - "codename": "Core", - "name": "CentOS Linux", - "family": "redhat", - "type": "linux", - "version": "7 (Core)", - "platform": "centos" - }, - "containerized": true, - "ip": ["172.20.0.3", "fc00:f853:ccd:e793::3", "fe80::42:acff:fe14:3"], - "id": "bb43eb848699cf59adb70cc299cb4597", - "mac": ["02:42:ac:14:00:03"], - "architecture": "x86_64" - }, - "event": { - "agent_id_status": "verified", - "ingested": "2021-10-07T11:54:52.832230793Z" - } -} diff --git a/main.rego b/main.rego index 0e349905..f446add0 100644 --- a/main.rego +++ b/main.rego @@ -1,11 +1,11 @@ package main -import data.compliance.cis +import data.compliance.cis_k8s # input is a resource -# data is configuration +# data is policy/configuration # output is findings resource = input -findings = cis.findings +findings = cis_k8s.findings