Polaris Agent - rogers-group-inc/polaris GitHub Wiki

Polaris Agent

A small Go binary installed on Windows, Linux and macOS hosts. It pushes monitoring samples back to Polaris over HTTPS and holds a long-lived outbound WebSocket for on-demand probes.

Managed from the Integrations β†’ Polaris Agents tab, and per-device from the asset slide-over.


The posture

The agent is a satellite. It never self-acts, and it refuses unknown actions. It accepts two queued actions: run_script β€” see Automation scripts β€” and reboot, only on a host that opted in (Reboots).

Platform Runs as
Linux a hardened systemd unit β€” DynamicUser, NoNewPrivileges, ProtectSystem=strict β€” at one of two tiers
Windows LocalSystem, under the Service Control Manager
macOS a LaunchDaemon, as root

The two Linux privilege tiers

Tier Grants Enough for
unprivileged (default) nothing extra all monitoring
ptrace CAP_SYS_PTRACE and CAP_DAC_READ_SEARCH Application Map connection attribution

The pair is load-bearing β€” do not grant one without the other. A foreign /proc/<pid>/fd is an owner-only directory whose open is a plain DAC check that only CAP_DAC_READ_SEARCH passes; CAP_SYS_PTRACE is consulted only at the readlink step. A SYS_PTRACE-only unit fails at the open, every socket comes back unattributed, and the agent collects zero connection rows while looking perfectly healthy.

A unit that holds only CAP_SYS_PTRACE stays broken until reinstalled β€” the unit text is written only at install or reinstall.

The security cost is stated in every warning, and it is real: CAP_DAC_READ_SEARCH bypasses read permission checks on all files, and CAP_SYS_PTRACE reads any process's memory. Grant it deliberately.

Pick the tier on the per-asset install modal or the bulk Deploy Agent modal (confirmation-gated). An existing Linux agent changes tier via Reinstall.

Requested vs verified

privilegeTier is only what was requested at install. The Linux agent reports its actual capability mask on every heartbeat, and the installed-agents list renders the Privilege column three ways:

Rendering Means
pair-verified βœ“ the running unit really holds both capabilities
"reinstall" in red a stale unit β€” the tier was requested but the unit does not deliver it
unverified, amber no report yet

So a reinstall visibly updates the column within one heartbeat.

Reboots

Polaris can reboot a host through its agent from the asset's Reboot button, now or on a schedule β€” but only a host that opted in (rule 115). Off by default. Turn it on with Allow Polaris to reboot this host in the install modal (or these hosts in the bulk Deploy Agent modal), or later with Enable… on the Reboots row of the agent card; Disable turns it off. Both need assets:fullwrite, and both sign in with the agent's stored install credential to change the host itself:

Platform What the opt-in installs
Linux a polkit rule letting the polaris-agent user (or the polaris-agent service) ask systemd-logind to reboot β€” the logind reboot actions and nothing else β€” written for both polkit rule formats, plus a root-owned marker file /etc/polaris-agent-reboot.enabled. The agent unit and its privilege tier are not changed, so nothing is reinstalled. The host needs systemd and polkit; without them the opt-in fails and says which is missing
Windows a marker file reboot.enabled in the agent's %ProgramData%\Polaris\agent folder, writable only by Administrators and SYSTEM. The service already runs as LocalSystem, so the marker is the opt-in rather than a new privilege
macOS a marker file /etc/polaris-agent/reboot.enabled

The agent refuses a reboot unless the marker is there, and reports on every heartbeat whether the host will let it reboot (on Linux: the marker is present and logind answers yes to the agent). The Reboot button is offered only when both Polaris and the host say yes, and the Reboots row reads Enabled βœ“, Enabled β€” waiting for the agent to confirm, or Enabled β€” the host refuses (turn it off and on again to reinstall the permission). Disabling stops Polaris from sending reboots straight away, even when the host cannot be reached to remove the permission β€” the Event says so. Uninstalling the agent removes the marker and the polkit rule.

