Host agent
The agent runs on every managed host. It opens every connection itself (no listening port), registers with the
manager with a bootstrap token and the sha256 fingerprint of the manager CA, then sends heartbeats, facts and metrics
and runs the tasks of the manager one at a time. The protocol, the task types and the security rules are in
navin-manager/CONTRACT.md sections 8 and 9.
Which agent to install
| Agent | Package | When |
|---|---|---|
| Go agent (shipped) | navin-manager-agent-go (RPM x86_64 and aarch64, DEB amd64 and arm64, tar.gz) | Every host. One static binary: no Python, no OpenSSL, no shared library. Certified systems: RHEL 8/9/10, Rocky Linux 8/9/10, AlmaLinux 8/9/10, Oracle Linux 8/9, CentOS Stream 9/10, Ubuntu 22.04/24.04, Debian 12, Arch Linux (rolling). It also starts on an end of life system such as RHEL 7 to report its facts, where the preflight blocks every installation. |
| Python agent (reference) | navin-manager-agent (RPM noarch, DEB all, tar.gz) | Kept for compatibility and as the reference implementation. Needs Python 3.9 or newer (RHEL 8: dnf install python39). |
Both agents use the same command (/usr/bin/nm-agent), the same configuration file
(/etc/navin-manager-agent/agent.json), the same state directory (/var/lib/navin-manager-agent) and the same
systemd unit (navin-manager-agent.service). The Go packages declare Provides and Conflicts on
navin-manager-agent: installing one replaces the other, and a registered host keeps its identity because the state
directory is kept.
The Go agent reports agent_impl: "go" in its facts. Its python fact is the version of the system python3 (or
null): Python is only needed on hosts that run a python.venv component.
Supported systems
The single list lives in navin_manager/os_support.py and is published by GET /api/v1/system/supported-os (any
signed in user); the System page of the Manager shows it in the "Supported systems" card. Certified systems: RHEL
8/9/10, Rocky Linux 8/9/10, AlmaLinux 8/9/10, Oracle Linux 8/9, CentOS Stream 9/10, Ubuntu 22.04/24.04, Debian 12,
Arch Linux (rolling). Packages: dnf on the RHEL family, apt on the Debian family, pacman on the Arch Linux family.
| Verdict | Example | Preflight |
|---|---|---|
| certified | Rocky Linux 10 | pass |
| not certified (newer release or other distribution of a known family) | Ubuntu 26.04, Fedora | warning, never blocking |
| end of life | CentOS 7, RHEL 7, Ubuntu 20.04, Debian 11 | blocking |
| not supported (unknown family) | SUSE Linux Enterprise Server | blocking |
Corporate proxy
When the hosts reach the package mirrors through a proxy, set it in Settings, card "Corporate proxy" (setting
proxy of PUT /api/v1/settings: http_proxy, https_proxy, no_proxy). The URLs are http:// or https://
only, without user name, password or path; a wrong value is refused with the error proxy_invalid (422). The SSH
bootstrap applies it:
- package manager:
apt-get -o Acquire::http::Proxy=... -o Acquire::https::Proxy=...,dnf --setopt=proxy=...(the https proxy when set, else the http proxy); - agent unit:
Environment="HTTP_PROXY=...",Environment="HTTPS_PROXY=..."andEnvironment="NO_PROXY=...". NO_PROXY always holdslocalhost,127.0.0.1,::1and the address of the Manager, so the agent never reaches its Manager through the proxy.
Empty fields mean a direct access: the unit then has no proxy line.
Facts
nm-agent facts prints, and the facts heartbeat sends, the facts of CONTRACT.md section 9: os, kernel, arch,
cpu_count, cpu_model, memory_mb, swap_mb, disks, network, selinux, firewall, time_sync, timezone,
python, podman, systemd, listening_ports, sysctl, ulimits, gpus, platform, binaries, fs_prefix,
rootless, agent_user, service_driver.
platform tells where the machine runs: virtualization (none on bare metal, else the name of
systemd-detect-virt: kvm, vmware, microsoft, xen, amazon, wsl, docker...), container,
cloud.provider (aws, azure, gcp, ibm, ovh, openstack, oracle, alibaba, scaleway, outscale,
hetzner, digitalocean, exoscale, none on premises, unknown) with cloud.source (dmi, virt, none),
instance_type (EC2 Nitro, such as m5.large), and the vendor, product, bios_vendor and chassis_asset_tag of
the DMI. Both agents give the same answer from local files only (/sys/class/dmi/id, systemd-detect-virt with a 2 s
timeout when it exists, /proc): they never call an instance metadata service. OVHcloud Public Cloud shows as
openstack; the host labels provider, region and zone (for example provider=ovh region=gra) complete the
inventory, and the manager labels win.
Security properties
- No remote shell.
command.run, thecommandchecks ofhealth.check,preflight.runandsmoke.run, and the process driver only run an absoluteargv[0]listed inallowed_commandsor whose real path lies inside the allowed roots. The program is started from its argument list, never through a shell:/bin/sh -c ...is refused withcommand_not_allowed. - Path guard. The allowed roots are resolved once at start. Below a root, a path with a symbolic link component,
a
..component or outside every root fails withpath_not_allowed. Files are opened relative to a directory descriptor obtained withopenat2(RESOLVE_NO_SYMLINKS | RESOLVE_BENEATH), or with anopenat(O_NOFOLLOW)walk on kernels withoutopenat2(RHEL 7 and 8), and the final open usesO_NOFOLLOW. - Archives. Absolute names,
.., devices, FIFOs and links whose target leaves the destination are refused witharchive_unsafebefore anything is written; an archive declaring more than 200 000 members or 64 GiB is refused witharchive_too_large. - Downloads. A file is used only after its sha256 matches (
checksum_mismatchotherwise); nothing unverified reaches its destination or the cache. A download stops past 64 GiB (download_too_large) or before the disk is full (disk_space_low). - Identity. An EC P-256 key and a certificate request are made on the host; the key never leaves it. After the
registration every call uses the client certificate (mutual TLS) and an
NM-HMACsignature of the request. - Secrets. Values of
sensitive_env,secrets(smoke tests) and certificate keys are replaced by******in every log line and result.
Install from the packages
Copy the package of the host architecture (from packaging/dist/agent-go/ or the offline bundle) and check it against
SHA256SUMS, then install it and register the host with the command shown by the console:
sha256sum -c --ignore-missing SHA256SUMS
dnf install ./navin-manager-agent-go-1.0.0-1.x86_64.rpm
nm-agent register --server https://<manager-host>:8460 --token <token> --ca-sha256 <fingerprint>
systemctl enable --now navin-manager-agent
On aarch64 use navin-manager-agent-go-1.0.0-1.aarch64.rpm; on Ubuntu use
apt install ./navin-manager-agent-go_1.0.0_amd64.deb (or _arm64.deb). On a host without a package manager, unpack
the tar.gz at the root: tar -xzf navin-manager-agent-go-1.0.0-linux-x86_64.tar.gz -C /, then
systemctl daemon-reload.
Offline
The agent needs nothing from the Internet: the packages hold the whole program. To ship it in the offline bundle, build the packages then give their directory to the bundle builder:
navin-manager/packaging/build-packages.sh agent-go
python3 navin-manager/packaging/offline/build-bundle.py --agent-dir navin-manager/packaging/dist/agent-go ...
build-packages.sh agent-go needs Go 1.26 or newer (NM_GO selects the binary) and the module cache or a Go proxy
of the bank (GOPROXY); it builds x86_64 and aarch64 (NM_AGENT_GO_ARCHES), checks that each binary is statically
linked and writes SHA256SUMS. The third party components and their licenses are listed in
/usr/share/doc/navin-manager-agent/THIRD_PARTY_LICENSES.
Commands
nm-agent --version
nm-agent [--config FILE] [--lang en|fr] register --server URL --token TOKEN --ca-sha256 HEX [--ca-file FILE]
nm-agent [--config FILE] run
nm-agent [--config FILE] status
nm-agent [--config FILE] facts
Messages follow --lang, else LC_ALL or LANG. Exit codes: 0 success, 1 status of a host not registered, 2
error (invalid configuration, refused registration, wrong CA fingerprint: nothing is stored).
Configuration
/etc/navin-manager-agent/agent.json keeps the keys of the Python agent: server_url, agent_url, state_dir,
log_dir, fs_prefix, allowed_roots, allowed_commands, service_driver (systemd or process),
heartbeat_interval_s, poll_wait_s, health_interval_s, stop_timeout_s, log_level, ca_file. The log is
written to /var/log/navin-manager-agent/agent.log (20 MB, 5 backups).
Every key, type and default is in the agent configuration reference. Installation on every system, security, daily operations and troubleshooting are in the Navin agent section.