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.
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:
- Spawn a shell inside the container to explore the environment
- Read the service account token at
/var/run/secrets/kubernetes.io/serviceaccount/token - Install network tools using the container’s package manager
- Scan the cluster network for other services to move laterally
- Exfiltrate data through DNS tunneling or HTTPS to external servers
- 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/shadowor 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:
| Rule | Priority | Detection |
|---|---|---|
| Terminal shell in container | NOTICE | Interactive shell spawned in any container |
| Read sensitive file untrusted | WARNING | Process reads /etc/shadow, SA tokens, etc. |
| Write below /etc | WARNING | File written to /etc/ inside a container |
| Launch privileged container | WARNING | Container started with --privileged flag |
| Contact K8s API server from container | NOTICE | Direct API server access from a pod |
| Outbound connection to C2 servers | CRITICAL | Connection to known malicious IPs |
| Modify binary dirs | CRITICAL | Writing 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:
| Priority | Destination | Response Time |
|---|---|---|
| CRITICAL | PagerDuty + Slack | Immediate (< 5 min) |
| WARNING | Slack #security-alerts | Within 30 min |
| NOTICE | SIEM / log aggregation | Next business day |
| INFO | Log storage only | Audit / 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:
- When did the first suspicious activity occur?
- What was the initial access vector (which vulnerability was exploited)?
- What actions did the attacker take (lateral movement, data access, persistence)?
- Are any other pods or namespaces affected?
- 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:
| Feature | Falco | Tetragon (Cilium) | KubeArmor | Tracee (Aqua) |
|---|---|---|---|---|
| CNCF Status | Incubating | Sandbox | Sandbox | N/A |
| Kernel Hook | eBPF / kmod | eBPF | eBPF + LSM | eBPF |
| Rule Language | Custom YAML DSL | Tracing policies (CRDs) | KubeArmor policies (CRDs) | Rego + signatures |
| Enforcement | Detection only | Detection + enforcement | Detection + enforcement | Detection only |
| K8s Integration | Metadata enrichment | Deep (via Cilium CNI) | Native CRD-based | Metadata enrichment |
| Community | Large, mature | Growing (Isovalent) | Growing | Moderate |
| Learning Curve | Moderate | Steep | Low | Moderate |
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.
Related Templates
Implement what you’ve learned with these production-ready YAML templates:
- Template 12: Falco Runtime Security — 7 detection rules with macros, MITRE ATT&CK tags, and severity levels for runtime threat detection.
- Template 10: Comprehensive Audit Policy — Kubernetes API audit logging to complement Falco’s syscall-level monitoring.
- Template 09: Seccomp Profile — Restrict syscalls at the kernel level to reduce the attack surface Falco needs to monitor.
- Template 03: Hardened Pod Security Context — Lock down pod security settings as the first line of defense before runtime detection.
Related Articles
- Kubernetes Network Policies: The Complete Guide to Zero Trust Networking — Complement runtime detection with network-level segmentation to contain compromised pods.
- Kubernetes Pod Security Standards: From PSP to PSS Migration Guide — Prevent many attack patterns at the admission level so Falco focuses on novel threats.
- Kubernetes Supply Chain Security: From Image Scanning to SLSA — Secure your images before deployment to reduce the risk of runtime compromise.
Get the Complete 50-Point Security Checklist
5 production-ready templates + audit checklist highlights, free for K8s engineers.
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