Перейти к содержимому

Collectors

A collector is the reachability domain that actually opens connections to devices and runs collections. Every source is bound to one. There are two kinds: the embedded collector built into the core, and standalone collectors you deploy near networks the core can’t reach directly — which also move the work of talking to those devices off the core entirely.

Collectors are a platform-wide primitive, so they live under Settings → System → Collectors — not inside the Configuration Tracker section.

Two things, and the second is easy to miss because the first is so visible.

Reach. A collector runs where the devices are, so a network the core cannot open a session to is still collectable.

Taking the work off the core. Collecting a fleet is not one expensive operation — it is hundreds of small, slow ones. Every device means opening a session, sending commands, and then waiting: on a switch’s CLI to echo back, on a slow WAN link, on a box that has decided to think about it for thirty seconds. A standalone collector does all of that at the site and hands the core only the finished result.

That is the honest shape of the win: collection is I/O-bound, not CPU-bound. What the core is relieved of is mainly the fan-out — hundreds of concurrent, long-lived, mostly-idle sessions and the retry churn around them — rather than raw processing. The CPU-bound steps the collector also performs (scrubbing, hashing, fingerprinting) are a small share of the cost, but they are done at the site too, and they are what turns a raw capture into something small enough to be worth shipping.

And it is a tool, not a place data lives. A standalone collector holds no database. Its durable state is its own identity (a private key it generates, its certificate, and the pinned fingerprint of the core it trusts) plus an outbox of results the core has not acknowledged yet. Nothing accumulates — once a result is acknowledged, it is gone from the site. There is no history there to query, back up or lose, and no device credentials at rest: a stolen collector volume yields already-scrubbed configs and nothing else.

The practical consequence: raw configuration bodies are never written down at the site. What crosses the wire is a scrubbed body and its hash — so the segment’s secrets stay in the segment, and the core stores the one copy of history, where your backups and your RBAC already are.

The one exception, and it is deliberate. A recipe can keep an unmasked copy of every capture. A standalone collector does collect it — but it holds that copy in memory only and re-attaches it at the moment it uploads the result; it is stripped out before anything reaches the outbox, because the outbox’s contract is that a device secret cannot touch disk. The memory buffer is bounded (64 captures / 64 MiB, oldest evicted first). So a result that gets queued — the collector restarted, or the core was unreachable long enough for the uploader to fall behind — arrives without its unmasked copy. The configuration snapshot itself is never lost; only that second copy is.

EmbeddedStandalone
RunsIn-process on the core (leader) nodeAs a separate container at a site
SetupNone — it’s built inDeploy + enroll (see the deploy guide)
ReachesWhatever the core can reach on the networkDevices local to its site
Connection to coreIt is the coreDials out to the core (outbound only)
Best forSingle-site / flat networksSegmented, remote or NAT’d networks; multi-site
CountExactly one, the default, undeletableAs many as you need

The embedded collector is seeded at first boot under the name default, and the Collectors list renders its mode as Local (built-in). It is always the default collector — the one a source binds to when you don’t pick one — and it can’t be deleted or turned into a standalone. Only the built-in may hold the default flag, so a standalone collector can never take it. For a single site it’s all you need: point sources at it and go.

The Collectors list in the Taranac admin UI The Collectors list under Settings → System — the built-in default collector (mode Local (built-in)) alongside a standalone one at a site, both online. Cluster node answers two different questions in one column, and says which it is answering: a standalone collector is connected to the node that served its last poll, because under HA there is no client-facing address shared by the nodes and each collector talks to exactly one — that is what tells you whose outage explains a collector gone quiet. The embedded collector is active on whichever node currently holds the leader role, and relocates itself at failover.

The standalone collector’s security posture

Section titled “The standalone collector’s security posture”
A standalone collector collects locally inside a segmented site and makes only outbound connections to the core — it listens on zero ports, carries an Ed25519 identity, and keeps no credentials at rest.