Rebooting needs agent 0.26.0 or newer. The agent acknowledges the reboot first and restarts the host five seconds later; Windows closes open applications without asking. An agent that does not pick the reboot up within about two and a half minutes never runs it β€” Polaris withdraws it β€” so an offline host never reboots hours after it was asked.

The host stays in maintenance through the reboot until monitoring has recorded it from the agent's first report of the new uptime β€” the agent reconnecting does not end the window, because it reconnects before that report. An automation's reboot action can book a reboot of an opted-in host too.


Installing

Three routes, all needing assets:fullwrite (rule 43) β€” deploying runs an installer on someone else's host over a stored credential and leaves a service behind.

Route
Per asset the asset slide-over's System tab carries a Polaris Agent card with an Install Agent button on every server and workstation that could take one β€” no need to pick "Polaris Agent" as a polling method first. Any other device type shows the card once an agent exists or a stream is set to the agent method. The edit modal's Monitoring tab has the same button. Neither appears on a FortiManager- or FortiGate-discovered asset or on an ESXi host: FortiOS and ESXi take no agent. On a Windows host the modal adds a Transport choice β€” SSH (preselected; needs OpenSSH Server running on the host) or WinRM β€” and shows the credential picker for whichever is chosen. Linux and macOS are SSH-only, and the row is hidden. Allow Polaris to reboot this host installs the reboot opt-in with the agent
Bulk the Assets bulk bar's Deploy Agent β€” one modal collects SSH + WinRM credentials and arch; OS and transport are resolved server-side, an asset whose last install failed is retried with the credentials you pick, and other ineligible assets come back as skips with reasons
Auto-deploy a per-class toggle on the AD / Entra / Arc workstation and server blocks and the vCenter Virtual Machines block, off by default β€” pushes to newly discovered agent-less devices during discovery, bounded and paced

Enabling an integration's auto-deploy checkbox is the same grant, chained onto integrations:write β€” a capability with two doors has to be gated at both. Only the on transition is gated; a role that inherits an enabled block can still switch it off.

What the installer does

Writes the binary, writes agent.conf, installs the service, starts it. The agent then enrols on first boot, receives a bearer token, and persists it back into agent.conf.

Over SSH, everything is first uploaded into a folder created for that one run, which no other account on the host can open: a fresh mktemp folder on Linux and macOS, a new folder in the SSH account's own temp folder on Windows. The installer checks the binary's SHA-256 before installing it, and the folder is deleted afterwards, whether the install worked or not. Upgrades, uninstalls and reboot-permission changes work the same way (rule 119). The SSH account's temp folder must not be C:\Windows\Temp; Polaris refuses to stage there.

agent.conf is readable only by the agent's service account and administrators. On Linux and macOS it is mode 0600. On Windows the installer makes Administrators the owner of %ProgramData%\Polaris\agent, and limits that folder to SYSTEM and Administrators, before it writes anything there. The agent (0.26.1+) protects each rewrite of the file the same way before the token goes into it (rule 117).

One Linux trap worth knowing, because its failure mode is silent from Polaris's side: the installer must chown agent.conf to the state directory's owner, never to root. systemd chowns the StateDirectory to the dynamic UID at start but leaves files already inside it alone β€” so a root-owned conf is readable on a first install and unreadable on every reinstall. The installer exits 0, the row reaches "enrolling", and the host crash-loops on a permission error forever with nothing marked failed, until the enrollment token expires.


SSH Deployment

Integrations β†’ Polaris Agents β†’ SSH Deployment. Polaris generates the ed25519 keypair used to install the agent over OpenSSH, owns the credential holding it, and emits the scripts that authorise the public half fleet-wide.

The private half is sealed at rest and never returned by any read path. Recovery is regenerate and re-run the script, which is why the scripts are idempotent. The public key is deliberately non-secret so the script can be re-rendered without rotating the key.

