joinTokens
Join tokens are single-purpose credentials that let a limited number of daemons join one pool for a limited time. The bearer form `bcjt_<id>.<secret>` is returned once, when the token is created; the control plane stores only the SHA-256 of the secret. Every method is decided on `compute-pool/{poolId}`. See [Joining nodes](/docs/guides/nodes/joining).
Join tokens are single-purpose credentials that let a limited number of daemons join one pool for a limited time. The bearer form bcjt_<id>.<secret> is returned once, when the token is created; the control plane stores only the SHA-256 of the secret. Every method is decided on compute-pool/{poolId}. See Joining nodes.
All 3 methods are served by this release.
| Method | Kind | Authorization | Phase | Status |
|---|---|---|---|---|
create | mutation | compute:join-tokens:create @ compute-pool | v0.1 | registered |
list | read | compute:join-tokens:read @ compute-pool | v0.1 | registered |
revoke | mutation | compute:join-tokens:revoke @ compute-pool | v0.1 | registered |
create
POST /api/compute/joinTokens/create
Mints a role-node join token for one pool and returns its record with the bearer token, which is never shown again.
Only the pool's owner tenant can mint tokens for it; another tenant gets NOT_FOUND. A pool whose machines run no daemon (its agent is not bcd) answers INVALID_STATE. expect pins the token to one machine and must name at least one identifier, otherwise the call is INVALID_INPUT. ttlSeconds runs from 60 to 86,400 and maxUses defaults to 1.
hosted: 'kubernetes' marks a token for bcd running as a DaemonSet on a Kubernetes cluster. That cluster's admins have root on its machines, so a node joining with it becomes tenant-controlled, with a node-tenant certificate that never receives platform secrets. The exception is a pool whose policy.kubernetes.platformOperated is true, and only when the platform owns that pool (it is the pool's site's owner, on a site that is not custom): anyone who can edit a pool's policy could otherwise vouch for their own cluster, so set it only on pools whose clusters the platform runs. The token decides this, never the machine's claims, and it only ever lowers platform trust: a tenant's own site stays tenant-owned.
The token id derives from the tenant, the calling identity and idempotencyKey. A retry with the same key returns the stored record without token and without a new IAM decision. The same key with a different pool, expect, allowReclaim or hosted is CONFLICT.
Publishes security.join-token.created, whose pinned field says whether the token has an expect binding; hosted is included when set.
- Kind: mutation
- Authorization:
compute:join-tokens:create@compute-pool - Module:
server - Phase: v0.1 (registered)
Input
| Field | Type | Required | Constraints |
|---|---|---|---|
tenantId | string | yes | at most 128 characters; matches ^[A-Za-z0-9._:-]{1,128}$ |
poolId | string | yes | at most 128 characters; matches ^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$ |
maxUses | integer | 1-10000; default 1 | |
ttlSeconds | integer | yes | 60-86400 |
expect | object | ||
expect.productUuid | string | at most 64 characters; matches ^[0-9A-Fa-f-]{8,64}$ | |
expect.serial | string | at most 128 characters; matches ^[A-Za-z0-9._:/+-]{1,128}$ | |
expect.mac | string | at most 17 characters; matches ^[0-9A-Fa-f]{2}(?::[0-9A-Fa-f]{2}){5}$ | |
expect.gpuUuid | string | at most 68 characters; matches ^GPU-[0-9A-Fa-f-]{8,64}$ | |
allowReclaim | boolean | default false | |
hosted | one of kubernetes | ||
idempotencyKey | string | yes | at most 128 characters; matches ^[A-Za-z0-9._~:/+=-]{1,128}$ |
list
POST /api/compute/joinTokens/list
Lists a pool's join tokens in id order, never with their secrets.
By default only live tokens appear: not revoked, with uses left and not expired. includeInactive: true adds used-up, expired and revoked tokens. Pages hold up to 200 tokens (100 by default); pass the returned cursor to read the next page.
- Kind: read
- Authorization:
compute:join-tokens:read@compute-pool - Module:
server - Phase: v0.1 (registered)
Input
| Field | Type | Required | Constraints |
|---|---|---|---|
tenantId | string | yes | at most 128 characters; matches ^[A-Za-z0-9._:-]{1,128}$ |
poolId | string | yes | at most 128 characters; matches ^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$ |
includeInactive | boolean | default false | |
limit | integer | 1-200; default 100 | |
cursor | string | at most 64 characters; matches ^jt_[0-9a-hjkmnp-tv-z]{26,52}$ |
revoke
POST /api/compute/joinTokens/revoke
Revokes a join token at once and returns its record with revokedAt set.
Revoking a token that is already revoked returns it unchanged and publishes nothing. A token that does not exist in the tenant and pool is NOT_FOUND. A first revocation publishes security.join-token.revoked.
- Kind: mutation
- Authorization:
compute:join-tokens:revoke@compute-pool - Module:
server - Phase: v0.1 (registered)
Input
| Field | Type | Required | Constraints |
|---|---|---|---|
tenantId | string | yes | at most 128 characters; matches ^[A-Za-z0-9._:-]{1,128}$ |
poolId | string | yes | at most 128 characters; matches ^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$ |
tokenId | string | yes | at most 64 characters; matches ^jt_[0-9a-hjkmnp-tv-z]{26,52}$ |
Better Compute is created by Sean Filimon
Last updated
joinRequests
Join requests are the approval queue for joins an attestor deferred: a machine with placeholder hardware identifiers, a machine the `discovery` attestor did not know, or a TPM whose endorsement key is on no allow-list. An approval admits exactly one join, which the machine's retry with the same CSR consumes. The group is decided on `compute-pool/{poolId}` with the join-token actions. See [Joining nodes](/docs/guides/nodes/joining).
metal
The metal group enrolls machines by their BMCs and moves them through the provision state machine: inspect, commission, deploy, rescue, release and retire. Each verb checks the move against the provision state table, records it in one transaction and queues the metal reconciler, which runs the workflow of the new state; no verb touches the machine itself. Every method returns the node's metal view, which reports whether BMC credentials are set but never returns them. See [Bare metal](/docs/guides/bare-metal) and [BMC drivers and credentials](/docs/guides/bare-metal/bmc).