Capabilities

Machine identity

Service accounts with rotating secrets, snt_ API keys capped by the owner's live permissions, and workload identity federation that swaps GitHub Actions or Kubernetes OIDC tokens for Sentinel tokens — secretless CI/CD.

Machines outnumber humans in most production systems, and their credentials outlive most laptops. Sentinel gives machine identity the same first-class treatment as human identity: three principal shapes, one authorization engine, and a way to stop shipping long-lived secrets to CI at all.

Service accounts

Client-credentials principals (ServiceAccount): a key, a display name, an optional organization scope, and a hashed secret (sns_… prefix) with rotation and an overlap window — the previous secret keeps verifying until its expiry so a fleet redeploy never races a credential rollout. Managed by MachineAuthService (CreateServiceAccountAsync, RotateServiceAccountSecretAsync, VerifyServiceAccountSecretAsync), and consumable directly through the OIDC client_credentials grant — a service account is an OAuth client where that’s convenient. Rejected secrets emit service_account.secret_rejected; you find out about brute-forcing, not just about lockouts.

API keys

API keys are Sentinel’s personal-access-token shape, and they inherit the two best ideas from the Node-era design:

  1. Effective permissions = owner’s current snapshot ∩ key scopes, denies preserved, recomputed at use time. A key is never more powerful than its owner is right now. Demote the owner and every key they minted shrinks in the same instant; a deny on the owner rides through the intersection untouched.
  2. The credential is the subject; the human is the attribution. The request context separates SubjectId (the key, for authorization) from OwnerUserId (the person, for audit). “Which credential did this?” and “who answers for it?” get different, correct answers.

Mechanically: snt_ + 43 base64url chars (256 bits of entropy), SHA-256 at rest, plaintext shown exactly once at creation, a 12-char display prefix for recognition in lists. Presentation is just a header — Authorization: Bearer snt_… or a bare Authorization: snt_… — handled by the same SentinelAuthenticationHandler that does JWTs and cookies; the resulting SentinelPrincipal has Kind = ApiKey.

Management HTTP endpoints for keys and service accounts are a later deliverable this wave — today keys are minted via MachineAuthService from your own admin surface, and the HTTP tests exercise exactly that path.

Workload identity federation

The best machine secret is none. Workload federation exchanges the OIDC tokens that platforms already issue — GitHub Actions job tokens, Kubernetes service-account tokens, cloud managed identities — for short-lived Sentinel access tokens:

POST /oidc/workload/token
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&subject_token=eyJ…            # the external platform's OIDC token
&subject_token_type=urn:ietf:params:oauth:token-type:jwt
&audience=example-api

A trust configuration decides who may exchange: issuer, JWKS (or discovery), audience, a subject pattern with a single-* wildcard, and additional claim rules. GitHub Actions, for example:

workloadTrusts:
  - serviceAccount: ci-deployer
    issuer: https://token.actions.githubusercontent.com
    audience: sentinel
    subjectPattern: "repo:nuvoralabs/*"
    claimRules:
      - claim: ref
        value: refs/heads/main

The exchanged token is minted for the trust’s service account, carries a wtrust claim naming the trust that authorized it, and comes with no refresh token — workloads re-exchange, they don’t hold long-lived credentials. Denials return a uniform error to the caller while the audit event (workload.exchange_denied) records the precise reason: unknown_issuer, subject_mismatch, claim_mismatch:ref, and friends. The HTTP test Github_style_token_exchanges_for_a_working_sentinel_access_token runs this loop end to end.

Result: CI/CD with zero stored Sentinel secrets — revoke a trust, and a compromised pipeline has nothing.

The system principal

Background jobs get a first-class system principal type for attribution instead of borrowing a human’s identity or running as an anonymous nobody — audit entries record ActorKind (User, ServiceAccount, ApiKey, System, BreakGlass) so “who did this?” always has an answer, even at 3 a.m. from a queue worker.

Learn by building

Article 007 — Workload identity federation configures a GitHub-style trust and exchanges a real signed token against a test host. For the audit trail these principals leave, see operations.

Learn by building

The tutorials for this area, in order — each with a runnable sample.