Skip to content

Kubernetes

Deployment Guide

This guide covers deploying Runtime Sensor on Kubernetes using the official Endura Helm chart. Unlike the per-host package installation used on bare-metal and virtual machine distributions, the Helm chart deploys the Sensor as a DaemonSet, automatically running a single Sensor instance on every node in your cluster.

How the Sensor and CI/CD Jobs Relate

Before deploying, it is important to understand how the Sensor’s lifecycle differs from the lifecycle of the CI/CD jobs it monitors. These are two separate, independent lifecycles:

Sensor lifecycle (long-lived, per-node):

  • The Helm chart deploys a DaemonSet, which schedules one Sensor Pod on every Linux node in the cluster.
  • Each Sensor starts once and runs continuously, waiting for jobs to start. You deploy it a single time and leave it running.
  • Each Sensor exposes a Unix socket on its node host at /run/endura/sensor.sock. This socket is how other processes on the node communicate with the Sensor.

Job lifecycle (ephemeral, per-build):

  • CI/CD builds are typically scheduled as ephemeral Pods. A build Pod is created when the build starts and is torn down when it finishes.
  • Each build Pod owns its own job lifecycle: it runs endura job start at the beginning of the build and endura job stop at the end.
  • The build Pod only needs the endura CLI binary — it does not start its own Sensor. The Sensor is already running on the node via the DaemonSet. The CLI communicates with that node-local Sensor over the mounted socket.

Two Lifecycles, One Socket

  • Sensor lifecycle: long-lived, one per node, started once by the DaemonSet (endura sensor start).
  • Job lifecycle: ephemeral, one per build, started and stopped by the build Pod (endura job start / endura job stop).

The build Pod installs only the endura CLI and reaches the node’s running Sensor through the mounted /run/endura/sensor.sock socket. It never runs a Sensor of its own.

Prerequisites

Before starting, ensure you have:

  • A Kubernetes cluster (1.19+) with Linux nodes running kernel 5.11+
  • The ability to schedule privileged Pods with host access (the Sensor requires this for eBPF)
  • helm 3.8.0+ (required for installing OCI-based charts) and kubectl configured for your cluster
  • Cluster-admin permissions for installing the DaemonSet and its RBAC resources
  • A valid Endura license key (ENDURA_LICENSE_KEY)
  • (Optional, for Team Server mode) Your Team Server URL and a sensor token

You can obtain a sensor token as follows:

  1. Browse to your Team Server instance and login.
  2. Select Sensors in the main navigation on the left-hand side.
  3. Click the Create button in the upper-left hand corner.
  4. Provide a name and description for the sensor and click Save.
  5. The provided Access Token serves as your ENDURA_SENSOR_TOKEN.

Deploy the Sensor DaemonSet

Step 1: Create the Namespace and License Secret

The Helm chart reads the license key from a Kubernetes Secret named endura-sensor-secrets, which must exist before you install the chart. Create the namespace and the secret:

# Create the namespace
kubectl create namespace endura

# Create the license secret the chart expects
kubectl create secret generic endura-sensor-secrets \
  --from-literal=ENDURA_LICENSE_KEY=your_license_key_from_endura_security \
  -n endura

The chart injects every key in this secret into the Sensor Pods as environment variables, so this is also the recommended place to store any other sensitive values (for example, ENDURA_SENSOR_TOKEN):

kubectl create secret generic endura-sensor-secrets \
  --from-literal=ENDURA_LICENSE_KEY=your_license_key_from_endura_security \
  --from-literal=ENDURA_SENSOR_TOKEN=your_sensor_token_from_team_server \
  -n endura

Step 2: Install the Helm Chart

Install the chart directly from the Endura OCI registry:

helm install endura-sensor oci://ghcr.io/endurasecurity/helm/endura-sensor \
  -n endura \
  --set image.tag=0.37.6 \
  --set sensor.env.ENDURA_TEAM_SERVER=https://your-team-server.company.com

This deploys the DaemonSet, ServiceAccount, and RBAC resources into the endura namespace, starting one Sensor Pod on every Linux node.

Standalone vs. Team Server mode. Team Server configuration is optional. Omit ENDURA_TEAM_SERVER to run the Sensor in standalone mode with locally-defined policies. To report to a Team Server, set ENDURA_TEAM_SERVER as shown above and provide ENDURA_SENSOR_TOKEN via the secret created in Step 1.

