Skip to content

Falco Runtime Security

Overview

Falco is a cloud-native runtime security tool originally created by Sysdig and now a CNCF graduated project. It detects unexpected application behavior and alerts on threats at runtime by monitoring Linux system calls made by containers and hosts. Falco is the primary runtime security tool tested on the CKS exam.

CKS Exam Relevance

Falco is heavily tested on the CKS exam. You should be able to:

  • Understand Falco's architecture and how it detects threats
  • Read and interpret Falco rules
  • Write custom Falco rules
  • Investigate Falco alerts to identify the source of threats
  • Modify Falco configuration and rules files

What Falco Is and How It Works

Falco monitors the behavior of your applications by tapping into the Linux kernel's system call interface. Every time a process in a container (or on the host) makes a system call -- opening a file, establishing a network connection, executing a binary -- Falco sees it and evaluates it against a set of security rules.

If a system call matches a rule condition, Falco generates an alert with details about what happened, who did it, and where.

Key Capabilities

  • Detect shell execution inside containers
  • Detect reads/writes to sensitive files (/etc/shadow, /etc/passwd)
  • Detect privilege escalation attempts
  • Detect unexpected network connections
  • Detect container drift (new binaries executed)
  • Detect crypto mining processes
  • Detect reverse shells

Falco Architecture

Architecture Components

ComponentRole
Kernel Module / eBPF ProbeCaptures system calls at the kernel level with minimal overhead
libscapCaptures raw system call events from the kernel module/eBPF
libsinspEnriches raw events with metadata (container name, pod name, namespace)
Rule EngineEvaluates enriched events against Falco rules
Rules FilesDefine conditions and output for security violations
Output ChannelsSend alerts via stdout, files, syslog, HTTP webhooks, or gRPC

Kernel Module vs. eBPF Probe

FeatureKernel ModuleeBPF Probe
PerformanceExcellentExcellent
SecurityRequires kernel module loadingSafer -- no kernel module needed
CompatibilityBroad kernel supportRequires kernel 4.14+
InstallationNeeds kernel headersNo kernel headers needed
Preferred forLegacy systemsModern systems (recommended)

Exam Tip

On the CKS exam, Falco will typically be pre-installed. You do not need to install it from scratch, but you should know where its configuration and rules files are located.

Installing Falco

While Falco is pre-installed in the exam, understanding the installation process helps you know the file locations.

Installation on a Node

bash
# Add the Falco repository
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

# Install Falco
sudo apt-get update
sudo apt-get install -y falco

# Start Falco
sudo systemctl enable falco
sudo systemctl start falco

# Verify Falco is running
sudo systemctl status falco

Key File Locations

PathDescription
/etc/falco/falco.yamlMain Falco configuration file
/etc/falco/falco_rules.yamlDefault rules (do not modify)
/etc/falco/falco_rules.local.yamlCustom rules (add your rules here)
/etc/falco/rules.d/Directory for additional rule files
/var/log/syslog or journalctl -u falcoFalco log output

Falco Rules Syntax and Structure

Falco rules use a YAML-based domain-specific language. Each rule file can contain three types of elements: rules, macros, and lists.

Rule Processing Flow

Lists

Lists are named collections of values that can be referenced in macros and rules.

yaml
- list: sensitive_file_names
  items:
    - /etc/shadow
    - /etc/passwd
    - /etc/pam.conf
    - /etc/pam.d

- list: allowed_shells
  items:
    - bash
    - sh
    - zsh
    - dash

- list: package_managers
  items:
    - apt
    - apt-get
    - dpkg
    - yum
    - rpm
    - pip
    - pip3
    - npm

Macros

Macros are reusable condition fragments that simplify complex rules.

yaml
- macro: container
  condition: (container.id != host)

- macro: spawned_process
  condition: (evt.type in (execve, execveat) and evt.dir=<)

- macro: sensitive_files
  condition: (fd.name startswith /etc and fd.name in (sensitive_file_names))

- macro: shell_procs
  condition: (proc.name in (allowed_shells))

- macro: open_write
  condition: >
    evt.type in (open, openat, openat2) and
    evt.is_open_write=true and
    fd.typechar='f'

