Skip to content
Français
Account: not signed in, sync available My learning
Select theme
Français

Falco - Runtime threat detection in Kubernetes

By updated

Improve this page

Falco is the reference open source tool for detecting abnormal behaviour in Kubernetes containers, in real time. A CNCF Graduated project since February 2024, it observes the system calls of containers and, through a plugin, the Kubernetes audit logs: a shell opened in a container, the reading of a sensitive file, an unexpected binary. This guide is for a DevOps engineer who wants to deploy it and turn it into a usable signal. Everything is replayed on Falco 0.45.0, Helm chart 9.2.0 and Kubernetes 1.37: installation in 45 seconds, the modern eBPF probe chosen on its own on a 6.8 kernel, and an alert visible a few seconds after a cat /etc/shadow.

The CKS curriculum does not name Falco, but its Monitoring, Logging and Runtime Security domain asks you to "Perform behavioral analytics to detect malicious activities", and the Falco documentation is among the resources allowed during the exam. Knowing how to deploy it and read its rules is therefore part of what is expected.

What you will learn

  • Install Falco with Helm and check the probe actually chosen
  • Decode a Falco rule: lists, macros, condition, output, priority
  • Trigger the shipped rules and read their JSON alerts
  • Draft a custom rule and load it without breaking the pod
  • Reduce noise with the override mechanisms rather than by disabling
  • Route the alerts to the team's tools

Prerequisites

  • Working Linux Kubernetes cluster
  • Nodes compatible with the chosen capture mode (modern eBPF or kernel module)
  • Helm v3 installed
  • kubectl configured with cluster-admin access
  • Basics of Linux security (system calls, capabilities)

What is Falco?

Falco detects suspicious behaviour during execution by analysing two families of events. The table separates them, because they are not enabled the same way: the first one is there as soon as Falco is installed, the second one requires a plugin and an API server configuration.

SourceDescriptionDetection examples
Kernel system callsCaptured on each node by the modern eBPF probe or the kernel moduleShell opened, sensitive file read, binary modified
Kubernetes audit eventsReceived from the API server by the k8saudit pluginPrivileged pod created, exec into a pod, secret read

Simplified architecture

The diagram follows the path of an event inside a node: the source captures the system call, the rules engine evaluates it, then the outputs raise an alert if a condition matches. No central component is needed, everything happens on the node itself.

Falco architecture on a Kubernetes node: the system calls of containers A and B are captured by the eBPF source of the Falco DaemonSet, evaluated by the rules engine, then turned into alerts by the outputs.Falco (DaemonSet)Container Asystem callsContainer Bsystem callsSourceeBPF captureEngineevaluates the rulesOutputsalerts
Source · SVG
Esc to close, + and − to zoom, scroll to move around. 100 %

Falco runs as a DaemonSet: one pod per node, which observes the events of every container on that node. Plugins extend the sources: Kubernetes audit, CloudTrail, GitHub, among others.

A useful clarification before going further, because Falco is often presented as a security solution on its own. Falco detects behaviour during execution, and that is all: it blocks nothing. It replaces neither an image vulnerability scanner, the job of Trivy, nor a cluster configuration audit, the job of kube-bench (in French), nor an admission policy, the job of the Pod Security Standards. These four tools cover four different moments, and none of them catches what another let through.

Installation with Helm

The official falcosecurity/falco chart installs the DaemonSet, the default rules and, optionally, the Falcosidekick alert router. The parameter that decides the outcome is driver.kind, which chooses the capture mechanism for system calls. A wrong choice gives a pod that does not start; the right default choice, auto, adapts to the node's kernel.

Standard deployment

