k8s-security.pro
kubernetes security falco runtime-security monitoring

Kubernetes Runtime Security with Falco: A Complete Guide

Learn how to detect runtime threats in Kubernetes using Falco -- from installation and custom rules to alerting and incident response.

K8s Security Pro Team | | 16 min read

Kubernetes Runtime Security with Falco: A Complete Guide

You can lock down your Kubernetes cluster with network policies, RBAC, and Pod Security Standards. But what happens when an attacker gets past all of those controls? Static security configurations cannot detect a compromised container that is behaving abnormally at runtime. You need a tool that watches what processes, files, and network connections are actually happening inside your pods — in real time. That tool is Falco.

Why Runtime Security Matters

Most Kubernetes security controls are preventive: they stop bad configurations from being deployed. Network policies block unauthorized traffic. Pod Security Standards prevent privileged containers. RBAC limits API access. These are all critical, but they share a fundamental limitation: they cannot detect an attacker who has already gained code execution inside a container.

Consider a scenario where an attacker exploits a remote code execution (RCE) vulnerability in your Node.js application. The container was deployed with proper security context, minimal RBAC, and network policies. But now the attacker can:

  1. Spawn a shell inside the container to explore the environment
  2. Read the service account token at /var/run/secrets/kubernetes.io/serviceaccount/token
  3. Install network tools using the container’s package manager
  4. Scan the cluster network for other services to move laterally
  5. Exfiltrate data through DNS tunneling or HTTPS to external servers
  6. Deploy a cryptocurrency miner to profit from your compute resources

None of these activities violate any static configuration. The pod is running exactly as defined in its spec. The only way to detect this compromise is by monitoring what the container’s processes are actually doing at the system call level — and that is exactly what Falco does.

Runtime security bridges the gap between prevention and detection. It operates on the assumption that breaches will happen (the “assume breach” principle from zero trust) and focuses on detecting and responding to threats as quickly as possible.

Falco Architecture: How It Works

Falco is an open-source runtime security tool created by Sysdig and donated to the Cloud Native Computing Foundation (CNCF), where it is an incubating project. It monitors kernel-level system calls (syscalls) in real time and matches them against a set of configurable rules.

Core Components

1. Kernel Instrumentation

Falco hooks into the Linux kernel to capture syscalls. It supports three drivers:

  • eBPF probe (recommended) — Runs as a BPF program in the kernel. Safe, performant, and does not require a kernel module. Preferred for production and managed Kubernetes (EKS, GKE, AKS).
  • Kernel module — A traditional loadable kernel module (.ko). Higher performance but requires matching the exact kernel version. Used when eBPF is not available.
  • Modern eBPF — Uses CO-RE (Compile Once, Run Everywhere) technology. Works across kernel versions without recompilation. The newest and most portable option (kernel 5.8+).

2. Rule Engine

Falco’s rule engine evaluates every captured syscall against a set of rules. Rules are written in a YAML-based DSL that supports conditions, macros, and lists. When a syscall matches a rule’s condition, Falco generates an alert with the configured priority and output format.

3. Alert Outputs

Falco sends alerts to multiple channels simultaneously:

  • stdout (captured by kubectl logs)
  • syslog
  • Files (JSON or text)
  • gRPC (for the Falco Sidekick integration)
  • HTTP/HTTPS webhooks

How Falco Monitors Containers

When a process inside a container makes a syscall (opening a file, spawning a process, establishing a network connection), the kernel driver captures it. Falco enriches the event with Kubernetes metadata — pod name, namespace, container image, labels — by querying the container runtime. The enriched event is then evaluated against every loaded rule. If a match is found, an alert fires.

This approach means Falco can detect threats that no other tool can see:

  • A shell being spawned in a container that should never have interactive sessions
  • A process reading /etc/shadow or Kubernetes service account tokens
  • An outbound network connection to a known cryptomining pool port
  • A package manager running in a production container (indicating either compromise or bad CI/CD practices)

Installing Falco with Helm

The recommended installation method for Kubernetes is the official Falco Helm chart.

Prerequisites

  • Kubernetes 1.25+
  • Helm 3.x
  • Cluster admin access (Falco needs privileged access for kernel instrumentation)

Installation

# Add the Falco Helm repository
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo update

# Install Falco with the eBPF driver (recommended)
helm install falco falcosecurity/falco \
  --namespace falco \
  --create-namespace \
  --set driver.kind=ebpf \
  --set falcosidekick.enabled=true \
  --set falcosidekick.webui.enabled=true

Verify the Installation

# Check that Falco pods are running on every node
kubectl get pods -n falco -o wide