A standalone collector is designed so that deploying one into a sensitive segment adds as little attack surface as possible:

  • Dial-out only — listens on zero ports. The core never connects to a collector. The collector makes outbound connections to the core, long-polls for work, and streams results back. There is no inbound listener to expose or firewall.
  • Reveal-once Ed25519 identity. A collector enrolls with a one-time token and then proves itself on every request by signing with an Ed25519 key it generates locally and never sends. The core pins the collector’s public key on first enrollment; each subsequent request carries a signature and a timestamp, accepted only within a five-minute clock-skew window — which also bounds how long any replay of it could matter. A verbatim repeat inside that window is rejected outright.
  • Credentials handed out just-in-time. A collector receives the credentials for a collection only in the poll response for that work, uses them in memory, and keeps nothing long-lived — including just-in-time passwords, which rotate the moment the collector’s work drains.
  • Credential-free at rest. The collector persists its own identity key and a durable result outbox, but no device credentials — a stolen disk yields no way into your fleet.
  • Durable outbox. Results are buffered locally in a small on-disk queue and delivered idempotently — the core deduplicates on the result’s key — so a restart or a link outage never loses a capture or double-writes one. It is also backpressure: once the queue is full the collector stops claiming new work and says so, and the uploader keeps draining until it recovers. The one thing the outbox will not hold is an unmasked copy (above).

The Collectors list shows each collector’s name, mode, status, cluster node, when it was last seen, and what uses it. A collector’s own page adds the address it last dialled in from, its version pair and compatibility badge, and its enrolled identity.

Status is worked out when you read the page, from the last time a collector reported in — it isn’t a stored flag, so a wedged collector reads correctly. A standalone collector long-polls the core every few tens of seconds, and that poll is its heartbeat:

StatusMeaning
OnlineReported in within the staleness window.
OfflineHasn’t reported within the window — 15 minutes, which is many missed polls: a deliberately coarse signal, not an SLA.
UnknownHas never reported (freshly created, not yet enrolled/started).

The embedded collector is a different question, and it is answered differently. It has no dial-in heartbeat that could go stale — it runs wherever the writable primary is, so its liveness is “is there a primary to run it”. On a single node that is always yes and it reads Online. Under HA it reads Online when a writable primary is observed, Offline during a failover window or a quorum loss when no node is sweeping, and Unknown when the cluster could not be reached at all — because failing to look is not the same as finding out that nothing is running, and the two must not render alike.

This is also why the collection cadence never moves the embedded collector’s status: the two were deliberately decoupled.

A standalone collector that goes offline raises one ncm_collector_offline alert — one per collector, not one per config, carrying the count of tracked configs it serves as the blast radius. The scan runs every 5 minutes. An embedded collector never raises it, and neither does a standalone that has never reported (Unknown, not Offline).

A standalone collector’s identity is managed from its detail page:

  • Issue enrollment token (Re-enroll, once it has an identity) issues a reveal-once enrollment token — with a lifetime you choose, default 60 minutes and at most 7 days — plus the core’s URL and a ready-to-paste join command with both already filled in. The token is shown once; copy it then. Issuing a new token revokes any token issued earlier for that collector.
  • Trust is pinned, not configured. The collector accepts the certificate the core presents on first contact and nothing else afterwards, so there is no CA file to stage before deploying one. Verifying against a CA bundle is available as a stricter mode.
  • Revoke identity invalidates the collector’s key immediately: its very next signed request is rejected — the check is a lookup on every request, so there is no CRL to publish and no cache to wait out. After a few consecutive rejections the collector stops polling and halts into a re-enroll required state rather than hammering the core; it keeps whatever is in its outbox, which uploads once it has an identity again. Re-enrolling issues a fresh token and identity.

The full deploy walkthrough is in Deploy a standalone collector.

Version compatibility — two numbers, only one of which can stop you

Section titled “Version compatibility — two numbers, only one of which can stop you”

A standalone collector reports two versions on every poll, and they do completely different jobs. Mixing them up is the difference between a nudge and a stopped fleet.

What it isWhat it does
Contract versionThe snapshot-identity contract: how a config is scrubbed, hashed and fingerprinted. Bumped only when those bytes change.Gates. Any mismatch — in either direction — fail-closes.
Release versionWhich build the collector image is.Cosmetic. Feeds an “update recommended” nudge and nothing else.

The collector’s page shows both as a pair (core vX · collector vY) with one badge:

