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.
5.3 KiB
Credentials
The swarm's credential store is bao. This page is the overview of how the swarm
treats credentials; 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
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 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 against one of these. This is a different cut from the 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.
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.
Adding a secret
State three things, in the row you add to the reference: 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.