# Verify Falco is capturing events
kubectl logs -n falco -l app.kubernetes.io/name=falco --tail=20

# Trigger a test alert by spawning a shell in any container
kubectl exec -it deploy/nginx -- /bin/sh
# You should see a "Shell spawned in container" alert in the logs

Key Helm Values

# values-production.yaml
driver:
  kind: ebpf          # Use eBPF probe (no kernel module needed)

falco:
  grpc:
    enabled: true      # Enable gRPC output for Falco Sidekick
  json_output: true    # JSON format for log aggregation
  log_level: info

  # Load custom rules from a ConfigMap
  rules_file:
    - /etc/falco/falco_rules.yaml        # Default rules
    - /etc/falco/falco_rules.local.yaml  # Your custom rules (overrides defaults)

# Falco Sidekick routes alerts to external systems
falcosidekick:
  enabled: true
  config:
    slack:
      webhookurl: "https://hooks.slack.com/services/T00/B00/xxxxx"
      minimumpriority: "warning"
    pagerduty:
      routingKey: "your-pagerduty-integration-key"
      minimumpriority: "critical"

Default Rules: What Falco Detects Out of the Box

Falco ships with approximately 100 default rules that cover common attack patterns. Some of the most important ones:

RulePriorityDetection
Terminal shell in containerNOTICEInteractive shell spawned in any container
Read sensitive file untrustedWARNINGProcess reads /etc/shadow, SA tokens, etc.
Write below /etcWARNINGFile written to /etc/ inside a container
Launch privileged containerWARNINGContainer started with --privileged flag
Contact K8s API server from containerNOTICEDirect API server access from a pod
Outbound connection to C2 serversCRITICALConnection to known malicious IPs
Modify binary dirsCRITICALWriting to /bin, /sbin, /usr/bin

These defaults provide a solid baseline, but you should customize them for your environment. Default rules generate many false positives because they do not know which behaviors are expected in your specific workloads.

Writing Custom Falco Rules

Custom rules are where Falco becomes truly powerful. You can tailor detection to your specific environment, reduce false positives, and detect threats unique to your applications.

Rule Structure

Every Falco rule has three required fields:

- rule: Name of the rule
  desc: What this rule detects and why
  condition: >
    Boolean expression using Falco fields
  output: >
    Alert message template with field substitution
  priority: CRITICAL|WARNING|NOTICE|INFO|DEBUG
  tags:
    - container
    - mitre_execution

Seven Custom Rules for Production Kubernetes

Here are seven custom rules that address the most critical runtime threats. These match the rules included in Template 12: Falco Runtime Security.

Rule 1: Shell Spawned in Container

Detects interactive shells — the first action an attacker takes after gaining access.

- rule: Shell spawned in container
  desc: >
    An interactive shell was spawned inside a running container.
    Strong indicator of hands-on-keyboard activity.
  condition: >
    spawned_process
    and container
    and shell_procs
    and proc.tty != 0
    and not user_expected_shell_in_container
  output: >
    Shell spawned in container
    (user=%user.name container=%container.name image=%container.image.repository
    shell=%proc.name pod=%k8s.pod.name ns=%k8s.ns.name)
  priority: WARNING
  tags: [container, shell, mitre_execution, T1059.004]

Rule 2: Cryptocurrency Mining Detection

Cryptojacking is the most common attack outcome in compromised Kubernetes clusters.

- rule: Cryptocurrency mining process detected
  desc: >
    A known cryptocurrency mining process was detected in a container.
  condition: >
    spawned_process
    and container
    and proc.name in (xmrig, xmr-stak, minerd, cpuminer, cgminer,
                       ethminer, nbminer, t-rex, gminer, lolminer)
  output: >
    CRITICAL: Crypto miner detected
    (process=%proc.name container=%container.name image=%container.image.repository
    pod=%k8s.pod.name ns=%k8s.ns.name)
  priority: CRITICAL
  tags: [container, cryptomining, mitre_impact, T1496]

Rule 3: Sensitive File Access

Detects reads of credential files and Kubernetes tokens.

- rule: Read sensitive file in container
  desc: >
    A process read a sensitive file such as /etc/shadow or SA tokens.
  condition: >
    open_read
    and container
    and (fd.name startswith /etc/shadow
      or fd.name startswith /var/run/secrets/kubernetes.io
      or fd.name startswith /etc/kubernetes/pki)
  output: >
    Sensitive file read in container
    (file=%fd.name process=%proc.name container=%container.name
    pod=%k8s.pod.name ns=%k8s.ns.name)
  priority: CRITICAL
  tags: [container, credential_access, T1552.001]

