Linux Agent Guide
Install Options
One-line installer (recommended)
From the dashboard, open Agent Setup and switch the OS toggle to Linux. Pick an agent token (the dropdown only offers active tokens with public download enabled and a target OS of Linux or Either) and your subdomain — the page renders the exact command to copy:
curl -fsSL https://etducky.com/install.sh \
| sudo bash -s -- --token=<TOKEN_ID> --subdomain=<SUBDOMAIN>
The installer enrolls the host, writes /etc/etducky/agent/AgentConfig.json (owner etducky, mode 0600), and enables + starts the service. It is idempotent: re-running on the same host re-uses the existing agent record (keyed on /etc/machine-id), rotates the agent's bearer token, and restarts the service cleanly. Add --enable-smart or --disable-smart to answer the SMART disk-monitoring prompt non-interactively (opting in installs smartmontools if missing).
Package downloads
The Agent Setup Linux tab also links the raw packages (or fetch them from Downloads):
- .deb — Debian / Ubuntu:
sudo apt install ./etducky-agent_<version>_amd64.deb - .rpm — RHEL / Fedora / Rocky:
sudo dnf install ./etducky-agent-<version>-1.x86_64.rpm - .run — distro-agnostic self-extracting installer for hosts without dpkg/rpm:
sudo bash ./etducky-agent-<version>.run
A SHA256SUMS file is published alongside the packages for verification. Package installs still need enrollment — use the one-liner on fresh hosts, or run the packaged install script with a token afterwards.
The systemd Service
The agent runs as the etducky-agent systemd unit under the unprivileged etducky user — not root. Capabilities are scoped to exactly what eBPF and diagnostics need (CAP_BPF, CAP_PERFMON, CAP_NET_ADMIN, CAP_SYS_PTRACE, CAP_DAC_READ_SEARCH), with filesystem hardening (ProtectSystem=strict, read-only /home, private /tmp) and resource caps (512 MB memory, 50% of one CPU).
sudo systemctl status etducky-agent
sudo journalctl -u etducky-agent -n 50 --no-pager
Paths
/opt/etducky/agent— binary and eBPF objects (read-only)/etc/etducky/agent/AgentConfig.json— configuration (mode 0600; the agent refuses to start if permissions are weaker)/var/lib/etducky— local state/var/log/etducky— log files (stdout/stderr also go to the journal)
Online/offline status is tracked from heartbeat freshness in the cloud, not by systemd. Restart=on-failure handles real crashes.
The Sudoers Policy (/etc/sudoers.d/etducky-rmm)
Packages ship a deliberately narrow sudoers drop-in. It grants the etducky user passwordless sudo for only five categories:
- Read-only diagnostics —
smartctl,dmidecode,lshw,lspci,lsusb,journalctl,dmesg. Root-required to read, but cannot mutate anything; used by heartbeat collectors and AI introspection. - Self-management —
systemctl restart etducky-agentonly (the agent's own restart after an in-place upgrade). Argument-restricted to theetducky-agentunit and the restart verb. - Package operations via the
etducky-pmhelper unit — all privileged package work (third-party app install/remove/upgrade and the agent's own self-update) routes through a constrained systemd template unit rather than a directsudo apt/dnf. The grant is starting that unit and nothing else:systemctl start --wait etducky-pm@<encoded-op>.service. The agent picks the opaque instance id, but the actual operation is read from a request file and validated by the helper script against a fixed allowlist — only anapt/dnf/zypper/snap/flatpakpaired withinstall/remove/upgradeof a syntactically-valid package name, run as fixed argv, is ever executed. So this constrained package install/remove/upgrade is passwordless by design, but the agent can never turn the grant into an arbitrary root command. Delete this rule to hard-disable all Linux package operations (patch, app-deploy, and self-update) and update out of band. See Package operations & the etducky-pm helper below. - Repository subscription via the
etducky-subscribeunit — starting one fixed, argument-less unit that registers the host with the ET Ducky package repository (see Agent auto-update below). Unlike theetducky-pmtemplate there is no instance id, no request file and no argument of any kind, so there is nothing about it the agent can influence; the repository URL is compiled into the script rather than passed in, for exactly that reason. It is a unit rather than a plainsudocall because the agent runs underProtectSystem=strictand asudochild inherits that read-only view of/usrand/etc. Delete this rule to subscribe hosts by hand instead; the agent then logs one line saying it is unsubscribed and carries on. - Network isolation — applying/removing the dedicated
etducky_isolationnftables table (iptables fallback on hosts without nft) so a high-confidence ransomware detection can quarantine the host without waiting for an operator. - On-device approval prompt — launching
zenity/kdialog/xmessageas the logged-in console user, never as root, for the unisolate approval flow below.
Everything else requires operator-driven elevation. Direct sudo apt/dnf/zypper, firewall changes, user management, mounting, arbitrary systemctl — none of it is passwordless. Privileged package management is the one write category that is passwordless, and only through the allowlisted helper unit described above — never via a direct package-manager invocation.
Package operations & the etducky-pm helper
Every privileged package operation on Linux — deploying a third-party app, patching it, removing it, and the agent's own self-update — runs through the same constrained path, not a direct sudo apt/dnf.
Why the indirection. The etducky-agent service runs ProtectSystem=strict, so a package manager the agent spawns (even under sudo) inherits that read-only mount namespace and fails to write /usr or the package database. Instead, the agent writes a small request file (manager/op/package) to /var/lib/etducky/pm/<id>.req and asks systemd to start a separate, unsandboxed oneshot unit:
sudo -n systemctl start --wait etducky-pm@<id>.service
That unit (PID 1–launched, so it gets a fresh mount namespace where the package manager can work) runs the helper script /opt/etducky/agent/scripts/etducky-pm-op.sh. The helper validates the request against a fixed allowlist before it runs anything:
- Manager must be one of
apt,dnf,zypper,snap,flatpak. - Operation must be one of
install,remove,upgrade. - Package name must match a strict pattern (no spaces, no shell metacharacters, no leading dash), and is passed as a single argv element — never through a shell.
Each (manager, operation) pair maps to a fixed command (for example apt:upgrade → apt-get install --only-upgrade -y <pkg>). The unit blocks with --wait and the helper writes the package manager's exit code and combined output back for the agent to read. Because the operation is read from the request file and allowlist-validated — not taken from the sudoers command line — the agent's single privileged capability (starting one unit) can never become an arbitrary root command.
The helper is dormant until both the agent's PatchExecuteEnabled config and the server's Patch Management execute flag are on; otherwise the agent simply never starts the unit.
Operator-Driven Elevation
When a live-session command needs root (any sudo-prefixed command outside the allowlist above), the agent does not run it directly. Instead:
- The agent posts an elevation request to the cloud; the dashboard pops a password modal showing the command summary.
- The operator (must be an org admin) types a sudo password for the host. It travels exactly two encrypted hops — browser to backend, backend to agent — and is never persisted or logged.
- The agent feeds the password to
sudo -Svia stdin (never argv), runs the command, zeroes the password buffer, and reports the result. - Every request is audited: who approved, what ran, from where, and the outcome (pending → granted → executed, or denied/expired/failed). Grants expire after 5 minutes.
The trust model: compromising the agent alone no longer equals root — an attacker would also need a real operator to authenticate a future elevation.
Unisolate approval
Lifting network isolation is a dual-party action: in addition to the dashboard operator, a GUI confirmation prompt is shown to the logged-in console user on the host (via zenity/kdialog/xmessage). On headless hosts with no graphical session, the on-device prompt cannot be shown and the lift is rejected through that path.
eBPF Capture vs. Windows ETW
Kernel telemetry on Linux comes from eBPF tracepoint programs (libbpf + CO-RE), loaded when KernelEventsEnabled is true in AgentConfig.json (the default). Three provider buckets can be toggled via KernelProviders:
- Process — exec and exit tracepoints
- File — open and close syscalls
- Network — connect and accept (IPv4 + IPv6)
Events are normalized to the same shape as Windows ETW events, so live-session AI analysis, inflection-bracketed correlation, and behavioral detections work identically on both platforms.
Kernel requirements
- Kernel 5.8+ for
CAP_BPF(older kernels fall back to broader capabilities). - Built-in BTF (
/sys/kernel/btf/vmlinux) — standard on Ubuntu 22.04+ and Fedora 36+. For RHEL 8 / Ubuntu 18.04 / Amazon Linux 2, drop a matching<uname -r>.btffile into/opt/etducky/agent/bpf/btfhub/. - If the eBPF library is absent or capture is disabled, the agent runs in a no-op capture mode: heartbeats, health metrics, live sessions, and remote desktop all keep working — only kernel events are off.
Kill switch: set "KernelEventsEnabled": false in /etc/etducky/agent/AgentConfig.json to disable kernel capture without uninstalling.
Deploying third-party apps
You can deploy third-party applications to Linux agents through the host's OS package manager. On a Software Catalog entry, set the Linux package id field (the package name the target distro's manager knows, e.g. htop) — that gives the entry the linux_pm deploy method. When you deploy, each Linux agent installs the package through the same allowlisted etducky-pm helper unit described above (apt/dnf/zypper/snap/flatpak install), so no direct root shell is involved.
See Patch Management for the full deploy workflow (choosing a method, scheduling, and reading back per-agent job results).
Agent auto-update
The Linux agent can keep itself current by upgrading its own package through the OS package manager — routed through the same etducky-pm helper unit, so it works under the sandboxed service.
It periodically fetches the published version manifest (version.json) and compares the advertised Linux version against the running one. Self-update is gated on the agentLinux.autoUpdate flag in that manifest: when it's off, the agent never self-upgrades and you update out of band. When it's on and a newer version is published, the agent requests an upgrade of the etducky-agent package via the helper; the package's post-install step restarts the service.
Auto-update needs the host to be subscribed to the ET Ducky package repository and the etducky-pm sudoers grant present. Without the repo the upgrade finds no candidate; without the grant the attempt fails fast with a clear log line.
Repository subscription
Upgrading through a package manager means upgrading from a repository. A downloadable .deb is not enough: apt resolves candidates only from configured repositories, so a host with no ET Ducky sources entry reports "already the newest version" no matter what is published.
Hosts are subscribed in one of two ways:
- At install. The one-line installer fetches the signing keyring to
/usr/share/keyrings/etducky-archive-keyring.gpgand writes/etc/apt/sources.list.d/etducky.list(or/etc/yum.repos.d/etducky.repo), pinned to that keyring. Pass--no-repoto skip it on air-gapped hosts. - Afterwards, by the agent itself. Hosts enrolled before the repository existed have no sources entry — and could not get one by updating, because updating is the thing that needs it. On its first update check after upgrading to a build that supports this, an unsubscribed agent registers itself once. If the repository is unreachable it changes nothing and retries on the next cycle.
The subscribe step never leaves a sources entry it has not verified. It installs the keyring, writes the entry, refreshes only that source, and confirms a candidate resolves — if any of that fails it removes what it wrote and reports the host unchanged. A broken sources file would break apt-get update for every package on the host, not just ours, so failing unsubscribed is always the safer outcome.
Network access
If you allowlist outbound traffic, auto-update needs these in addition to the API endpoint:
https://etducky.com/etducky-archive-keyring.gpg— the signing keyring, fetched once at subscriptionhttps://etducky.com/apt/— the signed APT index and package pool (Debian/Ubuntu)https://etducky.com/yum/— the signed YUM repository (RHEL/Fedora/SUSE)https://etducky.com/downloads/version.json— the version manifest the agent compares against
Blocking these does not raise an error anywhere in the console. The agent keeps reporting healthy on the version it has, and the only symptom is a fleet that quietly never updates. If you allowlist by URL rather than by host, check these first when agents are not moving to a version you have published.
Self-hosted (local‑first) deployments do not use this path. Their agents point at your own server, which does not serve a signed package repository, so repository subscription is skipped and Linux agents are updated out of band.
File transfers & POSIX paths
File transfers to Linux agents accept POSIX absolute paths — a single leading forward slash, e.g. /etc/etducky/… or /opt/… — so pushes and pulls aren't rejected as “not rooted” the way a Windows drive path would be validated. The same anti-traversal guards apply on both platforms: ./.. segments, empty interior segments, and control characters are rejected, and the agent re-checks the resolved path at open time.
Known Platform Differences
The Linux agent is at operational parity with Windows for enrollment, heartbeats, health and hardware metrics, live sessions, remote desktop, inventory, alerts, and behavioral rules. Remaining differences:
| Area | Windows | Linux |
|---|---|---|
| Kernel telemetry breadth | 30+ configurable ETW providers (registry, DNS, .NET, firewall, …) | 3 eBPF buckets: Process, File, Network |
| Remote desktop capture | DXGI Desktop Duplication | x11vnc (Xorg) or desktop portal / PipeWire (Wayland), with an H.264 GStreamer helper |
| Privileged commands | Agent runs as LocalSystem; commands execute directly | Operator-driven sudo elevation with per-command audit |
| SMART disk health | On by default (WMI) | Opt-in at install (--enable-smart); requires smartmontools |
| Distro / kernel / init reporting | Full OS version reporting | Partial — basic OS info reported; richer distro detail still in progress |
| H.264 remote desktop prerequisites | Media Foundation (built in) | Needs gstreamer1.0-vaapi (hardware) or gstreamer1.0-plugins-ugly (x264 software); falls back to JPEG without them |
Troubleshooting
- Service won't start; journal says "config has weak permissions" —
AgentConfig.jsonmust be 0600. Re-run the one-liner; it sets permissions atomically. - Crash loop on start — check
journalctl -u etducky-agent -n 200. Common causes: kernel older than 5.8 with eBPF enabled, or missinglibssl3. - 403 from the one-liner — the token isn't public-download enabled, or its target OS is Windows-only. Fix it on the Agent Setup page.
- Agent online but no kernel events — the host is likely in no-op capture mode (no BTF, old kernel, or
KernelEventsEnabledfalse). See the eBPF section above.