BadgeMeaning
CompatibleContracts match. Nothing to do.
Update recommendedContracts match, but the core is a newer release. It works fine; upgrade when convenient.
Update requiredContracts differ. The collector is already idle — see below.

The embedded collector has no badge at all: it is the core, so there is nothing to compare.

The contract check runs before the core will hand out any work. On a mismatch the core dispatches nothing and ingests nothing from that collector — and this is not scoped to the configs affected by whatever changed. The collector idles entirely: every tracked config it serves stops being collected. A version-skewed collector writing history the core would hash differently is worse than a collector that collects nothing, so idling it is the intended outcome.

It recovers by itself. The collector keeps slow-polling while refused, so the moment its image matches the core again it resumes — nothing to re-enable, nothing to re-enrol.

A refused poll never counts as a heartbeat — the contract check runs before the core gets that far. So a fail-closed collector doesn’t just stop collecting, it also stops reporting in, and within 15 minutes it reads Offline and raises the ordinary collector-offline alert. The alert names a silent collector; the version skew underneath it is what the collector’s badge and its own log tell you.

Before 1.2.7 this could read as its own opposite. The core attached its version only to answers that succeeded, so the one answer that needed it — the refusal — carried none; the collector went on reporting the version it had heard before the core was upgraded, which naturally matched the version it was still running, and its own updater answered “already in step with the core — nothing to do” while nothing at all was being collected. Since 1.2.7 the core reports its version on refusals too, so the way out is no longer locked by the failure it exists for. (Unauthenticated callers still learn nothing: the version is attached only after a signature has verified.) The command that moves a collector to the version its core runs is on the deploy page.

One flat site. Do nothing — use the built-in default collector for every source.

A remote branch behind NAT. Deploy a standalone collector at the branch, enroll it, and set your branch sources’ collector to it. Nothing needs to be opened inbound to the branch or the core.

A hardened DMZ or OT segment. Put a standalone collector inside the segment. It reaches the gear locally and dials out to the core — no inbound path into the segment, no device credentials stored on the collector.

SituationCollector
Core can reach the devices directlyEmbedded
Devices are in a segment the core can’t route toStandalone
Site is behind NAT / has no inbound pathStandalone (dial-out)
Multiple sites, each isolatedOne standalone per site
You need zero new inbound listeners in a sensitive zoneStandalone
The core is spending its time waiting on hundreds of slow device sessionsStandalone, one per site — the waiting happens there
Raw configuration bodies must not be written down in a segmentStandalone (a scrubbed body and its hash are shipped; nothing unmasked ever reaches the site’s disk)
FieldNotes
NameUnique. The built-in one is seeded as default.
Modeembedded (rendered Local (built-in) — exactly one, always the default, undeletable, and its mode can’t be changed) or standalone. Only standalone collectors can be created.
Site labelFree text, standalone only — where this collector runs. It is not a URL: the core never calls a collector.
Statusonline · offline · unknown — derived when read, not stored. Standalone = heartbeat staleness (15 min); embedded = is there a writable primary.
Cluster nodeStandalone: the node that served its last poll — observed, not inferred. Embedded: the node currently holding the leader role, resolved live, so it moves on failover. Either renders when it can’t be resolved.
Last seenStandalone: the last poll, plus the address the collector dialled in from — this is the liveness signal. Embedded: a “last swept” stamp only; its status doesn’t come from it.
Release versionThe collector image’s build. Cosmetic — drives the “update recommended” nudge only.
Contract versionThe snapshot-identity contract. Must equal the core’s, or the poll fail-closes and the collector idles for every config it serves.
Compatibilitycompatible · update_recommended · update_required. Derived from the contract, never from the release. None for the embedded collector.
IdentityStandalone only: Ed25519 key generated on the collector and pinned at enrollment; status active or revoked.
Enrollment tokenReveal-once; operator-chosen lifetime (default 60 min, maximum 7 days); one live token at a time.
Used bySources and tracked-config addresses referencing the collector (blocks deletion).
PermissionsCollectors carry their own Collectors permission section under System (view · create · edit · delete), separate from the Configuration Tracker sections — running collectors is a distinct trust from curating the config inventory.