Package: endura-sensor
Version: 1.0.23-1
Architecture: amd64
Maintainer: Infrared Security, LLC.
Installed-Size: 30577
Filename: ./endura-sensor_1.0.23-1_amd64.deb
Size: 4474880
MD5sum: e6fc05e46426ccea7f1a4ab4d11f7675
SHA1: fa2a311946bf36c18ddb1425f5fed7cead109c51
SHA256: 63f278a9a7b3774fdc4a6e48b96dd96909ca0630650030ffcefa792ca3e8802c
Section: Development
Priority: optional
Description: endura sensor
 # Endura Runtime Sensor
 .
 A Linux runtime security sensor that uses eBPF and LSM hooks to provide
 kernel-level security monitoring and policy enforcement for CI/CD pipelines and
 production deployments.
 .
 ## Overview
 .
 The Endura Runtime Sensor intercepts and validates security-relevant operations
 at the kernel level before they execute. It supports a deny-by-default policy
 model where operations not explicitly permitted are blocked when enforcement is
 enabled.
 .
 ### Key Capabilities
 .
 - **File System Monitoring** - Execution, file reads/writes/overwrites,
 creation, deletion, renaming, hard links, symbolic links, mounting, chroot,
 pivot root, disk quotas
 - **Network Monitoring** - TCP/IP bind/connect (IPv4/IPv6), Unix domain
 sockets, raw/packet sockets, netlink sockets, virtual sockets (vsock)
 - **Container Security** - Container image execution control, socket access
 restrictions
 - **Process Management** - Process termination, scheduling, resource limits,
 process groups
 - **Memory Protection** - Memory mapping control, W+X (write-execute) violation
 detection, LD_PRELOAD injection detection
 - **Reverse Shell Detection** - Stdio-over-socket detection (a process exec'd
 with stdin/stdout/stderr connected to a network socket), ptrace injection,
 PTRACE_TRACEME
 - **Kernel Operations** - eBPF program loading, kernel module loading, kernel
 memory access
 - **Privilege Escalation** - Linux capability monitoring (setuid, setgid,
 net_admin, sys_admin, etc.)
 - **IPC Monitoring** - System V shared memory and message queues
 .
 ### Architecture
 .
 The sensor operates in two layers:
 .
 1. **Kernel Space** (C/eBPF) - LSM and fentry hooks intercept security
 operations, evaluate policies via shared BPF LPM-trie maps, and emit events
 through four processor-sharded 32 MiB ring buffers
 2. **User Space** (Rust) - Processes events from ring buffers, manages jobs and
 policies, reports violations to the Endura Team Server
 .
 Each hook has both LSM and fentry variants for maximum kernel compatibility
 (5.11+). Some hooks cover both legacy and modern kernel APIs (e.g.,
 `security_sb_mount` and `security_move_mount` for mount operations).
 .
 A hook a given kernel cannot provide does not stop the sensor — it is
 reported instead. `endura sensor status` carries an attached/total count, and
 `endura sensor hooks` lists every eBPF program with the kernel hook it targets
 and whether it attached, so a partially-attached sensor is visible without
 reading the log.
 .
 ### Policy Enforcement
 .
 Policies are JSON documents that define permitted runtime operations:
 .
 - **Derive** - Monitor behavior and auto-generate policy rules
 - **Observe** - Log violations without blocking
 - **Enforce** - Block unauthorized operations
 .
 Policy rules use pipe-delimited expressions with support for wildcards (`all`),
 brace expansion (`{a,b}`), and workspace variables (`%workspace%`). Path
 expressions also do **parent-path matching** — a rule for a directory (e.g.
 `/usr/bin`) permits everything beneath it (`/usr/bin/cat`). A rule may expand
 to at most 1024 values, counted as the product across its pipe-delimited
 registers, and each register is limited to 8192 bytes.
 .
 ### Jobs
 .
 A policy is activated by starting a **job** over a workspace directory:
 .
 ```bash
 endura job start --workspace <dir> --policy <file>
 ```
 .
 `endura job get`, `job status` and `job stop` take either form: an argument of
 **exactly 16 hex digits** is a job id, and anything else is a workspace path.
 Ids are always printed as 16 hex digits, so the value from `job start` or `job
 list` pastes straight back. Name a directory whose bare name happens to be 16
 hex digits as `./<name>` — anything containing `/` is always read as a path.
 A workspace resolves to a job only within the mount namespace the job was
 started from; from anywhere else, use the id.
 .
 Starting a job for a workspace that already has one **replaces** it, keeping
 the same job id — the sensor authorizes the workspace and stops the previous
 job within the same request. This is how a running job's policy or mode is
 changed. The policy file is parsed and validated before the request is sent and
 the workspace is authorized before anything is torn down, so a bad policy path
 or an unauthorized workspace leaves the original job running rather than
 removing protection.
 .
 A job is anchored to its workspace by **object identity as well as by path**,
 so an alias cannot move the workspace out of the job's reach — a bind mount
 or hard link of it still resolves to the owning job. Creating such an alias is
 itself an operation the policy must permit.
 .
 Every job workspace must exist on disk. Non-root users may start jobs only for
 workspaces they own,
 which confines an unprivileged user's policy to its own files. Root bypasses
 the ownership check but
 must still name an existing workspace.
 .
 ### Control Socket
 .
 The CLI reaches the sensor daemon over a Unix socket at
 `/run/endura/sensor.sock`. The socket is world-connectable, so each request is
 authorized by the caller's peer credentials: `endura sensor logs`, `endura
 sensor hooks` and `endura sensor stop` are root-only, job operations are
 limited to the job's owner (or root), and `endura sensor status` is
 unauthenticated. The split for hook reporting is deliberate: the attached/total
 count is public, so any caller can see that enforcement is degraded, while the
 listing that names *which* hooks are blind — an evasion map — needs root.
 Requests are bounded as well as authorized — a frame larger than 16 MiB is
 refused, and a client that has not delivered its request within
 `ENDURA_SENSOR_TIMEOUT` seconds (default `10`) is disconnected. Setting that
 variable to `0` removes the time bound entirely, which lets any local user hold
 sensor threads open indefinitely; raise it rather than disable it.
 .
 Concurrency is bounded too. The sensor serves at most
 `ENDURA_SENSOR_MAX_CLIENTS` connections at once (default `256`), one thread
 each, and closes the rest immediately with `client limit reached` rather than
 spawning threads without limit. Two shares are carved out of that budget so no
 local user can starve another: any single non-root uid may hold at most a
 quarter of it, and an eighth is reserved for root, which keeps `endura job
 start` and the Kubernetes readiness probe working while a flood is in progress.
 Refusals are logged in aggregate rather than one line per connection, so a
 connection flood cannot become a log flood. The systemd unit pairs this with
 `TasksMax=512`; raise that alongside `ENDURA_SENSOR_MAX_CLIENTS` if you
 increase the limit substantially.
 .
 ## Configuration
 .
 ### Environment Variables
 .
 | Variable | Description | Default |
 | --- | --- | --- |
 | `ENDURA_BATCHER_AUTOFLUSH` | Submit violations as detected instead of
 batching them | `false` |
 | `ENDURA_EXIT_ZERO` | Force every `endura` command to exit with status code
 `0` even when an error is reported | `false` |
 | `ENDURA_HTTP_TIMEOUT` | HTTP client timeout, in seconds, when communicating
 with the Team Server | `5` |
 | `ENDURA_JOB_TIMEOUT` | Max duration a job may run before it is auto-purged
 (`s`/`m`/`h`/`d` suffix, e.g. `2h`); `0` or unset disables it | disabled |
 | `ENDURA_LICENSE_KEY` | License key required for sensor operation | — |
 | `ENDURA_LOG_FILE` | Log file destination (created mode `0600`, readable only
 by root) | `/var/log/endura/sensor.log` |
 | `ENDURA_LOG_FORMAT` | Format of the log file written to `ENDURA_LOG_FILE`:
 `text` (human-readable) or `json` (one JSON record per line, for log shippers
 that parse the file). Standard output and the records submitted to Team Server
 always use the text format | `text` |
 | `ENDURA_LOG_LEVEL` | Log verbosity: `trace`, `debug`, `info`, `warn`, or
 `error` | `info` |
 | `ENDURA_PROC_PATH` | Full path to the procfs the sensor reads, letting a
 sensor that runs in a container read the host's procfs. **Required for
 Docker/Podman deployments** — set to `/host/proc` with the host `/proc`
 bind-mounted there. The Helm chart sets it for you | — |
 | `ENDURA_SENSOR_KILL_TASK` | Kill tasks/processes that trigger violations |
 `true` |
 | `ENDURA_SENSOR_MAX_CLIENTS` | Concurrent control socket clients the sensor
 will serve. A quarter of this is the most any one non-root user may hold and an
 eighth is reserved for root, so no local user can lock the operator out; `0`
 disables the limit (not recommended — see [Control Socket](#control-socket))
 | `256` |
 | `ENDURA_SENSOR_POLICY_NOCACHE` | Disable the per-job event cache, forcing
 full policy re-evaluation and repeated derive/DNS records (diagnostics/testing
 only; increases overhead and event volume) | `false` |
 | `ENDURA_SENSOR_TIMEOUT` | Seconds a client has to deliver a complete request
 on the control socket before it is disconnected; `0` disables the limit (not
 recommended — see [Control Socket](#control-socket)) | `10` |
 | `ENDURA_SENSOR_TOKEN` | Team Server authentication token | — |
 | `ENDURA_TEAM_SERVER` | Team Server URL for centralized reporting | — |
 | `ENDURA_TLS_PIN` | Path to a PEM file whose certificate(s) become the only
 trusted roots for the Team Server connection (CA pinning); fails closed if
 missing or unloadable | — |
 | `ENDURA_TLS_VERIFY` | Verify Team Server TLS certificates (disabling is
 dangerous, testing only) | `true` |
 | `ENDURA_VERSION_CHECK` | Gate Team Server submission on a matching major
 version, checked at startup and every 15 seconds. Setting `false` submits to a
 Team Server of any major version (not recommended; temporary measure while
 coordinating a major upgrade — the sensor logs a warning at startup while it
 is set) | `true` |
 .
 ### Exit Codes
 .
 By default `endura` exits non-zero when a command reports an error. Two
 mechanisms override this so a failure does not abort the surrounding script or
 CI/CD pipeline:
 .
 - `ENDURA_EXIT_ZERO=true` — makes **every** `endura` command exit `0` even on
 error.
 - `--exit-zero` flag on `endura sensor stop` and `endura job stop` — the
 per-command equivalent; the error is printed to stderr but the process still
 exits `0`.
 .
 ## Building
 .
 Install [mise 2026.9.1 or newer](https://mise.jdx.dev/getting-started.html),
 then run:
 .
 ```bash
 # install minimal host prerequisites
 mise trust
 mise bootstrap --yes --update
 .
 # validate and build sensor
 mise run check
 mise run build
 .
 # create all deployment formats
 mise run package
 ```
 .
 Fedora, Ubuntu, and Arch hosts need Podman, Git, OpenSSH, curl, tar, and sudo.
 Mise's
 `bootstrap.packages` installs the appropriate distribution packages. Rust,
 Clang,
 bpftool, native libraries, and packaging tools come from the pinned Alpine
 build
 image; no native musl compiler or sysroot is needed on the host. Builds require
 readable kernel BTF at `/sys/kernel/btf/vmlinux` and currently target AMD64.
 .
 `build` produces `target/release/endura` and rejects a dynamically linked
 executable.
 `package` creates RPM, DEB, TGZ, runtime-image, and Helm artifacts beneath
 `target`.
 Each package task depends on `build`. Package versions come from the compiled
 binary and must match `Cargo.toml`.
 .
 Use `mise run fmt` to format changed code, `mise run audit` to check dependency
 advisories, and `mise run dev` for an interactive privileged development
 container.
 Inside that shell, Cargo is available directly. `mise run clean` is explicit;
 ordinary builds retain Cargo's incremental artifacts. Podman keeps Cargo
 downloads
 in the `endura-sensor-cargo` volume, separate from the image's tool binaries.
 Rootless and privileged Podman use their own cache stores. The host BTF
 directory
 is mounted read-only so unchanged kernels do not invalidate every container
 build.
 .
 Host linters use latest-stable selectors resolved in `mise.lock`. Run `mise
 upgrade`
 to update those tools and review the lockfile. Update installed host
 prerequisites
 with `mise bootstrap packages upgrade`. Updating the builder requires reviewing
 its
 digest in `mise.toml`, cleaning build artifacts, and rerunning the
 compatibility
 tests.
 .
 ## Testing
 .
 ```bash
 # run isolated tooling regressions
 mise run test:tooling
 .
 # run privileged rust tests
 export ENDURA_LICENSE_KEY='your license'
 mise run test
 .
 # run prepared local suites
 mise run test:policy path_rename
 mise run test:k8s
 mise run test:ebpf
 ```
 .
 Rust tests run in a privileged Podman container. Local policy, Kubernetes, and
 eBPF
 tests require existing packages and elevate their runtime execution with sudo.
 Runtime tasks serialize access to the host Sensor. Policy suites are discovered
 by
 `main.bats`; preparation scripts compile fixtures where needed. Kubernetes
 suites
 run in numeric directory order, with `99_helm_uninstall` last.
 .
 For disposable VM tests, install the hypervisor prerequisites described in
 [`machine`'s README](vendor/machine/README.md), then use its public mise
 interface:
 .
 ```bash
 # check native hypervisor prerequisites
 mise -C vendor/machine run host:check
 mise -C vendor/machine run vm:list
 .
 # test the existing packages
 mise run test:vm ubuntu-24-amd64 policy --suite path_rename
 mise run test:vm k3s-rolling-amd64 k8s
 .
 # retain a debugging machine
 mise run test:vm ubuntu-24-amd64 ebpf --keep
 mise -C vendor/machine run vm:ssh ubuntu-24-amd64
 mise -C vendor/machine run vm:destroy ubuntu-24-amd64
 ```
 .
 `test:vm` refuses existing VMs or image artifacts, collects failure diagnostics
 in
 `target/diagnostics`, and cleans up the VM it created. `--keep` leaves it
 available
 for debugging. For an intentionally reused VM, use `vm:create` from the
 submodule,
 `mise run vm:sync <triplet>` from Sensor, and `vm:run` from the submodule to
 execute
 `endura-sensor/scripts/guest-test <kind> [suite]`.
 .
 Fresh RHEL machines require `RHEL_ORG` and the appropriate
 `RHEL_ACTIVATION_KEY`.
 CI forwards the corresponding RHEL 9 or 10 secret. The guest receives only test
 inputs and existing release artifacts; its compiler and Bats remain managed by
 the
 guest distribution. The license travels in a protected file, outside
 shell-command
 arguments.
 .
 ## Publishing
 .
 `mise run publish:prepare` stages signed package repositories using
 `GPG_PRIVATE_KEY`
 and the public key in `endura.asc`. `GPG_KEY_ID` optionally selects the signer.
 Preparation does not push artifacts. `mise run publish`
 prepares and publishes the existing packages, runtime image, and Helm chart
 using
 `CICD_GITHUB_USER`, `CICD_GITHUB_TOKEN`, and SSH access to the release
 repository.
 Publishing does not rebuild the tested binary.
 .
 CI checks out source separately from the release artifact archive so executable
 permissions survive transfer without uploading the whole working tree. See the
 [build-system review](docs/build-system-review.md) for implementation details
 and
 validation coverage.
 .
 ## License
 .
 Copyright Endura Security. All rights reserved.

