Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Attributes

Audience: operators who need to know which host directories a deployment reads principal.* and account.* out of — and how fast a revocation lands.

An attribute slot is a host directory: the user table, the service-account registry, the tenant catalogue. There are exactly three — user, machine, and account — and each caches the bags it has fetched, with its own ttl: and max_size:. See Providers for the seam itself and Seed & portability for the YAML that wires it.

aperture attributes <slots|query|invalidate>

All three read through the same wiring builder every other command uses, so the slots a listing reports are the slots a decision resolves through: the CLI cannot describe a wiring it does not itself run. All three therefore take --seed (and --store) exactly as check does.

SubcommandTierWhat it does
attributes slotsnoneone row per slot: source, ttl, max-size, and how many bags this process has cached
attributes query <slot>system-admina page of that slot's directory as [{id, attributes}], narrowed by attribute predicates
attributes invalidate <slot>system-admindrop cached bags so the next decision re-reads them

The cache window is a security property

Object metadata going stale for a TTL is usually tolerable — a document's category is a fact about a thing. An attribute bag is the asker's standing: the clearance, the department, the plan. Until a cached bag expires, every decision about that subject keeps evaluating against access the host may have already taken away, so a revocation that takes effect ttl: later is a revocation that has not happened yet.

That is the frame for both of the interesting columns below and for the whole of invalidate: pick a slot's ttl: for how fast its revocations must land, read back what the deployment is actually running, and close the window explicitly when you cannot wait.

slots — what is wired, and how stale it may be

bin/aperture attributes slots --seed ./seed.yaml
slot     source  ttl    max-size  cached
user     sql     1m0s   10000     12
machine  csv     30s    10000     0
account  inline  never  10000     3

(An unwired slot renders as (unwired) with - in the three columns that describe a cache it does not have.)

  • source is where that slot's bags come from: csv or sql (an attribute_providers: entry), inline (the attributes: block), (host) for a registry a host wired in Go rather than from the seed, and (unwired) for a slot this deployment declares no source for. An unwired slot is not an error: every decision for it resolves the floor bag and proceeds.
  • ttl is the revocation window. never means a fetched bag is dropped only by eviction or by an explicit invalidate — correct for a fixed inline block, dangerous for a live directory.
  • cached counts this process. A one-shot invocation starts cold and reads 0; it is the number that matters in a long-running serve.

slots needs no actor. It discloses nothing the caller did not already supply: it reads the seed file named on the command line plus the cache configuration this process built from it, contacts no provider, names no key, and prints no bag. Requiring system-admin authority to read back a file you just passed in would only mean nobody could diagnose "is the user slot even wired?" without already holding the authority the diagnosis exists to explain.

When a seed declares one slot in both attribute_providers: and attributes:, every command that builds the stack prints a warning naming the affected slots — the external entry wins and the inline bags for that slot are discarded entirely. Only slot names are named, never keys.

query — read a directory (system-admin)

bin/aperture attributes query user \
  --principal alice --account acme \
  --field department=eng --fields-json '{"clearance":3}' --limit 100

Prints a JSON array of {id, attributes}.

Unfiltered, this returns the head of the host's user table — keys and bags together — so it is a system-tier read: --principal must hold system-admin authority in --account. A refusal returns nothing: no partial page, no count, and no way to tell an empty slot from a full one or from an unwired one. That is deliberate — the authority check runs before the slot name is even parsed, so a refused caller cannot use the error to probe which directories a deployment wires. If a refusal is unexpected, ask aperture explain about your own authority.

--field and --fields-json narrow by attribute, on exactly the predicate aperture enumerate applies to object metadata: predicates are ANDed, a field the bag does not carry never matches, a list-valued field matches by membership, and everything else matches by typed equality, so the string "5" never matches the number 5. --field always sends a string; reach for --fields-json when a number, bool, or list is genuinely meant. Given both, --fields-json is merged first and --field entries override it by key.

A slot whose attribute_providers: entry declares no get_all: is fetch-only by design — it answers the decision path without exposing the whole table to an enumeration — and query reports that provider's coded refusal rather than an empty page.

invalidate — close the window now (system-admin)

bin/aperture attributes invalidate user --id alice --principal root --account acme
bin/aperture attributes invalidate user --principal root --account acme
bin/aperture attributes invalidate --all --principal root --account acme

The three forms — one subject, one slot, everything — are mutually exclusive, and a conflict is refused rather than resolved by precedence: "--all plus a slot" has two plausible readings, and guessing the broader one would clear caches the operator did not ask to clear.

"Nothing was cached" is reported, not silently succeeded (no cached user bag for "alice"): an operator invalidating a subject they believe is cached wants to know their key did not match. Note that --id takes the bare subject id — alice, never user:alice.

It is gated for the same reason query is, even though it writes nothing and discloses no bag: the result says whether this process had that key cached, which is a fact about who has recently been decided about, and clearing a large slot costs the next wave of decisions a provider round-trip each. invalidate --all names no slot, so it cannot be used to probe which exist.

Invalidation is process-local. It clears the caches of the process that runs it. That makes it exact for a host embedding Aperture, and self-contained for a one-shot CLI invocation (which starts cold and exits cold) — but it cannot reach a running aperture serve. The controls that reach that process's cache are the slot's ttl: and a restart.

Full flags: attributes.

  • Global options--principal / --account / --seed / --store.
  • Providers — the attribute seam, its leniency contract, and why enumerating a slot can never be scope resolution.
  • Seed & portability — the attributes: and attribute_providers: blocks these commands report on.
  • Rules engine — what a rule reads when a slot answers nothing.
  • Command-Line Reference — the generated flag tables.