Skip to content

eBPF Daemonset Installation

The cloudtaser eBPF agent is a DaemonSet deployed on every node in the cluster. It provides runtime enforcement and secret leak detection by monitoring syscalls via eBPF kprobes and tracepoints. The agent blocks exfiltration vectors such as /proc/pid/environ reads, /proc/pid/mem access, and ptrace attach attempts on cloudtaser-protected processes.

Purpose

Without the eBPF agent, cloudtaser protects secrets at the infrastructure level -- secrets bypass etcd and Kubernetes Secrets entirely. The eBPF agent adds runtime protection on the node itself:

  • Blocks /proc access -- Prevents reading /proc/<pid>/environ and /proc/<pid>/mem of protected processes, even by root
  • Blocks ptrace -- Prevents debugger attach and memory inspection of protected processes
  • Exfiltration detection -- Monitors for suspicious syscall patterns that indicate secret extraction attempts
  • Reactive kill -- Optionally terminates processes that attempt to read protected memory regions

Defense in depth

The eBPF agent is a defense-in-depth layer. Even without it, secrets never touch etcd or disk. The agent protects against a compromised node or container escape scenario where an attacker has root access on the host.

Kernel Requirements

The eBPF agent requires a Linux kernel with BPF support. The following table summarizes compatibility.

Kernel Version Support Level Notes
< 5.8 Not supported Missing required BPF features
5.8 -- 5.13 Basic Minimum for the agent to load; readiness depends on the conditions below
5.14+ Recommended Includes memfd_secret integration. Kernel version alone does not make the install ready
6.1+ Recommended Long-term support kernel

Kernel version is necessary but not sufficient. With the default chart the agent is ready only on kernels with CONFIG_BPF_KPROBE_OVERRIDE=y. BPF LSM hooks cover only some of the required vectors, so BPF LSM alone does not make the agent ready. Otherwise /healthz returns HTTP 503 and protected workloads are refused. See Kernel Compatibility.

Check your node kernel version

kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.nodeInfo.kernelVersion}{"\n"}{end}'

All nodes must run Linux 5.8 or later, and each must also provide a synchronous deny path for every required vector (see above).

Managed Kubernetes Kernel Versions

Node Image Kernel Supported
Container-Optimized OS (COS), measured 29 October 6.12.105+ Tier 1 lsm+fmod_ret, Ready with default strict settings on the tested cohort
Measured Ubuntu 24.04.5 6.8.0-1062-gke Refused by default: BPF LSM is built but inactive

Qualify the exact image and agent release. See the recorded COS cohort and platform matrix; kernel version or a GKE label alone does not establish readiness.

AMI Kernel Supported
Amazon Linux 2023 6.1+ Yes
Amazon Linux 2 5.10+ Yes (basic)
Ubuntu 22.04 5.15+ Yes

Amazon Linux 2023 is recommended for EKS deployments.

Node Image Kernel Supported
Ubuntu 22.04 5.15+ Yes
Azure Linux (Mariner) 5.15+ Yes

AKS with Ubuntu node images meets kernel requirements by default.

Managed Kubernetes Compatibility

Serverless/Autopilot environments are not supported

The eBPF agent requires hostPID: true and privileged container access, which are not available on serverless Kubernetes platforms.

Platform Supported Reason
GKE Standard Yes Full host access available
GKE Autopilot No Cannot run privileged DaemonSets
EKS (managed nodes) Yes Full host access available
EKS (self-managed nodes) Yes Full host access available
AWS Fargate No No host access, no DaemonSet support
AKS (regular node pools) Yes Full host access available
AKS (Virtual Nodes) No Backed by Azure Container Instances, no host access

Installation

The eBPF agent is part of the unified cloudtaser Helm chart and is enabled by default. If you already installed cloudtaser following the operator installation guide, the eBPF DaemonSet is already running.

Before deploying protected applications, enroll their workload namespaces with label cloudtaser.io/inject=true and retain pod injection annotations. A running node agent alone does not enroll a namespace or inject its workloads.

Verify Default Installation

kubectl get daemonset -n cloudtaser-system

Expected output:

NAME              DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
cloudtaser-ebpf   3         3         3       3            3           <none>          2m

Enable or Disable via Helm Values

To explicitly control the eBPF agent during installation (the examples use the direct secret-store profile; see Operator Installation):

helm repo add cloudtaser https://charts.cloudtaser.io
helm repo update

helm install cloudtaser cloudtaser/cloudtaser \
  --namespace cloudtaser-system \
  --create-namespace \
  --set operator.secretBackend=vault \
  --set operator.enableReverseConnect=false \
  --set operator.broker.beacon.enabled=false \
  --set operator.secretstore.address=https://vault.eu.example.com \
  --set networkPolicy.vaultCIDR=<secret-store CIDR> \
  --set ebpf.enabled=true
helm repo add cloudtaser https://charts.cloudtaser.io
helm repo update

helm install cloudtaser cloudtaser/cloudtaser \
  --namespace cloudtaser-system \
  --create-namespace \
  --set operator.secretBackend=vault \
  --set operator.enableReverseConnect=false \
  --set operator.broker.beacon.enabled=false \
  --set operator.secretstore.address=https://vault.eu.example.com \
  --set networkPolicy.vaultCIDR=<secret-store CIDR> \
  --set ebpf.enabled=false

Warning

Disabling the eBPF agent removes runtime enforcement. Secrets are still protected at the infrastructure level (memory-only, no etcd), but node-level exfiltration attacks are not blocked. The protection score for workloads will be reduced.

Helm Values