These three steps are enough to get a working Falco that writes its alerts in JSON format on standard output. The chart is pinned to 9.2.0, the version that ships Falco 0.45.0.

  1. Add the Falco Helm repository

    Terminal window
    helm repo add falcosecurity https://falcosecurity.github.io/charts
    helm repo update
  2. Install Falco with automatic driver detection

    Terminal window
    helm install falco falcosecurity/falco --version 9.2.0 \
    --namespace falco \
    --create-namespace \
    --set driver.kind=auto \
    --set tty=true \
    --set falco.json_output=true \
    --set falco.json_include_output_property=true

    The tty=true parameter forces Falco's output into line-by-line mode instead of the block buffering that a process without a terminal uses by default. On a quiet cluster, this avoids waiting for the buffer to fill up before seeing an alert.

    It is not a condition for seeing the alerts. Measured on Falco 0.45.0: with tty=false, a triggered alert appears in kubectl logs in under six seconds, just as with it. If you see nothing, look elsewhere, at the probe or the rule.

    The chart recommends driver.kind=auto, and it is the right default: it picks the modern eBPF probe when the kernel allows it, from version 5.8 onwards, and otherwise falls back to the kernel module. The old eBPF probe was removed from Falco in version 0.44.

  3. Check the deployment

    Terminal window
    kubectl get pods -n falco
    kubectl logs -n falco -l app.kubernetes.io/name=falco --tail=20

    Measured result:

    NAME READY STATUS RESTARTS AGE
    falco-69vhs 2/2 Running 0 45s

    The 2/2 counts the falco container and the falcoctl-artifact-follow container, which updates the rules. Two init containers come before them: falco-driver-loader and falcoctl-artifact-install.

Advanced installation options

These values are passed with --set on the command line or in a values.yaml file. The first two rows cover a standard deployment; the following ones depend on the context, in particular the explicit choice of driver when auto does not fit. The table follows the values of chart 9.2.0.

OptionValueDescription
driver.kindautoRecommended, automatic selection of the best driver
falco.json_outputtrueStructured JSON output, recommended for analysis
driver.kindmodern_ebpfModern eBPF probe (kernel 5.8 and later, built into the binary)
driver.kindkmodKernel module (compatibility, requires the kernel headers)
ttytrueLine-by-line output, without buffering
falcosidekick.enabledtrueDeploys Falcosidekick to route the alerts
falco.rules_filesList of filesRule files and folders to load

Between the two capture mechanisms, the modern eBPF probe is the one to aim for: it is built into the Falco binary, which removes all the complexity of a kernel module to compile at the pace of kernel updates. If your kernel is 5.8 or later, there is no reason to choose anything else. The ebpf option and the gRPC API of older versions disappeared in 0.44.

Understanding Falco rules

Falco rules are written in YAML and read as a condition on an event: when the condition is true, Falco emits the output message with the given priority. Three building blocks let you write these conditions without repeating yourself.

Structure of a rule

A Falco rule relies on three building blocks declared in the same file. Lists group values, macros name reusable conditions, and the rule combines everything with an output message and a priority. A rule can only reference a macro or a list already defined, here open_read and container, shipped with the default rules.

# 1. List: set of reusable values
- list: my_sensitive_files
items: [/etc/shadow, /etc/sudoers, /root/.ssh/authorized_keys]
# 2. Macro: reusable condition, built on the shipped macros
- macro: read_my_sensitive_files
condition: open_read and fd.name in (my_sensitive_files)
# 3. Rule: complete detection logic
- rule: Read sensitive file in container
desc: Detect reading of sensitive files inside containers
condition: read_my_sensitive_files and container
output: >
Sensitive file read in container
(file=%fd.name user=%user.name container=%container.name
image=%container.image.repository)
priority: WARNING
tags: [filesystem, cks]

Two pitfalls show up when loading this file. Redeclaring a shipped macro, such as open_read, replaces it for all the default rules: hence names specific to the team. And Falco applies rule_matching: first by default: an event only triggers the first matching rule. Measured: a cat /etc/shadow only produces Read sensitive file untrusted, loaded before this one, whereas a cat /root/.ssh/authorized_keys does trigger Read sensitive file in container.

Alert priorities

The priority field changes nothing in the detection itself: it is used for downstream filtering, typically to decide what triggers an on-call page. The EMERGENCY and DEBUG levels remain marginal in the shipped rules.

PriorityUseExample
EMERGENCYSystem unusable-
ALERTImmediate action requiredMalware detected
CRITICALCritical conditionsBinary missing from the image executed
ERRORSignificant errorsRepeated authentication failure
WARNINGSuspicious behaviourReading of /etc/shadow
NOTICENormal but notable eventShell opened (may be legitimate)
INFOInformationNew container started
DEBUGDebugging-