- macro: never_true
  condition: (evt.num=0)

- macro: always_true
  condition: (evt.num>=0)

Rules

Rules combine lists and macros into complete detection conditions with formatted output.

yaml
- rule: <name>
  desc: <description>
  condition: <filter expression>
  output: <output format string with %fields>
  priority: <severity level>
  tags: [<tag1>, <tag2>]
  enabled: true|false
  source: syscall|k8s_audit

Priority Levels

PriorityLevelUse Case
EMERGENCY0System is unusable
ALERT1Action must be taken immediately
CRITICAL2Critical conditions
ERROR3Error conditions
WARNING4Warning conditions
NOTICE5Normal but significant condition
INFORMATIONAL6Informational messages
DEBUG7Debug-level messages

Output Fields

Common output fields you can use in rule output strings:

FieldDescription
%evt.timeEvent timestamp
%proc.nameProcess name
%proc.pnameParent process name
%proc.cmdlineFull command line
%proc.pcmdlineParent command line
%user.nameUser name
%user.uidUser ID
%container.idContainer ID
%container.nameContainer name
%container.image.repositoryContainer image name
%fd.nameFile descriptor name (file path or network address)
%evt.typeSystem call type
%k8s.pod.nameKubernetes pod name
%k8s.ns.nameKubernetes namespace

Writing Custom Falco Rules

Rule 1: Detect Shell Spawned in Container

yaml
- rule: Terminal shell in container
  desc: >
    Detect a shell (bash, sh, etc.) being spawned inside a container.
    This is a common indicator of compromise -- attackers often spawn
    interactive shells after exploiting a vulnerability.
  condition: >
    spawned_process and
    container and
    shell_procs
  output: >
    Shell spawned in container
    (user=%user.name user_uid=%user.uid shell=%proc.name
    parent=%proc.pname cmdline=%proc.cmdline
    container_id=%container.id container_name=%container.name
    image=%container.image.repository
    pod=%k8s.pod.name ns=%k8s.ns.name)
  priority: WARNING
  tags: [container, shell, mitre_execution]

Rule 2: Detect Write to Sensitive Files

yaml
- rule: Write below etc
  desc: >
    Detect any write to files under /etc inside a container.
    Configuration files should not be modified at runtime in
    properly designed immutable containers.
  condition: >
    open_write and
    container and
    fd.name startswith /etc
  output: >
    File below /etc modified in container
    (user=%user.name user_uid=%user.uid file=%fd.name
    process=%proc.name command=%proc.cmdline
    container_id=%container.id container_name=%container.name
    image=%container.image.repository
    pod=%k8s.pod.name ns=%k8s.ns.name)
  priority: ERROR
  tags: [container, filesystem, mitre_persistence]

Rule 3: Detect Privilege Escalation

yaml
- rule: Container privilege escalation via setuid
  desc: >
    Detect a process calling setuid or setgid to escalate privileges
    inside a container. This is a common technique used by attackers
    after gaining initial access.
  condition: >
    evt.type in (setuid, setgid) and
    container and
    evt.dir=< and
    not (user.name=root)
  output: >
    Privilege escalation detected in container
    (user=%user.name uid=%user.uid target_uid=%evt.arg.uid
    process=%proc.name command=%proc.cmdline
    container_id=%container.id container_name=%container.name
    image=%container.image.repository
    pod=%k8s.pod.name ns=%k8s.ns.name)
  priority: CRITICAL
  tags: [container, privilege_escalation, mitre_privilege_escalation]

Rule 4: Detect Package Manager Execution

yaml
- rule: Package manager launched in container
  desc: >
    Detect the execution of a package manager (apt, yum, pip, etc.)
    inside a container. Containers should be immutable and should
    not install packages at runtime.
  condition: >
    spawned_process and
    container and
    proc.name in (package_managers)
  output: >
    Package manager launched in container
    (user=%user.name package_manager=%proc.name
    command=%proc.cmdline
    container_id=%container.id container_name=%container.name
    image=%container.image.repository
    pod=%k8s.pod.name ns=%k8s.ns.name)
  priority: ERROR
  tags: [container, software_mgmt, mitre_persistence]

Rule 5: Detect Outbound Connection to Unusual Port

