Skip to main content

ENROLLMENT TOKENS

Enrollment tokens are short-lived credentials that bind a worker to a Swamp server. They are created with swamp worker token create and consumed when a worker first connects. By default, each token binds to a single machine. Fleet tokens (--max-enrollments) extend this to allow multiple machines to enroll on one token.

State machine

A token moves through four states:

State Description
unused Created but no worker has connected with it yet
enrolled At least one worker has connected and bound the token to a machine identity
expired The --duration lifetime has elapsed; bound workers are cut off and the orchestrator rejects the token
revoked Manually invalidated via swamp worker token revoke; bound workers are cut off (Revocation)

Valid transitions:

unused ──► enrolled ──► expired
  │            │
  ▼            ▼
revoked     revoked

revoked can be applied from unused or enrolled. Once a token reaches expired, it cannot be revoked (it is already terminal). Both expired and revoked are terminal states.

Machine binding

When a worker connects with an unused token for the first time, the token binds to the worker's machine identity. The identity is read from a machine-id file stored in the worker's --cache-dir directory.

  • The bound machine can reconnect across socket interruptions, process restarts, and machine reboots, as long as the machine-id file survives.
  • For single-enrollment tokens (the default), any other machine presenting the same token is rejected. The orchestrator compares the connecting machine's identity against the identity recorded at enrollment time.
  • The machine-id is client-asserted. It prevents accidental reuse from different machines but does not defend against a malicious token holder. See the Security page for the full trust model.

Fleet tokens

Fleet tokens are created with --max-enrollments <n> (a positive integer or unlimited). They allow multiple machines to bind to a single token:

  • Each machine gets a distinct worker name: <token-name>-<suffix>, where <suffix> is a 4-character hex hash of the machine ID.
  • A fleet=<token-name> label is auto-injected at enrollment. Use this label in workflow placement to target the fleet.
  • The enrollment allowance is a hard cap. Once exhausted, new machines are rejected with "enrollment allowance exhausted."
  • Each enrolled machine is tracked independently — reconnection, expiry, and revocation behave identically to single-enrollment tokens per machine.

Warning

Always set --cache-dir to a stable path. Without --cache-dir, the worker uses a fresh temporary directory each time it starts. This means:

  • A new machine-id is generated per process.
  • After a restart, the worker presents a different identity and the orchestrator rejects the connection (the token is already bound to the previous identity).

Set --cache-dir to a persistent path (e.g., /var/lib/swamp-worker) for any worker that needs to survive restarts. See swamp worker start --cache-dir for details.

Expiry

Expiry is a hard deadline set at creation time via --duration. The countdown starts when the token is created, not when the worker enrolls.

  • When the lifetime elapses, every worker bound to the token, fleet members included, is removed from the pool at once. Its session and dispatch credentials are revoked with no reconnection grace window.
  • Re-enrollment with an expired token is rejected, and the rejection is permanent: the worker process stops instead of retrying.
  • To cut off a worker before the expiry time, revoke the token.

Revocation

swamp worker token revoke cuts off every worker bound to the token, fleet members included. When the cut-off happens depends on where the revoke runs:

  • Through the server (--server): the orchestrator disconnects the bound workers straight away, with no reconnection grace window, and revokes their session and dispatch credentials at once. The response lists them under disconnectedWorkers.
  • Locally (no --server), on an HA peer, or by re-minting the token name: the orchestrator's revalidation pass picks up the change. It runs every 30 seconds; on an HA peer, add the datastore poll interval. A worker on a newer mint of the same name is kept.

After the cut-off:

  • A step running on the worker follows the usual disconnect rules. A step that had written data fails, as does a step in an affinity group; a step that had written nothing is rescheduled.
  • The worker process stops reconnecting, because a revoked rejection is permanent.

Restart and reboot scenarios

Scenario Token state What happens
Socket blip (network hiccup) enrolled Worker reconnects automatically; same machine-id matches
Process restart (same machine) enrolled Worker re-enrolls with the same machine-id from --cache-dir; connection resumes
Machine reboot (same disk) enrolled Same as process restart — machine-id file persists across reboots
Token expired expired Connected workers are removed at expiry with no grace window; the worker stops and re-enrollment is rejected. Mint a new token
Token revoked revoked Connected workers are cut off (at once with --server, else within the revalidation pass); the worker stops. Mint a new token
Second machine (different id) enrolled Single-enrollment: rejected. Fleet token: appends a new binding (if allowance remains)
Worker drains (signal, max-dispatches, idle-timeout) enrolled Worker finishes in-flight work, disconnects cleanly, exits 0. Token remains enrolled — a new process with the same --cache-dir can re-enroll
Worker fails --verify-on-enroll probe enrolled Worker is marked unverified — visible in swamp worker list but excluded from scheduling. Re-enroll or run swamp worker verify to retry