Cilium and Tetragon let you enforce runtime security policies by observing and acting on kernel events.

Let’s see Tetragon in action. Imagine we want to prevent any new pods from starting if they try to mount a host path. This is a common security requirement to avoid privilege escalation.

First, we need Tetragon installed and running. Typically, this involves deploying a DaemonSet to each node.

# Example kubectl command to deploy Tetragon
kubectl apply -f https://raw.githubusercontent.com/cilium/tetragon/main/install/tetragon.yaml

Once Tetragon is running, it’s listening for events. We can define a policy using its custom resource definition (CRD), CiliumNetworkPolicy. Tetragon leverages the Cilium agent, so we use the same CRDs for both networking and security policies.

Here’s a policy that denies pods attempting to mount host paths:

apiVersion: cilium.io/v1alpha1
kind: CiliumNetworkPolicy
metadata:
  name: deny-hostpath-mount
spec:
  description: "Deny pods from mounting host paths"
  endpointSelector: {} # Apply to all pods
  policyTypes:
    - Ingress
    - Egress
  egress:
    - toPorts:
        - ports:
            - port: "0" # All ports
              protocol: TCP
      toEndpoints:
        - matchLabels: {} # All endpoints
  # This is where the runtime enforcement happens
  runtime:
    requirements:
      - matchCapabilities:
          - CAP_SYS_ADMIN # Often required for host mounts
        matchProcesses:
          - pathRegex: "^/usr/bin/mount$" # The mount binary
            argsRegex: ".*-o.*bind.*" # Looking for bind mount options
        matchActions:
          - deny # Deny the operation

This policy is a bit of a blunt instrument for demonstration. A more sophisticated policy would target specific mount operations or paths. Tetragon’s power comes from its ability to observe granular kernel events.

The core of Tetragon is its ability to hook into the Linux kernel using eBPF. It can trace syscalls, network events, and even process execution. When a specific pattern is detected – like a mount syscall with certain arguments – Tetragon can be configured to take action.

Let’s consider another example: preventing sensitive binaries from being executed. Suppose we want to block kubectl from running inside pods, as this could be a vector for attackers to gain more control.

apiVersion: cilium.io/v1alpha1
kind: CiliumNetworkPolicy
metadata:
  name: block-kubectl-execution
spec:
  description: "Block execution of kubectl inside pods"
  endpointSelector: {} # Apply to all pods
  runtime:
    requirements:
      - matchProcesses:
          - pathRegex: "^/usr/bin/kubectl$" # The kubectl binary
        matchActions:
          - deny # Deny execution

When a pod tries to execute /usr/bin/kubectl, Tetragon intercepts this event. Because the policy explicitly denies processes matching that path, the execution is blocked. The pod’s process will likely receive a SIGKILL or similar signal.

The matchProcesses field is crucial here. You can specify exact paths, use regular expressions for more flexible matching, and even look at the arguments passed to the process. This allows for very precise control.

The matchCapabilities field is another powerful lever. You can restrict pods from using certain Linux capabilities, which are fine-grained privileges. For instance, denying CAP_NET_ADMIN can prevent a pod from manipulating network interfaces.

apiVersion: cilium.io/v1alpha1
kind: CiliumNetworkPolicy
metadata:
  name: deny-net-admin-capability
spec:
  description: "Deny CAP_NET_ADMIN capability to pods"
  endpointSelector: {}
  runtime:
    requirements:
      - matchCapabilities:
          - CAP_NET_ADMIN # The capability to deny
        matchActions:
          - deny

This policy would prevent any process within a pod from acquiring or using the CAP_NET_ADMIN capability, effectively stopping it from performing network administration tasks.

A key aspect of Tetragon is its observability. It doesn’t just enforce; it also provides detailed logs of what it’s seeing and acting upon. You can use kubectl logs <tetragon-pod-name> -n kube-system to see these events. This is invaluable for debugging policies and understanding runtime behavior.

The most surprising thing is how many otherwise unobservable system events become visible and actionable. You can trace file access, network connections at the syscall level, and process lifecycles with incredible granularity, all without modifying applications or the kernel itself.

The runtime section of the CiliumNetworkPolicy is where the magic for Tetragon lies. It translates high-level security intent into specific eBPF programs that run in the kernel. These programs are triggered by specific events (like syscalls) and can then decide whether to allow or deny the operation based on the defined requirements.

The next step is to explore how to integrate Tetragon’s runtime policies with your existing network policies for a comprehensive security posture.

Want structured learning?

Take the full Cilium course →