yaml
- list: allowed_outbound_ports
  items: [53, 80, 443, 8080, 8443]

- rule: Unexpected outbound connection
  desc: >
    Detect an outbound network connection from a container to a port
    not in the allowed list. This can indicate data exfiltration,
    command-and-control communication, or crypto mining.
  condition: >
    evt.type=connect and
    evt.dir=< and
    container and
    fd.typechar=4 and
    fd.ip != "0.0.0.0" and
    not (fd.sport in (allowed_outbound_ports))
  output: >
    Unexpected outbound connection from container
    (process=%proc.name command=%proc.cmdline
    connection=%fd.name
    container_id=%container.id container_name=%container.name
    image=%container.image.repository
    pod=%k8s.pod.name ns=%k8s.ns.name)
  priority: WARNING
  tags: [container, network, mitre_command_and_control]

Rule 6: Detect Sensitive File Read

yaml
- rule: Read sensitive file
  desc: >
    Detect a process reading a sensitive file such as /etc/shadow
    or /etc/passwd inside a container.
  condition: >
    evt.type in (open, openat, openat2) and
    evt.is_open_read=true and
    container and
    fd.name in (/etc/shadow, /etc/passwd, /etc/sudoers)
  output: >
    Sensitive file read in container
    (user=%user.name file=%fd.name process=%proc.name
    command=%proc.cmdline
    container_id=%container.id container_name=%container.name
    image=%container.image.repository
    pod=%k8s.pod.name ns=%k8s.ns.name)
  priority: WARNING
  tags: [container, filesystem, mitre_credential_access]

Rule 7: Detect Process Running as Root

yaml
- rule: Non-root container running as root
  desc: >
    Detect a new process running as root (UID 0) inside a container
    that should not require root access.
  condition: >
    spawned_process and
    container and
    user.uid=0 and
    not (container.image.repository in (allowed_root_images))
  output: >
    Process running as root in container
    (user=%user.name uid=%user.uid process=%proc.name
    command=%proc.cmdline
    container_id=%container.id container_name=%container.name
    image=%container.image.repository
    pod=%k8s.pod.name ns=%k8s.ns.name)
  priority: NOTICE
  tags: [container, process, mitre_execution]

- list: allowed_root_images
  items: []

Default Rules That Matter for CKS

Falco ships with many default rules. These are the most relevant for the CKS exam:

Rule NameWhat It Detects
Terminal shell in containerInteractive shell in a container
Write below etcWrite to /etc directory in a container
Read sensitive file untouchedRead of /etc/shadow, etc.
Write below binary dirWrite to /bin, /usr/bin, etc.
Change thread namespaceNamespace escape attempts
Launch Privileged ContainerPrivileged container started
Contact K8S API Server From ContainerContainer accessing the API server
Unexpected outbound connection destinationConnection to unusual endpoints
Launch Package Management Process in ContainerPackage manager in a container
Mkdir binary dirsCreating directories in /bin, /usr/bin
Launch Sensitive Mount ContainerContainer with sensitive host mounts
Launch Remote File Copy Tools in Containerwget, curl, scp in containers

Do Not Modify Default Rules

Never edit /etc/falco/falco_rules.yaml directly. Instead, override or add rules in /etc/falco/falco_rules.local.yaml or files in /etc/falco/rules.d/. If you need to disable a default rule, override it in the local file with enabled: false.

Disabling a Default Rule

yaml
# In /etc/falco/falco_rules.local.yaml
- rule: Terminal shell in container
  desc: Override to disable this rule
  condition: never_true
  output: Shell spawned in container
  priority: WARNING
  enabled: false

Overriding a Default Rule's Output

yaml
# In /etc/falco/falco_rules.local.yaml
- rule: Terminal shell in container
  desc: Override with custom output
  condition: >
    spawned_process and container and shell_procs
  output: >
    CUSTOM ALERT - Shell in container
    (user=%user.name container=%container.name
    pod=%k8s.pod.name ns=%k8s.ns.name
    command=%proc.cmdline image=%container.image.repository)
  priority: CRITICAL
  tags: [custom, container, shell]

Falco Outputs and Alerting

Falco supports multiple output channels configured in /etc/falco/falco.yaml.