Generating it carries a chained gate: serverSettingsSystem:write and credentials:write, since it mints a fleet-wide admin credential.

Settings are per platform, and Polaris maintains one managed credential per platform β€” a credential holds one username, and a Windows DOMAIN\user is meaningless on Linux.

Two scripts per platform

Script Does
Remediation installs and starts the SSH server, optionally creates the local admin account, installs the public key with the right ACL/ownership, optionally scopes inbound TCP/22, and on Windows settles the firewall profile (below)
Detection exit 0 = onboarded, 1 = remediate

Pairing them under an Intune Remediation or an SCCM Configuration Baseline is what makes rollout self-healing β€” a plain platform script runs once per device and never retries.

When sshd is installed but will not start

The remediation installs OpenSSH Server only when Windows reports it missing. It never checks the version, and it never reinstalls. A machine can report OpenSSH Server as Installed while its sshd.exe is years out of date. The service then times out on start (error 1053), and the script stops before it reaches the account and key steps.

When that happens, both scripts name the cause in the Intune output columns:

Script Output
Detection remediate: sshd not running (sshd.exe OpenSSH_7.7p1 for Windows; last SCM event 7009 at …: A timeout was reached …)
Remediation error: sshd failed to start - …, then the same version and Service Control Manager event, and exit 1

An sshd.exe version far older than a healthy machine on the same Windows build means a stale install. Remove and reinstall the capability on that endpoint (Remove-WindowsCapability, then Add-WindowsCapability, with a reboot between them if Windows asks for one). The next remediation run then finishes on its own. A current version together with a timeout points instead at something stopping sshd.exe, such as endpoint security or application control.

Platform differences that matter:

  • Windows β€” the key goes in administrators_authorized_keys with the Administrators+SYSTEM ACL sshd demands.
  • Linux β€” the key goes in the user's ~/.ssh/authorized_keys (700/600, correctly owned) with a restorecon for SELinux, and the script installs a NOPASSWD sudoers drop-in, validated with visudo -cf before install since a bad one locks sudo out for everyone. The agent installer runs sudo -n, so key auth alone cannot install an agent. It deliberately does not install openssh-server.

The Windows firewall rule, and the one Windows writes for itself

Installing the OpenSSH Server capability makes Windows create its own rule, OpenSSH-Server-In-TCP, and that rule is Private profile only and accepts any source. Both halves of that are wrong for a fleet:

  • On a domain-joined endpoint the active profile is Domain, so the rule never applies. sshd is installed, running and unreachable, with nothing in the service or the event log to say why.
  • On a Private network it leaves port 22 open to every host on it. Firewall rules are additive allows, so a tightly scoped Polaris rule alongside it narrows nothing.

What the remediation script does about it depends on Polaris server address:

Server address Windows firewall after the run
set Polaris SSH (TCP 22) allows TCP/22 from that address on every profile, and OpenSSH-Server-In-TCP is disabled β€” the Polaris rule is the only inbound path to sshd
blank nothing is opened; OpenSSH-Server-In-TCP is widened from Private to Domain, Private so a domain-joined endpoint is reachable. Which sources may connect is unchanged, so restrict port 22 some other way

Public is deliberately never added. Reachable-from-Domain is the problem being solved; an any-source TCP/22 rule on the profile a laptop picks up in an airport is not. Both paths are idempotent.

The detection script checks the firewall too, against whichever of the two states the same Polaris server address produces:

Server address Detection reports "needs remediation" when
set Polaris SSH (TCP 22) is missing, disabled, not on every profile, or allows a different address; or OpenSSH-Server-In-TCP is still enabled
blank OpenSSH-Server-In-TCP does not cover the Domain profile. Whether it is enabled is not checked, because the remediation never turns back on a rule you turned off

So a machine set up some other way (by hand, or by another script) is caught and remediated too. Otherwise, on a domain network, sshd would be listening with nothing able to reach it, and the first sign would be an agent install timing out while waiting for the SSH handshake. Detection and remediation are built from the same saved address, so change the address and re-publish both.

