On this page
Object authorization
The object API authorizes an action in two stages:
- the caller bearer selects one namespace policy;
- the object API verifier uses its own host-local Skarbiec grant to read the exact namespace credential items declared in
object_api.namespaces.
The probierz policy must grant every prefix in
queue::copy::CANONICAL_PREFIXES for get, put, list, stat and delete, because
that list is what the queue reads and writes. stado config validate, config set and host config set refuse a policy that leaves one out, naming it, and
stado doctor on the host fails object-auth with the same sentence. A prefix
the binary writes without a grant on the host makes the object API answer every
agent claim with 401 while the agent's capacity broadcast keeps saying the host
is alive, so the gap is refused when the policy is written rather than found
at run time.
The verifier bearer lives in WC_OBJECT_SKARBIEC_TOKEN_FILE on the object API host. To restore its grant without moving the bearer off that host:
stado repair stado --step object-verifier --target <target> --json
The command derives the item set from object_api.namespaces, asks Skarbiec on the target to bind the existing bearer to that exact set, and reports item names and expiry only. It never prints the bearer.
The verifier keeps each namespace's bearer with the version Skarbiec read it
under (the item, its item_uid and its revision) and asks Skarbiec, on every
object request, only for the item's current version
(POST /v1/items/revision, which decrypts nothing). The same version answers
from the kept bearer; a new one reads the bearer again. A rotated or replaced
namespace bearer is therefore refused on the next request, with no grace
window. A vault read that fails is a 503 object authorization unavailable;
no bearer kept from earlier stands in for it. The release publisher's bearer
is read on every request. The verifier grant needs only read of each item's
token: the revision route takes the same grant. A vault older than item
revisions answers no version, and the verifier refuses with the vault's answer names no item version, naming the Skarbiec release to install.
Release publication has a separate verifier and per-product policy set. Reconcile the verifier to the complete declared publisher set:
stado repair stado --step release-verifier --target <target> --json
The command compares the caller's release_api.publishers with the configuration
the target actually consumes and refuses before mutation when they differ. It
copies every controller-owned publisher item into the target-local shadows and
binds the existing verifier bearer to exactly their token reads, removing
capabilities for retired publishers without rotating or printing the bearer.
Release preflight proves the caller credential with an authenticated operation
under the same product prefix. A public releases/ stat proves neither boundary.
Use stado storage stat <stado-uri> --json as the smallest final check. present and absent are both authoritative answers. 503 object authorization unavailable means the verifier boundary failed; it is not evidence that the requested object is absent.
A publishing client's product declaration
A client publishing one product may set WC_RELEASE_API_PUBLISHERS to that
product's entry. This client behavior requires Stado 0.16.35 or newer:
WC_RELEASE_API_PUBLISHERS='{"wisent-backend":{"item":"wisent-backend-release-publisher","prefix":"wisent-backend/"}}' \
stado storage put stado://releases/wisent-backend/api/sha256/<digest>.tar.gz \
<archive> --if-absent --content-type application/gzip
By default the client reads the selected item's token field with its configured
Skarbiec consumer and grant file. An isolated publisher that already holds that
product's bearer may instead set STADO_RELEASE_PUBLISHER_TOKEN_FILE to an
owner-only file containing the bearer alone, without a trailing newline. The
server still verifies it against the selected product's publisher item.
An unreadable, empty or malformed explicit file fails by name without falling
back to another credential. STADO_API_TOKEN remains the generic object
credential and is not substituted for a release publisher.
Unrelated products need not appear in this client's environment, and an
undeclared product still fails with release_api.publishers declares no publisher for <key>.
Invalid JSON or a malformed entry instead reports release_api.publishers is invalid: followed by the actual configuration errors. Fix that declaration;
repeating the upload does not repair it. The serving release API and stado config validate still require their complete active-publisher table. This client
override does not change server authorization or reconcile the server's grants.
The object API is the host Stado process
The object API is not a unit of its own. It is served by the one Stado
process on the host, the unit com.wisent.stado, which runs
$HOME/.stado/bin/stado, the managed binary every roll moves. So
stado release version declare --host <host> --binary stado --version <v> followed by
stado release version converge --host <host> --binary stado moves the object API
with the rest of Stado, and the deploy-control-plane job needs no step of
its own for it.
A host that still runs the object API under its former label hands it over:
when the init system starts stado serve --api as
com.wisent.stado, the process retires that predecessor before it binds,
provided it serves the same storage root, and logs
[stado] predecessor UNIT: STATE (DETAIL). stado release catalog declare-publisher --reload HOST=UNIT refuses any unit other than the host
Stado process, because only that process serves the release API.
A unit's declared program must exist in the incoming archive.
stado service update --from-archive checks the archive's member list and
refuses a mismatch before relinking current, naming the declared program
and available members. A successful extraction alone cannot prove that
launchd can execute the installed program.
stado service update --from-archive and --rollback-to resolve the host,
its SSH destination and the unit from the registry this machine already
holds, never from the registry authority's snapshot: they are how the
services that snapshot is served through (the vault, the resolver) are
repaired while it stands unanswered. With a store on this disk that store is
read; otherwise the last-known-good copy, announced on stderr as installing onto <host> from this machine's record from the last-known-good registry copy from <age>s ago (<path>, read_at <time>, generation <g>), without asking the registry authority. With no copy the command refuses: a local install resolves <host> without the registry authority, and this machine holds no registry to resolve it from: no registry document at <path>; any registry
read that reaches the authority writes that copy. The channel key for the
vault's own host is chosen from the same copy. --from-artifact reads the
fleet's store and asks the authority as every fleet command does.
When the service's catalog installation recipe declares state through Stado
after install (Brama's brama maintain schedule pinned to its host),
stado service update declares it too, for the host it updated, under the id
stado product install derives for that installation, so where it already
stands nothing changes. --json reports each step under declarations
({"argv", "ran"}; null when the recipe declares nothing). A declaration
that fails ends the update with <host>: <service> was updated, and the state its installation recipe declares could not be declared: <cause>, naming
stado repair <service> --step declarations --target <host> --apply, which
declares it on its own.
Reading a slow object API
Each stado serve component runs on its own thread with a single-threaded
runtime, so the object API serves every connection on one thread,
interleaved where a route waits: a route that holds the thread holds every
request behind it.
Each request it answers is logged with the time its route took:
[dashboard] "<method> <path> HTTP/1.1" <status> - <milliseconds> ms, in the
host Stado unit's log (stado service logs com.wisent.stado --host <host> --lines <n>). A client waiting on it sees the same stall from its side in
stado resolver status: the stado-object-api connections the resolver
still holds unanswered, each with the seconds it has waited.
A read of one object asks the store for that object's own metadata by listing its exact path. On a local store that listing walks only the entries of the object's directory whose name begins with the object's name, never the rest of its namespace, so one read costs that object alone, and every listing walks on the runtime's blocking pool rather than on the thread that serves requests.
Source: this website