mirror of
https://github.com/falcosecurity/falco.git
synced 2025-09-16 06:48:31 +00:00
JSON/K8s Audit Evts extract multiple typed values
Refactor how JSON event/k8s audit events extract values in two important ways: 1. An event can now extract multiple values. 2. The extracted value is a class json_event_value instead of a simple string. The driver for 1. was that some filtercheck fields like "ka.req.container.privileged" actually should extract multiple values, as a pod can have multiple containers and it doesn't make sense to summarize that down to a single value. The driver for 2. is that by having an object represent a single extracted value, you can also hold things like numbers e.g. ports, uids, gids, etc. and ranges e.g. [0:3]. With an object, you can override operators ==, <, etc. to do comparisons between the numbers and ranges, or even set membership tests between extracted numbers and sets of ranges. This is really handy for a lot of new fields implemented as a part of PSP support, where you end up having to check for overlaps between the paths, images, ports, uids, etc in a K8s Audit Event and the acceptable values, ranges, path prefixes enumerated in a PSP. Implementing these changes also involve an overhaul of how aliases are implemented. Instead of having an optional "formatting" function, where arguments to the formatting function were expressed as text within the index, define optional extraction and indexing functions. If an extraction function is defined, it's responsible for taking the full json object and calling add_extracted_value() to add values. There's a default extraction function that uses a list of json_pointers with automatic iteration over array values returned by a json pointer. There's still a notion of filter fields supporting indexes--that's simply handled within the default extraction or custom extraction function. And for most fields, there won't be a need to write a custom extraction function simply to implement indexing. Within a json_event_filter_check object, instead of having a single extracted value as a string, hold a vector of extracted json_event_value objects (vector because order matters) and a set of json_event_value objects (for set comparisons) as m_evalues. Values on the right hand side of the expression are held as a set m_values. json_event_filter_check::compare now supports IN/INTERSECTS as set comparisons. It also supports PMATCH using path_prefix_search objects, which simplifies checks like ka.req.pod.volumes.hostpath--now they can be expressed as "ka.req.pod.volumes.hostpath intersects (/proc, /var/run/docker.sock, /, /etc, /root)" instead of "ka.req.volume.hostpath[/proc]=true or ka.req.volume.hostpath[/root]=true or ...". Define ~10 new filtercheck fields that extract pod properties like hostIpc, readOnlyRootFilesystem, etc. that are relevant for PSP validation. As a part of these changes, also clarify the names of filter fields related to pods to always have a .pod in the name. Furthermore, fields dealing with containers in a pod always have a .pod.containers prefix in the name. Finally, change the comparisons for existing k8s audit rules to use "intersects" and/or "in" when appropriate instead of a single equality comparison. Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
This commit is contained in:
committed by
Leo Di Donato
parent
b6fec781b7
commit
154dd18c8f
@@ -55,7 +55,7 @@
|
||||
# your environment. In this main falco rules file, there isn't any way
|
||||
# to know all the containers that can run, so any container is
|
||||
# allowed, by using the always_true macro. In the overridden macro, the condition
|
||||
# would look something like (ka.req.container.image.repository=my-repo/my-image)
|
||||
# would look something like (ka.req.pod.containers.image.repository in (my-repo/my-image))
|
||||
- macro: allowed_k8s_containers
|
||||
condition: (k8s_audit_always_true)
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
desc: >
|
||||
Detect an attempt to start a pod with a container image outside of a list of allowed images.
|
||||
condition: kevt and pod and kcreate and not allowed_k8s_containers
|
||||
output: Pod started with container not in allowed list (user=%ka.user.name pod=%ka.resp.name ns=%ka.target.namespace image=%ka.req.container.image)
|
||||
output: Pod started with container not in allowed list (user=%ka.user.name pod=%ka.resp.name ns=%ka.target.namespace images=%ka.req.pod.containers.image)
|
||||
priority: WARNING
|
||||
source: k8s_audit
|
||||
tags: [k8s]
|
||||
@@ -116,26 +116,22 @@
|
||||
- rule: Create Privileged Pod
|
||||
desc: >
|
||||
Detect an attempt to start a pod with a privileged container
|
||||
condition: kevt and pod and kcreate and ka.req.container.privileged=true and not ka.req.container.image.repository in (falco_privileged_images)
|
||||
output: Pod started with privileged container (user=%ka.user.name pod=%ka.resp.name ns=%ka.target.namespace image=%ka.req.container.image)
|
||||
condition: kevt and pod and kcreate and ka.req.pod.containers.privileged intersects (true) and not ka.req.pod.containers.image.repository in (falco_privileged_images)
|
||||
output: Pod started with privileged container (user=%ka.user.name pod=%ka.resp.name ns=%ka.target.namespace images=%ka.req.pod.containers.image)
|
||||
priority: WARNING
|
||||
source: k8s_audit
|
||||
tags: [k8s]
|
||||
|
||||
- macro: sensitive_vol_mount
|
||||
condition: >
|
||||
(ka.req.volume.hostpath[/proc*]=true or
|
||||
ka.req.volume.hostpath[/var/run/docker.sock]=true or
|
||||
ka.req.volume.hostpath[/]=true or
|
||||
ka.req.volume.hostpath[/etc]=true or
|
||||
ka.req.volume.hostpath[/root*]=true)
|
||||
(ka.req.pod.volumes.hostpath intersects (/proc, /var/run/docker.sock, /, /etc, /root))
|
||||
|
||||
- rule: Create Sensitive Mount Pod
|
||||
desc: >
|
||||
Detect an attempt to start a pod with a volume from a sensitive host directory (i.e. /proc).
|
||||
Exceptions are made for known trusted images.
|
||||
condition: kevt and pod and kcreate and sensitive_vol_mount and not ka.req.container.image.repository in (falco_sensitive_mount_images)
|
||||
output: Pod started with sensitive mount (user=%ka.user.name pod=%ka.resp.name ns=%ka.target.namespace image=%ka.req.container.image mounts=%jevt.value[/requestObject/spec/volumes])
|
||||
condition: kevt and pod and kcreate and sensitive_vol_mount and not ka.req.pod.containers.image.repository in (falco_sensitive_mount_images)
|
||||
output: Pod started with sensitive mount (user=%ka.user.name pod=%ka.resp.name ns=%ka.target.namespace images=%ka.req.pod.containers.image volumes=%jevt.value[/requestObject/spec/volumes])
|
||||
priority: WARNING
|
||||
source: k8s_audit
|
||||
tags: [k8s]
|
||||
@@ -143,8 +139,8 @@
|
||||
# Corresponds to K8s CIS Benchmark 1.7.4
|
||||
- rule: Create HostNetwork Pod
|
||||
desc: Detect an attempt to start a pod using the host network.
|
||||
condition: kevt and pod and kcreate and ka.req.container.host_network=true and not ka.req.container.image.repository in (falco_hostnetwork_images)
|
||||
output: Pod started using host network (user=%ka.user.name pod=%ka.resp.name ns=%ka.target.namespace image=%ka.req.container.image)
|
||||
condition: kevt and pod and kcreate and ka.req.pod.host_network intersects (true) and not ka.req.pod.containers.image.repository in (falco_hostnetwork_images)
|
||||
output: Pod started using host network (user=%ka.user.name pod=%ka.resp.name ns=%ka.target.namespace images=%ka.req.pod.containers.image)
|
||||
priority: WARNING
|
||||
source: k8s_audit
|
||||
tags: [k8s]
|
||||
@@ -220,7 +216,7 @@
|
||||
- rule: Pod Created in Kube Namespace
|
||||
desc: Detect any attempt to create a pod in the kube-system or kube-public namespaces
|
||||
condition: kevt and pod and kcreate and ka.target.namespace in (kube-system, kube-public)
|
||||
output: Pod created in kube namespace (user=%ka.user.name pod=%ka.resp.name ns=%ka.target.namespace image=%ka.req.container.image)
|
||||
output: Pod created in kube namespace (user=%ka.user.name pod=%ka.resp.name ns=%ka.target.namespace images=%ka.req.pod.containers.image)
|
||||
priority: WARNING
|
||||
source: k8s_audit
|
||||
tags: [k8s]
|
||||
@@ -257,7 +253,7 @@
|
||||
|
||||
- rule: ClusterRole With Wildcard Created
|
||||
desc: Detect any attempt to create a Role/ClusterRole with wildcard resources or verbs
|
||||
condition: kevt and (role or clusterrole) and kcreate and (ka.req.role.rules.resources contains '"*"' or ka.req.role.rules.verbs contains '"*"')
|
||||
condition: kevt and (role or clusterrole) and kcreate and (ka.req.role.rules.resources intersects ("*") or ka.req.role.rules.verbs intersects ("*"))
|
||||
output: Created Role/ClusterRole with wildcard (user=%ka.user.name role=%ka.target.name rules=%ka.req.role.rules)
|
||||
priority: WARNING
|
||||
source: k8s_audit
|
||||
@@ -265,11 +261,7 @@
|
||||
|
||||
- macro: writable_verbs
|
||||
condition: >
|
||||
(ka.req.role.rules.verbs contains create or
|
||||
ka.req.role.rules.verbs contains update or
|
||||
ka.req.role.rules.verbs contains patch or
|
||||
ka.req.role.rules.verbs contains delete or
|
||||
ka.req.role.rules.verbs contains deletecollection)
|
||||
(ka.req.role.rules.verbs intersects (create, update, patch, delete, deletecollection))
|
||||
|
||||
- rule: ClusterRole With Write Privileges Created
|
||||
desc: Detect any attempt to create a Role/ClusterRole that can perform write-related actions
|
||||
@@ -281,7 +273,7 @@
|
||||
|
||||
- rule: ClusterRole With Pod Exec Created
|
||||
desc: Detect any attempt to create a Role/ClusterRole that can exec to pods
|
||||
condition: kevt and (role or clusterrole) and kcreate and ka.req.role.rules.resources contains "pods/exec"
|
||||
condition: kevt and (role or clusterrole) and kcreate and ka.req.role.rules.resources intersects ("pods/exec")
|
||||
output: Created Role/ClusterRole with pod exec privileges (user=%ka.user.name role=%ka.target.name rules=%ka.req.role.rules)
|
||||
priority: WARNING
|
||||
source: k8s_audit
|
||||
@@ -395,7 +387,7 @@
|
||||
- rule: K8s Role/Clusterrolebinding Created
|
||||
desc: Detect any attempt to create a clusterrolebinding
|
||||
condition: (kactivity and kcreate and clusterrolebinding and response_successful)
|
||||
output: K8s Cluster Role Binding Created (user=%ka.user.name binding=%ka.target.name subjects=%ka.req.binding.subjects role=%ka.req.binding.role resp=%ka.response.code decision=%ka.auth.decision reason=%ka.auth.reason foo=%ka.req.binding.subject.has_name[cluster-admin])
|
||||
output: K8s Cluster Role Binding Created (user=%ka.user.name binding=%ka.target.name subjects=%ka.req.binding.subjects role=%ka.req.binding.role resp=%ka.response.code decision=%ka.auth.decision reason=%ka.auth.reason)
|
||||
priority: INFO
|
||||
source: k8s_audit
|
||||
tags: [k8s]
|
||||
|
Reference in New Issue
Block a user