From 3e5b2f1db010700abd71bd4057f09bd9caa83da7 Mon Sep 17 00:00:00 2001 From: Barak Fatal Date: Sun, 11 Dec 2022 10:15:32 +0200 Subject: [PATCH 1/3] Added basic tests that should fail --- .../Failing/1/clusterrole1.yaml | 8 ++++++++ .../Failing/1/clusterrolebinding1.yaml | 12 ++++++++++++ .../Failing/2/clusterrole2.yaml | 8 ++++++++ .../Failing/2/clusterrolebinding2.yaml | 12 ++++++++++++ .../ImpersonatePermissions/Failing/3/Role.yaml | 10 ++++++++++ .../Failing/3/RoleBinding.yaml | 13 +++++++++++++ .../resources/ImpersonatePermissions/expected.yaml | 4 ++++ tests/kubernetes/graph/checks/test_yaml_policies.py | 4 ++++ 8 files changed, 71 insertions(+) create mode 100644 tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/1/clusterrole1.yaml create mode 100644 tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/1/clusterrolebinding1.yaml create mode 100644 tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/2/clusterrole2.yaml create mode 100644 tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/2/clusterrolebinding2.yaml create mode 100644 tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/3/Role.yaml create mode 100644 tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/3/RoleBinding.yaml create mode 100644 tests/kubernetes/graph/checks/resources/ImpersonatePermissions/expected.yaml diff --git a/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/1/clusterrole1.yaml b/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/1/clusterrole1.yaml new file mode 100644 index 00000000000..be5ebd0e57c --- /dev/null +++ b/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/1/clusterrole1.yaml @@ -0,0 +1,8 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: failing-cr1 +rules: +- apiGroups: [""] + resources: ["serviceaccounts"] + verbs: ["*"] \ No newline at end of file diff --git a/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/1/clusterrolebinding1.yaml b/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/1/clusterrolebinding1.yaml new file mode 100644 index 00000000000..92d4a2bb460 --- /dev/null +++ b/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/1/clusterrolebinding1.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: failing-crb1 +subjects: +- kind: ServiceAccount + name: over-privileged-sa1 + namespace: default +roleRef: + kind: ClusterRole + name: failing-cr1 + apiGroup: rbac.authorization.k8s.io \ No newline at end of file diff --git a/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/2/clusterrole2.yaml b/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/2/clusterrole2.yaml new file mode 100644 index 00000000000..2c98a18b469 --- /dev/null +++ b/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/2/clusterrole2.yaml @@ -0,0 +1,8 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: failing-cr2 +rules: +- apiGroups: [""] + resources: ["users"] + verbs: ["impersonate"] \ No newline at end of file diff --git a/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/2/clusterrolebinding2.yaml b/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/2/clusterrolebinding2.yaml new file mode 100644 index 00000000000..0d7ded36575 --- /dev/null +++ b/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/2/clusterrolebinding2.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: failing-crb2 +subjects: +- kind: ServiceAccount + name: over-privileged-sa2 + namespace: prod +roleRef: + kind: ClusterRole + name: failing-cr2 + apiGroup: rbac.authorization.k8s.io \ No newline at end of file diff --git a/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/3/Role.yaml b/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/3/Role.yaml new file mode 100644 index 00000000000..7f4c54ea730 --- /dev/null +++ b/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/3/Role.yaml @@ -0,0 +1,10 @@ + +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + namespace: default + name: risky-impersonate-role +rules: + - apiGroups: ["*"] + resources: ["groups", "users", "serviceccounts", "*"] + verbs: ["impersonate"] \ No newline at end of file diff --git a/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/3/RoleBinding.yaml b/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/3/RoleBinding.yaml new file mode 100644 index 00000000000..f56ac5cf94f --- /dev/null +++ b/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/3/RoleBinding.yaml @@ -0,0 +1,13 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: sa-escalate + namespace: default +subjects: +- kind: ServiceAccount + name: escalating-sa + namespace: dev +roleRef: + kind: Role + name: risky-impersonate-role + apiGroup: rbac.authorization.k8s.io \ No newline at end of file diff --git a/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/expected.yaml b/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/expected.yaml new file mode 100644 index 00000000000..7db4ff58542 --- /dev/null +++ b/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/expected.yaml @@ -0,0 +1,4 @@ +fail: + - "ClusterRoleBinding.default.failing-crb1" + - "ClusterRoleBinding.default.failing-crb2" + - "RoleBinding.dev.RoleBinding.sa-escalate" \ No newline at end of file diff --git a/tests/kubernetes/graph/checks/test_yaml_policies.py b/tests/kubernetes/graph/checks/test_yaml_policies.py index 4aca0c3df86..07ee0d797e0 100644 --- a/tests/kubernetes/graph/checks/test_yaml_policies.py +++ b/tests/kubernetes/graph/checks/test_yaml_policies.py @@ -46,6 +46,10 @@ def test_AllowPrivilegeEscalation(self): def test_RoleBindingPE(self) -> None: self.go('RoleBindingPE') + @with_k8s_graph_flags() + def test_ImpersonatePermissions(self) -> None: + self.go("ImpersonatePermissions") + def create_report_from_graph_checks_results(self, checks_results, check): report = Report("kubernetes") first_results_key = list(checks_results.keys())[0] From e6c59affb87ec8177423f6732cacfc107d120804 Mon Sep 17 00:00:00 2001 From: Barak Fatal Date: Sun, 11 Dec 2022 10:24:43 +0200 Subject: [PATCH 2/3] Added yaml check for impersonate permissions --- .../graph_checks/ImpersonatePermissions.yaml | 61 +++++++++++++++++++ .../ImpersonatePermissions/expected.yaml | 2 +- 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 checkov/kubernetes/checks/graph_checks/ImpersonatePermissions.yaml diff --git a/checkov/kubernetes/checks/graph_checks/ImpersonatePermissions.yaml b/checkov/kubernetes/checks/graph_checks/ImpersonatePermissions.yaml new file mode 100644 index 00000000000..29df1f02662 --- /dev/null +++ b/checkov/kubernetes/checks/graph_checks/ImpersonatePermissions.yaml @@ -0,0 +1,61 @@ +metadata: + id: "CKV2_K8S_3" + name: "No ServiceAccount/Node should have `impersonate` permissions for groups/users/service-accounts" + category: "KUBERNETES" +definition: + and: + - cond_type: filter + value: + - ClusterRoleBinding + - RoleBinding + operator: within + attribute: kind + - or: + - cond_type: connection + operator: not_exists + resource_types: + - ClusterRoleBinding + - RoleBinding + connected_resource_types: + - ClusterRole + - Role + - not: + cond_type: attribute + attribute: 'subjects.*.kind' + operator: within + value: + - 'Node' + - 'ServiceAccount' + resource_types: + - ClusterRoleBinding + - RoleBinding + - and: + - cond_type: connection + operator: exists + resource_types: + - ClusterRoleBinding + - RoleBinding + connected_resource_types: + - ClusterRole + - Role + - or: + - cond_type: attribute + attribute: rules.resources + operator: not_intersects + value: + - 'groups' + - 'users' + - 'serviceaccounts' + - '*' + resource_types: + - ClusterRole + - Role + - cond_type: attribute + attribute: rules.verbs + operator: not_intersects + value: + - 'impersonate' + - '*' + resource_types: + - ClusterRole + - Role diff --git a/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/expected.yaml b/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/expected.yaml index 7db4ff58542..9336a382291 100644 --- a/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/expected.yaml +++ b/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/expected.yaml @@ -1,4 +1,4 @@ fail: - "ClusterRoleBinding.default.failing-crb1" - "ClusterRoleBinding.default.failing-crb2" - - "RoleBinding.dev.RoleBinding.sa-escalate" \ No newline at end of file + - "RoleBinding.default.sa-escalate" \ No newline at end of file From 694edd684e6fa5e87057c967d52d943d6a507023 Mon Sep 17 00:00:00 2001 From: Barak Fatal Date: Sun, 11 Dec 2022 10:29:33 +0200 Subject: [PATCH 3/3] Added a passing test and fixed yaml lists --- .../Failing/1/clusterrole1.yaml | 9 ++++++--- .../Failing/2/clusterrole2.yaml | 9 ++++++--- .../ImpersonatePermissions/Failing/3/Role.yaml | 13 +++++++++---- .../Passing/1/clusterrole1.yaml | 11 +++++++++++ .../Passing/1/clusterrolebinding1.yaml | 12 ++++++++++++ .../resources/ImpersonatePermissions/expected.yaml | 4 +++- 6 files changed, 47 insertions(+), 11 deletions(-) create mode 100644 tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Passing/1/clusterrole1.yaml create mode 100644 tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Passing/1/clusterrolebinding1.yaml diff --git a/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/1/clusterrole1.yaml b/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/1/clusterrole1.yaml index be5ebd0e57c..82421dc58c0 100644 --- a/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/1/clusterrole1.yaml +++ b/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/1/clusterrole1.yaml @@ -3,6 +3,9 @@ kind: ClusterRole metadata: name: failing-cr1 rules: -- apiGroups: [""] - resources: ["serviceaccounts"] - verbs: ["*"] \ No newline at end of file +- apiGroups: + - "" + resources: + - "serviceaccounts" + verbs: + - "*" \ No newline at end of file diff --git a/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/2/clusterrole2.yaml b/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/2/clusterrole2.yaml index 2c98a18b469..54ad5bf3531 100644 --- a/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/2/clusterrole2.yaml +++ b/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/2/clusterrole2.yaml @@ -3,6 +3,9 @@ kind: ClusterRole metadata: name: failing-cr2 rules: -- apiGroups: [""] - resources: ["users"] - verbs: ["impersonate"] \ No newline at end of file +- apiGroups: + - "" + resources: + - "users" + verbs: + - "impersonate" \ No newline at end of file diff --git a/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/3/Role.yaml b/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/3/Role.yaml index 7f4c54ea730..aeeae8e5dff 100644 --- a/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/3/Role.yaml +++ b/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Failing/3/Role.yaml @@ -1,10 +1,15 @@ - apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: default name: risky-impersonate-role rules: - - apiGroups: ["*"] - resources: ["groups", "users", "serviceccounts", "*"] - verbs: ["impersonate"] \ No newline at end of file + - apiGroups: + - "*" + resources: + - "groups" + - "users" + - "serviceccounts" + - "*" + verbs: + - "impersonate" \ No newline at end of file diff --git a/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Passing/1/clusterrole1.yaml b/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Passing/1/clusterrole1.yaml new file mode 100644 index 00000000000..2a02ce3cef0 --- /dev/null +++ b/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Passing/1/clusterrole1.yaml @@ -0,0 +1,11 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: passing-cr1 +rules: +- apiGroups: + - "" + resources: + - "serviceaccounts" + verbs: + - "create" diff --git a/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Passing/1/clusterrolebinding1.yaml b/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Passing/1/clusterrolebinding1.yaml new file mode 100644 index 00000000000..3a497e862fa --- /dev/null +++ b/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/Passing/1/clusterrolebinding1.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: passing-crb1 +subjects: +- kind: ServiceAccount + name: over-privileged-sa1 + namespace: default +roleRef: + kind: ClusterRole + name: passing-cr1 + apiGroup: rbac.authorization.k8s.io \ No newline at end of file diff --git a/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/expected.yaml b/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/expected.yaml index 9336a382291..73600b3df83 100644 --- a/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/expected.yaml +++ b/tests/kubernetes/graph/checks/resources/ImpersonatePermissions/expected.yaml @@ -1,4 +1,6 @@ fail: - "ClusterRoleBinding.default.failing-crb1" - "ClusterRoleBinding.default.failing-crb2" - - "RoleBinding.default.sa-escalate" \ No newline at end of file + - "RoleBinding.default.sa-escalate" +pass: + - "ClusterRoleBinding.default.passing-crb1" \ No newline at end of file