Worker Tickets
Use a Worker ticket when a client needs a Worker role’s namespace view. The ticket narrows an authenticated session; it does not create, start or prove a target Worker. Roles and scheduling explains the separate executable lifecycle. Host action tickets and REST delegated tickets authorize different host-side paths. Every REST mutation needs a finite scoped delegated ticket, including one made by a Queen caller. A direct Queen session’s optional Worker ticket does not replace it.
The selected target profiles have executable Worker and baseline isolated driver authority, but model/session roles alone have no VM capabilities. Production Worker ticket/lease ledger binding, the complete selected-driver ledger and structured quarantine remain outside the current selected profile; the compiler rejects claims that require them. See the Build Plan for the owning work.
For path enforcement and limits, see Secure9P, Userland and CLI and Security.
The selected QEMU and Pi profiles declare worker-heartbeat, worker-gpu,
and worker-lora as executable target roles. Root constructs their generated
seL4 bundles suspended, and the Worker supervisor resumes a role only after a
separate bounded /queen/ctl admission. worker-bus remains model-only. A
ticket authorizes a role-scoped session and namespace view; attachment alone
does not load, admit, resume, or prove a target Worker task.
1. Why worker tickets exist
Worker tickets are the application-layer authority boundary for worker-role sessions. They:
- enforce role-scoped access to Secure9P namespaces (no ad-hoc RPC or shared memory shortcuts).
- bind a worker identity (subject) to the session, so telemetry and leases are attributable.
- carry optional scopes and quotas that NineDoor enforces deterministically.
- keep ticket issuance on the host; the target verifies the ticket during authenticated attachment.
1a. Ticket vs auth token
- Auth token (
COH_AUTH_TOKEN/COHSH_AUTH_TOKEN) authenticates the console session. - Worker ticket authorizes the role and namespace slice during
attach. - A session can require both; missing either yields deterministic
ERRon attach.
2. Source of truth
- Ticket inventory and credential references come from the selected source and
resolved manifests under
[[tickets]]. Checked-in development literals are fixtures, not live credentials. The host issuer and target verifier receive matching key material from the selected deployment. - Ticket limits and quotas are manifest-driven and emitted by
coh-rtcinto canonical docs:docs/USERLAND_AND_CLI.md(ticket policy + limits)docs/SECURITY.md(ticket quota limits)
- The root task registers the secrets at boot and validates presented tickets during
attach.
3. Ticket structure (claims)
Worker tickets use the cohesix-ticket format and are MACed with a BLAKE3 keyed hash. Claims include:
- role (
worker-heartbeat,worker-gpu,worker-bus,worker-lora; WorkerBus is a model/session role, not an executable target Worker) - budget (ticks/ops/ttl)
- subject identity (required for worker roles)
- mounts (optional)
- issued_at_ms (millisecond timestamp)
- optional UI scopes + per-ticket quotas (must respect manifest limits)
The encoded token string has the form:
cohesix-ticket-<payload_hex>.<mac_hex>
4. Minting a worker ticket (host-side)
- Choose the worker role and subject identity (for example,
worker-1). - Resolve the role’s enrolled issuer secret on the host. Do not copy a checked-in development literal into a live deployment.
- Build
TicketClaimswith the role, subject, budget, and issued_at_ms timestamp. - Sign and encode with
TicketIssuer::new(secret).issue(claims)?.encode()?. - Pass the resulting token to
cohshor SwarmUI when attaching.
Example (Rust, host tooling)
use cohesix_ticket::{BudgetSpec, MountSpec, Role, TicketClaims, TicketIssuer};
use std::time::{SystemTime, UNIX_EPOCH};
fn unix_time_ms() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_millis() as u64
}
fn mint_worker_heartbeat(secret: &str, subject: &str) -> Result<String, cohesix_ticket::TicketError> {
let claims = TicketClaims::new(
Role::WorkerHeartbeat,
BudgetSpec::default_heartbeat(),
Some(subject.to_owned()),
MountSpec::empty(),
unix_time_ms(),
);
let token = TicketIssuer::new(secret).issue(claims)?.encode()?;
Ok(token)
}
Attach with the minted token
./cohsh --transport tcp --tcp-host 127.0.0.1 --tcp-port 31337 \
--role worker-heartbeat --ticket "$WORKER_TICKET"
5. Host tooling shortcuts
cohsh --mint-ticket --role worker-heartbeat --ticket-subject worker-1prints a token and exits.swarmui --mint-ticket --role worker-heartbeat --ticket-subject worker-1does the same; the UI also exposes a “Mint ticket” button.- Override secrets with
COHSH_TICKET_CONFIG/COHSH_TICKET_SECRETorSWARMUI_TICKET_CONFIG/SWARMUI_TICKET_SECRET(fallback toCOHSH_*).
6. Operational notes
- Worker tickets are mandatory for worker roles; queen tickets are optional.
- Subject identity is required for worker roles and is used to build the attach identity.
- Ticket length and quota limits are enforced by
cohshand NineDoor; ensure scopes/quotas stay within the manifest limits. - The TCP console auth token is separate from worker tickets; both may be required in a single session.
- Ticket acceptance proves only session authority. It does not satisfy target
admission,
READY, receipt, teardown, QEMU, or fresh-Pi evidence. - An executable target Worker becomes live only through the generated
supervisor lifecycle: exact role admission, resume, identity-matched
READY, bounded work, and complete generation-fenced containment. - Static executable declarations for QEMU and Pi are not execution proof. The matching target acceptance record must bind the exact kernel, root image, Worker archive, image manifest, role image, and five-part Worker identity.
7. Attach flow (operator mental model)
- Client opens a TCP console session and authenticates with the auth token.
- Client issues
ATTACH <role> <ticket?>. - NineDoor validates ticket MAC, role, subject, and mount table.
- On success, the session is bound to the role-specific namespace. This does
not start or attach a target Worker task;
/queen/ctladmission and identity-matchedREADYare separate operations.
8. Worker tickets versus host action tickets
Worker tickets authorize application sessions. The host-ticket/v1 and
host-ticket/v2 records on /host/tickets/* authorize host-side actions and
are a different contract.
Receipt-bearing GPU lease and PEFT actions require version 2. Root accepts the
caller record only after it matches an exact live worker-gpu or
worker-lora, then publishes a normalized read-only spec.snapshot containing
the resolved slot, lease epoch, supervisor generation, cap generation, and a
globally increasing admission sequence. Root separately derives the executable
Worker control sequence from that exact Worker’s last accepted control and
admits at most one unresolved receipt action per identity, so the Worker’s
single-slot control page cannot skip or overwrite a control. The host agent
claims only that root-owned snapshot. A terminal result is digest-checked
against the pinned identity before root publishes a confirmed, rejected, or
stale Worker receipt; the host agent never creates or tears down the receipt
Worker.
GPU lease reconciliation reads /proc/lease/by-id/<operation_id> rather than
scanning the byte-bounded /proc/lease/active aggregate. Each exact lookup is
bounded by the same per-record byte limit, returns either one identity-bound
record or an empty payload, and preserves one unresolved operation per receipt
Worker. This permits independent GPU Workers to hold independent leases
without making transaction recovery depend on an aggregate display window.
9. Common errors and recovery
1) ERR ATTACH with valid auth token
Signal
- Attach fails even though the console token is correct.
Impact
- Ticket is missing, malformed, expired by policy, or does not match the role/subject.
Recovery
- Mint a fresh ticket for the correct role and subject, then retry attach.
2) Access denied after attach
Signal
PermissionorEPERMon paths outside the worker’s namespace.
Impact
- Ticket scope does not include the requested path.
Recovery
- Attach as the correct role or update the mount spec in the ticket.
10. Security hygiene
- Treat ticket secrets like signing keys. Keep them out of logs, issues and client arguments; the selected target verifier still needs its matching key material.
- Rotate a deployed issuer through its selected credential reference and rebuild/restart the affected target or gateway according to the owning authority contract. Keep the old and new ticket domains separate.