Commonly used fields

Writing a detection condition requires knowing the fields Falco exposes. When the event is evaluated, they give access to information about the process, the container, the file, the network and the user.

# Process
proc.name # Process name (bash, python)
proc.pname # Parent process name
proc.cmdline # Full command line
# Container
container.id # Container ID
container.name # Container name
container.image.repository # Image without tag
# Files
fd.name # File path
fd.directory # Parent directory
# Network
fd.sip # Source IP
fd.sport # Source port
fd.dip # Destination IP
fd.dport # Destination port
# User
user.name # User name
user.uid # UID

Rules included by default

The chart installs the stable falco-rules rule set, which falcoctl keeps up to date. Measured on the version shipped with Falco 0.45.0, the /etc/falco/falco_rules.yaml file contains 25 rules, focused on the behaviours that are safest to report. Two broader sets, incubating and sandbox, can be installed on top when you accept more noise.

Checking which probe Falco actually chose

This is the first thing to read after installation, and it fits in one line of the logs:

Terminal window
kubectl -n falco logs ds/falco | grep -i probe
Output
Thu Oct 01 13:53:07 2026: Opening 'syscall' source with modern BPF probe.

modern BPF probe is what you want to see: the probe is built into the binary, with no kernel module to compile or maintain. On a Linux 6.8 kernel, with BTF available, driver.kind=auto picks it without any extra configuration: the falco-driver-loader log shows type: modern_ebpf then No artifacts needed for the selected driver.

A lab detail: on a kind cluster, whose nodes are themselves containers, Falco also sees the node's activity and raises Drop and execute new binary in container alerts without a pod name. This noise is specific to this type of test cluster.

Terminal/shell detection

The Terminal shell in container rule, shipped by default, fires as soon as a shell process gets a terminal inside a container.

Terminal window
# Watch the alerts in real time
kubectl logs -n falco -l app.kubernetes.io/name=falco -f | grep -i shell

Test the detection:

Terminal window
# In another terminal, open an interactive shell
kubectl run test-shell --image=nginx:1.30@sha256:9bf97bd7714f5e24c1ccd545ecb9eb5435cb6d109c97cebb15e7e455e0239edb --rm -it -- /bin/bash

The -it is not a display convenience, it determines the detection. Measured: a kubectl exec without a terminal does run a shell in the container and does not trigger this rule, whereas the same command with -it triggers it. The condition requires proc.tty != 0: the rule is called "Terminal shell", and it takes that word seriously.

A consequence to remember for real detection: an attacker who runs commands without allocating a terminal slips under this rule. It covers interactive intrusion, not command execution.

Actual alert, captured on Falco 0.45.0 and trimmed to the useful fields:

{
"output": "13:46:06.499212890: Notice A shell was spawned in a container with an attached terminal | evt_type=execve user=root ... process=sh ... command=sh -c exit 0 terminal=34816 ... container_name=cible ... k8s_pod_name=cible k8s_ns_name=demo",
"priority": "Notice",
"rule": "Terminal shell in container",
"source": "syscall",
"tags": ["T1059", "container", "maturity_stable", "mitre_execution", "shell"]
}

Reading sensitive files

The Read sensitive file untrusted rule watches reads of the files listed in sensitive_file_names: /etc/shadow, /etc/sudoers, /etc/pam.conf and /etc/security/pwquality.conf, plus the /etc/sudoers.d and /etc/pam.d folders. /etc/passwd is not one of them: measured, reading it triggers nothing. An application container has no reason to open these files: an alert points to reconnaissance after a compromise, or to a tool misplaced in the image.

This rule also produces false positives, because some legitimate agents read these files. Its condition already excludes a series of known programs, including the read_sensitive_file_binaries list. The right reflex is to extend this list with override, never to disable the rule: you keep the detection and you document what is allowed to read what.

# Add a legitimate agent to the allowed readers
- list: read_sensitive_file_binaries
items: [mon-agent]
override:
items: append

The alert measured on a cat /etc/shadow in a pod, priority Warning:

Output
Warning Sensitive file opened for reading by non-trusted program | file=/etc/shadow
... process=cat ... command=cat /etc/shadow ... container_name=cible ... k8s_ns_name=demo

