falco

The following gives an overview of Falco, a security tool that provides runtime security across hosts, containers, Kubernetes, and cloud environments.

Overview

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
ℹ️
We use –set tty=true to ensure Falco does not buffer the detection information, but that it logs them directly.

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

falcosidekick

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"
ℹ️
Webhhoks.app is a demo application providing a dedicated webhook endpoint to test and to visualize JSON payloads

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.

webhook

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
ℹ️
Currently, it’s not possible to create a PVC with a size less than 10Gi on the Exoscale block storage. This limitation will be removed very soon.

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

falcosidekick

We log in using admin/admin credentials. We get an empty dashboard as no event have been triggered yet.

falcosidekick

We run a shell in the www Pod.

kubectl exec www -it -- bash
root@www:/#

Then, the UI shows a new event was created.

falcosidekick

We get the event’s details from the Events menu.

falcosidekick

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.

values.yaml
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.

Custom rule

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.