Building a Small Rust eBPF EDR 7: Running, Packaging, Health, and Roadmap
Table of Contents
The final post summarizes how to build, run, package, and verify rand-guard. An eBPF EDR is not finished when the code compiles. Build artifacts must exist, the eBPF object must be loaded with sufficient privileges, and the output must be verifiable.
rand-guard groups these repeated workflows through xtask.
xtask Workflow
From the repository root, these commands are available.
cargo run -p xtask -- ci-format
cargo run -p xtask -- check
cargo run -p xtask -- clippy
cargo run -p xtask -- test
cargo run -p xtask -- build
Cargo aliases are also available.
cargo xf
cargo xc
cargo xl
cargo xt
cargo xb
Building the eBPF program requires nightly Rust, rust-src, and bpf-linker. Userspace crates build with stable Rust. This split reflects the special requirements of the eBPF target.
The agent can be run like this.
cargo run -p xtask -- run
This command loads an eBPF object, so root or suitable capabilities are required. On a typical Linux environment, sudo may be needed.
Package Workflow
Release artifacts can be created with the package command.
cargo run -p xtask -- package
The package includes:
- userspace binary
- eBPF object
- default config
- sample rules
- systemd unit
- installer script
According to the quickstart flow, the install paths are:
/usr/local/bin/rand-guard
/usr/local/lib/rand-guard/edr-ebpf
/etc/rand-guard/config.toml
/etc/rand-guard/rules.d/sample-rules.toml
/etc/systemd/system/rand-guard.service
The systemd unit sets the EDR_CONFIG and EDR_EBPF_OBJECT environment variables. That keeps the runtime binary location and eBPF object location explicit.
Quick Verification
After the agent is running, a process event can be generated simply.
/bin/true
A file event can be checked by creating and removing a demo service file.
sudo sh -c 'printf "# rand-guard quickstart\n" > /etc/rand-guard-quickstart.service'
sudo rm -f /etc/rand-guard-quickstart.service
Network telemetry is disabled by default, so it must be enabled in config first.
[events]
network = true
[network]
enabled = true
hooks = ["connect", "bind", "listen"]
collect_dns = false
collect_payload = false
Then a loopback listener demo can be run.
nc -l 127.0.0.1 4444
printf 'demo\n' | nc 127.0.0.1 4444Health Records
The runtime periodically writes health records. A health record is not a detection. It is telemetry about runtime state.
Representative fields include:
- raw events read
- normalized events output
- alerts output
- userspace filtered count
- userspace rate limited count
- invalid schema count
- unsupported kind count
- output failure count
- process table size
- pending exec source size
- eviction count
- uptime
- RSS
This information is important when investigating performance problems or event loss. For example, if many raw events arrive but few normalized events are written, filtering or rate limiting may be involved. If process table eviction is high, the cache limit or workload should be reviewed.
Throughput Workflow
rand-guard also includes a local throughput workflow.
cargo run -p xtask -- throughput
This benchmark creates a controlled file-write workload, parses health records, and writes a summary under .local/throughput/.
The important point is that benchmark numbers should not be treated as general performance guarantees. Results vary with kernel version, CPU, filesystem, background load, enabled hooks, and build mode. This workflow is local comparison data for comparing code changes on the same host.
Threat Model
rand-guard is not an agent that can stop a root attacker. A root attacker can stop the service, change config, replace binaries, or tamper with output.
The current threat model is closer to this:
- Local user-space commands generate telemetry.
- eBPF programs stay small and verifier-friendly.
- Output records are treated as sensitive host telemetry.
- Detections model selected behaviors as investigation signals.
Documenting these limits is important. For a security project, clearly stating what it does not do is as important as stating what it does.
Roadmap
The current MVP implements:
- process lifecycle collection
- file collection and filtering
- optional network syscall telemetry
- shared event ABI
- ring buffer delivery
- userspace normalization and enrichment
- built-in persistence and suspicious port detection
- MVP
[[rules]] - stable alert records
- packaging and smoke workflows
Near-term work is closer to expanding rule evaluation tests, stabilizing alert output, improving demo scenarios, documenting benchmarks, improving config validation, and documenting false positives.
Longer-term research includes scenario-based detections such as reverse shell, web shell execution, credential access, systemd persistence, and drop-and-execute. These should not be described as implemented coverage. They are research directions, not completed features.
Series Summary
This series covered the process of building a small Rust eBPF EDR end to end.
- Part 1 established the overall architecture.
- Part 2 covered the ABI between eBPF and userspace.
- Part 3 covered process lifecycle telemetry and process table enrichment.
- Part 4 covered file telemetry and persistence-sensitive detections.
- Part 5 covered opt-in network telemetry.
- Part 6 covered the MVP rule engine and alert records.
- Part 7 summarized running, packaging, health, benchmarks, and the roadmap.
The core of rand-guard is not adding as many features as possible. It is building a small and explainable EDR pipeline in real code. The eBPF programs collect safely in the kernel, and userspace turns those events into understandable telemetry and alerts. Keeping that boundary clear is the most important design principle of the project.