Watch
0
0
Fork
You've already forked hyperhive
0
hyperhive/docs/2-handbook/swarm/credentials.md
iris 0e99662710 docs: the swarm README and credentials page keep the overview, the rest moves to its own pages
The hive directory and the WireGuard mesh become handbook pages of their own,
the controller's mint-failure handling moves to controller.md, and the
credential-by-credential mechanics and the secret store UI's proxy move to a new
implementation page.
2026-11-14 13:33:50 +01:00

91 lines
5.3 KiB
Markdown

# Credentials
The swarm's credential store is bao. This page is the overview of how the swarm
treats credentials; [`credentials-reference.md`](../../4-implementation/swarm/credentials-reference.md)
lists each one: who mints it, who reads it, and how it renews, with the notes for
operating them, and [`credentials.md`](../../4-implementation/swarm/credentials.md)
holds the store's mechanics.
**Store secrets stay off disk.** A process pulls a value from the store at
runtime and holds it in memory only.
**The mTLS client certificate is the only credential on disk.** Each
identity (an agent, a hive, a swarm-level service) has one. It's what logs a
principal in to the store, so you place a hive's or service's certificate by
hand. The nix option for it takes a path to the certificate, never its bytes,
because a literal in a nix expression lands in the world-readable nix store.
A hive hands each agent its certificate; the agent pulls everything else
itself.
**Each credential has a minter, a reader and a renewal story.** Who mints it, who
reads it, and whether it renews without an operator are what the
[reference table](../../4-implementation/swarm/credentials-reference.md) gives for every credential, with the
operating notes that go with them.
## Where a secret lives
A swarm generates its credentials in three different places and reads them
in a fourth, so "where does this file go" has a different answer per deployment.
This page is that answer, one row per secret.
Two rules run through all of it.
**Private key material and access tokens are paths, never values.** Every option
carrying one takes a file path (`*File`), because a literal written into a nix
expression ends up in the nix store — world-readable and permanent. No
option in this tree accepts one inline, and adding one would be a leak rather
than a convenience.
The rule is about what must stay secret, not about credentials generally.
**Public material is a value**: a certificate, or a public nkey like
the queue callout's user key, reaches every client that connects,
so the store is a perfectly good place for it.
**The generator and the reader typically live in different containers.** They share
the host's network namespace, which makes them feel co-located, but their
filesystem roots are separate. That's why delivery is a **host-side copy rather
than a bind mount**: `nixos-container` refuses to start when a bind source is
missing, and a secret minted on another container's first boot doesn't exist
yet. Binding it would make one container wait on a file that waits on a
container that starts after it.
### Topologies, by who places secrets
Read every row of the [reference tables](../../4-implementation/swarm/credentials-reference.md#where-each-secret-lives-on-disk) against one of these. This is a different cut
from the [deployment shapes](services.md#deployment-shapes) --- those
say _where services run_, these say _who is responsible for a secret
file being there_ --- the two lists don't line up one-to-one, and
neither is a renaming of the other.
| topology | what it means | who places secrets |
| ------------------ | ---------------------------------------------------------- | -------------------------------------------------------------------------- |
| **all-local** | one host runs the swarm's shared services and its own hive | nobody — the reader itself generates each secret, or a host unit copies it |
| **swarm-managed** | the swarm's services run on a host with `swarmctl` | `swarmctl` writes what it owns; the rest is still generated in place |
| **hive elsewhere** | a hive that federates with a swarm it doesn't host | the operator provides the file and names it in config |
## Swarm-level and hive-level secrets
Swarm-level secrets belong to a swarm service (authelia's keys and client
secrets, the collectors' and Grafana's OIDC secrets, the forge and queue
credentials); hive-level ones belong to a hive and its agents. Each has a unit
that mints or copies it and a reader that holds it only in memory. Which unit,
where the value lands and what a missing identity costs, secret by secret:
[how each credential reaches its reader](../../4-implementation/swarm/credential-delivery.md).
## The browser UI
OpenBao's built-in web UI is at `https://bao-ui.<swarm domain>/`
(`swarm.bao.ui.domain`), for members of authelia's `admins` group only. Log in
with the **OIDC** tab, or with a bao token under **Other**. ⚠️ The UI's
listener asks for **no client certificate**, because a browser has none to
present, so on this one door a bao token is the whole credential: anything on
the store's host that can dial loopback, and any `admins` session through the
vhost, needs only a token to use the API. Unseal from the host's `bao` CLI;
the UI's unseal form gets a 403. The proxy:
[the secret store browser UI](../../4-implementation/swarm/credential-delivery.md#the-secret-store-browser-ui).
## Adding a secret
State three things, in the row you add to the [reference](../../4-implementation/swarm/credentials-reference.md#where-each-secret-lives-on-disk): **who mints it**, **which
container reads it**, and **what happens when they differ**. If they differ, it
needs a delivery unit, and the unit copies — it doesn't bind.