You'll deploy Falco in eBPF mode, trigger a default alert, then extend Falco with a custom rule that catches curl and wget being run inside containers.
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo update
helm install falco falcosecurity/falco \
--namespace falco \
--create-namespace \
--set driver.kind=modern_ebpf \
--set tty=true \
--waitConfirm Falco is running on every node:
kubectl get pods -n falcoNAME READY STATUS RESTARTS AGE
falco-x8k2p 1/1 Running 0 45s
falco-m9nqr 1/1 Running 0 45s
falco-j4tpw 1/1 Running 0 45sOne pod per node — Falco runs as a DaemonSet because it needs to monitor syscalls on every node independently.
Open a second terminal and stream the Falco logs:
# Terminal 2 — watch for alerts
kubectl logs -n falco -l app.kubernetes.io/name=falco -f --max-log-requests 3In your first terminal, exec into the secure-app pod:
# Terminal 1 — trigger the shell detection
POD=$(kubectl get pod -n staging -l app=secure-app \
-o jsonpath='{.items[0].metadata.name}')
kubectl exec -it $POD -n staging -- shWithin a second, Terminal 2 shows:
2024-03-15T14:23:41.456Z: Notice A shell was spawned in a container with an attached terminal
(user=root user_loginuid=-1 k8s.ns=staging k8s.pod=secure-app-7d9f8b-xxx
container=app shell=sh parent=runc cmdline=sh terminal=34816)
rule=Terminal shell in container priority=NOTICE
tags=[container, shell, mitre_execution]
This is Falco's built-in Terminal shell in container rule firing. It detected the kubectl exec session the moment you ran it.
The built-in rules are comprehensive, but every production environment has workloads with unique behaviour. Here is a custom rule that alerts when curl or wget is executed inside any container:
# custom-rules.yaml
customRules:
custom-rules.yaml: |-
- rule: Suspicious network tool in container
desc: >
Detects execution of curl or wget inside a running container.
These tools are commonly used for data exfiltration, downloading
attacker payloads, or reaching command-and-control servers.
Production containers should not be making ad-hoc HTTP requests.
condition: >
spawned_process
and container
and proc.name in (curl, wget)
output: >
Network tool executed in container
(user=%user.name tool=%proc.name cmd=%proc.cmdline
pod=%k8s.pod.name ns=%k8s.ns.name image=%container.image)
priority: WARNING
tags: [network, exfiltration, custom]Apply it by upgrading the Helm release:
helm upgrade falco falcosecurity/falco \
--namespace falco \
--set driver.kind=modern_ebpf \
--set tty=true \
-f custom-rules.yaml \
--wait# Terminal 1 — run curl inside the container
kubectl exec -it $POD -n staging -- sh -c 'curl https://example.com'Terminal 2 immediately shows:
2024-03-15T14:31:07.812Z: Warning Network tool executed in container
(user=root tool=curl cmd=curl https://example.com
pod=secure-app-7d9f8b-xxx ns=staging image=nginx:1.25-alpine)
rule=Suspicious network tool in container priority=WARNING
tags=[network, exfiltration, custom]
Streaming logs is useful during development. In production, you need alerts routed to your alerting pipeline. Falcosidekick handles this with support for Slack, PagerDuty, Datadog, Elasticsearch, and over 50 other outputs:
# falcosidekick-values.yaml
config:
slack:
webhookurl: "https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
minimumpriority: "warning"
messageformat: >
[{{.Priority}}] {{.Rule}} |
pod: {{.OutputFields.k8s.pod.name}} |
ns: {{.OutputFields.k8s.ns.name}} |
image: {{.OutputFields.container.image}}helm install falcosidekick falcosecurity/falcosidekick \
--namespace falco \
-f falcosidekick-values.yamlTuning Falco for production: A fresh Falco deployment will generate false positives, especially in the first week. Your job is to tune rules to match your workloads' normal behaviour, not to respond to every alert. The workflow: deploy in staging → identify false positives → add
exceptconditions to rules → validate the false positive rate is low → enable in production with alerting.