Skip to main content
ImmutableLog logo
BackLinux

Host agent

The agent runs on your server and records every access and every command into the immutable chain, without requiring any change to your code. It complements the SDKs: while they record what your application does, the agent records what people do on the machine it runs on.

Requirements

  • Linux with systemd (Debian/Ubuntu, RHEL/Rocky/Alma, or any systemd distro via tarball).
  • x86_64 and aarch64 architectures. The binary is static — it also runs on older distros.
  • An API key for your tenant with the events:write scope.
  • Outbound HTTPS to the ImmutableLog API. No inbound port is opened.

Windows and macOS are not supported yet.

Installation

The installer detects your distribution and architecture, downloads the right package, verifies the SHA-256, and only then installs, configures the key and starts the service. If the checksum does not match, nothing is installed.

install.sh
curl -sSL https://get.immutablelog.com/agent \
  | IMTBL_API_KEY=iml_live_… sudo --preserve-env=IMTBL_API_KEY sh

Prefer to inspect before running?

The installer is a single file, on purpose. Download it, read it, and run it afterwards — or use --dry-run, which downloads and verifies the package without installing anything.

bash
curl -sSL https://get.immutablelog.com/agent -o get.sh
less get.sh
IMTBL_API_KEY=iml_live_… sudo --preserve-env=IMTBL_API_KEY sh get.sh --dry-run

Automated installs (Ansible, CI, images)

Pass the key through a file, which does not depend on sudo's environment policy, and pin the version for reproducible installs.

bash
printf %s 'iml_live_…' > /root/.imtbl_key && chmod 600 /root/.imtbl_key
sudo IMTBL_API_KEY_FILE=/root/.imtbl_key \
     IMTBL_AGENT_VERSION=0.1.8 \
     sh get.sh

Note that the variables come after sudo. Before it, the default sudoers configuration discards them and the install stops for lack of a key. This is safe here: what must never appear on the command line is the key itself, not the path to the file holding it.

The API key rule

Your key must never appear on the command line. sudo writes the arguments it receives to the auth log and the system journal — and the journal is exactly what this agent reads and seals into the chain. A key passed as an argument would be captured by the agent itself and recorded immutably, with no way to erase it.

CorrectIMTBL_API_KEY=… sudo --preserve-env=IMTBL_API_KEY shThe key travels in the environment, not in the arguments.
Neversudo IMTBL_API_KEY=… shHere the key becomes a sudo argument — and lands in the journal.

The installer detects that invocation, refuses to install and tells you to rotate the key. Note also that it is --preserve-env=IMTBL_API_KEY, not -E: with the default sudo configuration on most distributions, -E is ignored and the variable arrives empty.

Once installed, the key lives in /etc/imtbl_agent/imtbl_agent.env, owned by root with mode 0600 — not even the user running the service can read it.

What is captured

Each event below is sent to the API, sealed into the chain, and flows to the SIEM already normalized.

alert.user.login

Successful server login, with user, source IP and method.

alert.user.logout

Session end — closes the window of how long the access lasted.

alert.auth.failed_login

Rejected attempt. This is the event that feeds brute-force detection in the SIEM.

alert.process.exec

Executed command, with user, PID and an already-redacted command line. Opt-in.

alert.agent.gap

A window in which the agent was not observing — including crashes or kills.

alert.agent.heartbeat

Periodic liveness signal with the agent's counters, sealed into the chain.

For attempts with an invalid password or key to appear in detail, sshd needs LogLevel VERBOSE.

Command capture (opt-in)

Command capture is off by default, deliberately: the command line goes sealed and immutable into the chain. Secret redaction runs before sending, but it recognizes patterns — a secret in an unknown format may slip through, and there is no erasing it afterwards. Enable it consciously.

bash
# 1. regra de auditoria do kernel
sudo cp /usr/share/imtbl_agent/imtbl-agent-execve.rules \
        /etc/audit/rules.d/99-imtbl-agent.rules
sudo augenrules --load

# 2. ligar no agente
sudo sed -i 's/^IMTBL_CAPTURE_COMMANDS=.*/IMTBL_CAPTURE_COMMANDS=1/' \
        /etc/imtbl_agent/imtbl_agent.env
sudo systemctl restart imtbl-agent

A configurable per-minute command cap protects your quota during activity spikes. It applies to commands only: access events are never limited, because a brute force is precisely when you cannot sample. Anything dropped by the cap is counted and reported.

Configuration

Everything lives in /etc/imtbl_agent/imtbl_agent.env. After editing, restart the service.

VariableDefaultWhat it does
IMTBL_API_KEYYour tenant key. Required.
IMTBL_CAPTURE_COMMANDS0Enables command capture.
IMTBL_MAX_EVENTS_PER_MIN600Command cap per minute. 0 removes the cap.
IMTBL_REDACT_MODEfullRedaction policy. Cannot be turned off.
IMTBL_HEARTBEAT_SECS3600Sealed liveness signal interval. 0 disables.
IMTBL_QUEUE_CAPACITY50000Cap of events in the durable queue.
IMTBL_HOST_LABELhostnameHow the host appears in events.

Operations

bash
systemctl status imtbl-agent
journalctl -u imtbl-agent -f

# reprocessa eventos que ficaram retidos após erro do servidor
sudo systemctl kill -s USR1 --kill-whom=main imtbl-agent

The --kill-whom=main is mandatory: without it the signal hits every process in the service, including the helper that reads the journal.

If the key is rotated, update the config file and restart. While the key is rejected, the agent keeps capturing and queueing — nothing is lost, and the reason stays in the journal.

Guarantees

The agent cannot erase its own trail

Every event is sealed into the chain the moment it happens. Not even root on the host can rewrite what has already been recorded — the only option is to stop generating new events, and that gets recorded too.

Stopping the agent leaves a mark

The agent writes a liveness tick to disk every minute. If it is stopped, killed, or the server goes down, the unobserved window becomes a gap event on the next start — with start, end, and whether the shutdown was clean.

Secrets are redacted before sending

Redaction runs on the host, before any send and even before the local log. Because the record is immutable, there is no fixing it afterwards — so it is mandatory and cannot be turned off, only configured to redact more.

Network loss does not lose events

Events go into a durable on-disk queue and are delivered when the network returns. The queue survives process and server restarts, and each event carries an idempotency key — resending does not duplicate.

Does not run as root and opens no port

The service runs under its own shell-less user with a single audit-read capability. It exposes no network port: counters go to the log and into the sealed heartbeat itself.

An invalid key does not start the service

The key is validated against the API at boot. If rejected, the agent does not start and the reason appears in the journal — a service running without being able to record anything is worse than one that fails in the operator's face.

Uninstall

bash
sudo systemctl disable --now imtbl-agent
sudo apt purge imtbl-agent        # ou: sudo dnf remove imtbl-agent

The data directory is preserved on purpose, even on purge: the queue may contain captured events not yet sealed into the chain, and silently deleting it would destroy evidence. Remove it by hand when you are sure.

API documentation