<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Falco Archives - Linuxcent</title>
	<atom:link href="https://linuxcent.com/tag/falco/feed/" rel="self" type="application/rss+xml" />
	<link>https://linuxcent.com/tag/falco/</link>
	<description>Infrastructure security, from the kernel up.</description>
	<lastBuildDate>Mon, 06 Jul 2026 03:36:01 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0.4</generator>

<image>
	<url>https://linuxcent.com/wp-content/uploads/2026/04/favicon-512x512-1-150x150.png</url>
	<title>Falco Archives - Linuxcent</title>
	<link>https://linuxcent.com/tag/falco/</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">211632295</site>	<item>
		<title>Detection Engineering with eBPF: Kernel-Level Visibility for Cloud Incidents</title>
		<link>https://linuxcent.com/detection-engineering-ebpf-cloud/</link>
					<comments>https://linuxcent.com/detection-engineering-ebpf-cloud/#respond</comments>
		
		<dc:creator><![CDATA[Vamshi Krishna Santhapuri]]></dc:creator>
		<pubDate>Mon, 06 Jul 2026 02:00:00 +0000</pubDate>
				<category><![CDATA[Purple Team]]></category>
		<category><![CDATA[Detection Engineering]]></category>
		<category><![CDATA[eBPF]]></category>
		<category><![CDATA[Falco]]></category>
		<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Tetragon]]></category>
		<guid isPermaLink="false">https://linuxcent.com/?p=1873</guid>

					<description><![CDATA[<p><span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 13</span> <span class="rt-label rt-postfix">minutes</span></span>eBPF gives detection engineers kernel-level visibility that no attacker can evade without kernel access. Build detection rules for the techniques your SIEM misses entirely.</p>
<p>The post <a href="https://linuxcent.com/detection-engineering-ebpf-cloud/">Detection Engineering with eBPF: Kernel-Level Visibility for Cloud Incidents</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></description>
										<content:encoded><![CDATA[<span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 13</span> <span class="rt-label rt-postfix">minutes</span></span><style>
pre{position:relative;background:#1e1e1e;color:#d4d4d4;
    padding:16px 16px 16px 20px;border-radius:6px;overflow-x:auto;
    font-family:'JetBrains Mono','Fira Code','Cascadia Code',Consolas,'Courier New',monospace;
    font-size:.88em;line-height:1.6;border-left:4px solid #555}
code{background:#f4f4f4;padding:2px 5px;border-radius:3px;font-size:.9em}
pre code{background:transparent;padding:0;color:inherit}
pre[data-lang="bash"],pre[data-lang="sh"],
pre[data-lang="shell"],pre[data-lang="zsh"]{border-left-color:#4ec9b0}
pre[data-lang="yaml"],pre[data-lang="json"],
pre[data-lang="toml"],pre[data-lang="xml"]{border-left-color:#569cd6}
pre[data-lang="python"],pre[data-lang="go"],pre[data-lang="rust"],
pre[data-lang="java"],pre[data-lang="c"],pre[data-lang="cpp"]{border-left-color:#c586c0}
pre[data-lang="text"],pre[data-lang="output"],
pre[data-lang="console"]{border-left-color:#888}
.lc-copy-btn{position:absolute;top:8px;right:8px;background:#2d2d2d;color:#ccc;
    border:1px solid #444;border-radius:4px;padding:3px 9px;font-size:.75em;
    font-family:system-ui,sans-serif;cursor:pointer;opacity:0;
    transition:opacity .15s,background .15s;line-height:1.6}
pre:hover .lc-copy-btn{opacity:1}
.lc-copy-btn:hover{background:#3a3a3a;color:#fff}
.lc-copy-btn.copied{color:#4ec9b0;border-color:#4ec9b0}
.lc-lang-badge{position:absolute;top:8px;left:20px;font-family:system-ui,sans-serif;
    font-size:.7em;color:#666;text-transform:uppercase;letter-spacing:.04em;
    line-height:1;pointer-events:none;opacity:0;transition:opacity .15s}
pre:hover .lc-lang-badge{opacity:1}
table{border-collapse:collapse;width:100%;margin:16px 0}
th,td{border:1px solid #ddd;padding:10px 14px;text-align:left}
th{background:#f0f0f0;font-weight:600}
tr:nth-child(even){background:#fafafa}
</style>
<p><script>
(function(){
  if(window.__lcCodeEnhanced)return;
  window.__lcCodeEnhanced=true;
  function enhance(){
    document.querySelectorAll('pre').forEach(function(pre){
      var code=pre.querySelector('code');
      var lang='';
      if(code){var m=(code.className||'').match(/language-(\S+)/);if(m)lang=m[1].toLowerCase();}
      if(lang)pre.setAttribute('data-lang',lang);
      if(lang){var badge=document.createElement('span');badge.className='lc-lang-badge';badge.textContent=lang;pre.insertBefore(badge,pre.firstChild);}
      var btn=document.createElement('button');
      btn.className='lc-copy-btn';btn.textContent='Copy';btn.setAttribute('aria-label','Copy code to clipboard');
      pre.appendChild(btn);
      btn.addEventListener('click',function(){
        var text=code?code.innerText:pre.innerText;
        if(navigator.clipboard&&window.isSecureContext){
          navigator.clipboard.writeText(text).then(function(){ok(btn);}).catch(function(){fb(text,btn);});
        }else{fb(text,btn);}
      });
    });
  }
  function ok(btn){btn.textContent='Copied!';btn.classList.add('copied');setTimeout(function(){btn.textContent='Copy';btn.classList.remove('copied');},2000);}
  function fb(text,btn){
    try{var ta=document.createElement('textarea');ta.value=text;ta.style.cssText='position:fixed;left:-9999px;top:-9999px;opacity:0';document.body.appendChild(ta);ta.select();document.execCommand('copy');document.body.removeChild(ta);ok(btn);}
    catch(e){btn.textContent='✗ Failed';setTimeout(function(){btn.textContent='Copy';},2000);}
  }
  if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',enhance);}else{enhance();}
})();
</script></p>
<p><a href="/what-is-purple-team-security/">What is purple team security</a> → <a href="/owasp-top-10-cloud-infrastructure/">OWASP Top 10 mapped to cloud infrastructure</a> → <a href="/cloud-security-breaches-2020-2025/">Cloud security breaches 2020–2025</a> → <a href="/broken-access-control-aws/">Broken access control in AWS</a> → <a href="/mfa-fatigue-attack/">MFA fatigue attacks</a> → <a href="/cicd-secrets-exposure/">CI/CD secrets exposure</a> → <a href="/ssrf-cloud-metadata-attack/">SSRF to cloud metadata</a> → <a href="/kubernetes-container-escape/">Kubernetes container escape</a> → <a href="/supply-chain-attack-detection/">Supply chain attack detection</a> → <a href="/cloud-lateral-movement-iam-role-chaining/">Cloud lateral movement</a> → <strong>Detection Engineering with eBPF</strong></p>
<hr />
<h2 id="tldr">TL;DR</h2>
<ul>
<li><strong>Detection engineering with eBPF</strong> addresses OWASP A09 directly: most process-level attack techniques leave no trace in CloudTrail, VPC Flow Logs, or syslog — eBPF hooks in the kernel observe them before the attacker has any ability to suppress the record</li>
<li>CloudTrail is API-plane only; VPC Flow Logs are network-plane only with a 15-minute aggregation delay and no process context; syslog captures only what userspace processes voluntarily emit — all three miss the OS-level attack surface entirely</li>
<li>eBPF attaches to kernel syscall tracepoints and kprobes to capture <code class="" data-line="">connect()</code>, <code class="" data-line="">execve()</code>, <code class="" data-line="">mount()</code>, <code class="" data-line="">setuid()</code>, and <code class="" data-line="">open()</code> with full context: PID, process name, container cgroup, parent process, timestamp — in real time</li>
<li>Falco and Tetragon are the production-grade always-on options; bpftrace is the ad-hoc investigation tool — use each for what it is designed for</li>
<li>Tetragon&#8217;s <code class="" data-line="">TracingPolicy</code> can kill a process at the moment of the violating syscall, before the attack completes — this is enforcement, not just alerting</li>
<li>Every attack in EP07 through EP10 has a detectable kernel-level signal; this episode maps each one to a concrete eBPF detection rule</li>
</ul>
<hr />
<blockquote>
<p><strong>OWASP Mapping:</strong> A09 Security Logging and Monitoring Failures — the structural gap this series has referenced from EP04 onward: attacks that succeed not because defenses are absent, but because the telemetry layer cannot see the OS surface where the attacks execute.</p>
</blockquote>
<hr />
<h2 id="the-big-picture">The Big Picture</h2>
<pre><code class="" data-line="">┌─────────────────────────────────────────────────────────────────────────┐
│                  DETECTION ENGINEERING WITH eBPF                        │
│                                                                         │
│   KERNEL SPACE                          USERSPACE                       │
│                                                                         │
│   syscall/kprobe hooks                                                  │
│   ┌──────────────────┐                                                  │
│   │ connect()        │──&#x25b6; ring buffer ──&#x25b6; Tetragon ──&#x25b6; Hubble/SIEM     │
│   │ execve()         │                                                  │
│   │ mount()          │──&#x25b6; ring buffer ──&#x25b6; Falco   ──&#x25b6; Slack/PagerDuty │
│   │ setuid()         │                                                  │
│   │ open()           │──&#x25b6; perf buffer ──&#x25b6; bpftrace ──&#x25b6; stdout/log     │
│   └──────────────────┘                                                  │
│          │                                                              │
│          │  Context captured at hook:                                   │
│          │  PID · comm · cgroup (container ID) · args · timestamp      │
│          │  parent PID · network namespace · mount namespace           │
│                                                                         │
│   ═══════════════════════════════════════════════════════════           │
│   WHAT OTHER TOOLS SEE                                                  │
│   CloudTrail:     API calls only — nothing below the AWS SDK            │
│   VPC Flow Logs:  src/dst IP+port only — 15-min delay, no PID          │
│   Syslog:         What the process chose to log — attacker controls it  │
│   eBPF:           Every syscall — attacker cannot suppress it          │
│                   without kernel access                                 │
└─────────────────────────────────────────────────────────────────────────┘
</code></pre>
<p><strong>Detection engineering with eBPF</strong> closes the observability gap that every previous episode in this series exploited. The SSRF in EP07 made an outbound connection to 169.254.169.254 — the EC2 metadata endpoint — from a web application process. VPC Flow Logs show that IP eventually. CloudTrail shows nothing. eBPF shows the <code class="" data-line="">connect()</code> syscall with the PID, the process name, the container cgroup ID, and the timestamp, in the sub-millisecond window it occurred.</p>
<hr />
<h2 id="the-problem-your-siem-has-a-15-minute-hole">The Problem: Your SIEM Has a 15-Minute Hole</h2>
<p>During a cloud incident response engagement, the question came up in the first hour: did this process make any outbound connections in the last 30 minutes?</p>
<p>Four telemetry sources, four answers:</p>
<p><strong>CloudTrail:</strong> Not applicable. CloudTrail records AWS API calls. A process inside an EC2 instance making a raw TCP connection to an external IP — or to the metadata endpoint — is OS-level activity. CloudTrail has no record of it.</p>
<p><strong>VPC Flow Logs:</strong> Maybe, eventually. Flow Logs aggregate at 1-minute or 10-minute intervals (configurable), then land in S3 or CloudWatch Logs with additional delay. In practice, you&#8217;re looking at 10–15 minutes before the data is queryable. The flow record contains source IP, destination IP, source port, destination port, protocol, bytes, packets — and nothing else. There is no PID. There is no process name. There is no indication of which container inside the EC2 instance made the connection. If ten pods are running on the same node, VPC Flow Logs tells you the node talked to an external IP. You don&#8217;t know which pod.</p>
<p><strong>Syslog:</strong> Nothing logged. The process — a compromised web application exploited via SSRF — didn&#8217;t log the connection. It wouldn&#8217;t. Application code doesn&#8217;t emit syslog entries for every outbound connection it makes. And an attacker controlling the process would not add logging.</p>
<p><strong>eBPF TC hook:</strong> Every TCP connection attempt, from the moment it entered the network stack, with PID, process name, container cgroup ID, destination IP, destination port, source IP, and timestamp — in real time, with zero delay.</p>
<p>That is the gap. Everything in EP04 through EP10 of this series lived in it.</p>
<p>The OWASP A09 framing is exactly right: these are not failures of detection rules, they are failures of the telemetry layer. You cannot write a SIEM rule for data that is never collected. eBPF collects the data that the other layers structurally cannot.</p>
<hr />
<h2 id="what-ebpf-detects-that-other-tools-miss">What eBPF Detects That Other Tools Miss</h2>
<table>
<thead>
<tr>
<th>Technique</th>
<th>CloudTrail</th>
<th>VPC Flow Logs</th>
<th>Syslog</th>
<th>eBPF</th>
</tr>
</thead>
<tbody>
<tr>
<td>Process spawn inside container</td>
<td>No</td>
<td>No</td>
<td>Maybe (if auditd configured)</td>
<td>Yes — execve(): PID, command, args, parent PID, container cgroup</td>
</tr>
<tr>
<td>Outbound TCP connection</td>
<td>No</td>
<td>IP+port, 15-min delay, no PID</td>
<td>No</td>
<td>connect(): IP+port+PID+comm+container, real-time</td>
</tr>
<tr>
<td>File write to /etc/passwd</td>
<td>No</td>
<td>No</td>
<td>No</td>
<td>openat()+write(): exact path, PID, comm, container</td>
</tr>
<tr>
<td>Privilege escalation (setuid/setgid)</td>
<td>No</td>
<td>No</td>
<td>Maybe (auditd)</td>
<td>Yes — setuid() syscall args: target UID, calling PID, comm</td>
</tr>
<tr>
<td>Container escape attempt via mount</td>
<td>No</td>
<td>No</td>
<td>No</td>
<td>mount(): args, mount namespace ID, calling PID — namespace mismatch detectable</td>
</tr>
<tr>
<td>SSRF to 169.254.169.254</td>
<td>No</td>
<td>IP only, 15-min delay</td>
<td>No</td>
<td>connect() from app process to metadata IP — PID, comm, container, real-time</td>
</tr>
<tr>
<td>Binary execution with unusual parent</td>
<td>No</td>
<td>No</td>
<td>No</td>
<td>execve(): full parent chain — detects shell spawned from web process</td>
</tr>
<tr>
<td>Kubernetes secret file read</td>
<td>No</td>
<td>No</td>
<td>No</td>
<td>openat() on /run/secrets/kubernetes.io/serviceaccount/token</td>
</tr>
<tr>
<td>STS credential fetch from Lambda</td>
<td>No</td>
<td>Endpoint IP only</td>
<td>No</td>
<td>connect() to sts.amazonaws.com from unexpected process</td>
</tr>
</tbody>
</table>
<p>The pattern across the table is consistent: CloudTrail covers the AWS control plane. VPC Flow Logs cover the network plane with delay and no process context. Syslog covers what processes choose to emit. eBPF covers the syscall surface — the layer where every one of these events must pass, regardless of what the attacker wants.</p>
<blockquote>
<p><strong>For operators not writing eBPF:</strong> This table tells you what your current SIEM can and cannot see. If your threat model includes container escapes, SSRF-to-metadata attacks, or post-compromise lateral movement through process execution, the detection signal for those techniques does not exist in your CloudTrail or your flow logs. It exists only at the kernel level.</p>
</blockquote>
<hr />
<h2 id="detection-rule-1-unexpected-outbound-from-an-application-container">Detection Rule 1: Unexpected Outbound from an Application Container</h2>
<p>The SSRF attack in EP07 — and the lateral movement in EP10 — both required an outbound TCP connection from a process that had no legitimate reason to make one. This is the detection.</p>
<h3 id="ad-hoc-investigation-with-bpftrace">Ad-hoc investigation with bpftrace</h3>
<p>When you&#8217;re on a node right now and need to know what&#8217;s connecting outbound:</p>
<pre><code class="" data-line=""># Shows PID, process name, and destination IP in real time
# Run on the node (requires root or CAP_BPF)
bpftrace -e &#039;
#include &lt;linux/socket.h&gt;
#include &lt;linux/in.h&gt;

tracepoint:syscalls:sys_enter_connect {
  $sa = (struct sockaddr_in *)args-&gt;uservaddr;
  if ($sa-&gt;sin_family == AF_INET) {
    printf(&quot;connect: pid=%-6d comm=%-20s dst=%s:%d\n&quot;,
           pid,
           comm,
           ntop($sa-&gt;sin_addr.s_addr),
           (uint16)bswap($sa-&gt;sin_port));
  }
}
&#039;
</code></pre>
<p>Sample output — what you&#8217;d see during an SSRF exploit targeting the EC2 metadata service:</p>
<pre><code class="" data-line="">connect: pid=18422  comm=python3              dst=169.254.169.254:80
connect: pid=18422  comm=python3              dst=169.254.169.254:80
connect: pid=18432  comm=curl                 dst=169.254.169.254:80
</code></pre>
<p>The <code class="" data-line="">python3</code> process — your web application — connecting to <code class="" data-line="">169.254.169.254</code> is the metadata endpoint. That&#8217;s not a legitimate application dependency. That&#8217;s the SSRF signal.</p>
<blockquote>
<p><strong><a href="/bpftrace-kernel-observability/">bpftrace — kernel answers in one line</a></strong> goes deep on the tracepoint/kprobe model and how to filter by cgroup for container-specific traces. The one-liners above are the starting point; that post covers building targeted investigation scripts.</p>
</blockquote>
<h3 id="production-grade-enforcement-with-tetragon">Production-grade enforcement with Tetragon</h3>
<p>bpftrace is for investigation. Tetragon is for always-on detection — and optionally, prevention.</p>
<pre><code class="" data-line=""># TracingPolicy: alert on outbound connections from non-host network namespaces
# (any container making outbound TCP connections)
apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata:
  name: &quot;detect-outbound-connections&quot;
spec:
  kprobes:
  - call: &quot;tcp_connect&quot;
    syscall: false
    args:
    - index: 0
      type: &quot;sock&quot;
    selectors:
    - matchNamespaces:
      - namespace: Net
        operator: NotIn
        values:
        - &quot;host&quot;
      matchActions:
      - action: Post   # Generate an alert event; change to Sigkill to prevent
</code></pre>
<p>To detect specifically the SSRF-to-metadata pattern — connections to <code class="" data-line="">169.254.169.254</code>:</p>
<pre><code class="" data-line="">apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata:
  name: &quot;detect-imds-access&quot;
spec:
  kprobes:
  - call: &quot;tcp_connect&quot;
    syscall: false
    args:
    - index: 0
      type: &quot;sock&quot;
    selectors:
    - matchArgs:
      - index: 0
        operator: &quot;Equal&quot;
        values:
        - &quot;169.254.169.254/32&quot;
      matchActions:
      - action: Post
        rateLimit: &quot;1/minute&quot;
</code></pre>
<p>Tetragon events include <code class="" data-line="">process_kprobe</code> JSON with the pod name, namespace, container ID, binary path, parent binary, and all arguments. This feeds directly into your SIEM or to Hubble&#8217;s flow log.</p>
<hr />
<h2 id="detection-rule-2-process-execution-inside-a-container">Detection Rule 2: Process Execution Inside a Container</h2>
<p>A shell spawning inside a container that has no business running a shell is a post-compromise indicator. It covers the container escape setup from EP08, the supply chain implant from EP09, and any hands-on-keyboard phase after initial access.</p>
<h3 id="falco-rule-shell-spawned-from-application-container">Falco rule: shell spawned from application container</h3>
<pre><code class="" data-line=""># Falco rule: detect any shell spawned in a container
# Add to /etc/falco/rules.d/purple-team.yaml
- list: shell_binaries
  items: [bash, sh, zsh, ksh, fish, tcsh, csh, dash]

- list: allowed_shell_images
  items: [
    &quot;debug-tools&quot;,     # Your approved debug container image names
    &quot;toolbox&quot;
  ]

- rule: Shell Spawned in Container
  desc: &gt;
    A shell was spawned inside a container. In application containers (web servers,
    APIs, data processors) this is almost always a post-compromise indicator.
  condition: &gt;
    evt.type = execve and
    evt.dir = &lt; and
    container and
    container.image.repository != &quot;&quot; and
    proc.name in (shell_binaries) and
    not proc.pname in (shell_binaries) and
    not container.image.repository in (allowed_shell_images) and
    not k8s.ns.name in (kube-system, kube-public)
  output: &gt;
    Shell spawned in container
    (user=%user.name
     container=%container.name
     image=%container.image.repository
     cmd=%proc.cmdline
     parent=%proc.pname
     pod=%k8s.pod.name
     ns=%k8s.ns.name)
  priority: WARNING
  tags: [purple-team, post-compromise, container]
</code></pre>
<p>The <code class="" data-line="">proc.pname</code> condition is the key signal: a shell spawned by a web server process (<code class="" data-line="">nginx</code>, <code class="" data-line="">node</code>, <code class="" data-line="">gunicorn</code>, <code class="" data-line="">java</code>) is a different threat than a shell spawned by another shell in a debug context. The rule above passes the second case through the <code class="" data-line="">allowed_shell_images</code> exclusion; it flags the first.</p>
<h3 id="detecting-the-supply-chain-implant-pattern">Detecting the supply chain implant pattern</h3>
<p>EP09 covered supply chain attacks where a build artifact executes unexpected binaries at runtime. The bpftrace version for ad-hoc investigation of what a specific container is executing:</p>
<pre><code class="" data-line=""># bpftrace: trace all execve() calls from processes inside a specific container
# First, find the container&#039;s cgroup ID:
# systemd-cgls | grep &lt;pod-name&gt;
# Or: cat /sys/fs/cgroup/unified/&lt;cgroup-path&gt;/cgroup.procs

bpftrace -e &#039;
tracepoint:syscalls:sys_enter_execve {
  printf(&quot;execve: pid=%-6d ppid=%-6d comm=%-20s file=%s\n&quot;,
         pid,
         curtask-&gt;real_parent-&gt;tgid,
         comm,
         str(args-&gt;filename));
}
&#039; 2&gt;/dev/null | grep -v &quot;^\[&quot; | head -50
</code></pre>
<p>Sample output during a supply chain compromise scenario — unexpected binary execution from a package manager implant:</p>
<pre><code class="" data-line="">execve: pid=31204  ppid=31190  comm=node                 file=/bin/sh
execve: pid=31205  ppid=31204  comm=sh                   file=/tmp/.x/beacon
execve: pid=31206  ppid=31205  comm=beacon               file=/usr/bin/curl
</code></pre>
<p>The chain <code class="" data-line="">node → sh → /tmp/.x/beacon → curl</code> — application process spawning a shell, which executes an unknown binary from <code class="" data-line="">/tmp</code>, which runs <code class="" data-line="">curl</code> — is the supply chain implant execution pattern. None of this appears in CloudTrail.</p>
<hr />
<h2 id="detection-rule-3-privilege-escalation-setuid0-and-capability-abuse">Detection Rule 3: Privilege Escalation — setuid(0) and Capability Abuse</h2>
<p>A process calling <code class="" data-line="">setuid(0)</code> to elevate to root, or <code class="" data-line="">setcap</code> to acquire new capabilities, is a privilege escalation indicator. The EP08 container escape path used a setuid binary to gain root inside the container as the first step toward escaping the namespace.</p>
<h3 id="bpftrace-catch-setuid0-calls-in-real-time">bpftrace: catch setuid(0) calls in real time</h3>
<pre><code class="" data-line=""># bpftrace: alert on any process calling setuid(0)
# Any process attempting to switch to UID 0
bpftrace -e &#039;
tracepoint:syscalls:sys_enter_setuid {
  if (args-&gt;uid == 0) {
    printf(&quot;ALERT setuid(0): pid=%-6d comm=%-20s ppid=%d pcomm=%s\n&quot;,
           pid,
           comm,
           curtask-&gt;real_parent-&gt;tgid,
           str(curtask-&gt;real_parent-&gt;comm));
  }
}
tracepoint:syscalls:sys_enter_setresuid {
  if (args-&gt;ruid == 0 || args-&gt;euid == 0) {
    printf(&quot;ALERT setresuid(root): pid=%-6d comm=%-20s\n&quot;, pid, comm);
  }
}
&#039;
</code></pre>
<h3 id="falco-rule-setuid-binary-execution-inside-container">Falco rule: setuid binary execution inside container</h3>
<pre><code class="" data-line="">- rule: Setuid Binary Executed in Container
  desc: &gt;
    A setuid binary was executed inside a container. Setuid binaries inside
    containers are a privilege escalation path — they run as root regardless
    of the container&#039;s user setting.
  condition: &gt;
    evt.type = execve and
    evt.dir = &lt; and
    container and
    proc.is_suid_exe = true
  output: &gt;
    Setuid binary executed in container
    (binary=%proc.exepath
     user=%user.name
     container=%container.name
     pod=%k8s.pod.name
     cmd=%proc.cmdline)
  priority: ERROR
  tags: [purple-team, privilege-escalation, container]
</code></pre>
<hr />
<h2 id="detection-rule-4-container-escape-attempt-via-namespace-crossing-mount">Detection Rule 4: Container Escape Attempt via Namespace-Crossing Mount</h2>
<p>The privileged container escape path from EP08 requires calling <code class="" data-line="">mount()</code> from a container namespace to access the host filesystem. The kernel records the mount namespace of the calling process — an eBPF kprobe on <code class="" data-line="">mount()</code> can detect when the caller&#8217;s mount namespace differs from the host namespace.</p>
<h3 id="tetragon-policy-kill-any-mount-from-a-non-host-namespace">Tetragon policy: kill any mount from a non-host namespace</h3>
<pre><code class="" data-line=""># This covers the --privileged container escape path documented in EP08
# The mount() call that crosses from container namespace to host filesystem
apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata:
  name: &quot;detect-container-mount-escape&quot;
spec:
  kprobes:
  - call: &quot;security_sb_mount&quot;
    syscall: false
    args:
    - index: 0
      type: &quot;string&quot;     # dev_name
    - index: 3
      type: &quot;string&quot;     # mount flags
    selectors:
    - matchNamespaces:
      - namespace: Mnt
        operator: NotIn
        values:
        - &quot;host&quot;
      matchArgs:
      - index: 0
        operator: &quot;NotEqual&quot;
        values:
        - &quot;proc&quot;
        - &quot;sysfs&quot;
        - &quot;tmpfs&quot;        # Common legitimate mounts in containers
      matchActions:
      - action: Sigkill
        rateLimit: &quot;10/minute&quot;
</code></pre>
<p>Start with <code class="" data-line="">action: Post</code> and tune the exclusions for your environment before switching to <code class="" data-line="">Sigkill</code>. See the production gotchas below.</p>
<h3 id="bpftrace-ad-hoc-namespace-crossing-investigation">bpftrace: ad-hoc namespace crossing investigation</h3>
<pre><code class="" data-line=""># bpftrace: trace mount() calls and show the mount namespace of the caller
# Mount namespace ID of the host: read from /proc/1/ns/mnt
HOST_MNT_NS=$(readlink /proc/1/ns/mnt | grep -oP &#039;\d+&#039;)

bpftrace -e &#039;
#include &lt;linux/nsproxy.h&gt;
#include &lt;linux/mount.h&gt;

kprobe:__x64_sys_mount {
  $nsproxy = (struct nsproxy *)curtask-&gt;nsproxy;
  $mnt_ns_id = $nsproxy-&gt;mnt_ns-&gt;ns.inum;
  printf(&quot;mount: pid=%-6d comm=%-20s mnt_ns=%u\n&quot;,
         pid, comm, $mnt_ns_id);
}
&#039; 2&gt;/dev/null
</code></pre>
<p>Compare the <code class="" data-line="">mnt_ns</code> value in output against <code class="" data-line="">$HOST_MNT_NS</code>. Any mount call with a <code class="" data-line="">mnt_ns</code> value other than the host&#8217;s is from inside a container. A privileged container attempting host filesystem access shows a container namespace ID.</p>
<hr />
<h2 id="building-a-detection-pipeline">Building a Detection Pipeline</h2>
<p>Ad-hoc bpftrace commands answer questions during an incident. Always-on detection requires a pipeline that runs continuously, routes alerts to a durable destination, and survives pod restarts. The two production-grade options in this stack:</p>
<pre><code class="" data-line="">eBPF hooks
    │
    ├── Tetragon (always-on, Kubernetes-native)
    │       └── TracingPolicy CRDs
    │               └── JSON events → Hubble → Grafana
    │                               → SIEM (Splunk/Elastic)
    │                               → PagerDuty
    │
    └── Falco (rule-based, declarative)
            └── /etc/falco/rules.d/*.yaml
                    └── falcosidekick
                            ├── Slack
                            ├── PagerDuty
                            ├── Elasticsearch
                            └── AWS Lambda (custom response)
</code></pre>
<p>The <a href="/ebpf-tc-pod-policy/">TC eBPF pod-level network policy</a> post covers how Cilium and Tetragon share the same underlying kernel attachment points — understanding TC hooks helps explain why Tetragon&#8217;s network-level policies fire at the same layer as Cilium&#8217;s NetworkPolicy enforcement.</p>
<h3 id="falco-with-falcosidekick-complete-local-testing-setup">Falco with falcosidekick: complete local testing setup</h3>
<p>Use this to validate your Falco rules before deploying to a cluster. It routes Falco alerts to Slack in real time.</p>
<pre><code class="" data-line=""># docker-compose.yml — local Falco + falcosidekick testing
# Requires: Docker with kernel headers or eBPF driver support
version: &quot;3.8&quot;

services:
  falco:
    image: falcosecurity/falco-no-driver:latest
    privileged: true
    volumes:
      - /var/run/docker.sock:/host/var/run/docker.sock
      - /dev:/host/dev
      - /proc:/host/proc:ro
      - /boot:/host/boot:ro
      - /lib/modules:/host/lib/modules:ro
      - /usr:/host/usr:ro
      - /etc/falco:/etc/falco
      - ./rules:/etc/falco/rules.d:ro
    environment:
      FALCO_GRPC_ENABLED: &quot;true&quot;
      FALCO_GRPC_BIND_ADDRESS: &quot;0.0.0.0:5060&quot;
    ports:
      - &quot;5060:5060&quot;
    command: &gt;
      /usr/bin/falco
        --modern-bpf
        -o &quot;json_output=true&quot;
        -o &quot;grpc.enabled=true&quot;
        -o &quot;grpc_output.enabled=true&quot;

  falcosidekick:
    image: falcosecurity/falcosidekick:latest
    depends_on:
      - falco
    environment:
      FALCO_GRPC_CONN: &quot;falco:5060&quot;
      FALCO_GRPC_TLS: &quot;false&quot;
      SLACK_WEBHOOKURL: &quot;${SLACK_WEBHOOK}&quot;
      SLACK_MINIMUMPRIORITY: &quot;warning&quot;
      SLACK_MESSAGEFORMAT: &gt;
        &quot;[{{.Priority}}] {{.Rule}}
        | pod={{.OutputFields.k8s_pod_name}}
        | ns={{.OutputFields.k8s_ns_name}}
        | cmd={{.OutputFields.proc_cmdline}}&quot;
    ports:
      - &quot;2801:2801&quot;
</code></pre>
<pre><code class="" data-line=""># Start the stack (set SLACK_WEBHOOK first)
export SLACK_WEBHOOK=&quot;https://hooks.slack.com/services/YOUR/WEBHOOK/URL&quot;
docker compose up -d

# Trigger a test alert: exec into any running container
docker exec -it &lt;any-container&gt; /bin/sh

# Check falcosidekick received it
curl -s http://localhost:2801/metrics | grep falcosidekick_inputs_total
</code></pre>
<h3 id="deploying-falco-to-kubernetes-with-helm">Deploying Falco to Kubernetes with Helm</h3>
<pre><code class="" data-line=""># Add Falco Helm repo
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo update

# Install Falco with eBPF driver (not kernel module — required in Kubernetes)
helm install falco falcosecurity/falco \
  --namespace falco \
  --create-namespace \
  --set driver.kind=modern_ebpf \
  --set falcosidekick.enabled=true \
  --set falcosidekick.config.slack.webhookurl=&quot;${SLACK_WEBHOOK}&quot; \
  --set falcosidekick.config.slack.minimumpriority=warning \
  --set customRules.&quot;purple-team\.yaml&quot;=&quot;$(cat ./rules/purple-team.yaml)&quot;

# Verify Falco pods are running on all nodes
kubectl get pods -n falco -o wide

# Tail Falco logs for a specific node&#039;s pod
kubectl logs -n falco -l app.kubernetes.io/name=falco -f
</code></pre>
<pre><code class="" data-line=""># Validate a specific rule is loaded
kubectl exec -n falco &lt;falco-pod&gt; -- falco --list-rules 2&gt;/dev/null | grep &quot;Shell Spawned&quot;
</code></pre>
<hr />
<h2 id="what-this-means-for-each-prior-attack">What This Means for Each Prior Attack</h2>
<p>Every attack in EP07 through EP10 had a detectable kernel-level signal that the standard telemetry stack missed. Here&#8217;s the detection mapping:</p>
<table>
<thead>
<tr>
<th>Episode</th>
<th>Attack</th>
<th>What Standard Telemetry Missed</th>
<th>eBPF Detection Signal</th>
</tr>
</thead>
<tbody>
<tr>
<td>EP07</td>
<td>SSRF to EC2 IMDS</td>
<td>CloudTrail: nothing. VPC Flow Logs: 169.254.169.254 destination, 15-min delay, no PID</td>
<td>TC kprobe: <code class="" data-line="">connect()</code> to <code class="" data-line="">169.254.169.254</code> from app process — PID, comm, container, real-time</td>
</tr>
<tr>
<td>EP08</td>
<td>Container escape via privileged mount</td>
<td>CloudTrail: nothing. Syslog: nothing</td>
<td>kprobe: <code class="" data-line="">security_sb_mount()</code> from non-host mount namespace — namespace ID mismatch fires alert</td>
</tr>
<tr>
<td>EP09</td>
<td>Supply chain implant execution</td>
<td>CloudTrail: nothing (OS-level). GuardDuty: maybe if beacon calls AWS APIs</td>
<td>kprobe: <code class="" data-line="">execve()</code> with anomalous parent chain — web process → shell → unknown binary from <code class="" data-line="">/tmp</code></td>
</tr>
<tr>
<td>EP10</td>
<td>Lateral movement via cross-account role chaining</td>
<td>CloudTrail: AssumeRole events present but no process context</td>
<td>TC hook: <code class="" data-line="">connect()</code> to <code class="" data-line="">sts.amazonaws.com</code> from Lambda handler process — unexpected process identity</td>
</tr>
</tbody>
</table>
<p>The table is not theoretical. It reflects what you would actually observe running these detection rules against the attack simulations in those episodes.</p>
<p>For the SSRF case (EP07): the connection to <code class="" data-line="">169.254.169.254</code> from the web application process would fire within milliseconds of the exploit. VPC Flow Logs would record the same IP 10–15 minutes later, with no information about which process made it. By the time the flow log is queryable, the attacker has the IAM credentials and may have made subsequent API calls in a different region.</p>
<p>For the container escape (EP08): the <code class="" data-line="">mount()</code> from a non-host mount namespace is the earliest detectable signal of the escape attempt. It fires before the attacker has host filesystem access. With <code class="" data-line="">action: Sigkill</code> in the Tetragon policy, the process is terminated at this syscall — the escape does not complete.</p>
<hr />
<h2 id="production-gotchas"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Production Gotchas</h2>
<p><strong>Use the eBPF driver for Falco in Kubernetes, not the kernel module.</strong> The kernel module requires installing a kernel module on every node, which creates a dependency on kernel headers being present and compatible. The <code class="" data-line="">modern_ebpf</code> driver (Falco 0.35+) uses BTF and CO-RE — it works on kernels 5.8+ without kernel module installation and survives kernel upgrades. In managed Kubernetes (EKS, GKE, AKS), the kernel module path often doesn&#8217;t work at all due to the OS image restrictions.</p>
<p><strong>Test Tetragon&#8217;s <code class="" data-line="">Sigkill</code> action exhaustively before enabling it in production.</strong> The <code class="" data-line="">Sigkill</code> action terminates the process at the moment of the violating syscall — before it completes. This is powerful for prevention but catastrophic if your exclusions are wrong. Common false positive sources: debug containers (<code class="" data-line="">kubectl debug</code>), init containers that perform legitimate mounts, Kubernetes admission webhooks calling shell scripts. Always deploy with <code class="" data-line="">action: Post</code> first, tune for two weeks of normal traffic, then switch to <code class="" data-line="">Sigkill</code> only on rules with zero false positives in your environment.</p>
<p><strong>bpftrace is an investigation tool, not a production detector.</strong> bpftrace compiles and loads an eBPF program per invocation — it has no persistence, no alerting, and no output routing to your SIEM. It is for the incident response scenario described in the opening: &#8220;did this process make outbound connections in the last 30 minutes?&#8221; (answered: it&#8217;s what&#8217;s happening right now). For always-on detection, use Tetragon or Falco. Running bpftrace as a daemon substitute introduces overhead without the management plane that production tools provide.</p>
<p><strong>The shell-in-container rule will fire on <code class="" data-line="">kubectl exec</code> sessions.</strong> Any time an operator runs <code class="" data-line="">kubectl exec -it &lt;pod&gt; -- /bin/bash</code>, the Falco rule above triggers. This is working as intended — <code class="" data-line="">kubectl exec</code> is a post-compromise technique as well as an operational tool. Handle this with an exclusion on the user identity or namespace:</p>
<pre><code class="" data-line=""># Add to the rule condition to exclude operator kubectl exec sessions
# Map your cluster admin users or service account here
and not user.name in (cluster-admin-users)
and not k8s.ns.name in (ops-tooling, debug-ns)
</code></pre>
<p><strong>High-frequency kprobes on hot paths add measurable overhead.</strong> Attaching to <code class="" data-line="">tcp_connect</code> fires on every outbound connection from every process on the node. On a node handling hundreds of microservices with high connection rates (service mesh with short-lived connections), this adds CPU overhead. Profile before deploying. Tetragon&#8217;s namespace-scoped selectors (<code class="" data-line="">matchNamespaces: NotHost</code>) help by skipping host-namespace processes. Filter as narrowly as your threat model allows.</p>
<p><strong>Ring buffer overflow silently drops events on high-throughput nodes.</strong> Both Falco and bpftrace use kernel ring buffers to pass events to userspace. If the userspace consumer (the Falco daemon, the bpftrace process) cannot keep up with the event rate, the kernel drops events silently. Falco exposes a <code class="" data-line="">falco_events_dropped_total</code> metric — monitor it. Tune <code class="" data-line="">ring_buffer_size</code> in the Falco configuration if drops occur on high-throughput nodes.</p>
<hr />
<h2 id="quick-reference">Quick Reference</h2>
<table>
<thead>
<tr>
<th>Use Case</th>
<th>Tool</th>
<th>Hook Type</th>
<th>Detection Latency</th>
</tr>
</thead>
<tbody>
<tr>
<td>Ad-hoc outbound connection investigation</td>
<td>bpftrace</td>
<td>tracepoint:syscalls:sys_enter_connect</td>
<td>Real-time</td>
</tr>
<tr>
<td>Always-on container shell detection</td>
<td>Falco</td>
<td>eBPF modern driver / syscall</td>
<td>&lt; 100ms</td>
</tr>
<tr>
<td>Container escape prevention</td>
<td>Tetragon + Sigkill</td>
<td>kprobe: security_sb_mount</td>
<td>Blocking (pre-completion)</td>
</tr>
<tr>
<td>Privilege escalation detection</td>
<td>Falco / bpftrace</td>
<td>tracepoint:syscalls:sys_enter_setuid</td>
<td>Real-time</td>
</tr>
<tr>
<td>Supply chain implant execution</td>
<td>Falco execve rule</td>
<td>eBPF modern driver</td>
<td>&lt; 100ms</td>
</tr>
<tr>
<td>SSRF-to-metadata detection</td>
<td>Tetragon kprobe</td>
<td>kprobe: tcp_connect</td>
<td>Real-time</td>
</tr>
<tr>
<td>Lateral movement via unexpected STS call</td>
<td>Tetragon kprobe</td>
<td>kprobe: tcp_connect + process filter</td>
<td>Real-time</td>
</tr>
<tr>
<td>Audit trail for incident response</td>
<td>Tetragon JSON events</td>
<td>kprobe / tracepoint</td>
<td>Persistent, SIEM-routable</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th>Tool</th>
<th>Best For</th>
<th>Not For</th>
</tr>
</thead>
<tbody>
<tr>
<td>bpftrace</td>
<td>Ad-hoc node investigation during IR</td>
<td>Always-on production detection</td>
</tr>
<tr>
<td>Falco</td>
<td>Rule-based behavioral detection</td>
<td>Network-layer enforcement</td>
</tr>
<tr>
<td>Tetragon</td>
<td>Always-on detection + optional enforcement</td>
<td>Ad-hoc one-liner investigation</td>
</tr>
</tbody>
</table>
<hr />
<h2 id="key-takeaways">Key Takeaways</h2>
<ul>
<li><strong>Detection engineering with eBPF</strong> closes the telemetry gap that CloudTrail, VPC Flow Logs, and syslog cannot close: OS-level process activity is only visible at the kernel syscall layer, and eBPF is the only production-grade mechanism that reads it without kernel module risk</li>
<li>Every attack in EP07 through EP10 has a real-time kernel-level signal — SSRF connections, container mount calls, unexpected execve chains, privilege escalation attempts — none of which appear in your current SIEM unless you&#8217;ve built this layer</li>
<li>Falco provides declarative, rule-based behavioral detection; Tetragon provides syscall-level enforcement that can terminate an attack before it completes — use both with complementary scopes</li>
<li>bpftrace is the incident response tool for asking the kernel a direct question right now; it is not a monitoring agent and should not be treated as one</li>
<li>The false positive problem is real and must be addressed before enabling enforcement: <code class="" data-line="">kubectl exec</code>, debug containers, init containers with legitimate mounts — exclusions must be tuned per environment before moving from <code class="" data-line="">action: Post</code> to <code class="" data-line="">action: Sigkill</code></li>
</ul>
<hr />
<h2 id="whats-next">What&#8217;s Next</h2>
<p>EP11 closed the detection gap. You&#8217;ve instrumented the kernel, you&#8217;re receiving Falco alerts, Tetragon is firing on namespace-crossing mount attempts. Then the alert fires at 2:47 AM on a Sunday — not a test, not a false positive. Something got in.</p>
<p>EP12 is the playbook for the first 24 hours after a confirmed cloud breach: what to isolate and how without destroying forensic evidence, what to preserve before it rotates out of CloudTrail&#8217;s 90-day window, what eBPF data to capture while the node is still live, who to call and in what order, and how to avoid the common mistakes that turn a containable incident into a regulatory event. The response phase — where everything you built in EP04 through EP11 either pays off or reveals what you missed.</p>
<p>Get EP12 in your inbox when it publishes → <a href="#subscribe">subscribe at linuxcent.com</a></p>
<p><a class="a2a_button_mastodon" href="https://www.addtoany.com/add_to/mastodon?linkurl=https%3A%2F%2Flinuxcent.com%2Fdetection-engineering-ebpf-cloud%2F&amp;linkname=Detection%20Engineering%20with%20eBPF%3A%20Kernel-Level%20Visibility%20for%20Cloud%20Incidents" title="Mastodon" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_email" href="https://www.addtoany.com/add_to/email?linkurl=https%3A%2F%2Flinuxcent.com%2Fdetection-engineering-ebpf-cloud%2F&amp;linkname=Detection%20Engineering%20with%20eBPF%3A%20Kernel-Level%20Visibility%20for%20Cloud%20Incidents" title="Email" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_whatsapp" href="https://www.addtoany.com/add_to/whatsapp?linkurl=https%3A%2F%2Flinuxcent.com%2Fdetection-engineering-ebpf-cloud%2F&amp;linkname=Detection%20Engineering%20with%20eBPF%3A%20Kernel-Level%20Visibility%20for%20Cloud%20Incidents" title="WhatsApp" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_reddit" href="https://www.addtoany.com/add_to/reddit?linkurl=https%3A%2F%2Flinuxcent.com%2Fdetection-engineering-ebpf-cloud%2F&amp;linkname=Detection%20Engineering%20with%20eBPF%3A%20Kernel-Level%20Visibility%20for%20Cloud%20Incidents" title="Reddit" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_x" href="https://www.addtoany.com/add_to/x?linkurl=https%3A%2F%2Flinuxcent.com%2Fdetection-engineering-ebpf-cloud%2F&amp;linkname=Detection%20Engineering%20with%20eBPF%3A%20Kernel-Level%20Visibility%20for%20Cloud%20Incidents" title="X" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_linkedin" href="https://www.addtoany.com/add_to/linkedin?linkurl=https%3A%2F%2Flinuxcent.com%2Fdetection-engineering-ebpf-cloud%2F&amp;linkname=Detection%20Engineering%20with%20eBPF%3A%20Kernel-Level%20Visibility%20for%20Cloud%20Incidents" title="LinkedIn" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_copy_link" href="https://www.addtoany.com/add_to/copy_link?linkurl=https%3A%2F%2Flinuxcent.com%2Fdetection-engineering-ebpf-cloud%2F&amp;linkname=Detection%20Engineering%20with%20eBPF%3A%20Kernel-Level%20Visibility%20for%20Cloud%20Incidents" title="Copy Link" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Flinuxcent.com%2Fdetection-engineering-ebpf-cloud%2F&#038;title=Detection%20Engineering%20with%20eBPF%3A%20Kernel-Level%20Visibility%20for%20Cloud%20Incidents" data-a2a-url="https://linuxcent.com/detection-engineering-ebpf-cloud/" data-a2a-title="Detection Engineering with eBPF: Kernel-Level Visibility for Cloud Incidents"></a></p><p>The post <a href="https://linuxcent.com/detection-engineering-ebpf-cloud/">Detection Engineering with eBPF: Kernel-Level Visibility for Cloud Incidents</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://linuxcent.com/detection-engineering-ebpf-cloud/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1873</post-id>	</item>
		<item>
		<title>eBPF Program Types — What&#8217;s Actually Running on Your Nodes</title>
		<link>https://linuxcent.com/ebpf-program-types-kubernetes/</link>
					<comments>https://linuxcent.com/ebpf-program-types-kubernetes/#respond</comments>
		
		<dc:creator><![CDATA[Vamshi Krishna Santhapuri]]></dc:creator>
		<pubDate>Sun, 12 Apr 2026 09:51:22 +0000</pubDate>
				<category><![CDATA[eBPF]]></category>
		<category><![CDATA[bpftool]]></category>
		<category><![CDATA[Cilium]]></category>
		<category><![CDATA[eBPF program types]]></category>
		<category><![CDATA[Falco]]></category>
		<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[SRE]]></category>
		<guid isPermaLink="false">https://linuxcent.com/ebpf-program-types-kubernetes/</guid>

					<description><![CDATA[<p><span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 8</span> <span class="rt-label rt-postfix">minutes</span></span>What eBPF program types run on your Kubernetes nodes — XDP, TC, tracepoints, LSM explained through real SRE incidents using bpftool, Cilium, and Falco.</p>
<p>The post <a href="https://linuxcent.com/ebpf-program-types-kubernetes/">eBPF Program Types — What&#8217;s Actually Running on Your Nodes</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></description>
										<content:encoded><![CDATA[<span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 8</span> <span class="rt-label rt-postfix">minutes</span></span><style>
pre{position:relative;background:#1e1e1e;color:#d4d4d4;
    padding:16px 16px 16px 20px;border-radius:6px;overflow-x:auto;
    font-family:'JetBrains Mono','Fira Code','Cascadia Code',Consolas,'Courier New',monospace;
    font-size:.88em;line-height:1.6;border-left:4px solid #555}
code{background:#f4f4f4;padding:2px 5px;border-radius:3px;font-size:.9em}
pre code{background:transparent;padding:0;color:inherit}
pre[data-lang="bash"],pre[data-lang="sh"],
pre[data-lang="shell"],pre[data-lang="zsh"]{border-left-color:#4ec9b0}
pre[data-lang="yaml"],pre[data-lang="json"],
pre[data-lang="toml"],pre[data-lang="xml"]{border-left-color:#569cd6}
pre[data-lang="python"],pre[data-lang="go"],pre[data-lang="rust"],
pre[data-lang="java"],pre[data-lang="c"],pre[data-lang="cpp"]{border-left-color:#c586c0}
pre[data-lang="text"],pre[data-lang="output"],
pre[data-lang="console"]{border-left-color:#888}
.lc-copy-btn{position:absolute;top:8px;right:8px;background:#2d2d2d;color:#ccc;
    border:1px solid #444;border-radius:4px;padding:3px 9px;font-size:.75em;
    font-family:system-ui,sans-serif;cursor:pointer;opacity:0;
    transition:opacity .15s,background .15s;line-height:1.6}
pre:hover .lc-copy-btn{opacity:1}
.lc-copy-btn:hover{background:#3a3a3a;color:#fff}
.lc-copy-btn.copied{color:#4ec9b0;border-color:#4ec9b0}
.lc-lang-badge{position:absolute;top:8px;left:20px;font-family:system-ui,sans-serif;
    font-size:.7em;color:#666;text-transform:uppercase;letter-spacing:.04em;
    line-height:1;pointer-events:none;opacity:0;transition:opacity .15s}
pre:hover .lc-lang-badge{opacity:1}
table{border-collapse:collapse;width:100%;margin:16px 0}
th,td{border:1px solid #ddd;padding:10px 14px;text-align:left}
th{background:#f0f0f0;font-weight:600}
tr:nth-child(even){background:#fafafa}
</style>
<p><script>
(function(){
  if(window.__lcCodeEnhanced)return;
  window.__lcCodeEnhanced=true;
  function enhance(){
    document.querySelectorAll('pre').forEach(function(pre){
      var code=pre.querySelector('code');
      var lang='';
      if(code){var m=(code.className||'').match(/language-(\S+)/);if(m)lang=m[1].toLowerCase();}
      if(lang)pre.setAttribute('data-lang',lang);
      if(lang){var badge=document.createElement('span');badge.className='lc-lang-badge';badge.textContent=lang;pre.insertBefore(badge,pre.firstChild);}
      var btn=document.createElement('button');
      btn.className='lc-copy-btn';btn.textContent='Copy';btn.setAttribute('aria-label','Copy code to clipboard');
      pre.appendChild(btn);
      btn.addEventListener('click',function(){
        var text=code?code.innerText:pre.innerText;
        if(navigator.clipboard&&window.isSecureContext){
          navigator.clipboard.writeText(text).then(function(){ok(btn);}).catch(function(){fb(text,btn);});
        }else{fb(text,btn);}
      });
    });
  }
  function ok(btn){btn.textContent='Copied!';btn.classList.add('copied');setTimeout(function(){btn.textContent='Copy';btn.classList.remove('copied');},2000);}
  function fb(text,btn){
    try{var ta=document.createElement('textarea');ta.value=text;ta.style.cssText='position:fixed;left:-9999px;top:-9999px;opacity:0';document.body.appendChild(ta);ta.select();document.execCommand('copy');document.body.removeChild(ta);ok(btn);}
    catch(e){btn.textContent='✗ Failed';setTimeout(function(){btn.textContent='Copy';},2000);}
  }
  if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',enhance);}else{enhance();}
})();
</script></p>
<p><em>eBPF: From Kernel to Cloud, Episode 4</em><br />
<em><a href="https://linuxcent.com/what-is-ebpf-linux-kubernetes/">What Is eBPF?</a> · <a href="https://linuxcent.com/bpf-verifier-kubernetes-safety/">The BPF Verifier</a> · <a href="https://linuxcent.com/ebpf-vs-kernel-modules-kubernetes/">eBPF vs Kernel Modules</a> · </em><em>eBPF Program Types</em>**</p>
<hr />
<p style="font-size:0.72em;font-weight:700;letter-spacing:0.12em;color:#f59e0b;text-transform:uppercase;margin:2em 0 0.75em 0;text-align:center;">Architecture Overview</p>
<figure class="wp-block-image size-full" style="margin:0 0 0.5em 0;">
<img fetchpriority="high" decoding="async" width="2400" height="1828" src="https://linuxcent.com/wp-content/uploads/2026/05/ep04-ebpf-program-types-og-2.png" alt="eBPF Program Types — tracing, networking, and security hook points across the Linux kernel" class="wp-image-2111" style="width:100%;height:auto;display:block;border-radius:8px;" srcset="https://linuxcent.com/wp-content/uploads/2026/05/ep04-ebpf-program-types-og-2.png 2400w, https://linuxcent.com/wp-content/uploads/2026/05/ep04-ebpf-program-types-og-2-300x229.png 300w, https://linuxcent.com/wp-content/uploads/2026/05/ep04-ebpf-program-types-og-2-1024x780.png 1024w, https://linuxcent.com/wp-content/uploads/2026/05/ep04-ebpf-program-types-og-2-768x585.png 768w, https://linuxcent.com/wp-content/uploads/2026/05/ep04-ebpf-program-types-og-2-1536x1170.png 1536w, https://linuxcent.com/wp-content/uploads/2026/05/ep04-ebpf-program-types-og-2-2048x1560.png 2048w" sizes="(max-width: 2400px) 100vw, 2400px" /><figcaption style="text-align:center;font-size:0.85em;color:#6b7280;margin-top:0.75em;">Each eBPF program type attaches to a different kernel hook — from socket filters to LSM enforcement points.</figcaption></figure>
<hr style="border:none;border-top:1px solid #e5e7eb;margin:0.5em 0 2em 0;"/>
<h2 id="tldr">TL;DR</h2>
<ul>
<li><code class="" data-line="">bpftool prog list</code> and <code class="" data-line="">bpftool net list</code> show every eBPF program on a node — run these first when debugging eBPF-based tool behavior</li>
<li>TC programs can stack on the same interface; stale programs from incomplete Cilium upgrades cause intermittent packet drops — check <code class="" data-line="">tc filter show</code> after every Cilium upgrade</li>
<li>XDP fires before <code class="" data-line="">sk_buff</code> allocation — fastest hook, but no pod identity; Cilium uses it for service load balancing, not pod policy</li>
<li>XDP silently falls back to generic mode on unsupported NICs — verify with <code class="" data-line="">ip link show | grep xdp</code></li>
<li>Tracepoints are stable across kernel versions; kprobe-based tools may silently break after node OS patches</li>
<li>LSM hooks enforce at the kernel level — what makes Tetragon&#8217;s enforcement mode fundamentally different from sidecar-based approaches</li>
</ul>
<hr />
<h2 id="the-big-picture">The Big Picture</h2>
<pre><code class="" data-line="">  WHERE eBPF PROGRAM TYPES ATTACH IN THE KERNEL

  NIC hardware
       ↓
  DMA → ring buffer
       ↓
  ┌─────────────────────────────────────────────────┐
  │  XDP hook  (Cilium: service load balancing)     │
  │  Sees: raw packet bytes only. No pod identity.  │
  └─────────────────────────┬───────────────────────┘
                            │ XDP_PASS
                            ▼
  sk_buff allocated
       ↓
  ┌─────────────────────────────────────────────────┐
  │  TC ingress hook  (Cilium: pod policy ingress)  │
  │  Sees: sk_buff + socket + cgroup → pod identity │
  └─────────────────────────┬───────────────────────┘
                            ↓
  netfilter / IP routing
       ↓
  socket → process (syscall boundary)
  ┌─────────────────────────────────────────────────┐
  │  Tracepoint / kprobe  (Falco: syscall monitor)  │
  │  Sees: any kernel event, any process, any pod   │
  └─────────────────────────────────────────────────┘
  ┌─────────────────────────────────────────────────┐
  │  LSM hook  (Tetragon: kernel-level enforcement) │
  │  Sees: security check context. Can DENY.        │
  └─────────────────────────────────────────────────┘
       ↓
  IP routing → qdisc
  ┌─────────────────────────────────────────────────┐
  │  TC egress hook  (Cilium: pod policy egress)    │
  │  Sees: socket + cgroup on outbound traffic      │
  └─────────────────────────────────────────────────┘
       ↓
  NIC → wire
</code></pre>
<hr />
<p>eBPF program types define where in the kernel a hook fires and what it can see — and knowing the difference is what makes you effective when Cilium or Falco behave unexpectedly. What we hadn&#8217;t answered — and what a 2am incident eventually forced — is what kind of eBPF programs are actually running on your nodes, and why the difference matters when something breaks.</p>
<p>A pod in production was dropping roughly one in fifty outbound TCP connections. Not all of them — just enough to cause intermittent timeouts in the application logs. NetworkPolicy showed egress allowed. Cilium reported no violations. Running <code class="" data-line="">curl</code> manually from inside the pod worked every time.</p>
<p>I spent the better part of three hours eliminating possibilities. DNS. MTU. Node-level conntrack table exhaustion. Upstream firewall rules. Nothing.</p>
<p>Eventually, almost as an afterthought, I ran this:</p>
<pre><code class="" data-line="">sudo bpftool prog list
</code></pre>
<p>There were two TC programs attached to that pod&#8217;s veth interface. One from the current Cilium version. One from the previous version — left behind by a rolling upgrade that hadn&#8217;t cleaned up properly. Two programs. Different policy state. One was occasionally dropping packets based on rules that no longer existed in the current policy model.</p>
<p>The answer had been sitting in the kernel the whole time. I just didn&#8217;t know where to look.</p>
<p>That incident forced me to actually understand something I&#8217;d been hand-waving for two years: eBPF isn&#8217;t a single hook. It&#8217;s a family of program types, each attached to a different location in the kernel, each seeing different data, each suited for different problems. Understanding the difference is what separates &#8220;I run Cilium and Falco&#8221; from &#8220;I understand what Cilium and Falco are actually doing on my nodes&#8221; — and that difference matters when something breaks at 2am.</p>
<h2 id="the-command-you-should-run-on-your-cluster-right-now">The Command You Should Run on Your Cluster Right Now</h2>
<p>Before getting into the theory, do this:</p>
<pre><code class="" data-line=""># See every eBPF program loaded on the node
sudo bpftool prog list

# See every eBPF program attached to a network interface
sudo bpftool net list
</code></pre>
<p>On a node running Cilium and Falco, you&#8217;ll see something like this:</p>
<pre><code class="" data-line="">42: xdp           name cil_xdp_entry       loaded_at 2026-04-01T09:23:41
43: sched_cls     name cil_from_netdev      loaded_at 2026-04-01T09:23:41
44: sched_cls     name cil_to_netdev        loaded_at 2026-04-01T09:23:41
51: cgroup_sock_addr  name cil_sock4_connect loaded_at 2026-04-01T09:23:41
88: raw_tracepoint  name sys_enter          loaded_at 2026-04-01T09:23:55
89: raw_tracepoint  name sys_exit           loaded_at 2026-04-01T09:23:55
</code></pre>
<p>Each line is a different program type. Each one fires at a different point in the kernel. The type column — <code class="" data-line="">xdp</code>, <code class="" data-line="">sched_cls</code>, <code class="" data-line="">raw_tracepoint</code>, <code class="" data-line="">cgroup_sock_addr</code> — tells you where in the kernel execution path that program is attached and therefore what it can and cannot see.</p>
<p>If you see more programs than you expect on a specific interface — like I did — that&#8217;s your first clue.</p>
<h2 id="why-program-types-exist">Why Program Types Exist</h2>
<p>The Linux kernel isn&#8217;t a single pipeline. Network packets, system calls, file operations, process scheduling — these all run through different subsystems with different execution contexts and different available data.</p>
<p>eBPF lets you attach programs to specific points within those subsystems. The &#8220;program type&#8221; is the contract: it defines where the hook fires, what data the program receives, and what it&#8217;s allowed to do with it. A program designed to process network packets before they hit the kernel stack looks completely different from one designed to intercept system calls across all containers simultaneously.</p>
<p>Most of us will interact with four or five program types through the tools we already run. Understanding what each one actually is — where it sits, what it sees — is what makes you effective when those tools behave unexpectedly.</p>
<h2 id="the-types-behind-the-tools-you-already-use">The Types Behind the Tools You Already Use</h2>
<h3 id="tc-why-cilium-can-tell-which-pod-sent-a-packet">TC — Why Cilium Can Tell Which Pod Sent a Packet</h3>
<p>TC stands for Traffic Control. It&#8217;s where Cilium enforces your NetworkPolicy, and it&#8217;s what caused my incident.</p>
<p>TC programs attach to network interfaces — specifically to the ingress and egress directions of the pod&#8217;s virtual interface (<code class="" data-line="">lxcXXXXX</code> in Cilium&#8217;s naming). They fire after the kernel has already processed the packet enough to know its context: which socket created it, which cgroup that socket belongs to. Cgroup maps to container, container maps to pod.</p>
<p>This is the critical piece: <strong>TC is how Cilium knows which pod a packet belongs to</strong>. Without that cgroup context, per-pod policy enforcement isn&#8217;t possible.</p>
<pre><code class="" data-line=""># See TC programs on a pod&#039;s veth interface
sudo tc filter show dev lxc12345 ingress
sudo tc filter show dev lxc12345 egress

# If you see two entries on the same direction — that&#039;s the incident I described
# The priority number (pref 1, pref 2) tells you the order they run
</code></pre>
<p>When there are two TC programs on the same interface, the first one to return &#8220;drop&#8221; wins. The second program never runs. This is why the issue was intermittent rather than consistent — the stale program only matched specific connection patterns.</p>
<p>Fixing it is straightforward once you know what to look for:</p>
<pre><code class="" data-line=""># Remove a stale TC filter by its priority number
sudo tc filter del dev lxc12345 egress pref 2
</code></pre>
<p>Add this check to your post-upgrade runbook. Cilium upgrades are generally clean but not always.</p>
<h3 id="xdp-why-cilium-doesnt-use-tc-for-everything">XDP — Why Cilium Doesn&#8217;t Use TC for Everything</h3>
<p>If TC is good enough for pod-level policy, why does Cilium also run an XDP program on the node&#8217;s main interface? Look at the <code class="" data-line="">bpftool prog list</code> output again — there&#8217;s an <code class="" data-line="">xdp</code> program loaded alongside the TC programs.</p>
<p>XDP fires earlier. Much earlier. Before the kernel allocates any memory for the packet. Before routing. Before connection tracking. Before anything.</p>
<p>The tradeoff is exactly what you&#8217;d expect: XDP is fast but context-poor. It sees raw packet bytes. It doesn&#8217;t know which pod the packet came from. It can&#8217;t read cgroup information because no socket buffer has been allocated yet.</p>
<p>Cilium uses XDP specifically for ClusterIP service load balancing — when a packet arrives at the node destined for a service VIP, XDP rewrites the destination to the actual pod IP in a single map lookup and sends it on its way. No iptables. No conntrack. The work is done before the kernel stack is involved.</p>
<p>There&#8217;s a silent failure mode worth knowing about here. XDP runs in one of two modes:</p>
<ul>
<li><strong>Native mode</strong> — runs inside the NIC driver itself, before any kernel allocation. This is where the performance comes from.</li>
<li><strong>Generic mode</strong> — fallback when the NIC driver doesn&#8217;t support XDP. Runs later, after <code class="" data-line="">sk_buff</code> allocation. No performance benefit over iptables.</li>
</ul>
<p>If your NIC doesn&#8217;t support native XDP, Cilium silently falls back to generic mode. The policy still works — but the performance characteristics you assumed aren&#8217;t there.</p>
<pre><code class="" data-line=""># Check which XDP mode is active on your node&#039;s main interface
ip link show eth0 | grep xdp
# xdpdrv  ← native mode (fast)
# xdpgeneric ← generic mode (no perf benefit)
</code></pre>
<p>Most cloud provider instance types with modern Mellanox/Intel NICs support native mode. Worth verifying rather than assuming.</p>
<h3 id="tracepoints-how-falco-sees-every-container">Tracepoints — How Falco Sees Every Container</h3>
<p>Falco loads two programs: <code class="" data-line="">sys_enter</code> and <code class="" data-line="">sys_exit</code>. These are raw tracepoints — they fire on every single system call, from every process, in every container on the node.</p>
<p>Tracepoints are explicitly defined and maintained instrumentation points in the kernel. Unlike hooks that attach to specific internal function names (which can be renamed or inlined between kernel versions), tracepoints are stable interfaces. They&#8217;re part of the kernel&#8217;s public contract with tooling that wants to instrument it.</p>
<p>This matters operationally. When you patch your nodes — and cloud-managed nodes get patched frequently — tools built on tracepoints keep working. Tools built on kprobes (internal function hooks) may silently stop firing if the function they&#8217;re attached to gets renamed or inlined by the compiler in a new kernel build.</p>
<pre><code class="" data-line=""># Verify what Falco is actually using
sudo bpftool prog list | grep -E &quot;kprobe|tracepoint&quot;

# Falco&#039;s current eBPF driver should show raw_tracepoint entries
# If you see kprobe entries from Falco, you&#039;re on the older driver
# Check: falco --version and the driver being loaded at startup
</code></pre>
<p>If you&#8217;re running Falco on a cluster that gets regular OS patch upgrades and you haven&#8217;t verified the driver mode, check it. The older kprobe-based driver has a real failure mode on certain kernel versions.</p>
<h3 id="lsm-how-tetragon-blocks-operations-at-the-kernel-level">LSM — How Tetragon Blocks Operations at the Kernel Level</h3>
<p>LSM hooks run at the kernel&#8217;s security decision points: file opens, socket connections, process execution, capability checks. The defining characteristic is that they can <em>deny</em> an operation. Return an error from an LSM hook and the kernel refuses the syscall before it completes.</p>
<p>This is qualitatively different from observability hooks. kprobes and tracepoints watch. LSM hooks enforce.</p>
<p>When you see Tetragon configured to kill a process attempting a privileged operation, or block a container from writing to a specific path, that&#8217;s an LSM hook making the decision inside the kernel — not a sidecar watching traffic, not an admission webhook running before pod creation, not a userspace agent trying to act fast enough. The enforcement is in the kernel itself.</p>
<pre><code class="" data-line=""># See if any LSM eBPF programs are active on the node
sudo bpftool prog list | grep lsm

# Verify LSM eBPF support on your kernel (required for Tetragon enforcement mode)
grep CONFIG_BPF_LSM /boot/config-$(uname -r)
# CONFIG_BPF_LSM=y   ← required
</code></pre>
<h2 id="the-practical-summary">The Practical Summary</h2>
<table>
<thead>
<tr>
<th>What&#8217;s happening on your node</th>
<th>Program type</th>
<th>Where to look</th>
</tr>
</thead>
<tbody>
<tr>
<td>Cilium service load balancing</td>
<td>XDP</td>
<td><code class="" data-line="">ip link show eth0 \| grep xdp</code></td>
</tr>
<tr>
<td>Cilium pod network policy</td>
<td>TC (<code class="" data-line="">sched_cls</code>)</td>
<td><code class="" data-line="">tc filter show dev lxcXXXX egress</code></td>
</tr>
<tr>
<td>Falco syscall monitoring</td>
<td>Tracepoint</td>
<td><code class="" data-line="">bpftool prog list \| grep tracepoint</code></td>
</tr>
<tr>
<td>Tetragon enforcement</td>
<td>LSM</td>
<td><code class="" data-line="">bpftool prog list \| grep lsm</code></td>
</tr>
<tr>
<td>Anything unexpected</td>
<td>All types</td>
<td><code class="" data-line="">bpftool prog list</code>, <code class="" data-line="">bpftool net list</code></td>
</tr>
</tbody>
</table>
<h2 id="the-incident-revisited">The Incident, Revisited</h2>
<p>Three hours of debugging. The answer was a stale TC program sitting at priority 2 on a pod&#8217;s veth interface, left behind by an incomplete Cilium upgrade.</p>
<pre><code class="" data-line=""># What I should have run first
sudo bpftool net list
sudo tc filter show dev lxc12345 egress
</code></pre>
<p>Two commands. Thirty seconds. If I&#8217;d known that TC programs can stack on the same interface, I&#8217;d have started there.</p>
<p>That&#8217;s the point of understanding program types — not to write eBPF programs yourself, but to know where to look when the tools you depend on don&#8217;t behave the way you expect. The programs are already there, running on your nodes right now. <code class="" data-line="">bpftool prog list</code> shows you all of them.</p>
<h2 id="key-takeaways">Key Takeaways</h2>
<ul>
<li><code class="" data-line="">bpftool prog list</code> and <code class="" data-line="">bpftool net list</code> show every eBPF program on a node — run these before anything else when debugging eBPF-based tool behavior</li>
<li>TC programs can stack on the same interface; stale programs from incomplete Cilium upgrades cause intermittent drops — check <code class="" data-line="">tc filter show</code> after every Cilium upgrade</li>
<li>XDP runs before the kernel stack — fastest hook, but no pod identity; Cilium uses it for service load balancing, not pod policy</li>
<li>XDP silently falls back to generic mode on unsupported NICs — verify with <code class="" data-line="">ip link show | grep xdp</code></li>
<li>Tracepoints are stable across kernel versions; kprobe-based tools may silently break after node OS patches — verify your Falco driver mode</li>
<li>LSM hooks enforce at the kernel level — this is what makes Tetragon&#8217;s enforcement mode fundamentally different from sidecar-based approaches</li>
</ul>
<h2 id="whats-next">What&#8217;s Next</h2>
<p>Every eBPF program fires, does its work, and exits — but the work always involves data.</p>
<p>Get EP05 in your inbox when it publishes → <a href="https://linuxcent.com/subscribe">linuxcent.com/subscribe</a> Counting connections. Tracking processes. Streaming events to a detection engine. In EP05, I&#8217;ll cover eBPF maps: the persistent data layer that connects kernel programs to the tools consuming their output. Understanding maps explains a class of production issues — and makes <code class="" data-line="">bpftool map dump</code> useful rather than cryptic.</p>
<p><a class="a2a_button_mastodon" href="https://www.addtoany.com/add_to/mastodon?linkurl=https%3A%2F%2Flinuxcent.com%2Febpf-program-types-kubernetes%2F&amp;linkname=eBPF%20Program%20Types%20%E2%80%94%20What%E2%80%99s%20Actually%20Running%20on%20Your%20Nodes" title="Mastodon" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_email" href="https://www.addtoany.com/add_to/email?linkurl=https%3A%2F%2Flinuxcent.com%2Febpf-program-types-kubernetes%2F&amp;linkname=eBPF%20Program%20Types%20%E2%80%94%20What%E2%80%99s%20Actually%20Running%20on%20Your%20Nodes" title="Email" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_whatsapp" href="https://www.addtoany.com/add_to/whatsapp?linkurl=https%3A%2F%2Flinuxcent.com%2Febpf-program-types-kubernetes%2F&amp;linkname=eBPF%20Program%20Types%20%E2%80%94%20What%E2%80%99s%20Actually%20Running%20on%20Your%20Nodes" title="WhatsApp" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_reddit" href="https://www.addtoany.com/add_to/reddit?linkurl=https%3A%2F%2Flinuxcent.com%2Febpf-program-types-kubernetes%2F&amp;linkname=eBPF%20Program%20Types%20%E2%80%94%20What%E2%80%99s%20Actually%20Running%20on%20Your%20Nodes" title="Reddit" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_x" href="https://www.addtoany.com/add_to/x?linkurl=https%3A%2F%2Flinuxcent.com%2Febpf-program-types-kubernetes%2F&amp;linkname=eBPF%20Program%20Types%20%E2%80%94%20What%E2%80%99s%20Actually%20Running%20on%20Your%20Nodes" title="X" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_linkedin" href="https://www.addtoany.com/add_to/linkedin?linkurl=https%3A%2F%2Flinuxcent.com%2Febpf-program-types-kubernetes%2F&amp;linkname=eBPF%20Program%20Types%20%E2%80%94%20What%E2%80%99s%20Actually%20Running%20on%20Your%20Nodes" title="LinkedIn" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_copy_link" href="https://www.addtoany.com/add_to/copy_link?linkurl=https%3A%2F%2Flinuxcent.com%2Febpf-program-types-kubernetes%2F&amp;linkname=eBPF%20Program%20Types%20%E2%80%94%20What%E2%80%99s%20Actually%20Running%20on%20Your%20Nodes" title="Copy Link" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Flinuxcent.com%2Febpf-program-types-kubernetes%2F&#038;title=eBPF%20Program%20Types%20%E2%80%94%20What%E2%80%99s%20Actually%20Running%20on%20Your%20Nodes" data-a2a-url="https://linuxcent.com/ebpf-program-types-kubernetes/" data-a2a-title="eBPF Program Types — What’s Actually Running on Your Nodes"></a></p><p>The post <a href="https://linuxcent.com/ebpf-program-types-kubernetes/">eBPF Program Types — What&#8217;s Actually Running on Your Nodes</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://linuxcent.com/ebpf-program-types-kubernetes/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1450</post-id>	</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Page Caching using Disk: Enhanced 

Served from: linuxcent.com @ 2026-08-30 22:29:59 by W3 Total Cache
-->