Rule 4: Privilege Escalation via Setuid

Catches attempts to use setuid binaries like sudo, su, or pkexec.

- rule: Privilege escalation via setuid binary
  desc: >
    A setuid binary was executed inside a container.
  condition: >
    spawned_process
    and container
    and proc.name in (sudo, su, pkexec, newgrp, chsh, passwd, mount)
  output: >
    Privilege escalation attempt
    (command=%proc.cmdline container=%container.name
    pod=%k8s.pod.name ns=%k8s.ns.name)
  priority: CRITICAL
  tags: [container, privilege_escalation, T1548.001]

Rule 5: Network Reconnaissance Tools

Detects scanning and recon tools that attackers use for lateral movement.

- rule: Network reconnaissance tool in container
  desc: >
    A network scanning tool was executed in a container.
  condition: >
    spawned_process
    and container
    and proc.name in (nmap, nc, netcat, socat, tcpdump, masscan, zmap)
  output: >
    Network recon tool executed
    (command=%proc.cmdline container=%container.name
    pod=%k8s.pod.name ns=%k8s.ns.name)
  priority: WARNING
  tags: [container, network, mitre_discovery, T1046]

Rule 6: Package Manager in Production Container

Production containers should be immutable. Package installation indicates compromise or bad practices.

- rule: Package manager in running container
  desc: >
    A package manager was executed in a running container.
  condition: >
    spawned_process
    and container
    and proc.name in (apt, apt-get, dpkg, yum, rpm, dnf, apk, pip, npm)
    and not proc.pname in (docker-entrypoint, entrypoint.sh)
  output: >
    Package manager executed
    (command=%proc.cmdline container=%container.name
    pod=%k8s.pod.name ns=%k8s.ns.name)
  priority: WARNING
  tags: [container, software_installation, T1105]

Rule 7: Write Below /etc

Catches tampering with system configuration files for persistence or evasion.

- rule: Write below /etc in container
  desc: >
    A file was written below /etc inside a container.
  condition: >
    open_write
    and container
    and fd.name startswith /etc/
    and not fd.name in (/etc/resolv.conf, /etc/hostname, /etc/hosts)
  output: >
    File written below /etc
    (file=%fd.name process=%proc.name container=%container.name
    pod=%k8s.pod.name ns=%k8s.ns.name)
  priority: WARNING
  tags: [container, filesystem, mitre_persistence, T1036]

Deploying Custom Rules

Save your custom rules to a file and deploy them as a ConfigMap:

# Create ConfigMap from your rules file
kubectl create configmap falco-custom-rules \
  --from-file=falco_rules.local.yaml=custom-rules.yaml \
  -n falco

# Update Falco Helm release to mount the ConfigMap
helm upgrade falco falcosecurity/falco \
  --namespace falco \
  --set "falco.rules_file[0]=/etc/falco/falco_rules.yaml" \
  --set "falco.rules_file[1]=/etc/falco/falco_rules.local.yaml" \
  --set-file customRules."falco_rules.local\.yaml"=custom-rules.yaml

Alerting: Slack, PagerDuty, and Beyond

Falco itself generates alerts to stdout or files. Falco Sidekick is the companion project that routes these alerts to 50+ external systems. Install it alongside Falco for production alerting.

Slack Integration

# Sidekick values for Slack
falcosidekick:
  config:
    slack:
      webhookurl: "https://hooks.slack.com/services/T00/B00/xxxxx"
      channel: "#k8s-security-alerts"
      minimumpriority: "warning"
      messageformat: |
        *Priority:* {{ .Priority }}
        *Rule:* {{ .Rule }}
        *Output:* {{ .Output }}
        *Namespace:* {{ index .OutputFields "k8s.ns.name" }}
        *Pod:* {{ index .OutputFields "k8s.pod.name" }}

PagerDuty Integration

For critical alerts that need immediate human response:

falcosidekick:
  config:
    pagerduty:
      routingKey: "your-pagerduty-integration-key"
      minimumpriority: "critical"

Alert Routing Strategy

Not every alert deserves a page. Implement a tiered alerting strategy:

PriorityDestinationResponse Time
CRITICALPagerDuty + SlackImmediate (< 5 min)
WARNINGSlack #security-alertsWithin 30 min
NOTICESIEM / log aggregationNext business day
INFOLog storage onlyAudit / forensics

This prevents alert fatigue while ensuring critical threats get immediate attention.

Incident Response with Falco

When Falco fires a critical alert, you need a systematic response process.

Immediate Containment

