Runtime Security
    eBPF

    Deploy Falco + Tetragon on a VPS

    Runtime security on a RamNode VPS with Falco and Tetragon — eBPF probes, detection rules, in-kernel enforcement, and tuning for noisy hosts.

    Falco and Tetragon are the two leading open-source runtime security tools built on eBPF. They observe syscalls, network activity, and process behavior at the kernel level, then evaluate that telemetry against detection policies. Falco came out of Sysdig and is a CNCF graduated project oriented around alerting on policy violations. Tetragon comes from Isovalent (the Cilium team) and emphasizes deep observability and in-kernel enforcement. They serve overlapping but distinct purposes, and running them together gives you both broad rule-based alerting and targeted policy enforcement. This guide deploys both on a single RamNode VPS for host-level runtime security.

    Sizing, Kernel Requirements, and Prerequisites

    eBPF is a kernel feature, and the version of the kernel matters more than RAM here. Confirm what you have:

    shell
    uname -r

    You want 5.10 or later for Falco's modern eBPF probe, and 5.10 or later for Tetragon. Ubuntu 24.04 LTS ships with 6.8, which is ideal. Ubuntu 22.04 ships with 5.15, which works for both. Anything older needs a HWE kernel or an upgrade.

    Plan the following on RamNode:

    • 2 GB RAM minimum for a host-only deployment
    • 2 vCPU minimum
    • 20 GB disk; eBPF tooling itself is small but you need room for logs
    • Ubuntu 24.04 LTS

    The eBPF overhead is generally low (single-digit percent CPU under normal load), but a noisy ruleset on a busy host can spike. Plan to tune.

    Initial Setup

    Update the base system:

    shell
    apt update && apt -y full-upgrade
    apt -y install ufw curl gnupg2 software-properties-common dkms build-essential

    Install kernel headers, which Falco needs for some probe modes:

    shell
    apt -y install linux-headers-$(uname -r)

    Configure the firewall. Neither tool requires inbound ports unless you expose their gRPC or metrics endpoints externally, which you should not:

    shell
    ufw default deny incoming
    ufw default allow outgoing
    ufw allow 22/tcp
    ufw --force enable

    Installing Falco

    The Falcosecurity project maintains an apt repository. Add it and install:

    shell
    curl -fsSL https://falco.org/repo/falcosecurity-packages.asc \
      | gpg --dearmor -o /usr/share/keyrings/falco-archive-keyring.gpg
    
    echo "deb [signed-by=/usr/share/keyrings/falco-archive-keyring.gpg] \
      https://download.falco.org/packages/deb stable main" \
      | tee /etc/apt/sources.list.d/falcosecurity.list
    
    apt update
    apt -y install falco

    The installer will prompt for the driver type. Choose modern-bpf if you are on a 5.8+ kernel (which you should be on 24.04). The modern eBPF probe is the recommended path and does not require kernel module compilation or BCC.

    If you accidentally selected a different driver during the prompt, you can change it later:

    shell
    falcoctl driver config --type modern_ebpf

    Start Falco and confirm it is running:

    shell
    systemctl enable --now falco-modern-bpf
    systemctl status falco-modern-bpf

    Note the unit name reflects the driver. If you selected the kernel module driver, the unit is falco-kmod instead.

    Falco Rule Configuration

    Falco ships with a default ruleset at /etc/falco/falco_rules.yaml. Do not edit that file directly; it gets overwritten on package upgrade. Local overrides and additions go in /etc/falco/falco_rules.local.yaml.

    The default rules catch a lot of useful behavior: writes to sensitive paths, shell spawned by web servers, container escape patterns, and so on. For a non-Kubernetes host, disable the container-specific rules to cut noise:

    /etc/falco/falco_rules.local.yaml:

    shell
    - macro: container
      condition: (container.id != host)
      override:
        condition: replace
    
    - rule: Disallowed SSH Connection
      desc: Detect any new SSH connection to a host other than those in an allowed group
      condition: >
        inbound_outbound and ssh_port and not allowed_ssh_hosts
      output: >
        Disallowed SSH Connection (command=%proc.cmdline connection=%fd.name
        user=%user.name container_id=%container.id image=%container.image.repository)
      priority: NOTICE
      tags: [network]
    
    - list: allowed_ssh_hosts
      items: [your.bastion.ip.here]

    Reload Falco after rule changes:

    shell
    systemctl reload falco-modern-bpf

    Validate that the rule loaded:

    shell
    falco --validate /etc/falco/falco_rules.local.yaml

    Falco Output Configuration

    By default, Falco writes alerts to syslog and stdout. For production, you want at least one structured sink. Edit /etc/falco/falco.yaml:

    shell
    json_output: true
    json_include_output_property: true
    json_include_tags_property: true
    
    log_level: info
    
    stdout_output:
      enabled: true
    
    file_output:
      enabled: true
      keep_alive: false
      filename: /var/log/falco/events.json
    
    http_output:
      enabled: true
      url: https://your-siem.example.org/falco
      user_agent: "falco/0.39"
      insecure: false
      ca_cert: /etc/ssl/certs/ca-certificates.crt
      echo: false

    Create the log directory and restart:

    shell
    mkdir -p /var/log/falco
    systemctl restart falco-modern-bpf

    For Slack or webhook alerting without writing a custom sink, deploy falcosidekick. It is a small Go service that takes Falco's gRPC output and fans it out to dozens of destinations. Install via apt from the same repo:

    shell
    apt -y install falcosidekick

    Configure /etc/falco/falcosidekick.yaml with your destination of choice (Slack, PagerDuty, OpenObserve, Loki, and so on). Falcosidekick documentation lists the per-destination config keys.

    Installing Tetragon

    Tetragon ships as a static binary and a systemd unit. The official install path is via tarball:

    shell
    TETRAGON_VERSION=v1.4.1
    cd /tmp
    curl -LO "https://github.com/cilium/tetragon/releases/download/${TETRAGON_VERSION}/tetragon-${TETRAGON_VERSION}-amd64.tar.gz"
    tar -xzf "tetragon-${TETRAGON_VERSION}-amd64.tar.gz"
    cd "tetragon-${TETRAGON_VERSION}-amd64"
    ./install.sh

    The installer drops the binary at /usr/local/bin/tetragon, the CLI at /usr/local/bin/tetra, default policies at /etc/tetragon/, and a systemd unit. Start the service:

    shell
    systemctl enable --now tetragon
    systemctl status tetragon

    Verify Tetragon is producing events:

    shell
    tetra getevents -o compact

    Open another shell on the VPS and run something benign like ls /etc. You should see the process exec event appear in the tetra output stream within a second.

    Writing TracingPolicies for Tetragon

    Tetragon's detection logic lives in TracingPolicy custom resources. On a non-Kubernetes host, these are YAML files in /etc/tetragon/tetragon.conf.d/ or loaded via the CLI. A useful starter policy that catches suspicious binary execution from world-writable directories:

    /etc/tetragon/tetragon.conf.d/exec-from-tmp.yaml:

    shell
    apiVersion: cilium.io/v1alpha1
    kind: TracingPolicy
    metadata:
      name: "exec-from-tmp"
    spec:
      kprobes:
        - call: "security_bprm_check"
          syscall: false
          args:
            - index: 0
              type: "linux_binprm"
          selectors:
            - matchArgs:
                - index: 0
                  operator: "Prefix"
                  values:
                    - "/tmp/"
                    - "/var/tmp/"
                    - "/dev/shm/"
              matchActions:
                - action: Post

    Reload Tetragon to pick up the policy:

    shell
    systemctl restart tetragon

    Test by copying a binary to /tmp and running it:

    shell
    cp /bin/ls /tmp/testbin && /tmp/testbin
    tetra getevents -o compact | head

    You should see the exec event flagged.

    How Falco and Tetragon Complement Each Other

    The natural question is whether you need both. The answer for most production deployments is yes, for these reasons:

    Falco has a mature, community-maintained ruleset that covers the common attack patterns out of the box. The rules are written in a high-level DSL, the alerts are easy to triage, and the ecosystem (Falcosidekick, response actions, third-party integrations) is broad.

    Tetragon has lower overhead for high-volume event collection, supports in-kernel filtering and enforcement (it can kill a process from kernel space, not just alert on it), and produces more granular event data including full argument capture for tracked syscalls. The policy language is lower-level, which is more work but gives you more precision.

    Running both, Falco handles the breadth (default detection coverage) and Tetragon handles the depth (targeted high-fidelity policies for the highest-value detections, plus enforcement where appropriate).

    Performance Tuning

    Both tools have low default overhead, but a noisy ruleset can change that. Monitor both:

    shell
    systemctl status falco-modern-bpf
    systemctl status tetragon
    ps -p $(pgrep -x falco) -o pcpu,pmem,rss
    ps -p $(pgrep -x tetragon) -o pcpu,pmem,rss

    Falco exposes metrics on a Prometheus endpoint. Enable in /etc/falco/falco.yaml:

    shell
    metrics:
      enabled: true
      interval: 1h
      output_rule: true
      rules_counters_enabled: true
      resource_utilization_enabled: true
    
    webserver:
      enabled: true
      listen_port: 8765
      ssl_enabled: false
      threadiness: 0
      prometheus_metrics_enabled: true

    Tetragon exposes Prometheus metrics by default at port 2112. Scrape both from your existing Prometheus.

    The key metrics to alert on:

    • Falco falco_n_drops rising (eBPF buffer overflows)
    • Falco rule evaluation latency on hot rules
    • Tetragon tetragon_msg_op_total rate spikes
    • CPU and RSS of both daemons

    Log Shipping

    Falco's JSON output and Tetragon's event stream both need to leave the host to be useful for forensic timelines. Tetragon supports a built-in JSON file exporter; enable it in /etc/tetragon/tetragon.yaml:

    shell
    export-filename: /var/log/tetragon/tetragon.log
    export-file-perm: "600"
    export-file-max-size-mb: 100
    export-file-max-backups: 5
    export-file-compress: true

    Restart Tetragon. Then use Vector, Filebeat, or Fluent Bit to ship both Falco's /var/log/falco/events.json and Tetragon's /var/log/tetragon/tetragon.log to your SIEM. A Vector source block for both:

    shell
    sources:
      falco:
        type: file
        include: [/var/log/falco/events.json]
        read_from: end
    
      tetragon:
        type: file
        include: [/var/log/tetragon/tetragon.log]
        read_from: end

    Operational Hygiene

    Both tools touch the kernel and both will keep running through a graceful upgrade, but kernel upgrades require driver compatibility checks. After any kernel upgrade:

    shell
    falco --version
    tetragon --version
    systemctl status falco-modern-bpf tetragon

    The modern_bpf driver and Tetragon's eBPF programs are CO-RE (compile once, run everywhere), so they survive most kernel upgrades. If you are on the kernel module driver for Falco, you need to rebuild after every kernel change.

    Set up alerts for:

    • Either service in failed state
    • Driver load failure on boot (check journalctl for both units)
    • Event drop counters non-zero
    • Rule file syntax errors after edits (validate before reload)

    The natural progressions from here are detection engineering (writing custom Falco rules and Tetragon TracingPolicies for your specific threat model), response automation (using Falcosidekick to drive automated containment via webhook actions), and SOC integration (correlating runtime alerts with network telemetry from Suricata/Zeek and threat intel from MISP). Each of those is a substantial topic in its own right.