The script does not decide who may use SSH. It never writes sshd_config, so stock Windows OpenSSH rules apply: no AllowUsers/AllowGroups, and password authentication on. Every account the endpoint lets log on can authenticate once sshd is running β€” the account on the card is only the one whose key is authorized. The firewall scope above is what limits who can reach the port. On an endpoint that already ran sshd, the script leaves its config alone: it starts the service only if stopped, appends the key, and sets the service to start Automatically.

The account Polaris signs in as

Section 2 of the card, and the setting most likely to bite:

Mode What the script does
Use an existing administrator account installs the key only. It does not create the account or change its group membership β€” but it does verify both, and stops with error: account … does not exist on this host rather than installing a key for an account that is not there
Create a dedicated local account on each endpoint creates it with a random password it never reports (key auth only), and adds it to Administrators

Existing mode verifies without changing anything: choosing an account you already have is not asking Polaris to create one, or to promote one to administrator. If the check fails, the fix is yours to make β€” then the next remediation pass succeeds on its own.

A created Windows name is capped at 20 characters β€” the limit New-LocalUser enforces β€” and is refused on save rather than failing later on every endpoint. DOMAIN\user is legal only with an existing account: a domain account cannot be created locally.

Troubleshooting a login that fails after a successful onboarding run. If an agent install or upgrade reports All configured authentication methods failed, the account is the first thing to check, not the key. administrators_authorized_keys is machine-wide β€” it authorises any member of Administrators β€” so the key lands correctly even when the account named on the card does not exist, and every later login then fails in a way that reads like a key problem.

Detection catches this, on both platforms (business rule 72). It checks the account as well as the key, and reports which part is missing:

Detection output Meaning
remediate: local account <name> missing the account is not on the endpoint
remediate: local account <name> is disabled it exists but cannot log in
remediate: <name> is not a member of Administrators it exists but the agent installer cannot use it
ok: Polaris SSH onboarding present (<name> is a local administrator) ready

A domain account (DOMAIN\user) is invisible to Get-LocalUser, so for one of those only the group membership is checked.

If you want to confirm by hand, run Get-LocalUser and Get-LocalGroupMember -Group Administrators on the endpoint against the username the managed credential carries. On an Entra-joined endpoint Get-LocalGroupMember may list members as raw S-1-12-1-… SIDs, or fail outright; the detection script falls back to the WinNT:// provider for exactly that reason, so trust its verdict over a bare Get-LocalGroupMember that errored.

Without the account check, an endpoint whose account was never created would report Detection: Without issues and Remediation: Not run β€” indistinguishable, in the Intune console, from a healthy one. The scripts are generated, not live: regenerate both halves from the card after upgrading Polaris, and machines in that state report as needing remediation on their next pass and fix themselves.

The scripts are delivery-neutral and fleet-generic β€” no machine-specific values β€” so the same body runs under Intune, GPO startup, SCCM, Arc, an RMM or a one-off remote invocation.

Operator input (username, the Polaris server IP) is rejected, not escaped: it lands in a script an admin runs fleet-wide as SYSTEM.

Publishing

Two vehicles, each opt-in per integration:

  • Intune β€” Windows only, and Polaris never assigns the Remediation.
  • Azure Arc Run Command β€” Windows and Linux, the only vehicle reaching Linux or Windows Server, with explicit target selection as the review gate.

SSH host-key verification

On for every credential unless its Verify the server's host key box is unticked, and it fails closed (rule 21, rule 113).

Trust-on-first-use:

State Result
no pin stored stores and accepts
pin matches accepts
key changed refuses the connection and stamps an event
internal error refuses β€” it never silently skips

Pins are per (host, port) in their own table, never on the credential. WinRM over HTTPS gets the same treatment for its TLS certificate when Verify TLS certificate is off. Both kinds of pin are listed under Windows SSH Deployment β†’ Pinned server identities; delete one to trust a host that was legitimately rebuilt, re-keyed or re-certified. TLS certificates are also on Server Settings β†’ Web Server: View pinned certificates opens a list with the asset each certificate belongs to, and a changed certificate shows both fingerprints and Trust new certificate pins exactly the one shown.