values.yaml
ebpf:
  enabled: true
  image:
    repository: europe-west4-docker.pkg.dev/skipopsmain/cloudtaser/cloudtaser-ebpf
    tag: "v0.13.164"
    pullPolicy: IfNotPresent

  # Block exfiltration attempts (vs. log-only)
  enforceMode: true

  # Log all syscall events (verbose, for debugging only)
  logAll: false

  # Terminate processes that attempt to read protected memory
  reactiveKill: true

  resources:
    requests:
      cpu: 100m
      memory: 128Mi
    limits:
      cpu: 500m
      memory: 512Mi
Value Default Description
ebpf.enabled true Deploy the eBPF DaemonSet
ebpf.enforceMode true Block exfiltration attempts. Set to false for audit-only mode
ebpf.logAll false Log all monitored syscalls. Enable only for debugging
ebpf.reactiveKill true Kill processes that attempt to read protected process memory

Seccomp Profile Root

The agent writes the profiles/cloudtaser-memfd.json Localhost seccomp profile that injected containers use by default (operator.seccomp.localhostProfile). The kubelet resolves Localhost profiles under <kubelet --root-dir>/seccomp, so ebpf.seccompHostDir must be that directory on every node. It follows the kubelet's --root-dir, not the distribution name:

Kubelet ebpf.seccompHostDir
kubeadm, GKE, EKS, AKS /var/lib/kubelet/seccomp (chart default)
K3s, rootful (default) /var/lib/kubelet/seccomp (chart default). K3s passes no --root-dir, so the kubelet default applies
K3s rootless <data-dir>/agent/kubelet/seccomp
k0s /var/lib/k0s/kubelet/seccomp
Any kubelet started with --root-dir=<dir> (K3s: --kubelet-arg=root-dir=<dir>) <dir>/seccomp

Do not use /var/lib/rancher/k3s/agent/kubelet/seccomp on rootful K3s

Earlier guidance listed this path for K3s. Current rootful K3s never reads it: the agent writes the profile there, the runtime looks under /var/lib/kubelet/seccomp, and every injected pod stays in CreateContainerError.

To check a node, read the kubelet's --root-dir flag. On kubeadm-style nodes run ps -o args= -C kubelet. On K3s run journalctl -u k3s | grep -o -- '--root-dir=[^ ]*'; no match means the default /var/lib/kubelet. A wrong root shows up as:

cannot load seccomp profile "/var/lib/kubelet/seccomp/profiles/cloudtaser-memfd.json": open ...: no such file or directory

The directory before /profiles/ in that message is the value to set:

helm upgrade cloudtaser cloudtaser/cloudtaser -n cloudtaser-system --reuse-values \
  --set ebpf.seccompHostDir=/var/lib/kubelet/seccomp

Keep the Localhost profile. Do not switch workloads to Unconfined to get past the error.

Verify Installation

Check DaemonSet Status

Ensure the DaemonSet is running on all schedulable nodes:

kubectl get daemonset cloudtaser-ebpf -n cloudtaser-system

The DESIRED, CURRENT, and READY counts should all match and equal the number of nodes in your cluster.

Check Node Coverage

Verify every node has a running eBPF agent pod:

kubectl get pods -n cloudtaser-system -l app=cloudtaser-ebpf -o wide

Each node should have exactly one eBPF agent pod in Running state.

Check Agent Logs

kubectl logs -n cloudtaser-system daemonset/cloudtaser-ebpf --tail=20

Look for log lines confirming BPF programs have been loaded and the agent is monitoring protected PIDs.

Check Health Endpoints

The eBPF agent exposes HTTP health endpoints:

# Liveness
kubectl exec -n cloudtaser-system daemonset/cloudtaser-ebpf -- wget -qO- http://localhost:9090/healthz

# Readiness
kubectl exec -n cloudtaser-system daemonset/cloudtaser-ebpf -- wget -qO- http://localhost:9090/readyz

Validate with CLI

If you have the cloudtaser CLI installed:

cloudtaser-cli target status

The output includes eBPF enforcement coverage -- the percentage of nodes with a healthy eBPF agent.

Required Capabilities

The eBPF agent runs as a privileged DaemonSet with the following security context:

securityContext:
  privileged: true
hostPID: true

Required Linux capabilities:

Capability Purpose
SYS_ADMIN Load and attach BPF programs
SYS_PTRACE Access process information for PID monitoring
NET_ADMIN Attach network-related BPF programs
SYS_RESOURCE Increase locked memory limits for BPF maps

The agent uses priorityClassName: system-node-critical to ensure scheduling even under resource pressure.

Compliance note: enforcement modes

The eBPF agent supports two operational modes: detect (audit-only) and enforce (active blocking). In detect mode, exfiltration attempts are logged but not prevented -- suitable for initial assessment. In enforce mode, the agent actively blocks syscalls that would leak secrets, providing a verifiable runtime protection guarantee. For regulated environments, enforce mode with reactiveKill enabled provides the strongest protection posture. All events are logged and can be streamed to the cloudtaser Platform for centralized audit trails.

Troubleshooting

Symptom Cause Fix
DaemonSet pods in CrashLoopBackOff Kernel too old or BPF not enabled Check kernel version is 5.8+; verify /sys/fs/bpf is mounted
DESIRED != READY Agent failing on specific nodes Check logs on the failing node's pod; likely a kernel compatibility issue
Injected pods in CreateContainerError: cannot load seccomp profile ".../profiles/cloudtaser-memfd.json" ebpf.seccompHostDir is not the kubelet's seccomp root Set it to the directory before /profiles/ in the error; see Seccomp Profile Root
Agent running but no enforcement enforceMode: false Set ebpf.enforceMode=true in Helm values and upgrade
Low protection score despite agent running Agent not receiving PID registrations from operator Check connectivity between eBPF agent and operator on port 8199

For more details, see Troubleshooting and Kernel Compatibility.

Next Steps