Falco on Kubernetes is more than just a security tool; it’s a real-time threat detection engine that uses system call data to identify anomalous behavior.

Let’s get Falco running on your Kubernetes cluster.

First, ensure you have kubectl configured to talk to your cluster and a recent version of Helm installed. This guide assumes a standard Kubernetes setup.

Here’s the command to add the Falco Helm repository:

helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo update

This makes the Falco Helm chart available for installation.

Now, let’s install Falco using Helm. We’ll start with a basic configuration.

helm install falco falcosecurity/falco --namespace falco --create-namespace

This command installs Falco into a dedicated falco namespace. It will deploy a DaemonSet, ensuring a Falco instance runs on each node in your cluster.

To verify the installation, check the status of the Falco pods:

kubectl get pods -n falco

You should see one or more pods in a Running state, one for each node.

NAME        READY   STATUS    RESTARTS   AGE
falco-abcde   1/1     Running   0          2m
falco-fghij   1/1     Running   0          2m

The output confirms that Falco is up and running on your nodes.

Falco works by capturing and analyzing system calls. On Kubernetes, it runs as a DaemonSet, meaning a Falco agent pod is scheduled on every node. Each agent monitors the system calls originating from containers running on that node.

The core of Falco’s detection is its rules engine. These rules are defined in YAML files and specify patterns of system calls and other kernel events that might indicate malicious activity. For example, a rule might trigger if a shell process is spawned inside a container, or if a process attempts to write to sensitive system directories.

Let’s explore a bit more about the configuration. You can customize Falco’s behavior by passing values to the Helm chart. For instance, to enable the json output format for logs, which is useful for programmatic parsing:

helm install falco falcosecurity/falco \
  --namespace falco \
  --create-namespace \
  --set falco.jsonOutput=true

This change modifies the Falco configuration to emit logs in JSON format, making them easier to integrate with log aggregation systems.

The most surprising thing about Falco’s detection mechanism is its ability to correlate events across different system calls and even across different processes on the same node, all in real-time, without relying solely on network traffic or application logs. It’s looking at the fundamental interactions between processes and the operating system kernel.

Here’s how you can retrieve Falco logs to see the detections:

kubectl logs -n falco -l app.kubernetes.io/name=falco -f

When Falco detects a suspicious event, it will output a message. For example, you might see something like this:

{"@timestamp":"2023-10-27T10:30:00.123456789Z","output":"10:30:00.123456789: Evicted container (id=...) from node ...","priority":"WARNING","rule":"Evicted container","time_since_`: `0.000000000","nodename":"your-node-name","container.id":"your-container-id","container.name":"your-container-name","proc.name":"containerd","proc.cmdline":"...","proc.ppid":"...","proc.pid":"...","user.name":"root","fd.name":"/var/lib/docker/overlay2/...","fd.type":"file","evt.type":"open","evt.args":"...","container.runtime":"docker","container.image":"...","k8s.pod.name":"your-pod-name","k8s.namespace.name":"your-namespace","k8s.node.name":"your-node-name","k8s.pod.uid":"...","k8s.container.name":"your-container-name","k8s.container.id":"...","k8s.deployment.name":"your-deployment-name","k8s.replicaset.name":"your-replicaset-name","k8s.statefulset.name":"your-statefulset-name"}

This specific log entry indicates that a container was evicted, a common Kubernetes event that Falco can flag.

The real power of Falco lies in its extensibility. You can write custom rules to detect specific threats relevant to your applications. The rules are written in a DSL that allows you to define conditions based on system call arguments, process names, user IDs, and even Kubernetes metadata like pod names and namespaces.

For instance, if you wanted to alert on any attempt to execute sh or bash within a specific application’s pods, you could define a custom rule. This rule would look for the execve syscall, check if the executable name is sh or bash, and then filter by the k8s.deployment.name or k8s.pod.name to scope it to your application.

One of the less obvious aspects of Falco’s operation is how it handles the kernel module versus eBPF. While a kernel module provides the most direct access to system calls, eBPF (extended Berkeley Packet Filter) offers a more robust and secure alternative. Modern Falco installations often default to using eBPF, which runs in a sandboxed environment within the kernel, reducing the risk of kernel panics and simplifying deployment across different kernel versions. The eBPF probe is loaded into the kernel and hooks into specific syscall entry points to capture the necessary data.

The next step in mastering Falco is understanding its rich rule set and how to tailor it for your specific environment.

Want structured learning?

Take the full Falco course →