stdout Output (Default)

yaml
# In /etc/falco/falco.yaml
stdout_output:
  enabled: true

File Output

yaml
file_output:
  enabled: true
  keep_alive: false
  filename: /var/log/falco/falco_alerts.log

Syslog Output

yaml
syslog_output:
  enabled: true

HTTP Output (Webhook)

yaml
http_output:
  enabled: true
  url: "http://some-webhook-endpoint:8080/alerts"
  user_agent: "falcosecurity/falco"

gRPC Output

yaml
grpc:
  enabled: true
  bind_address: "unix:///run/falco/falco.sock"
  threadiness: 8

grpc_output:
  enabled: true

Falco Configuration File

The main configuration file is /etc/falco/falco.yaml. Key settings:

yaml
# Rule files to load (in order)
rules_file:
  - /etc/falco/falco_rules.yaml
  - /etc/falco/falco_rules.local.yaml
  - /etc/falco/rules.d

# Watch config and rule files for changes
watch_config_files: true

# Time format for output
time_format_iso_8601: false

# JSON output format (useful for parsing)
json_output: true
json_include_output_property: true
json_include_tags_property: true

# Log level for Falco itself
log_stderr: true
log_syslog: true
log_level: info

# Priority threshold -- only output rules at this level or higher
priority: debug

# Buffer configuration
syscall_buf_size_preset: 4

# Output channels
stdout_output:
  enabled: true

syslog_output:
  enabled: true

file_output:
  enabled: false
  keep_alive: false
  filename: /opt/falco/events.txt

http_output:
  enabled: false
  url: "http://localhost:8080"

# Metadata collection
metadata_download:
  max_mb: 100
  chunk_wait_us: 1000
  watch_freq_sec: 1

Exam Tip

In the CKS exam, you may need to:

  1. Change the output file path in falco.yaml
  2. Enable JSON output for better log parsing
  3. Add a custom rules file to the rules_file list
  4. Restart Falco after any configuration change: systemctl restart falco

Working with Falco in the Exam

Common Commands

bash
# Check Falco service status
systemctl status falco

# Restart Falco after config/rule changes
systemctl restart falco

# View Falco alerts in real time
journalctl -u falco -f

# View alerts from output file
tail -f /var/log/falco/falco_alerts.log

# Validate a rules file
falco -V /etc/falco/falco_rules.local.yaml

# Run Falco with a specific rules file (foreground)
falco -r /etc/falco/custom_rules.yaml

# Run Falco in dry-run mode (validate config only)
falco --dry-run

# List loaded rules
falco --list

Typical Exam Workflow

  1. Read the Falco alert to understand what was detected
  2. Identify the rule that triggered (check default or custom rules)
  3. Find the offending pod/container from the alert output
  4. Investigate the pod specification or runtime behavior
  5. Apply the fix (modify pod spec, add security context, etc.)
  6. Verify the fix by checking Falco alerts

Example: Investigating a Falco Alert

bash
# 1. Check recent Falco alerts
journalctl -u falco --since "5 minutes ago" --no-pager

# Example output:
# WARNING Shell spawned in container
# (user=root shell=bash parent=nginx cmdline=bash
#  container_id=abc123 container_name=web
#  image=nginx pod=web-pod ns=default)

# 2. Identify the pod
kubectl get pod web-pod -n default -o yaml

# 3. Check what's running in the container
kubectl exec web-pod -n default -- ps aux

# 4. Apply fix (e.g., add readOnlyRootFilesystem)
kubectl edit pod web-pod  # or recreate with fix

Summary

ConceptKey Point
What Falco doesMonitors system calls to detect runtime threats
How it worksKernel module/eBPF captures syscalls, rule engine evaluates
Rules locationDefault: /etc/falco/falco_rules.yaml, Custom: /etc/falco/falco_rules.local.yaml
Config location/etc/falco/falco.yaml
Rule componentsLists (values), Macros (reusable conditions), Rules (full detection)
Priority levelsEMERGENCY through DEBUG (8 levels)
Output channelsstdout, file, syslog, HTTP webhook, gRPC
After changesAlways restart: systemctl restart falco

Released under the MIT License.