The chart’s image.tag defaults to the testing channel. For Kubernetes you should pin an immutable version tag instead: channel tags such as testing are reused across builds, so Kubernetes will not pull a newer image when the underlying build changes. The examples here pin --set image.tag=0.37.6; substitute the version you intend to run.

Step 3: Verify the Deployment

Confirm the DaemonSet has rolled out and the Sensor Pods are running:

# Wait for the DaemonSet to finish rolling out
kubectl rollout status daemonset/endura-sensor -n endura

# Confirm one Sensor Pod is running per node
kubectl get pods -n endura -o wide

# View Sensor logs
kubectl logs -n endura -l app.kubernetes.io/name=endura-sensor

A Sensor Pod becomes Ready only after its readiness probe (endura sensor status) succeeds, indicating the Sensor has loaded its eBPF programs and is ready to accept jobs.

Configuration Reference

Non-sensitive configuration is provided through Helm values. The most commonly adjusted values are listed below. For the full semantics and defaults of every ENDURA_* variable — including ones not surfaced as Helm values — see the Runtime Sensor Configuration reference. Any of those variables can be injected via the endura-sensor-secrets Secret or a sensor.env.* value.

ValueDefaultDescription
image.repositoryghcr.io/endurasecurity/container/endura-sensorSensor container image
image.tagtestingImage tag. Pin an immutable version (e.g. 0.37.6) for Kubernetes rather than a mutable channel tag.
image.pullPolicyAlwaysImage pull policy
sensor.env.ENDURA_LOG_LEVELinfoLog verbosity (trace/debug/info/warn/error)
sensor.env.ENDURA_TEAM_SERVER(unset)Team Server URL (enables Team Server mode)
secrets.nameendura-sensor-secretsName of the Secret injected as environment variables
nodeSelectorkubernetes.io/os: linuxRestrict the Sensor to specific nodes
tolerations[]Tolerations so the Sensor can run on tainted nodes
resources100m/128Mi requests, 500m/512Mi limitsCPU and memory requests/limits

Privileged Host Access

The Sensor runs as a privileged container and mounts host paths such as /sys/fs/bpf, /sys/kernel, /proc, and /run/endura. These are required for eBPF program loading and kernel-level enforcement, and are configured by the chart automatically. Ensure your cluster’s Pod Security admission settings permit privileged workloads in the endura namespace.

You can override individual values on the command line:

helm install endura-sensor oci://ghcr.io/endurasecurity/helm/endura-sensor \
  -n endura \
  --set sensor.env.ENDURA_LOG_LEVEL=debug \
  --set image.tag=0.37.6

Or supply a values file for more extensive customization:

helm install endura-sensor oci://ghcr.io/endurasecurity/helm/endura-sensor \
  -n endura \
  -f values.yaml

Instrument CI/CD Jobs

With the Sensor running on every node, instrument your CI/CD build Pods to start and stop an Endura job around their workload. Because the Sensor already runs on the node, the build Pod installs only the endura CLI and communicates with the node’s Sensor through the mounted socket.

There are three requirements for a build Pod to use the Sensor:

  1. The Sensor DaemonSet must already be running on the node. This is satisfied by the deployment steps above — the DaemonSet runs on every node, so any build Pod is automatically co-located with a Sensor.

  2. The Pod must mount the Sensor socket. Mount the host directory /run/endura (which contains sensor.sock) into the Pod using a hostPath volume.

  3. The Pod must install the endura CLI and run the job lifecycle. Install the CLI with the bash install script, then run endura job start before your build steps and endura job stop after them:

    curl -sSf https://repo.endurasecurity.com/install/endura-sensor/testing.sh | sh
    endura job start
    # ... your build/test steps ...
    endura job stop

The Install Script Only Installs the CLI

Running the install script inside the build Pod installs the endura binary; it does not start a Sensor. The Sensor is already running on the node via the DaemonSet. The CLI uses the binary purely to send job start and job stop requests to that node-local Sensor over the socket.

Example Job Manifest