# 1. Identify the compromised pod
kubectl get pod <pod-name> -n <namespace> -o yaml

# 2. Isolate the pod with a deny-all network policy
kubectl apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: isolate-compromised-pod
  namespace: <namespace>
spec:
  podSelector:
    matchLabels:
      app: <pod-label>
  policyTypes:
    - Ingress
    - Egress
EOF

# 3. Capture forensic evidence before terminating
kubectl logs <pod-name> -n <namespace> > /tmp/compromised-pod-logs.txt
kubectl exec <pod-name> -n <namespace> -- cat /proc/1/status > /tmp/process-status.txt

# 4. Scale down the deployment to stop the compromised workload
kubectl scale deployment <deployment-name> -n <namespace> --replicas=0

Post-Incident Analysis

After containment, use Falco’s alert history (stored in your SIEM or log aggregation) to reconstruct the attack timeline:

  1. When did the first suspicious activity occur?
  2. What was the initial access vector (which vulnerability was exploited)?
  3. What actions did the attacker take (lateral movement, data access, persistence)?
  4. Are any other pods or namespaces affected?
  5. Were any secrets or credentials exposed?

Falco vs Alternatives

Falco is not the only runtime security tool available. Here is how it compares to alternatives:

FeatureFalcoTetragon (Cilium)KubeArmorTracee (Aqua)
CNCF StatusIncubatingSandboxSandboxN/A
Kernel HookeBPF / kmodeBPFeBPF + LSMeBPF
Rule LanguageCustom YAML DSLTracing policies (CRDs)KubeArmor policies (CRDs)Rego + signatures
EnforcementDetection onlyDetection + enforcementDetection + enforcementDetection only
K8s IntegrationMetadata enrichmentDeep (via Cilium CNI)Native CRD-basedMetadata enrichment
CommunityLarge, matureGrowing (Isovalent)GrowingModerate
Learning CurveModerateSteepLowModerate

Choose Falco when:

  • You want the most mature, battle-tested runtime detection tool
  • You need a large library of pre-built rules
  • You are already invested in the CNCF ecosystem
  • You want detection with flexible alerting (Falco Sidekick supports 50+ outputs)

Consider Tetragon when:

  • You already use Cilium as your CNI
  • You need both detection and enforcement (process killing, file access blocking)
  • You want deep integration with network policies

Consider KubeArmor when:

  • You want Kubernetes-native policy management via CRDs
  • You need enforcement at the kernel level (LSM hooks)
  • You prefer a simpler configuration model

Tuning for Production: Reducing False Positives

The biggest challenge with Falco in production is false positives. Default rules are designed for broad detection and will flag many legitimate operations.

Step 1: Run in Audit Mode First

Deploy Falco with all rules enabled but route alerts only to logs (not PagerDuty). Observe for 1-2 weeks to understand your cluster’s normal behavior.

Step 2: Create Exception Lists

For each rule generating false positives, create macros that exclude known-good behavior:

- macro: user_expected_shell_in_container
  condition: >
    (container.image.repository in (
      "docker.io/bitnami/kubectl",
      "gcr.io/my-project/debug-tools"
    ))

Step 3: Use Tags for Selective Alerting

Tag rules by category and configure Falco Sidekick to route different categories to different channels. Crypto mining alerts go to PagerDuty; package manager alerts go to a Slack channel for review.

Step 4: Continuously Refine

As your workloads change, your exception lists need to be updated. Treat Falco rule tuning as an ongoing operational task, not a one-time setup.

Putting It Into Practice

Runtime security is the last line of defense in Kubernetes. Network policies, RBAC, and Pod Security Standards prevent misconfigurations. Falco detects the attacks that get through.

Start with the default rules, deploy in audit mode, and spend two weeks tuning before enabling alerting. Focus your custom rules on the seven critical patterns: shells in containers, cryptomining, sensitive file access, privilege escalation, network reconnaissance, package managers, and system configuration tampering.

The complete set of seven production-ready Falco rules — with macros, MITRE ATT&CK tags, and detailed comments — is available in Template 12: Falco Runtime Security as part of the K8s Security Pro bundle.


Implement what you’ve learned with these production-ready YAML templates:

Get the Complete 50-Point Security Checklist

5 production-ready templates + audit checklist highlights, free for K8s engineers.

Get Free Kit

Get the Free K8s Security Quick-Start Kit

Get 5 essential templates + audit checklist highlights delivered to your inbox.

No spam. Unsubscribe anytime.

Secure Your Kubernetes Clusters

Get the complete 50-point audit checklist and 20+ production-ready YAML templates.

View Pricing Plans