Writing into system directories

A write under /etc in a container has no reason to exist on an immutable image. The stable rule set of Falco 0.45.0 does not contain a dedicated rule: you have to write it, with the shipped open_write macro. A version that uses a write macro fails to load, measured: Undefined macro 'write' used in filter.

- rule: Write below etc in container
desc: Detect writes beneath /etc inside a container
condition: >
open_write and container
and fd.name startswith /etc
output: >
File below /etc written (file=%fd.name container=%container.name)
priority: ERROR

Creating custom rules

The shipped rules cover generic behaviours, not your context: internal process names, staging namespaces. Your own rules therefore live in a separate file, loaded in addition to the default rules. This separation avoids modifying files that the next chart update would overwrite.

ConfigMap method

The chart's customRules key creates the falco-rules ConfigMap, mounted in the Falco pod under /etc/falco/rules.d: each entry becomes a rules file, loaded at start-up.

  1. Create a custom rules file

    custom-rules.yaml
    customRules:
    custom-rules.yaml: |-
    - rule: Crypto mining detection
    desc: Detect potential crypto mining activity
    condition: >
    container and spawned_process
    and (proc.name in (xmrig, minerd, minergate, cpuminer)
    or proc.cmdline contains "stratum+tcp://")
    output: >
    Crypto mining suspected
    (proc=%proc.name cmdline=%proc.cmdline container=%container.name)
    priority: CRITICAL
    tags: [cryptomining, malware]
    - rule: Write below etc in container
    desc: Detect writes beneath /etc inside a container
    condition: >
    open_write and container
    and fd.name startswith /etc
    output: >
    File below /etc written (file=%fd.name container=%container.name)
    priority: ERROR
  2. Deploy with Helm

    Terminal window
    helm upgrade falco falcosecurity/falco --version 9.2.0 \
    --namespace falco \
    --reuse-values \
    -f custom-rules.yaml
  3. Check the loading

    Terminal window
    kubectl logs -n falco -l app.kubernetes.io/name=falco | grep -i "custom-rules"
    # /etc/falco/rules.d/custom-rules.yaml | schema validation: ok

Measured: the two rules fire, the first on a command that contains stratum+tcp://, the second on a touch /etc/test in a pod. An invalid rule, on the other hand, makes the pod crash into CrashLoopBackOff: the message, LOAD_ERR_VALIDATE, is read with kubectl logs --previous.

Two precautions come out of these tests. --reuse-values merges the customRules: an entry removed from the file stays in the ConfigMap, and only --reset-values starts from scratch. And a rule meant to reject an unapproved image does not belong here: written on the container start event, it fired 32 times in one minute, before the image name was known. That control belongs to admission, with Kyverno.

Disabling a default rule

To disable a noisy rule without modifying the original files, you redeclare it with an override key. The short form, enabled: false on its own, still works but Falco 0.45.0 flags it as deprecated (LOAD_DEPRECATED_ITEM).

customRules:
custom-rules.yaml: |-
- rule: Terminal shell in container
enabled: false
override:
enabled: replace

To exclude only some namespaces, you append a clause to the existing condition rather than rewriting it, which keeps the shipped condition and its future updates intact. Measured with a demo namespace added to this list: an interactive shell in demo no longer produces an alert.

customRules:
custom-rules.yaml: |-
- rule: Terminal shell in container
condition: and not k8s.ns.name in (debug-namespace, dev)
override:
condition: append

Alert output (Outputs)

Detecting is useless if nobody sees the alert. Falco can feed several channels at once: standard output, a file on the node and an HTTP call. Enable json_output as soon as the alerts are consumed by another tool, because the default text format parses badly.

Configuring the output channels

These chart 9.2.0 keys enable each channel. The http_output URL must point to a receiver that accepts Falco's JSON as is: an alert manager that expects its own format, such as Alertmanager, does not fit without an intermediary.

# values.yaml for Helm
falco:
json_output: true
stdout_output:
enabled: true
file_output:
enabled: true
filename: /var/log/falco/alerts.log
http_output:
enabled: true
url: http://recepteur-alertes.supervision.svc:8080/falco

