Skip to content

feat(security): add Falco runtime threat detection - #25

Merged
leeclay95 merged 1 commit into
mainfrom
feat/falco-runtime-audit
Jul 17, 2026
Merged

leeclay95 merged 1 commit into
mainfrom
feat/falco-runtime-audit

Conversation

@leeclay95

Copy link
Copy Markdown
Owner

What

Adds Falco — syscall-level runtime threat detection — installed via Terraform, shipping alerts to floci CloudWatch.

This closes the gap we hit while investigating the audit log: /k8s/webapp/audit shows that someone exec'd into a pod and the launch command, but not the commands run inside the shell afterward. Falco taps execve at the kernel, so it sees them.

Layer Sees
k8s audit "system:admin exec'd bash into webapp"
Falco the cat /etc/shadow, id, … run inside

Changes

  • terraform/cluster/falco.tf — helm_release (chart 9.1.0, modern-eBPF driver, observe-only) in its own falco namespace (exempt from the webapp-scoped Gatekeeper constraints). Plus a null_resource that mounts debugfs on the node first.
  • scripts/recover.sh — re-mounts debugfs after a reboot (tmpfs, lost on restart — same class as flannel's subnet.env) and bounces Falco.
  • logging/cloudwatch-log-shipper.yaml — third stream: /var/log/pods/falco_*/falco/*.log → /k8s/falco.
  • docs/falco.md — driver rationale, the k3d debugfs catch, and full test flow.

The k3d gotcha (documented)

k3d nodes don't mount debugfs, so the eBPF probe can't resolve syscall tracepoint IDs and Falco captures nothing (failed to determine tracepoint ... perf event ID). Mounting it fixes it cleanly (0 tracepoint errors). Handled at both cluster-create (falco.tf) and reboot (recover.sh). I tried a self-contained init-container mount first but it left a propagation race (3 residual errors); the node-level mount is clean and matches the lab's existing node-fixup pattern.

Verified live (end to end)

  • modern eBPF loads with 0 tracepoint errors.
  • kubectl exec -it into webapp → Falco fires Terminal shell in container (MITRE T1059) with the exact proc.cmdline.
  • The alert reaches /k8s/falco in floci CloudWatch via the shipper.
  • Simulated a fresh node (unmounted debugfs, restarted) — the mount path restores capture.

Local scripts/security-gates.sh → all four gates PASS (tfsec clean on the new falco.tf).

Footprint

No vuln DB, no scan jobs — none of the disk-pressure risk Trivy Operator carries. ~256Mi/pod.

🤖 Generated with Claude Code

…loudWatch

Falco captures what the API-server audit log can't: the commands run INSIDE a
container after an exec (not just the exec call). Modern eBPF (CO-RE) driver,
observe-only, in its own falco namespace (exempt from the webapp Gatekeeper
constraints). Alerts ship to floci CloudWatch /k8s/falco.

- falco.tf: helm_release (chart 9.1.0) + a null_resource that mounts debugfs on
  the node first — k3d doesn't mount it, and without it the BPF probe can't read
  syscall tracepoints (Falco captures nothing).
- recover.sh: re-mount debugfs after a reboot (it's on tmpfs, lost on restart,
  like flannel's subnet.env) and bounce Falco to re-attach.
- cloudwatch-log-shipper.yaml: add a third stream, falco pods -> /k8s/falco.
- docs/falco.md: driver rationale, the debugfs catch, and how to test it end to
  end (trigger -> Falco logs -> CloudWatch).

Verified live: modern eBPF loads clean (0 tracepoint errors), a tty exec into
webapp fires "Terminal shell in container" with the full command line, and the
alert lands in /k8s/falco via the shipper.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@leeclay95
leeclay95 merged commit e0913db into main Jul 17, 2026
1 check passed
@leeclay95
leeclay95 deleted the feat/falco-runtime-audit branch July 17, 2026 23:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant