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 revokedrevoked 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-idfile 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-idis 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 underdisconnectedWorkers. - 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 |