spotlight_workspace_token_trust

The spotlight_workspace_token_trust resource, and the API's workspace-token-trust kind: a trust that lets a CI workload exchange the OIDC token its platform issues for a short-lived workspace token.

KindEndpointTerraformAddress
workspace-token-trust/api/resources/workspaces/{workspaceId}/token-trustsspotlight_workspace_token_trust<key>

See Resource API for the operations, headers and errors every kind shares.

Example

resource "spotlight_workspace_token_trust" "github_main" {
  workspace_id = spotlight_workspace.acme.id
  key          = "github-main"
  issuer       = "https://token.actions.githubusercontent.com"
  subject      = "repo:acme/platform:ref:refs/heads/main"
  claims = {
    repository_owner = "acme"
  }
  scopes           = ["configure", "secrets"]
  lifetime_minutes = 15
}

Fields

FieldTypeDefaultDescription
keystringrequiredLowercase words joined by dashes, at most 64 characters. Fixed: an update that changes it is refused; Terraform replaces the resource.
issuerstringrequiredThe issuer the workload's token must name in iss. https, or http only for localhost, 127.0.0.1 or [::1]. No query, fragment or credentials. At most 255 characters.
audiencestringspotlightA value the token's aud must hold. One word, at most 255 characters.
subjectstringrequiredA pattern the token's sub must match. See patterns.
claimsmap of name to string{}Further claims the token must carry, each matching its pattern. At most 16. See patterns.
scopesarray of stringsrequiredThe scopes of every token the trust mints, as for a workspace token.
lifetimeMinutesinteger151 to 60. How long a minted token admits its bearer.
definedBystringread-onlyThe person who defined the trust, or who issued the token that defined it.

Patterns

subject and each value of claims is one word of at most 255 characters, with no whitespace. * stands for any run of characters, colons included.

A subject with a * must name its owner before the first *: the text before it must contain /.

subjectAccepted
repo:acme/platform:ref:refs/heads/mainyes
repo:acme/platform:*yes
repo:acme/*yes
repo:*no
*no

A refused subject reads must name an owner before any *, as in repo:acme/* or repo:acme/platform:*.

Claim names are lowercase letters, digits and _, starting with a letter, at most 64 characters. iss, sub, aud, exp, nbf, iat and jti may not be named. Only claims whose value is a string can match.

Platform subjects

PlatformIssuersub
GitHub Actions, pull requesthttps://token.actions.githubusercontent.comrepo:<owner>/<repository>:pull_request
GitHub Actions, pushhttps://token.actions.githubusercontent.comrepo:<owner>/<repository>:ref:refs/heads/<branch>
GitHub Actions, environmenthttps://token.actions.githubusercontent.comrepo:<owner>/<repository>:environment:<name>
GitLab CI/CDhttps://gitlab.com, or the instance's addressset by the platform
CircleCIhttps://oidc.circleci.com/org/<organization id>set by the platform
Buildkitehttps://agent.buildkite.comset by the platform

Who may define a trust

Writing a trust needs the manage-token-trusts permission. See Roles and permissions.

A token may define a trust only with scopes it holds itself, may change a trust only when it holds both the trust's current scopes and the new ones, and may delete a trust only when it holds the trust's current scopes. Otherwise the write or delete is refused with 403, as for a caller without manage-token-trusts. See Permission titles. A person who is an owner or admin is not limited this way.

Exchange

POST /api/workspace-tokens/exchange

Needs no credentials. Takes an optional Spotlight-Client header.

FieldTypeDescription
truststringThe trust's id.
tokenstringThe OIDC token the platform issued the workload.

Workload token verification

The workload's token is verified against the keys the issuer publishes at <issuer>/.well-known/openid-configuration. It must be signed with RS256, RS384, RS512, ES256, ES384 or PS256, carry sub and exp, and be current within 30 seconds. A runner trust verifies a host's token the same way.

A 200 response:

FieldTypeDescription
tokenstringThe workspace token, sent as Authorization: Bearer <token>.
tokenIdstringIts id.
workspaceIdstringThe workspace it acts in.
scopesarray of stringsThe trust's scopes.
expiresAtstringAfter this RFC 3339 time it admits nobody.

Every refusal is 401 with Spotlight refused the exchange. Possible causes: an unknown trust, a token its issuer did not sign for the trust's audience, a workload the trust does not admit, or a closed workspace.

Each exchange is recorded as a configuration change: a created workspace token, with the trust, the subject, the scopes and the expiry.

Minted tokens

  • A minted token acts for the trust's definedBy, within the trust's scopes.
  • It is not listed among the workspace's tokens.
  • Any change to the trust's terms stops every token minted before the change.
  • Deleting the trust stops every token it minted, from that moment.

On this page