Verified8 commandsAI-assisted

Falco

.md

Verified against Falco 0.44.1 / falcoctl 0.13.0, installed via the official apt repo and flags verified · official docs

What it is and where it fits 🎯#

Every other tool in this Security & Compliance section is prevention-focused: it scans code, images, IaC, or dependencies before something ships, looking for a known-bad pattern. Falco is different — it's behavior-based runtime security, watching a live system's actual syscalls for anomalous activity: an unexpected shell spawned inside a container, a sensitive file read, a privilege escalation. This is the detection layer that catches a genuinely novel attack no scanner could have flagged in advance, because there's no signature to match against — only "this doesn't look like how this workload normally behaves." Falco runs as a long-lived daemon/DaemonSet, not a one-shot scan; falcoctl is its separate CLI for managing rules, drivers, and OCI-distributed rule bundles.

Where runtime detection fits relative to everything upstream#

Diagram

Everything to the left of Deploy is prevention — stop the bad thing from shipping. Falco is the only tool here that assumes something might get through anyway and watches for it happening live.

Installation (Debian/Ubuntu)#

curl -fsSL https://falco.org/repo/falcosecurity-packages.asc \
  | sudo gpg --dearmor -o /usr/share/keyrings/falco-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/falco-archive-keyring.gpg] https://download.falco.org/packages/deb stable main" \
  | sudo tee /etc/apt/sources.list.d/falcosecurity.list
sudo apt-get update
sudo apt-get install -y falco

falco --version
falcoctl version

RPM-based distros use the equivalent yum/dnf repo (see the official docs); a Helm chart is the standard install path for Kubernetes:

helm repo add falcosecurity https://falcosecurity.github.io/charts
helm install falco falcosecurity/falco -n falco --create-namespace

Important

Post-install, Falco auto-configures a driver type (modern_ebpf by default on recent kernels) via falcoctl driver config — a kernel-driver/eBPF probe is genuinely required for live syscall capture. A locked-down sandbox or container without kernel module access can install and configure Falco fine, but won't receive real live events — this isn't a bug, it's the fundamental mechanism Falco depends on to see syscalls at all.

Running Falco#

falco                                    # foreground, using the configured driver + default ruleset
falco -c /etc/falco/falco.yaml            # explicit config file
falco --dry-run                           # validate config and rules without processing events — good for CI-lint of a rules change
falco -M 60                                # stop after 60 seconds — useful for a bounded test run

Inspecting rules and fields#

falco -L                                  # list every loaded rule, name + description
falco -l "Terminal shell in container"     # show one rule's full detail
falco --list                               # list every field available for use in rule conditions
falco --list-events                        # list every syscall/tracepoint event source
falco --list-plugins                        # show loaded plugins

Real captured falco --list-plugins output from this cheat sheet's own verification run (a fresh apt install, one plugin loaded by default):

1 Plugins Loaded: Name: container Description: Falco container metadata enrichment Plugin Contact: github.com/falcosecurity/plugins Version: 0.7.1 Capabilities: - Field Extraction - Event Parsing - Async Events

Writing a custom rule#

# /etc/falco/rules.d/custom.yaml
- rule: Unexpected shell in checkout service
  desc: A shell was spawned inside the checkout container — should never happen
  condition: >
    spawned_process and container.name = "checkout" and proc.name in (bash, sh, zsh)
  output: >
    Shell spawned in checkout container (user=%user.name command=%proc.cmdline container=%container.name)
  priority: WARNING
falco --dry-run -r /etc/falco/rules.d/custom.yaml     # validate the new rule file before deploying it

Tip

Scope custom rules to a specific workload (container.name = "checkout") rather than writing a global rule whenever possible. A rule like "no shell spawned in any container, ever" sounds appealing but breaks the moment any team's legitimate debugging workflow (an kubectl exec into a pod during an incident) needs a shell — scoping to the specific workloads that genuinely should never see one avoids that false-positive fatigue, which is the fastest way a team starts ignoring Falco alerts entirely.

falcoctl — managing rules and drivers as OCI artifacts#

falcoctl artifact install falco-rules:latest          # pull the official rules bundle from the default OCI index
falcoctl driver config --type modern_ebpf              # (re)configure which driver type to use
falcoctl driver install                                  # install/load the configured driver
falcoctl registry pull oci://ghcr.io/org/falco-rules:latest    # pull a custom rules bundle from your own registry

Output config (config.d snippets)#

# /etc/falco/config.d/output.yaml
json_output: true
stdout_output:
  enabled: true

Combine with -o append_output.jsonoutput=true at the CLI, or -pk/-pc to append Kubernetes/container context onto every alert line — critical in a multi-tenant cluster where "a shell was spawned somewhere" is meaningless without knowing which namespace/pod/workload it happened in.

Real-world scenario: the checkout-service anomaly this series' own tutorial opens with#

An on-call engineer gets paged for "Terminal shell in container" on the checkout service — a workload that has no legitimate reason for anyone to open an interactive shell inside it. The temptation is to dismiss it as noise from a routine debugging session.

Caution

Investigate before dismissing. This is exactly the class of anomalous, behavior-based signal that prevention-focused tooling (scanning, RBAC) can't provide — it's specifically what runtime detection exists to surface. Check recent access/audit logs for who or what triggered it, and treat it as a potential active compromise until proven otherwise. Dismissing a genuinely novel, behavior-based security signal without investigation is exactly how real intrusions go undetected — the entire value of a tool like Falco is lost the moment a team trains itself to auto-dismiss its alerts.

Common pitfalls#

  • Assuming Falco "isn't working" in a sandboxed/CI environment — see the driver requirement above; no kernel access means no live events, by design, not by bug.
  • Global, unscoped rules causing alert fatigue — see the TIP above.
  • Treating a Falco alert as low-priority by default — unlike a scan finding (which represents a potential issue caught before it shipped), a Falco alert represents something that actually happened on a running system, which generally warrants faster triage than a static-analysis finding.

When to reach for something else#

Falco is the only runtime-detection tool in this series — there's no direct substitute among the others here. It's a complement to, never a replacement for, the prevention-focused scanners (Trivy/Grype/Checkov/tfsec/OPA) earlier in the pipeline; a mature security posture runs both layers, not one instead of the other.