Falcosidekick for advanced integrations

Falcosidekick is deployed with the same chart and takes care of distribution to alerting tools, which avoids writing and running a home-made HTTP receiver.

In production, do not leave the alerts in kubectl logs: add Falcosidekick, a router that distributes them to nearly 70 destinations, Slack, PagerDuty, Elasticsearch or Prometheus depending on your alerting chain. A detection nobody reads is useless.

Terminal window
helm upgrade falco falcosecurity/falco --version 9.2.0 \
--namespace falco \
--reuse-values \
--set falcosidekick.enabled=true \
--set falcosidekick.config.slack.webhookurl="https://hooks.slack.com/xxx"

A Slack webhook URL is a secret: passed with --set, it stays in the shell history. Outside a test, put it in an unversioned values file or a Kubernetes Secret.

Check Falcosidekick:

Terminal window
kubectl get pods -n falco -l app.kubernetes.io/name=falcosidekick
kubectl logs -n falco -l app.kubernetes.io/name=falcosidekick

Integration with Kubernetes Audit Logs

Falco can consume Kubernetes audit events through dedicated plugins. This integration is separate from system call capture and depends on your platform.

Do not confuse the two event sources, it is the most costly confusion on this topic. The Falco DaemonSet captures the kernel's system calls, so what happens inside the containers. Kubernetes audit logs describe actions on the API, and consuming them requires a separate configuration, through a plugin. Looking for a kubectl action in the DaemonSet's alerts will never give anything.

Key concepts

These two sources do not overlap: the first observes what happens inside the containers, the second what is requested from the API server. A command such as kubectl exec appears in both, from two different angles.

SourceCaptureExamples
Kernel (system calls)Falco DaemonSet on each nodeShell opened, file read, network connection
Kubernetes audit (plugin)Webhook from the API serverPod created, secret read, RBAC modified

Enabling the K8s Audit plugin

For a self-managed cluster, the API server sends its audit events to a dedicated Falco instance, which receives them on port 9765. The chart ships the reference configuration, values-k8saudit.yaml, whose essentials are below: no driver and no DaemonSet, but a Deployment, the two plugins k8saudit and json, and the k8saudit-rules rule set. This part was not replayed here: it requires configuring the API server's audit webhook, which a kind cluster only allows at the cost of a dedicated configuration. It follows the chart 9.2.0 file.

# values.yaml for Helm, based on values-k8saudit.yaml of chart 9.2.0
driver:
enabled: false
collectors:
enabled: false
controller:
kind: deployment
falcoctl:
config:
artifact:
install:
refs: [k8saudit-rules:0.16, k8saudit:0.16]
follow:
refs: [k8saudit-rules:0.16]
falco:
rules_files:
- /etc/falco/k8s_audit_rules.yaml
- /etc/falco/rules.d
plugins:
- name: k8saudit
library_path: libk8saudit.so
init_config: ""
open_params: "http://:9765/k8s-audit"
- name: json
library_path: libjson.so
init_config: ""
load_plugins: [k8saudit, json]

On a managed cluster, the audit logs are not in your hands: they land in CloudWatch, Cloud Logging or Azure Monitor depending on the provider. Falco can consume them through dedicated plugins, k8saudit-eks for example. The Falco documentation details the plugin matching your platform.

Included K8s Audit rules

These rules carry source: k8s_audit and use the fields prefixed with ka., specific to the audit plugin: they never fire as long as the plugin is not loaded. The two examples are taken from the k8s_audit_rules.yaml file of the falcosecurity/plugins repository.

# Excerpts from the shipped Kubernetes audit rules
- rule: K8s Secret Get Successfully
desc: >
Detect any attempt to get a secret. Service account tokens are excluded.
condition: >
secret and kget
and kactivity
and response_successful
output: K8s Secret Get Successfully (user=%ka.user.name secret=%ka.target.name ns=%ka.target.namespace ...)
priority: ERROR
source: k8s_audit
- rule: Create Privileged Pod
desc: >
Detect an attempt to start a pod with a privileged container
condition: kevt and pod and kcreate and any_container_privileged and not ka.req.pod.containers.image.repository in (k8s_audit_privileged_images)
output: Pod started with privileged container (user=%ka.user.name pod=%ka.resp.name ...)
priority: WARNING
source: k8s_audit