TLS certificate pinning

The agent does not use system roots. It compares the server's leaf certificate SHA-256 against a pin set carried in agent.conf.

The pin embedded at install comes from the same certificate file nginx serves, and a reinstall re-reads the live certificate rather than trusting the stored one β€” otherwise a reinstall against a host first enrolled before a rotation would bake in the stale pin, the handshake would fail, and the agent would sit forever at "enrolling".

Rotating the certificate without breaking the fleet

Server Settings β†’ Maintenance β†’ Polaris Agent β†’ Cert pin rotation. Each agent carries a canonical pin plus a list of staged additional pins; the union is its trust set.

  1. Stage the new pin. It propagates fleet-wide; online agents apply within seconds over the WebSocket, offline agents on their next config poll.
  2. Rotate the server certificate. Agents keep working β€” both pins are trusted.
  3. Retire the old pin. If the canonical one is removed and a staged pin remains, the first staged pin is promoted.

The union must never be empty for an active agent β€” a removal that would empty it is skipped and reported. An empty pin set bricks the agent's TLS dialer until a manual reinstall.

agent.conf always carries both the multi-pin key and a single-pin key, so a downgrade to an older binary keeps working.


What the agent collects

Stream
responseTime its own heartbeat
cpuMemory, temperature, interfaces, storage host telemetry
β€” interface link state agent 0.25.0+ reads each NIC's real link state, negotiated speed and duplex from the OS (sysfs on Linux, the network adapter on Windows). An older agent reports a NIC as up whenever it is enabled and sends no speed, so an unplugged cable reads up and an interface-down automation on that host never fires β€” upgrade the agent before relying on one
β€” interface addresses each interface's address goes onto the asset's Addresses list with the source Agent. Because the agent's key belongs to that one asset, these count as strong evidence in the address confidence score, and so does the private address the agent connects from
β€” per-core CPU and the memory breakdown the agent's own accounting β€” see below. vCenter reports both too, in its own vocabulary
processes agent-default-ON β€” an installed agent collects its process inventory automatically
services the unit / service inventory for the asset's Services tab, with per-service CPU and memory (agent 0.22.0+ on Windows). Ticking a service's Monitor box also collects its log: the journal on Linux, its Event Log entries on Windows (0.22.0+)
installed software agent 0.24.0+; the program list for the asset's Software tab, read every six hours β€” the Windows Apps & features list (machine-wide installs; per-user installs are not seen) or the dpkg / rpm package database on Linux. Change the interval with software_inventory_interval_sec in agent.conf
eventLog opt-in, behind a global master switch (PII and volume)
Application Map connections needs the ptrace tier on Linux
Path checks agent 0.21.0+; runs only the checks an operator created and pointed at this host. HTTP / HTTPS / TCP / ICMP plus traceroute, no extra privilege on any tier

The storage and interface collectors run under a 30-second guard, because statfs and interface ioctls can block indefinitely on a hung filesystem or an unresponsive NIC β€” without it the whole push loop freezes while the heartbeat keeps running and the agent looks connected.

When the host stops reporting

A dead host sends nothing, so Polaris treats the agent's silence as the missed poll. Once an agent that finished deploying has been silent for two polling intervals, each further miss counts toward your down-detection automation, and the asset goes Down and raises Asset down just as a host that stopped answering pings would. Restarts and updates of Polaris itself, and agent upgrades, do not count. See rule 86.

Host identity β€” hostname, OS, make, model, serial

Alongside the telemetry streams the agent reports what the machine is: hostname, OS and version, manufacturer, model, BIOS version and serial number. Because it runs on the host, this beats what a directory or MDM holds β€” those describe the machine as it was when it enrolled.