The following Kubernetes Job demonstrates the complete pattern: it mounts the Sensor socket, installs the endura CLI, starts a job, runs a workload, and stops the job. The job stop runs in a shell trap so it executes even if the build steps fail.

apiVersion: batch/v1
kind: Job
metadata:
  name: example-build
  namespace: endura
spec:
  backoffLimit: 0
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: build
          image: docker.io/redhat/ubi9:latest
          command: ["/bin/sh"]
          args:
            - "-c"
            - |
              set -e

              # Install the endura CLI (binary only; the Sensor runs on the node)
              curl -sSf https://repo.endurasecurity.com/install/endura-sensor/testing.sh | sh

              # Always stop the job, even if the build fails
              cleanup() {
                endura job stop "$WORKSPACE" 2>/dev/null || true
              }
              trap cleanup EXIT

              # Start the Endura job for this build
              export WORKSPACE=/workspace
              mkdir -p "$WORKSPACE"
              endura job start --workspace "$WORKSPACE"

              # ... run your build and test steps here ...

              # Stop the job (also handled by the trap above)
              endura job stop "$WORKSPACE"
          volumeMounts:
            - name: endura-socket
              mountPath: /run/endura
      volumes:
        - name: endura-socket
          hostPath:
            path: /run/endura
            type: DirectoryOrCreate

Socket Mount is Required

Without the /run/endura mount, the endura job start and endura job stop commands cannot communicate with the Runtime Sensor and will fail. The Sensor runs on the node host, not inside the build Pod — the socket mount bridges this gap.

Always Run the Stop Step

Ensure endura job stop always runs, even when the build fails or is cancelled. The example above uses a shell trap cleanup EXIT to guarantee this. Failing to stop the job prevents proper cleanup and policy evaluation.

Policy Modes

The endura job start command accepts a policy mode and an optional policy file:

ModeBehavior
deriveMonitor build behavior and generate a baseline policy (initial setup)
observeLog policy violations without taking action (testing/refinement)
enforceBlock unauthorized operations and fail builds on violations (production)

For example, to enforce a specific policy:

endura job start --workspace "$WORKSPACE" --policy /etc/policy/policy.json

The recommended workflow is derive → observe → enforce. Where these start and stop steps belong within a specific CI/CD vendor’s pipeline depends on that vendor.

Upgrading the Sensor

Upgrade to a newer chart or image version with helm upgrade:

# Upgrade to the latest published chart
helm upgrade endura-sensor oci://ghcr.io/endurasecurity/helm/endura-sensor -n endura

# Pin a specific image version
helm upgrade endura-sensor oci://ghcr.io/endurasecurity/helm/endura-sensor \
  -n endura \
  --set image.tag=0.37.6

The DaemonSet performs a rolling update, replacing the Sensor Pod on each node. Verify the rollout afterward:

kubectl rollout status daemonset/endura-sensor -n endura

Uninstalling the Sensor

Remove the Helm release and the license secret:

# Remove the DaemonSet and associated resources
helm uninstall endura-sensor -n endura

# Remove the license secret
kubectl delete secret endura-sensor-secrets -n endura

# Optionally remove the namespace
kubectl delete namespace endura

Troubleshooting

Sensor Pods are crash-looping or never become Ready:

# Inspect the Pod status and recent events
kubectl describe pod -n endura -l app.kubernetes.io/name=endura-sensor

# Check the Sensor logs for eBPF/LSM or license errors
kubectl logs -n endura -l app.kubernetes.io/name=endura-sensor

Common causes include a node kernel older than 5.11, eBPF LSM not enabled on the node, or the cluster’s Pod Security admission rejecting the privileged container.

license errors in the Sensor logs:

# Confirm the secret exists and contains the license key
kubectl get secret endura-sensor-secrets -n endura -o jsonpath='{.data.ENDURA_LICENSE_KEY}' | base64 -d

If the secret is missing or the key is wrong, recreate it (Step 1) and restart the DaemonSet with kubectl rollout restart daemonset/endura-sensor -n endura.

Build Pod cannot reach the Sensor (endura job start fails):

  • Verify the build Pod mounts /run/endura via a hostPath volume.
  • Confirm a Sensor Pod is running and Ready on the same node as the build Pod (kubectl get pods -n endura -o wide).
  • Confirm the Sensor on that node has finished starting (its readiness probe is passing).