Verification and tests

After installation, check the complete chain, from capture to the display of the alert. The quickest way is to deliberately trigger a behaviour covered by the default rules, then watch the DaemonSet's output.

Triggering test alerts

These commands target a test pod that is already running. Each one is annotated with the rule it actually triggered on Falco 0.45.0, including the one that triggers none by default.

Terminal window
# A target pod that stays alive
kubectl run cible --image=alpine:3.22@sha256:5291449c3df73caf6ed85e649dec1b9e818b39a5d8c871e97afc13e9cd5e8fa8 -- sleep 3600
# Test 1: reading a sensitive file -> Read sensitive file untrusted
kubectl exec cible -- cat /etc/shadow
# Test 2: interactive shell -> Terminal shell in container
kubectl exec -it cible -- sh -c 'exit 0'
# Test 3: writing to /etc -> no default rule, see the custom rule above
kubectl exec cible -- touch /etc/test

Watching the alerts

These monitoring commands work with or without tty=true: this setting changes the moment the line comes out, not whether it comes out. The first one assumes json_output is enabled, the second one filters on priority.

Terminal window
# Formatted JSON (the non-JSON start-up lines are filtered out)
kubectl logs -n falco -l app.kubernetes.io/name=falco -f | grep '^{' | jq .
# Filter by priority
kubectl logs -n falco -l app.kubernetes.io/name=falco | grep -i "warning\|error\|critical"

Troubleshooting

Two failures keep coming back: the pod does not start for lack of a driver compatible with the kernel, or it starts without loading your rules. Both are diagnosed in the logs, but not in the same container of the pod.

Falco does not start

Choosing and loading the driver happens in a dedicated init container, falco-driver-loader: that is where you read the logs, not in the falco container itself.

Terminal window
# Check the events
kubectl describe pod -n falco -l app.kubernetes.io/name=falco
# Common driver problems
kubectl logs -n falco -l app.kubernetes.io/name=falco -c falco-driver-loader

Common solutions:

SymptomLikely causeSolution
Modern eBPF probe refusedKernel older than 5.8 or without BTFUse driver.kind=kmod
Kernel module failingMissing kernel headersInstall linux-headers-$(uname -r)
Pod in CrashLoopBackOff after an upgradeInvalid custom ruleRead kubectl logs --previous, look for LOAD_ERR_VALIDATE
No alertsRules file not loadedCheck falco.rules_files

Custom rules not loaded

First check that the ConfigMap contains the expected content, then look in the start-up logs for the file loading line: that is where syntax errors and deprecations are reported.

Terminal window
# Check the ConfigMap content (only created when customRules is set)
kubectl get configmap -n falco falco-rules -o yaml
# Rule loading logs
kubectl logs -n falco -l app.kubernetes.io/name=falco | grep -i "rule\|error\|warn"

Best practices

These four reflexes weigh more on detection quality than the number of enabled rules. A rule that fires a hundred times a day ends up being ignored, which amounts exactly to never having written it.

  • Filtering by namespace: exclude monitoring or debugging namespaces with override: condition: append.
  • Appropriate priorities: keep CRITICAL and ALERT for real emergencies that require action.
  • Consistent tags: use tags to filter (MITRE, compliance, cks, filesystem).
  • Regular tests: replay the test triggers to check that the rules still detect.

Managing noise and false positives

Falco generates a lot of alerts by default. In production, fine-tuning is essential, and it goes through targeted exclusions, not through disabling entire rules.

Common sources of noise

Noise rarely comes from a badly written rule: it comes from legitimate activities that Falco cannot tell apart from an attack. Identify the recurring source before writing an exclusion, otherwise you neutralise detection well beyond the targeted case.

SourceExampleSolution
Debug namespaceskubectl exec in kube-systemExclude the namespace
Kubernetes operatorsControllers that read secretsAllow list by image
Admin jobsBackups, maintenanceExclude by label
Tool containersDebug images with shellsExclude by image

Example of a rule with exclusions