The serial comes from the firmware: /sys/class/dmi/id/product_serial on Linux, the IORegistry on macOS, and the SMBIOS table on Windows.

Windows needs agent 0.20.1 or later for a real serial. Windows publishes no serial number in the registry; the agent reads the firmware table directly and reports the same value Get-CimInstance Win32_BIOS shows. An agent below 0.20.1 reports the system SKU instead β€” a model code, identical on every unit of that model (a PowerEdge R740 reports SKU=NotProvided;ModelName=PowerEdge R740). Upgrade the agent, and the serial corrects itself on the next check-in. Two things you may see when it does: a serial that changes on a Windows asset for no other reason, and β€” where the firmware has no serial to give β€” one that clears instead, which is deliberate. Both are recorded in Events.

On a hardened Linux host product_serial is often root-only, so an agent on the unprivileged tier reports no serial and Polaris falls back to another source. A serial the hardware never had programmed (To Be Filled By O.E.M. and friends) is reported as no serial at all rather than passed on β€” see Business Rules.

The collections are spread across the minute

Each collection runs on its own cadence, and each one starts at a different offset inside the minute β€” so they never run at the same instant.

That matters more than it sounds. Several collections share a cadence: four of them run every five minutes, and on Windows two of those shell out, one to tasklist and one to PowerShell. Fired together, they make a visible CPU spike every five minutes on a small host β€” and because the agent measures its own response time by timing a round trip to Polaris, the spike lands on that measurement too. Both charts on the System tab grow a five-minute sawtooth that describes the agent rather than the host.

If you are looking at an agent host with that pattern, check the agent version: the stagger needs agent 0.19.0 or later, and an installed agent keeps its schedule until it is upgraded.

Each agent also picks a small random offset of its own at startup, so a fleet deployed in one batch does not arrive at the server in lockstep.

The offsets stagger when each collection starts. They cannot control how long one takes, and on a small or busy host a collection often overruns into the next one's slot β€” which is why nothing the agent measures is allowed to depend on having a quiet instant to itself. See the CPU reading below.

What the CPU number measures

Every CPU figure the agent reports is an average over the whole gap since its previous sample β€” by default the last 60 seconds, whatever telemetry_interval_sec is set to. The agent reads the kernel's running CPU counters and reports the difference; it does not sample a moment and it does not pause to watch.

That matters on small hosts. A single short window once a minute would describe 1 second in 60 and say nothing about the other 59. On a single-vCPU VM that is actively misleading: if one of the agent's own collections is still running when the window opens, it holds the only core, and the sample reports ~100% CPU for a host that is otherwise idle β€” the chart describes the agent, not the machine. Spreading the collections across the minute does not prevent that, because a collection that starts in its own slot can still be running when a short window opens.

Two things follow, both worth knowing before you read a chart or set a threshold:

  • The agent's own overhead cannot dominate a sample. It shows up as what it actually costs β€” a few percent of the interval β€” instead of as the entire reading on the ticks where it collides.
  • The cadence is the smoothing. A brief spike is averaged across the whole interval rather than caught or missed at random, so the chart is flatter than a point sample would draw, and CPU thresholds fire on a sustained average rather than on a lucky sample. If you want a sharper chart on a particular host, shorten telemetry_interval_sec; that shortens the averaging window with it.

This needs agent 0.20.0 or later. An agent below that takes a single 1-second sample once a minute until it is upgraded.

Per-core CPU and the memory breakdown

An agent-monitored host's Assets β†’ System tab splits CPU & Memory into two charts: a CPU chart drawing one coloured line per logical core alongside the cross-core average, and a Memory chart that is a stacked area in bytes. FortiOS, SNMP, WinRM and SSH can report neither, so those assets keep the single combined CPU & Memory chart on one 0–100% axis. vCenter splits too, in its own vocabulary β€” it measures the same host from outside.

The split follows the CPU/Memory stream's polling method, not the presence of an agent: a host with the agent installed but that stream still pointed at SNMP is collecting one CPU figure per sample, and gets the combined chart.

