Falco rules are your first line of defense against unexpected behavior in your Kubernetes cluster, but crafting effective ones from scratch can feel like a dark art.

Let’s watch Falco in action. Imagine this kubectl command executed in a cluster:

kubectl exec -it some-pod -- /bin/bash -c 'echo "hello" > /tmp/test.txt'

A good Falco rule should catch this if it’s unexpected. Here’s a rule that targets this specific scenario, focusing on a shell process (/bin/bash) writing to a temporary directory (/tmp) within a container:

- rule: Write to /tmp in container
  desc: "Detects unexpected writes to /tmp within a container, which could indicate malicious activity or misconfiguration."
  condition: >
    container and proc.name = "/bin/bash" and
     Tập.name = "write" and
     Tập.path startswith "/tmp/"
  enabled: true
  alert: Warning
  source: syscall
  tags:
    - k8s
    - container
    - defense

This rule fires when:

  • container is true (meaning the event is happening inside a container).
  • proc.name is exactly /bin/bash (we’re looking for shell activity).
  • Tập.name is write (the specific syscall we’re interested in).
  • Tập.path starts with /tmp/ (any file being written to within the temporary directory).

The enabled: true flag means this rule is active. alert: Warning sets the severity. source: syscall indicates Falco is monitoring system calls. tags are for organization.

This rule is a good starting point, but it’s too broad. What if a legitimate application needs to write to /tmp? We need to refine it.

Consider a more specific scenario: a web server process (nginx or apache2) writing to /tmp. This might be for temporary file handling, caching, or even logging if misconfigured. A rule to catch this:

- rule: Web server writing to /tmp
  desc: "Detects web server processes (nginx, apache2) writing to /tmp, which is often unexpected and could be a sign of compromise or misconfiguration."
  condition: >
    container and
    (proc.name = "nginx" or proc.name = "apache2") and
     Tập.name = "write" and
     Tập.path startswith "/tmp/"
  enabled: true
  alert: Warning
  source: syscall
  tags:
    - k8s
    - container
    - webserver
    - defense

This rule narrows the focus to specific process names (nginx, apache2).

Now, let’s talk about what makes a Falco rule effective. It’s about understanding the syscalls and the Kubernetes environment. Falco’s power comes from its ability to correlate events. For example, you might want to know who is running a shell inside a container and what they’re doing.

Here’s a rule that flags any new shell process (/bin/bash, /bin/sh) spawned within a container, but only if it’s not a known, expected process. This requires a bit more context.

- rule: Unexpected shell in container
  desc: "Detects the spawning of new shell processes (bash, sh) within containers, excluding known legitimate shells."
  condition: >
    container and
    proc.name in ("/bin/bash", "/bin/sh") and
    not proc.cwd = "/usr/local/bin/my-app" and # Example: exclude if cwd is your app dir
    not proc.executable in ("/usr/local/bin/app-startup.sh", "/opt/my-app/run.sh") # Example: exclude known scripts
  enabled: true
  alert: Warning
  source: syscall
  tags:
    - k8s
    - container
    - shell
    - anomaly

The not clauses are crucial here. You might need to adjust proc.cwd (current working directory) or proc.executable based on your application’s actual structure and startup scripts. This is where understanding your own environment is key.

What if a process is trying to execute something from a weird location?

- rule: Execute from unusual location in container
  desc: "Detects execution of files from non-standard directories within containers, potentially indicating malware or exploit attempts."
  condition: >
    container and
     Tập.name = "execve" and
     Tập.path !~ "^(/usr/local/bin/|/app/|/opt/my-app/)" # Example: allow execution from specific paths
  enabled: true
  alert: Warning
  source: syscall
  tags:
    - k8s
    - container
    - execution
    - defense

The !~ operator is a "does not match regex" operator. This rule flags any execution syscall (execve) where the executable path doesn’t match the provided regular expression, which we’ve set to allow common application directories. You must tailor this regex to your specific application paths.

Consider network activity. Unexpected outbound connections from a container are a huge red flag.

- rule: Unexpected outbound connection from container
  desc: "Detects outbound network connections from containers to unexpected destinations."
  condition: >
    container and
     Tập.name = "connect" and
    fd.family = "ipv4" and
     Tập.remote_port !in (80, 443, 5432) and # Example: allow standard web/db ports
     Tập.remote_ip !in ("192.168.0.0/16", "10.0.0.0/8") # Example: allow internal IPs
  enabled: true
  alert: Warning
  source: syscall
  tags:
    - k8s
    - container
    - network
    - anomaly

This rule looks for connect syscalls. fd.family = "ipv4" filters for IPv4. Tập.remote_port !in (80, 443, 5432) excludes common ports like HTTP, HTTPS, and PostgreSQL. Tập.remote_ip !in ("192.168.0.0/16", "10.0.0.0/8") excludes private IP ranges. You’ll need to adjust these in lists based on your cluster’s legitimate outbound traffic.

A very common attack vector is privilege escalation or modification of system files. Detecting changes to sensitive files is critical.

- rule: Modify sensitive file
  desc: "Detects modifications to critical system files, which could indicate an attempted compromise."
  condition: >
     Tập.name = "write" and
     Tập.path in ("/etc/passwd", "/etc/shadow", "/etc/sudoers", "/etc/ssh/sshd_config")
  enabled: true
  alert: Critical
  source: syscall
  tags:
    - k8s
    - defense
    - critical

This rule is simpler, focusing on specific, highly sensitive files. The alert: Critical severity reflects the danger.

The most subtle and powerful aspect of Falco rules is understanding the context provided by Kubernetes. Falco can enrich syscall events with Kubernetes metadata like pod name, namespace, and labels.

- rule: Sensitive syscall in privileged container
  desc: "Detects sensitive syscalls (e.g., mount, reboot) occurring in a privileged container, which should be highly restricted."
  condition: >
    container and
    k8s.pod.privileged = true and
     Tập.name in ("mount", "reboot", "setuid", "setgid")
  enabled: true
  alert: Critical
  source: syscall
  tags:
    - k8s
    - container
    - privileged
    - defense

This rule leverages k8s.pod.privileged = true to identify containers running with elevated privileges. If any sensitive syscalls occur in such a container, it’s flagged as critical. This requires Falco to be properly integrated with your Kubernetes API server to get this metadata.

When you’re writing rules, always start with a specific, observable behavior you want to detect. Then, translate that behavior into Falco’s rule language, leveraging syscalls, process information, and crucially, Kubernetes metadata. The key is iterative refinement: start broad, observe false positives, and then add more specific conditions (not, in, regex, metadata) to hone in on true threats.

The next error you’ll hit when you think you’ve got it all is a false positive caused by an application you forgot about.

Want structured learning?

Take the full Falco course →