On this page

Grant

How does a Stado process get a credential, and why does none of them have a cloud login? A grant is a narrow Skarbiec consumer identity: Skarbiec owns the credentials, and each Stado process consumes exactly the items its grant names.

What it is

Skarbiec is the separate credential service, reached over loopback HTTP or a TLS-protected remote endpoint, enforcing scoped consumer grants (stado-rs/src/skarbiec/mod.rs). A grant is a consumer name plus an opaque token in an owner-only file; a token file readable by group or other users, or empty, is refused before any request is made.

Grants are deliberately plural and narrow. Each verifier is an auth boundary: it enforces its exact consumer name and a token file distinct from every other grant, and it never routes through the credential-store selector (stado-rs/src/skarbiec/verifiers/api.rs):

Consumer Scope
stado-control-plane The coordinator's default consumer, with its owner-only grant file (cli).
stado-host-health-beacon The beacon publisher: resolves only stado-host-health-api/token, nothing else (operations).
object-api verifier Namespace-scoped product object bearers only; its token file must be distinct from the coordinator grant, enforced at construction.
release-signing reader One capability: read:stado-release-signing#private_key. Signing material is the last thing that should travel on a broad grant.
alert key reader The one credential the alert path needs. Paging is the last thing that should need a broad grant.

The narrowness is load-bearing: when release submit read the signing key through the coordinator grant, the vault refused with 403 consumer not authorized to read item field — the policy was right and the caller was reaching for the wrong identity (stado-rs/src/skarbiec/verifiers/api.rs).

Secrets stay where they are minted. When a managed service's bearer is synced from a Skarbiec item, the item is read on the host by the host's own Stado identity, so the value never travels on the operator's channel and the operator's consumer needs no grant for it (stado-rs/src/deploy/service.rs::sync_service_item_secret).

Who declares it

The fleet provisions least-privilege consumers in Skarbiec and configuration names them — only non-secret routing metadata is checked in (configuration): the Skarbiec origin, the exact consumer name, and the path of the owner-only token file (STADO_HOST_HEALTH_SKARBIEC_URL / _CONSUMER / _TOKEN_FILE for the beacon publisher). A workload-agent grant contains only the provider-neutral application items in agent.skarbiec.items; it must never contain stado-gcp, stado-azure, or stado-aws, and such a grant fails configuration validation (configuration).

One deliberate exception: a backend's own bootstrap credential stays outside the store, because putting the grant needed to unlock a manager inside that same manager would be circular (configuration).

Who observes it

stado host inventory reports the Skarbiec vault files under $HOME/.stado as metadata only — name, size, mode, owner-only — and never opens a vault: not to read a byte of ciphertext, not to count items. That is a boundary, not an oversight (cli). A missing, unreadable, or over-broad grant on the beacon path leaves the prior beacon untouched and returns failure (operations).

Where it lives

Owner-only token files on the consuming host, for example ~/.stado/host-health-beacon-skarbiec-token and ~/.stado/control-plane-skarbiec-token. Non-secret routing lives in /etc/stado/host-health.env on Linux and the launchd template on macOS (operations).

Commands

stado secrets ls
stado host publish-beacon FILE
stado host inventory <registry-target>

All stado secrets CRUD, provider reads, and scoped verifier reads use the selected credential store (configuration); flag detail lives in cli.

Keep a minted verifier bearer on its consuming host

Stado 0.16.33 adds a persistent destination to host vault-token-mint:

stado host vault-token-mint charless-mac-mini stado-registry-api-verifier \
  --capabilities read:stado-desktop-registry-api#token \
  --audience skarbiec \
  --token-file-name stado-registry-api-verifier-skarbiec-token --json

The command creates ~/.stado/NAME on the selected host with mode 0600 when it is absent, then asks that host's Skarbiec to mint the grant using that exact file. An existing file keeps its bearer. Skarbiec still controls the capabilities, audience and expiry; changing capabilities still requires --replace-capabilities. The response contains the file path and grant metadata, not the bearer.

An invalid basename, symlink, empty file or non-regular destination is refused. --token-file-name cannot be combined with --raw-token or --token-item. If Skarbiec refuses the mint, the file remains in place for a retry rather than being replaced with another value.

In Desktop, open Hosts → Vault bearer → Mint a new bearer and fill Keep bearer on this host with that basename. The review shows the exact command and explains whether the file will be created or reused. The returned receipt displays Bearer file on host; refusal details stay in the same sheet. Keeping a file and revealing a generated bearer are distinct modes.

The registry verifier file is not the Desktop client token. The verifier reads the separate stado-desktop-registry-api/token item, and registry_api.clients.stado-desktop assigns that client its permitted actions. Desktop binds the client file to its exact API endpoint.

Not to be confused with

  • An ambient cloud credential. There is no cloud CLI, provider SDK, direct bucket URL, ambient credential, or cross-backend fallback in the beacon writer, and no bootstrap, health, recovery, or release path invokes gcloud, gsutil, or az (operations, configuration). Provider access belongs to the enabled adapter's exact plugin identity, never to a grant.
  • A Skarbiec item. The item is the credential; the grant is the scoped permission to read named item fields. Rotating one does not rotate the other.
  • A fleet channel key. Host channels use fleet-held ed25519 keys managed by stado fleet key; a grant opens Skarbiec, not a host (cli). See security for the whole boundary.

Source: this website