What the agent sees and vCenter does not, and the reverse, is the point of running both on one VM. The agent reports the guest's own accounting β€” buffers and page cache, and which processes hold the rest. It cannot see ballooning or host swap at all: those are the hypervisor reclaiming memory from underneath the guest, and to the guest they simply look like memory it never had.

On the CPU chart:

  • The Average line is the one every automation threshold reads. It stays on top and is the only line that dives to the baseline across a missed poll.
  • The legend lists Average plus a chip per core. Click a chip to isolate that core; click it again, or click Average, to bring the rest back. The isolation survives the chart's automatic refresh.
  • Hovering names the six busiest cores at that moment (or just the isolated one). On a host with many cores, isolate before you hover.
  • Per-core detail is kept for the detail-retention window only (7 days by default β€” Server Settings β†’ Retention). Longer ranges are served from hourly/daily rollups, which keep the average alone; the chart says so when that is why the cores are missing.

On the Memory chart the bands stack to what is actually in use, against a dashed line at the installed total β€” the gap between the two is free memory:

Band
Processes resident in running programs
Buffers Linux block-layer buffers (absent on Windows)
Cache page cache (Linux) / system cache (Windows)
Swap / page file a dashed line, not a band β€” it is backing store, not RAM, so it stacks with nothing

Two figures here are commonly misread elsewhere and are deliberately not: Windows cache is the standby cache, which the usual API hides inside "available" memory, and Windows page file is the page file itself rather than the commit charge (which counts pages never written to disk and reads far higher).


Upgrading

An upgrade never refuses for want of a credential it can find itself, and never records one it has not proved (rule 49).

The credential is resolved in one order:

an explicit credentialId on the request
  β†’ the credential recorded at install
    β†’ the Polaris-managed SSH deployment credential for the platform
  • An id that no longer resolves counts as absent, not as an error β€” deleting a credential would otherwise silently strand every agent installed with it, and some installs have no recorded credential at all.
  • Only an explicit credential that fails to resolve is an error: an operator who names a credential is told it is wrong rather than quietly connected with another.
  • The transport follows the credential's type, never the row's recorded transport.
  • An adopted credential is written back only on success. Reaching the host is the proof. A genuinely WinRM-only box fails, keeps what it had recorded, and lands as upgrade_failed with a real reason β€” itself an upgradeable status.
  • An operator override is never adopted; Polaris does not record a choice it did not make.
  • A host the fan-out still cannot upgrade writes an agent.upgrade_skipped Event rather than being skipped silently.
  • A host that monitoring shows as down is skipped, not attempted, by Upgrade all out-of-date and by the automatic upgrade after a new build: connecting to it would only sit out a timeout while the reachable hosts wait. Nothing about the agent changes β€” it stays out of date, so the next fan-out picks it up once the host is back, or you can use the host's own Upgrade button, which is never skipped. Each one writes an info-level agent.upgrade_deferred Event (deliberately not agent.upgrade_skipped, so an automation watching for stranded hosts does not page about one that is simply off), and the toast says how many were skipped. A device that is not monitored is still attempted.

Upgrade only. Install, reinstall and uninstall require a credential on file; force-remove is the escape hatch.

The device goes quiet while it runs

An upgrade stops the agent service, which drops the agent's connection and raises agent.disconnected β€” so Polaris puts the asset into a maintenance window for the duration and the built-in disconnect automation stays quiet (rule 80). The same applies to a reinstall and an uninstall. A first install and a retry take no window: there is no agent running to disconnect.

The device reads maintenance while it runs, and its Maintenance tab names the operation. The window ends when the agent reconnects β€” or immediately if the upgrade fails, because an agent that is down for that reason is worth an alert. Nothing can leave it open: it expires after 20 minutes (30 for a reinstall) whatever happened to the operation, and the suppressed alert then fires late rather than never.

It silences the whole device for that minute or two, not just the agent β€” Maintenance Windows has the detail.


