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.
| Subcommand | Tier | What it does |
|---|---|---|
attributes slots | none | one row per slot: source, ttl, max-size, and how many bags this process has cached |
attributes query <slot> | system-admin | a page of that slot's directory as [{id, attributes}], narrowed by attribute predicates |
attributes invalidate <slot> | system-admin | drop 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.)
sourceis where that slot's bags come from:csvorsql(anattribute_providers:entry),inline(theattributes: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.ttlis the revocation window.nevermeans a fetched bag is dropped only by eviction or by an explicitinvalidate— correct for a fixed inline block, dangerous for a live directory.cachedcounts this process. A one-shot invocation starts cold and reads0; it is the number that matters in a long-runningserve.
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.
Related
- 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:andattribute_providers:blocks these commands report on. - Rules engine — what a rule reads when a slot answers nothing.
- Command-Line Reference — the generated flag tables.