Use Falco to detect suspicious behaviors inside containers in real-time and learn to configure custom security rules for Kubernetes environments.
Prerequisites
Understanding Falco
Falco is a cloud-native runtime security project that detects unexpected behavior, intrusions, and data theft in real-time. It works by monitoring system calls and Kubernetes events.
Q1: What does Falco monitor?
Answer
Falco monitors:
System calls: File access, process execution, network activity
Kubernetes events: Pod creation, service account changes, ConfigMap modifications
Falco uses rules written in a YAML format that define suspicious activities and generate alerts when these conditions are met.
Q2: How does Falco work in Kubernetes?
Answer
Falco typically runs as a DaemonSet in Kubernetes:
One pod per node: Monitors all containers on that node
Kernel module or eBPF: Captures system call information
Rule engine: Evaluates events against security rules
Output: Sends alerts to logs, SIEM systems, or notification channels
The default installation includes pre-built rules for common security scenarios.
Install Falco on Kubernetes
Setup Falco
helm repo update
# Install Falco in its own namespace# tty=true allow instant flush: as soon as an alert is generated, the line is "flushed" to the console.helm install --replace falco --namespace falco --create-namespace \
--set tty=true \
--set falcosidekick.enabled=true \
--set falcosidekick.webui.enabled=true \
falcosecurity/falco
Note for Kind Users: Since all nodes in a Kind cluster share the host’s Linux kernel, a Falco instance on one node may “hear” system calls from a pod running on another node. This leads to duplicate alerts where some entries show <NA> for Kubernetes metadata.
# Create a test deploymentkubectl create deployment test-app --image=nginx:alpine
# Wait for pod to be readykubectl wait --for=condition=Ready pod -l app=test-app --timeout=60s
# Get pod nameTEST_POD=$(kubectl get pods -l app=test-app -o jsonpath='{.items[0].metadata.name}')echo "Test pod: $TEST_POD"
Trigger Security Alerts
Solution
# Terminal 1: Watch Falco logs in real-time# ### 💡 Pro-tip: Cleaning the output# Since we are in a Kind environment, you will see background noise from the infrastructure.# To focus only on relevant security events, use `grep` to filter out empty metadata and infrastructure processes:kubectl logs -l app.kubernetes.io/name=falco -n falco -c falco -f | grep -v "k8s_pod_name=<NA>"# Terminal 2: Trigger various security violations# 1. Trigger "Read sensitive file untrusted" rulekubectl exec -it $TEST_POD -- cat /etc/shadow
# 2. Trigger "Shell in container" rulekubectl exec -it $TEST_POD -- /bin/sh -c "whoami"# 3. Trigger "Executing binary not part of base image" rulekubectl exec -it $TEST_POD -- chmod +s /bin/ls || echo "Expected to fail"# Check logs for alerts on given levels: Notice|Warning|Critical|Errorkubectl logs -l app.kubernetes.io/name=falco -n falco -c falco --tail=20 | grep -v "k8s_pod_name=<NA>" | grep -E "Error"
Expected output examples:
Warning Sensitive file opened for reading by non-trusted program
Notice A shell was spawned in a container with an attached terminal
Modify Falco Rules Directly
⚠️ Indentation Warning: YAML does not allow tab characters. Ensure your editor (VS Code, Vim, Nano) is configured to “Expand Tabs” (use 2 or 4 spaces). In Vim, you can run :set expandtab.
Setting up CKS Rules
We will start by injecting baseline detection rules for network reconnaissance and privilege escalation.
Create the configuration file
Create a file named falco-cks-values.yaml on your host machine:
cat << EOF > falco-cks-values.yaml
# Configuration for Falco CKS Lab
customRules:
cks_rules.yaml: |-
# 1. Rule for Network Tools
- rule: CKS Network Tool Usage
desc: Detect network reconnaissance tools
# Simple and robust condition for lab environments
condition: >
evt.type = execve and
(proc.name in (nmap, netcat, nc, telnet, wget, curl))
output: "ALERT_CKS: Network tool detected (user=%user.name pod=%k8s.pod.name tool=%proc.name cmdline=%proc.cmdline)"
priority: WARNING
tags: [network, reconnaissance]
# 2. Rule for Privilege Escalation
- rule: CKS Privilege Escalation Attempt
desc: Detect potential privilege escalation
# Note: 'passwd' is used here for testing even if run by root
condition: >
evt.type = execve and
(proc.name in (sudo, su, passwd))
output: "ALERT_CKS: Privilege escalation tool (user=%user.name pod=%k8s.pod.name proc=%proc.name)"
priority: CRITICAL
tags: [privilege_escalation]
EOF
# Edit local rule filecat << EOF >> falco-cks-values.yaml
- rule: Terminal shell in container
desc: A shell was spawned in a container with an attached terminal
condition: >
spawned_process and container
and shell_procs and proc.tty != 0
and container.id != host
and k8s.pod.name != "<NA>"
output: "[CKS_UPDATE] Shell detected! pod=%k8s.pod.name image=%container.image.repository tty=%proc.tty"
priority: WARNING
EOF# Apply the changeshelm upgrade falco falcosecurity/falco --namespace falco \
--set tty=true \
--set falcosidekick.enabled=true \
--set falcosidekick.webui.enabled=true \
-f falco-cks-values.yaml
# Wait for falco to restartkubectl wait --for=condition=Ready pods --all -n falco --timeout=300s
4. Final Test: Shell Validation
Run the following command to validate your custom rule:
# For automated testing, use timeout to avoid hangingtimeout 10 kubectl exec -it test-attack -- sh -c "echo 'Shell access test completed'"|| echo "Shell test completed"
Expected Result:
The alert should now display with the enriched suffix: ... | pod=test-attack image=nginx.