Building agent binaries in-app

The Polaris Agent card on Integrations β†’ Polaris Agents carries the build: cross-compile the agent for the platform matrix from the Go toolchain on the Polaris host, with an optional code-signing step for Windows binaries against your internal CA.

Go is needed only for this. Java is needed only for signing. Without either, nothing else changes β€” you can download prebuilt binaries instead.

The jsign jar is not a field on the card. Polaris finds it at tools/jsign.jar under the app or state directory (or /opt/polaris/tools/jsign.jar), and a jar elsewhere is named with the POLARIS_JSIGN_JAR environment variable, because the jar is run as code by the service account (rule 107).

The server URL the agents call back to can be overridden under Server Settings β†’ Agents. It must be a plain http:// or https:// address with an optional port and path of letters, digits and . _ ~ - /; anything else is refused.


Service & Process Discovery Rules

The card above the build card. Named rules that pin process and service items on the assets they select β€” now and on assets discovered later.

Each rule has a mode:

Mode
Monitor + map Application Map and telemetry β€” mapping implies monitoring
Monitor only per-program CPU/RAM and logs, per-unit log collection (journal / Event Log); never touches map pins

A four-step wizard: name β†’ devices β†’ items β†’ summary. The item step is scope-driven β€” it lists only what the selected devices report, which is what keeps a rule from pinning a unit on every host that happens to run it.

Rules only ever target workstations and servers, since nothing else reports an inventory.

Auto rules: ticking Monitor or Map on an asset's Services tab mints a single-item auto rule for that asset; pinning the same item elsewhere consolidates into it; un-ticking removes the asset, and an auto rule losing its last asset is deleted. Editing an auto rule in the wizard converts it to manual.

Mapping implies monitoring, one way. Nothing ever writes a map pin from a monitor pin. Removing an item or disabling a rule stops future auto-pinning; a separate Unmap everywhere action does the actual strip.


Troubleshooting

Symptom Look at
Stuck at "enrolling", host crash-looping the Linux agent.conf ownership trap above β€” reinstall
Agent connected but the Application Map is empty the Linux privilege tier. Check the Privilege column for "reinstall" β€” a SYS_PTRACE-only unit collects nothing while looking healthy
TLS handshake fails after a certificate rotation the pin. Stage the new pin before rotating
Samples stop but the heartbeat continues a hung filesystem or NIC in a collector β€” the 30 s guard bounds this
Upgrade skips a host check for agent.upgrade_skipped Events
An ICMP path check fails with icmp unsupported on this host (ping_group_range) Linux only. The agent opens ICMP without privilege, which needs the service's group inside net.ipv4.ping_group_range. Modern distributions allow every group; RHEL 8 does not. Fix it on the host: echo 'net.ipv4.ping_group_range = 0 2147483647' | sudo tee /etc/sysctl.d/90-polaris-ping.conf && sudo sysctl --system. HTTP, TCP and traceroute are unaffected
A path check never produces results the agent version (0.21.0+ runs checks β€” upgrade it), and whether the host is listed on the check's Results view. A host that is not listed does not match the check's Sources
Every traceroute hop after the first shows * the network drops ICMP errors (Time Exceeded) on the way back. The check result itself is unaffected
An agent host is powered off but the asset still reads Up whether an automation covers it (no automation means Passive, rule 36); whether the agent is revoked or not yet active; and, with a single agent, whether Polaris just restarted. The agent gets a full window from boot (rule 86)
A burst of agent.disconnected alerts right after an in-app update or restart the reason at the end of each Event's message. heartbeat timeout is a server too busy to answer while every agent redials it at once. A redialing agent's superseded connection closing does not raise a disconnect β€” Polaris ignores the old connection once the new one is up
agent.disconnected alerts never clear the counterpart reset β€” an event automation should clear on agent.connected, scoped to the same subject (rule 32e)
⚠️ **GitHub.com Fallback** ⚠️