falco
The following gives an overview of Falco, a security tool that provides runtime security across hosts, containers, Kubernetes, and cloud environments.
Falco is a rule engine, it enables the detection of abnormal behavior, potential security threats, and compliance violations in a container, including:
- execution of a shell
- host’s volume mounted
- installation of a package
- launched of a new process
- port opening
- creation of a privileged container
Falco comes with a set of predefined rules, and it allows custom rules to be added. When a rule is met, Falco produces an event.
Prerequisites
We need a Kubernetes cluster, which can be created following these instructions. We also need the kubectl binary configured with the cluster’s kubeconfig, and the helm binary.
Installing Falco
We install Falco with Helm:
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm install falco falcosecurity/falco --set tty=true --version 4.17.0
In the background, it installed Falco agents, which are running as Pods managed by a DaemonSet.
Triggering an event
First, we run a simple Pod based on nginx.
kubectl run www --image nginx:1.24
Next, we launch a new process in the Pod’s container.
kubectl exec -it www -- sh -c "ls /"
Falco detects this new process, we can see that from the logs.
k logs -l app.kubernetes.io/name=falco
...
11:09:37.291008432: Notice A shell was spawned in a container with an attached terminal (evt_type=execve user=root user_uid=0 user_loginuid=-1 process=sh proc_exepath=/bin/dash parent=runc command=sh -c ls / terminal=34816 exe_flags=EXE_WRITABLE|EXE_LOWER_LAYER container_id=85510af8dfe0 container_image=docker.io/library/nginx container_image_tag=1.24 container_name=www k8s_ns=default k8s_pod_name=www)
Checking the logs if not very handy, we’ll use an additional component falcosidekick to forward events to other systems.
Enabling falcosidekick
Falcosidekick allows to send the detection information to a bunch list of backends including:
- Slack
- Google Chat
- Datadog
- ElasticSearch
- Loki
- Grafana
- AWS S3
- NATS
- Kafka
- MQTT
- SMTP
- Webhook
In the following example, we’ll demo using NATS and webhooks.
Example 1: sending payload to a webhook
First, we enable falcosidekick to forward events to a demo webhook.
helm upgrade --install falco falcosecurity/falco \
--set tty=true \
--set falcosidekick.enabled=true \
--set falcosidekick.config.webhook.minimumpriority="debug" \
--set falcosidekick.config.webhook.address="https://webhooks.app/data?token=LJDEM0"
Next, we run a shell in the www Pod’s container.
kubectl exec www -it -- bash
root@www:/#
Then, we get the events details from our webhook frontend.
Example 2: sending payload to NATS
We enable falcosidekick to forward events to a NATS backend.
helm upgrade --install falco falcosecurity/falco \
--set tty=true \
--set falcosidekick.enabled=true \
--set falcosidekick.config.nats.hostport="nats://demo.nats.io:4222"
Next, we run a NATS subscriber on “falco.>” subject (falcosidekick forwards events to “falco..” by default).
$ nats sub -s nats://demo.nats.io "falco.>" | grep -i falco
14:56:22 Subscribing on falco.>
Next, we run a shell in the www Pod’s container.
kubectl exec www -it -- bash
root@www:/#
Then, in the subscriber’s terminal, we get the falco’s event.
[#1] Received on "falco.notice.terminal_shell_in_container"
{"uuid":"77b977fd-a4dd-4119-bcfb-4cfc0abec457","output":"14:23:43.127229440: Notice A shell was spawned
in a container with an attached terminal (evt_type=execve user=root user_uid=0 user_loginuid=-1
process=bash proc_exepath=/bin/bash parent=runc command=bash terminal=34817
exe_flags=EXE_WRITABLE|EXE_LOWER_LAYER container_id=85510af8dfe0
container_image=docker.io/library/nginx container_image_tag=1.24 container_name=www k8s_ns=default
k8s_pod_name=www)","priority":"Notice","rule":"Terminal shell in container",
"time":"2025-01-06T14:23:43.12722944Z","output_fields":{"container.id":"85510af8dfe0",
"container.image.repository":"docker.io/library/nginx","container.image.tag":"1.24",
"container.name":"www","evt.arg.flags":"EXE_WRITABLE|EXE_LOWER_LAYER","evt.time":1736173423127229440,
"evt.type":"execve","k8s.ns.name":"default","k8s.pod.name":"www","proc.cmdline":"bash",
"proc.exepath":"/bin/bash","proc.name":"bash","proc.pname":"runc","proc.tty":34817,
"user.loginuid":-1,"user.name":"root","user.uid":0},"source":"syscall",
"tags":["T1059","container","maturity_stable","mitre_execution","shell"],"hostname":"pool-6594f-lkgfv"}
Enabling falcosidekick web UI
Falcosidekick Web UI allows visualizing and get details about Falco events.
First, we upgrade the release to enable falcosidekick WebUI. Since it relies on a Redis database, we specify both the storageClass and the size of the PVC.
helm upgrade --install falco falcosecurity/falco \
--set tty=true \
--set falcosidekick.enabled=true \
--set falcosidekick.webui.enabled=true \
--set falcosidekick.webui.redis.storageClass=exoscale-sbs \
--set falcosidekick.webui.redis.storageSize=10Gi
When all the Pods are running, we run a port-forward to access the Web UI.
kubectl port-forward svc/falco-falcosidekick-ui 8888:2802
The UI is accessible at http://localhost:8888
We log in using admin/admin credentials. We get an empty dashboard as no event have been triggered yet.
We run a shell in the www Pod.
kubectl exec www -it -- bash
root@www:/#
Then, the UI shows a new event was created.
We get the event’s details from the Events menu.
Custom event
Falco triggers events for many predefined rules. It also allows defining custom rules.
The following file contains the properties defined above, and the definition of a custom rule which triggers an event when attempting to write a file within /usr/share/nginx/html folder.
tty: true
falcosidekick:
enabled: true
webui:
enabled: true
redis:
storageClass: exoscale-sbs
storageSize: 10Gi
customRules:
custom-rules.yaml: |-
- rule: Write inside nginx html folder
desc: An attempt to write to /etc directory
condition: >
(evt.type in (open,openat,openat2) and evt.is_open_write=true and fd.typechar='f' and fd.num>=0)
and fd.name startswith /usr/share/nginx/html
output: "File inside /usr/share/nginx/html opened for writing (file=%fd.name evt_type=%evt.type user=%user.name user_uid=%user.uid user_loginuid=%user.loginuid process=%proc.name proc_exepath=%proc.exepath parent=%proc.pname command=%proc.cmdline terminal=%proc.tty %container.info)"
priority: WARNING
tags: [filesystem, mitre_persistence]
We upgrade the application with this values file.
helm upgrade --install falco falcosecurity/falco -f values.yaml
Next, we run a shell in the www Pod’s container.
kubectl exec www -it -- bash
root@www:/#
Next, we edit the /usr/share/nginx/html/index.html file.
root@www:/# vi /usr/share/nginx/html/index.html
...
From falcosidekick Web UI, we can see several events were triggered. Below is the one related to the custom rule we defined.
Summary
This demo only gives an overview of Falco. Feel free to explore the documentation to get more details.
Tips
During the CKS (Certified Kubernetes Security Specialist), there may be a question requesting to run falco on a cluster and to modify an existing rule.