An exclusion is appended to the shipped condition with override: condition: append, rather than copying the whole condition: the rule keeps its future updates, and the exclusion stays readable at a glance.

customRules:
tuning.yaml: |-
- rule: Terminal shell in container
condition: >
and not k8s.ns.name in (kube-system, monitoring, debug)
and not container.image.repository in (busybox, alpine/debug)
override:
condition: append

The order of these steps matters. Wiring alerts to a team before filtering the noise guarantees they will be ignored within a few days, including the real ones.

  1. Deploy in observation mode: start without external alerting
  2. Collect the false positives: analyse the logs for 1 to 2 weeks
  3. Create exceptions: by namespace, image or process, with override
  4. Enable the alerts: connect Falcosidekick once things are stable
  5. Iterate: adjust as deployments evolve

Falcoctl: managing artifacts

falcoctl is the command-line tool that manages Falco's artifacts: rule sets and plugins, published as OCI images. On Kubernetes, the chart already uses it: the falcoctl-artifact-install init container installs the rules, and the falcoctl-artifact-follow container checks every week (every: 168h) for a new version of falco-rules:5. Measured: falcoctl 0.14.2 also verifies the signature of each artifact there before installing it.

Terminal window
# List the available artifacts, from the Falco pod
kubectl -n falco exec ds/falco -c falcoctl-artifact-follow -- falcoctl artifact list
Output (excerpt)
INDEX ARTIFACT TYPE REGISTRY REPOSITORY
falcosecurity falco-incubating-rules rulesfile ghcr.io falcosecurity/rules/falco-incubating-rules
falcosecurity falco-rules rulesfile ghcr.io falcosecurity/rules/falco-rules
falcosecurity falco-sandbox-rules rulesfile ghcr.io falcosecurity/rules/falco-sandbox-rules
falcosecurity k8saudit-rules rulesfile ghcr.io falcosecurity/plugins/ruleset/k8saudit

Outside a cluster, on a host where Falco runs as a service, falcoctl is installed in a pinned, verified version:

Terminal window
# Install falcoctl, pinned version and verified archive
VERSION=0.14.2
curl -fsSLO "https://github.com/falcosecurity/falcoctl/releases/download/v$VERSION/falcoctl_${VERSION}_linux_amd64.tar.gz"
curl -fsSLO "https://github.com/falcosecurity/falcoctl/releases/download/v$VERSION/falcoctl_${VERSION}_checksums.txt"
grep " falcoctl_${VERSION}_linux_amd64.tar.gz$" "falcoctl_${VERSION}_checksums.txt" | sha256sum -c -
tar -xzf "falcoctl_${VERSION}_linux_amd64.tar.gz" falcoctl
sudo mv falcoctl /usr/local/bin/
# Install a rule set from the registry
sudo falcoctl artifact install falco-incubating-rules

ConfigMaps remain the right place for your custom rules; the official rule sets, on the other hand, are updated by falcoctl, without you having to copy them.

Key points

ConceptDescription
FalcoCNCF Graduated runtime detection tool (system calls + plugins), it alerts without blocking
Driverauto recommended: modern eBPF probe if kernel 5.8+, otherwise kernel module
RulesYAML with lists, macros and conditions; 25 stable rules by default in 0.45.0
Matchingrule_matching: first: an event only triggers the first matching rule
Exclusionsoverride with append or replace, never by copying a shipped rule
PrioritiesEMERGENCY to DEBUG depending on criticality, for downstream filtering
FalcosidekickAlert router to nearly 70 destinations
K8s AuditSeparate plugin for API server events
falcoctlCLI for artifacts (rules, plugins), already built into the chart

Knowledge check

Seven questions to check your understanding of Falco before the CKS exam.

Knowledge check

Check what you have learned with this interactive quiz

7 questions
8 min
70% to pass

How it works

  • The timer starts when you click Start
  • Multiple choice, true/false and short answer questions
  • You can move between questions
  • Detailed results are shown at the end

Starts the quiz and the timer

Is this project useful to you?

The guides, courses, quizzes and labs stay free. If you use them regularly, you can contribute to their upkeep and development.

Become a supporting member (new tab) One-time support (new tab) Learn more

Follow the project on LinkedIn