docs: clear write-good.Passive hits in swarm secrets/README docs
Part of #4548 — third batch. This PR: docs/swarm/secrets.md (16 hits), docs/swarm/README.md (15 hits) = 31 more of the 353 (130 total across the three PRs so far). Same method as #4551/#4553: minimal, meaning-preserving active-voice rewrites, no restructuring beyond what each flagged sentence needed, no vale-off silencing. Genuine false positives left in place: predicate-adjective state descriptions ("is required" x4, "is enabled", "is disabled"), one systemd terminology reference ("is wanted (not required)" — literally naming systemd's Wants=/Requires= dependency-type distinction, not passive voice), and one design-intent idiom ("both are expected" — same shape as earlier docs-lint work).
This commit is contained in:
parent
18c5b5c5ad
commit
c985702bb0
2 changed files with 55 additions and 55 deletions
|
|
@ -18,7 +18,7 @@ build .#docs-swarm` / `.#docs-deploy` or the website's `/options/swarm.html`
|
||||||
own `services.hyperhive.domain` DNS name and its own set of agent
|
own `services.hyperhive.domain` DNS name and its own set of agent
|
||||||
containers.
|
containers.
|
||||||
- **swarm** — one or more hives whose operators have declared them
|
- **swarm** — one or more hives whose operators have declared them
|
||||||
as peers. Agents can be qualified as `agent@hive-domain`.
|
as peers. You can qualify an agent as `agent@hive-domain`.
|
||||||
- **peer hive** — any hive in `services.hyperhive.swarm.hives` other
|
- **peer hive** — any hive in `services.hyperhive.swarm.hives` other
|
||||||
than this one. Peers are _derived_, not declared: the directory lists
|
than this one. Peers are _derived_, not declared: the directory lists
|
||||||
every hive including yourself, and `hiveName` says which one you are.
|
every hive including yourself, and `hiveName` says which one you are.
|
||||||
|
|
@ -134,7 +134,7 @@ because `services.hyperhive.hiveName` says which entry is itself.
|
||||||
Empty (the default) means this host isn't in a swarm. Once non-empty it
|
Empty (the default) means this host isn't in a swarm. Once non-empty it
|
||||||
**must** contain an entry for `hiveName`; eval fails naming the missing
|
**must** contain an entry for `hiveName`; eval fails naming the missing
|
||||||
hive. That assertion is load-bearing rather than pedantic — "my peers"
|
hive. That assertion is load-bearing rather than pedantic — "my peers"
|
||||||
is derived as _everything that isn't me_, so a directory that doesn't
|
comes from _everything that isn't me_, so a directory that doesn't
|
||||||
contain you derives every hive as a peer and you peer with yourself.
|
contain you derives every hive as a peer and you peer with yourself.
|
||||||
|
|
||||||
`domain` defaults to `<name>.<swarm.domain>`, the convention every hive
|
`domain` defaults to `<name>.<swarm.domain>`, the convention every hive
|
||||||
|
|
@ -161,7 +161,7 @@ addressed by something else.
|
||||||
directory and serves it at `GET /api/hives`; `swarm-ui`'s overview
|
directory and serves it at `GET /api/hives`; `swarm-ui`'s overview
|
||||||
page renders it (`docs/swarm/ui.md`). This is the operator-facing
|
page renders it (`docs/swarm/ui.md`). This is the operator-facing
|
||||||
"what hives exist" surface — a per-hive dashboard "peer hives"
|
"what hives exist" surface — a per-hive dashboard "peer hives"
|
||||||
display existed here once and was removed in favour of it.
|
display existed here once; it no longer exists, in favour of this.
|
||||||
|
|
||||||
2. **Matrix federation** — when `matrix.enable` is on, tuwunel
|
2. **Matrix federation** — when `matrix.enable` is on, tuwunel
|
||||||
federates with the peer's matrix server (discovered via the peer's
|
federates with the peer's matrix server (discovered via the peer's
|
||||||
|
|
@ -170,12 +170,12 @@ addressed by something else.
|
||||||
**container's** trust bundle, independent of this directory.
|
**container's** trust bundle, independent of this directory.
|
||||||
|
|
||||||
⚠️ **That container currently trusts no swarm-internal CA**, so a
|
⚠️ **That container currently trusts no swarm-internal CA**, so a
|
||||||
self-signed gateway certificate doesn't federate. The swarm root
|
self-signed gateway certificate doesn't federate. You can't list the
|
||||||
can't be listed there: `security.pki.certificateFiles` is
|
swarm root there: `security.pki.certificateFiles` is
|
||||||
read when the system is _built_, and the root is a runtime file (its
|
read when the system is _built_, and the root is a runtime file (its
|
||||||
key must never enter the store), so there is no build-time name for
|
key must never enter the store), so there is no build-time name for
|
||||||
it. Bridging that needs a runtime mechanism and is tracked as its own
|
it. Bridging that needs a runtime mechanism; a separate issue tracks
|
||||||
issue. Until then, federation needs CA-issued certs (ACME). See
|
it. Until then, federation needs CA-issued certs (ACME). See
|
||||||
`docs/integrations/matrix.md` for federation firewall + TLS requirements.
|
`docs/integrations/matrix.md` for federation firewall + TLS requirements.
|
||||||
|
|
||||||
3. **WireGuard mesh** (optional) — `deploy.wireguard.enable` reads each
|
3. **WireGuard mesh** (optional) — `deploy.wireguard.enable` reads each
|
||||||
|
|
@ -281,7 +281,7 @@ is required. Out of scope for v0.
|
||||||
|
|
||||||
## Snapshot store
|
## Snapshot store
|
||||||
|
|
||||||
One further option lives in this namespace but is documented with the
|
One further option lives in this namespace but its docs live with the
|
||||||
service it points at: `services.hyperhive.swarm.snapshotStore.{address,
|
service it points at: `services.hyperhive.swarm.snapshotStore.{address,
|
||||||
port}` tells this hive where the swarm's `btrfs receive` endpoint is, so
|
port}` tells this hive where the swarm's `btrfs receive` endpoint is, so
|
||||||
`hivectl agent <name> subvol snapshot push` has somewhere to stream to.
|
`hivectl agent <name> subvol snapshot push` has somewhere to stream to.
|
||||||
|
|
@ -296,8 +296,8 @@ migrating agent keeps one unbroken incremental chain. See
|
||||||
`services.hyperhive.deploy.swarm-controller.enable` runs the `swarm-controller`
|
`services.hyperhive.deploy.swarm-controller.enable` runs the `swarm-controller`
|
||||||
daemon on this host. **Off by default and deliberately not derived from
|
daemon on this host. **Off by default and deliberately not derived from
|
||||||
`services.hyperhive.enable`**: a swarm has one controller, so enabling it
|
`services.hyperhive.enable`**: a swarm has one controller, so enabling it
|
||||||
is a statement about swarm topology, not about whether hyperhive is
|
is a statement about swarm topology, not about whether the operator has
|
||||||
installed. Every hive runs `hive-c0re` (the agents on that host); one
|
installed hyperhive. Every hive runs `hive-c0re` (the agents on that host); one
|
||||||
hive additionally runs this (what's true across hives).
|
hive additionally runs this (what's true across hives).
|
||||||
|
|
||||||
What it serves, why it's a unix socket rather than a port, and the
|
What it serves, why it's a unix socket rather than a port, and the
|
||||||
|
|
@ -380,8 +380,8 @@ with the credential itself and aren't configurable.
|
||||||
|
|
||||||
On a host that runs the queue, `agentNatsUrl` defaults to
|
On a host that runs the queue, `agentNatsUrl` defaults to
|
||||||
`nats://<network.bridgeIp>:<swarm.nats.port>`, which is the only address that
|
`nats://<network.bridgeIp>:<swarm.nats.port>`, which is the only address that
|
||||||
works from inside a container: the port is opened on the bridge interface and
|
works from inside a container: the firewall opens the port on the bridge
|
||||||
nowhere else. ⚠️ **Never a loopback address here** — the hive's own
|
interface and nowhere else. ⚠️ **Never a loopback address here** — the hive's own
|
||||||
`statusPublish.natsUrl` is loopback and correct, because `hive-c0re` shares the
|
`statusPublish.natsUrl` is loopback and correct, because `hive-c0re` shares the
|
||||||
host's network namespace. An agent doesn't, so `127.0.0.1` reaches the agent.
|
host's network namespace. An agent doesn't, so `127.0.0.1` reaches the agent.
|
||||||
|
|
||||||
|
|
@ -391,7 +391,7 @@ above, plus `HIVE_AGENT_OIDC_CLIENT_SECRET_FILE` and
|
||||||
`HIVE_AGENT_OIDC_CLIENT_ID_FILE`, which point into the unit's own credentials
|
`HIVE_AGENT_OIDC_CLIENT_ID_FILE`, which point into the unit's own credentials
|
||||||
directory. The last two come from the delivered credential rather than from
|
directory. The last two come from the delivered credential rather than from
|
||||||
config — see [`secrets.md`](secrets.md#hive-level--one-of-each-per-hive) for
|
config — see [`secrets.md`](secrets.md#hive-level--one-of-each-per-hive) for
|
||||||
how it gets there. A hive that hasn't been given the queue's address for its
|
how it gets there. A hive lacking the queue's address for its
|
||||||
agents sets none of the four and each agent logs that it has none; a half-set
|
agents sets none of the four and each agent logs that it has none; a half-set
|
||||||
environment logs an error and the harness keeps serving.
|
environment logs an error and the harness keeps serving.
|
||||||
|
|
||||||
|
|
@ -404,10 +404,10 @@ agent talks about itself here and reads nothing. Rows aren't retained — a
|
||||||
subscriber that wasn't listening missed them, the same as on the agent's own
|
subscriber that wasn't listening missed them, the same as on the agent's own
|
||||||
live stream.
|
live stream.
|
||||||
|
|
||||||
A row too large for the queue's `max_payload` would be refused outright and
|
The queue would refuse a row too large for its `max_payload` outright and
|
||||||
take the connection down with it, so the harness drops such a row's body before
|
take the connection down with it, so the harness drops such a row's body before
|
||||||
sending and leaves a marker in its place; the summary, level and icon still
|
sending and leaves a marker in its place; the summary, level and icon still
|
||||||
arrive. A row that's too large even without its body is logged and skipped.
|
arrive. The harness logs and skips a row that's too large even without its body.
|
||||||
|
|
||||||
The second thing an agent publishes is its **turn-state header**, on
|
The second thing an agent publishes is its **turn-state header**, on
|
||||||
`$SWARM.agent-state.<hive>.<agent>` — same shape of subject, same grant
|
`$SWARM.agent-state.<hive>.<agent>` — same shape of subject, same grant
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
# Swarm secrets: what exists, and where each one lives
|
# Swarm secrets: what exists, and where each one lives
|
||||||
|
|
||||||
A swarm's credentials are generated in three different places and read in a
|
A swarm generates its credentials in three different places and reads them
|
||||||
fourth, so "where does this file go" has a different answer per deployment.
|
in a fourth, so "where does this file go" has a different answer per deployment.
|
||||||
This page is that answer, one row per secret.
|
This page is that answer, one row per secret.
|
||||||
|
|
||||||
Two rules run through all of it.
|
Two rules run through all of it.
|
||||||
|
|
@ -14,7 +14,7 @@ than a convenience.
|
||||||
|
|
||||||
The rule is about what must stay secret, not about credentials generally.
|
The rule is about what must stay secret, not about credentials generally.
|
||||||
**Public material is a value**: a certificate, or a public nkey like
|
**Public material is a value**: a certificate, or a public nkey like
|
||||||
`deploy.nats.calloutUserPublicKey`, is published to every client that connects,
|
`deploy.nats.calloutUserPublicKey`, reaches every client that connects,
|
||||||
so the store is a perfectly good place for it.
|
so the store is a perfectly good place for it.
|
||||||
|
|
||||||
**The generator and the reader typically live in different containers.** They share
|
**The generator and the reader typically live in different containers.** They share
|
||||||
|
|
@ -33,31 +33,31 @@ 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
|
file being there_ --- the two lists don't line up one-to-one, and
|
||||||
neither is a renaming of the other.
|
neither is a renaming of the other.
|
||||||
|
|
||||||
| topology | what it means | who places secrets |
|
| topology | what it means | who places secrets |
|
||||||
| ------------------ | ---------------------------------------------------------- | --------------------------------------------------------------------------- |
|
| ------------------ | ---------------------------------------------------------- | -------------------------------------------------------------------------- |
|
||||||
| **all-local** | one host runs the swarm's shared services and its own hive | nobody — each secret is generated where it's read, or copied by a host unit |
|
| **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 |
|
| **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 |
|
| **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 — one of each per swarm
|
## Swarm-level — one of each per swarm
|
||||||
|
|
||||||
| secret | generated by | lives at | hive elsewhere |
|
| secret | generated by | lives at | hive elsewhere |
|
||||||
| --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| swarm root CA cert | `swarm-ca.nix` first-boot unit, when `autoConfigure` is set | `/var/lib/swarm-ca/root.pem` | operator copies the **cert** in; it's public |
|
| swarm root CA cert | `swarm-ca.nix` first-boot unit, when the operator sets `autoConfigure` | `/var/lib/swarm-ca/root.pem` | operator copies the **cert** in; it's public |
|
||||||
| swarm root CA key | same unit | `/var/lib/swarm-ca/root-key.pem`, `0600` | stays on whichever host holds it — see the constraint below |
|
| swarm root CA key | same unit | `/var/lib/swarm-ca/root-key.pem`, `0600` | stays on whichever host holds it — see the constraint below |
|
||||||
| swarm-services sub-CA (cert + key) | `swarm-ca.nix`, signed by the root | `/var/lib/swarm-ca/services-ca{,-key}.pem` | issued where the root lives |
|
| swarm-services sub-CA (cert + key) | `swarm-ca.nix`, signed by the root | `/var/lib/swarm-ca/services-ca{,-key}.pem` | issued where the root lives |
|
||||||
| authelia session, JWT and storage-encryption keys | authelia's first-boot unit, in-container | `/var/lib/authelia-swarm/{session,jwt,storage-encryption}.key` | generated in place; nothing outside that container reads them |
|
| authelia session, JWT and storage-encryption keys | authelia's first-boot unit, in-container | `/var/lib/authelia-swarm/{session,jwt,storage-encryption}.key` | generated in place; nothing outside that container reads them |
|
||||||
| authelia OIDC HMAC key | same unit | `/var/lib/authelia-swarm/oidc-hmac.key` | same |
|
| authelia OIDC HMAC key | same unit | `/var/lib/authelia-swarm/oidc-hmac.key` | same |
|
||||||
| authelia OIDC issuer key (RSA) | same unit | `/var/lib/authelia-swarm/oidc-issuer.key` | same — relying parties verify against the **public** half at `/jwks.json` |
|
| authelia OIDC issuer key (RSA) | same unit | `/var/lib/authelia-swarm/oidc-issuer.key` | same — relying parties verify against the **public** half at `/jwks.json` |
|
||||||
| OIDC client secret, plaintext half | `authelia crypto hash generate --random` | `/var/lib/authelia-swarm/oidc-clients/<id>.secret` | operator provides the file and names it in whichever option reads it — `sso.clientSecretFile` for a service, `otel.clientSecretFile` for the hive's telemetry collector |
|
| OIDC client secret, plaintext half | `authelia crypto hash generate --random` | `/var/lib/authelia-swarm/oidc-clients/<id>.secret` | operator provides the file and names it in whichever option reads it — `sso.clientSecretFile` for a service, `otel.clientSecretFile` for the hive's telemetry collector |
|
||||||
| OIDC client secret, digest half | the same mint | `oidc-clients/<id>.digest` | authelia's own half; merged at runtime via `settingsFiles` |
|
| OIDC client secret, digest half | the same mint | `oidc-clients/<id>.digest` | authelia's own half; merged at runtime via `settingsFiles` |
|
||||||
| the swarm collector's copy of its OIDC secret | `swarm-bao-otel-oidc.service` reads it out of the swarm secret store, **on every host that runs the collector and holds a store identity** | `/var/lib/swarm-otel-oidc/<id>.secret` inside the `swarm-otel` container | same unit, same path — one route, co-located or not. A collector with no store identity is left with `clientSecretFile == null`, its already-supported unauthenticated-push degrade — see below |
|
| the swarm collector's copy of its OIDC secret | `swarm-bao-otel-oidc.service` reads it out of the swarm secret store, **on every host that runs the collector and holds a store identity** | `/var/lib/swarm-otel-oidc/<id>.secret` inside the `swarm-otel` container | same unit, same path — one route, co-located or not. A collector with no store identity has `clientSecretFile == null`, its already-supported unauthenticated-push degrade — see below |
|
||||||
| Grafana's copy of its OIDC secret | `swarm-bao-grafana-oidc.service` reads it out of the swarm secret store, **on every host that runs Grafana** | `/var/lib/grafana-oidc/<id>.secret` inside the `swarm-grafana` container | same unit, same path — one route, co-located or not. Nothing for an operator to place beyond this host's store leaf, see below |
|
| Grafana's copy of its OIDC secret | `swarm-bao-grafana-oidc.service` reads it out of the swarm secret store, **on every host that runs Grafana** | `/var/lib/grafana-oidc/<id>.secret` inside the `swarm-grafana` container | same unit, same path — one route, co-located or not. Nothing for an operator to place beyond this host's store leaf, see below |
|
||||||
| authelia subject store | `swarmctl` and `swarm-authelia-bridge` | `users.yml` — one file, read and written by both | `swarmctl`, on the host that runs authelia |
|
| authelia subject store | `swarmctl` and `swarm-authelia-bridge` | `users.yml` — one file, read and written by both | `swarmctl`, on the host that runs authelia |
|
||||||
| wireguard private key | **the operator** — `wg genkey` | whatever `deploy.wireguard.privateKeyFile` names | always operator-provided; nothing generates this for you |
|
| wireguard private key | **the operator** — `wg genkey` | whatever `deploy.wireguard.privateKeyFile` names | always operator-provided; nothing generates this for you |
|
||||||
| queue auth-callout nkeys (user seed + account seed) | `swarm-nats-callout-keys` first-boot unit, when `deploy.nats.autoGenerateCallout` is set | `/var/lib/swarm-nats-callout/{callout-user,issuer}.seed`, `0600` | operator mints both with `nk` and names them in `deploy.nats.calloutUserSeedFile` / `deploy.nats.calloutIssuerSeedFile` |
|
| queue auth-callout nkeys (user seed + account seed) | `swarm-nats-callout-keys` first-boot unit, when the operator sets `deploy.nats.autoGenerateCallout` | `/var/lib/swarm-nats-callout/{callout-user,issuer}.seed`, `0600` | operator mints both with `nk` and names them in `deploy.nats.calloutUserSeedFile` / `deploy.nats.calloutIssuerSeedFile` |
|
||||||
| the secret store's own contents | openbao, on first `bao operator init` — **an operator action, not a unit** | inside the `swarm-bao` container, at its own `/var/lib/openbao`, kept across rebuilds by `ephemeral = false`. ⚠️ **Not a host path**: `nixos-container destroy swarm-bao` takes the raft data with it, so back up the container's tree, not `/var/lib/`. Only the store's TLS material (`/var/lib/swarm-bao-tls`) and its PKCS11 token (`/var/lib/swarm-bao-token`) are host-level | n/a — there is one store; a hive elsewhere is a _client_ of it and holds none of this |
|
| the secret store's own contents | openbao, on first `bao operator init` — **an operator action, not a unit** | inside the `swarm-bao` container, at its own `/var/lib/openbao`, kept across rebuilds by `ephemeral = false`. ⚠️ **Not a host path**: `nixos-container destroy swarm-bao` takes the raft data with it, so back up the container's tree, not `/var/lib/`. Only the store's TLS material (`/var/lib/swarm-bao-tls`) and its PKCS11 token (`/var/lib/swarm-bao-token`) are host-level | n/a — there is one store; a hive elsewhere is a _client_ of it and holds none of this |
|
||||||
| the secret store's unseal material | the HSM/TPM under `deploy.bao.seal = "pkcs11"`; openbao itself under `"shamir"` | in the token; or held by whoever ran `bao operator init`, which is what `"shamir"` means and why it's stated rather than inferred | n/a — only the host running the store seals anything |
|
| the secret store's unseal material | the HSM/TPM under `deploy.bao.seal = "pkcs11"`; openbao itself under `"shamir"` | in the token; or held by whoever ran `bao operator init`, which is what `"shamir"` means and why it's stated rather than inferred | n/a — only the host running the store seals anything |
|
||||||
|
|
||||||
Authelia mints the three keys for itself, in-container, precisely
|
Authelia mints the three keys for itself, in-container, precisely
|
||||||
because nothing outside that container ever reads them. **That's the test worth
|
because nothing outside that container ever reads them. **That's the test worth
|
||||||
|
|
@ -68,8 +68,8 @@ Two telemetry collectors exist, and they land on opposite sides of that test.
|
||||||
|
|
||||||
The **hive's** collector needs no delivery step. It authenticates to the swarm's
|
The **hive's** collector needs no delivery step. It authenticates to the swarm's
|
||||||
collector as its own hive, and it's a host unit rather than a container, so on
|
collector as its own hive, and it's a host unit rather than a container, so on
|
||||||
an all-local swarm it reads authelia's file where it lies and no second copy is
|
an all-local swarm it reads authelia's file where it lies and nothing makes a
|
||||||
made. On any other topology it's an ordinary "operator provides the file"
|
second copy. On any other topology it's an ordinary "operator provides the file"
|
||||||
case — see `services.hyperhive.otel.clientSecretFile`.
|
case — see `services.hyperhive.otel.clientSecretFile`.
|
||||||
|
|
||||||
The **swarm's** collector does need one, and its delivery route is the fourth
|
The **swarm's** collector does need one, and its delivery route is the fourth
|
||||||
|
|
@ -77,8 +77,8 @@ store reader — the same shape as Grafana's, described in full below. In short:
|
||||||
`swarm-bao-otel-oidc.service` reads `swarm/services/<client-id>/oidc/client`
|
`swarm-bao-otel-oidc.service` reads `swarm/services/<client-id>/oidc/client`
|
||||||
out of the store on every host that runs the collector and holds a store
|
out of the store on every host that runs the collector and holds a store
|
||||||
identity, whether authelia is a network away or in the container next door.
|
identity, whether authelia is a network away or in the container next door.
|
||||||
The client it reads for is registered unconditionally, the same call
|
The same call `glue-grafana-oidc-client.nix` makes for Grafana's registers
|
||||||
`glue-grafana-oidc-client.nix` makes for Grafana's: authelia refuses a
|
the client it reads for unconditionally: authelia refuses a
|
||||||
bearer-authz client with no audience, and the push audiences supply one even
|
bearer-authz client with no audience, and the push audiences supply one even
|
||||||
for a collector with nothing published to scrape.
|
for a collector with nothing published to scrape.
|
||||||
|
|
||||||
|
|
@ -90,9 +90,9 @@ there. `swarm-bao-otel-oidc.service` therefore doesn't render at all without
|
||||||
`deploy.bao.clientCertFile` / `clientKeyFile`, the same choice
|
`deploy.bao.clientCertFile` / `clientKeyFile`, the same choice
|
||||||
`glue-matrix-bao-token.nix` and `glue-queue-agent-credential.nix` make for
|
`glue-matrix-bao-token.nix` and `glue-queue-agent-credential.nix` make for
|
||||||
their own optional readers, rather than the hard assertion `swarm-grafana.nix`
|
their own optional readers, rather than the hard assertion `swarm-grafana.nix`
|
||||||
uses for its non-optional one. The secret can still be delivered by hand, at
|
uses for its non-optional one. The operator can still deliver the secret by
|
||||||
`services.hyperhive.deploy.swarm-otel.clientSecretFile`, on a collector this
|
hand, at `services.hyperhive.deploy.swarm-otel.clientSecretFile`, on a
|
||||||
unit never reaches.
|
collector this unit never reaches.
|
||||||
|
|
||||||
### Minting the queue's callout nkeys
|
### Minting the queue's callout nkeys
|
||||||
|
|
||||||
|
|
@ -178,8 +178,8 @@ Instead it keeps the value it minted under its `StateDirectory`,
|
||||||
`/var/lib/swarm-secret-publish/matrix-appservice-token/<hive>` (`0700` dir,
|
`/var/lib/swarm-secret-publish/matrix-appservice-token/<hive>` (`0700` dir,
|
||||||
`0600` file), and mints only when that file is missing or empty. The `put`
|
`0600` file), and mints only when that file is missing or empty. The `put`
|
||||||
itself runs every time: re-putting the same bytes changes nothing for any
|
itself runs every time: re-putting the same bytes changes nothing for any
|
||||||
reader, while a mint whose publish failed must not be left as a token this
|
reader, while a mint whose publish failed must not leave behind a token
|
||||||
host holds and no hive can reach.
|
this host holds and no hive can reach.
|
||||||
|
|
||||||
Lose the state directory and the next run mints once more and republishes.
|
Lose the state directory and the next run mints once more and republishes.
|
||||||
That rotates the token, which readers pick up on their next start — nothing
|
That rotates the token, which readers pick up on their next start — nothing
|
||||||
|
|
@ -187,7 +187,7 @@ that already registered breaks, because the token authenticates the
|
||||||
appservice rather than living inside any account it created.
|
appservice rather than living inside any account it created.
|
||||||
|
|
||||||
The path was `…/matrix/registration-token` while the homeserver still took a
|
The path was `…/matrix/registration-token` while the homeserver still took a
|
||||||
shared registration secret; a value left at the old path is read by nothing.
|
shared registration secret; nothing reads a value left at the old path.
|
||||||
|
|
||||||
The **second reader** is the agent containers' queue credential:
|
The **second reader** is the agent containers' queue credential:
|
||||||
`glue-queue-agent-credential.nix` lands it as two files, the client secret and
|
`glue-queue-agent-credential.nix` lands it as two files, the client secret and
|
||||||
|
|
@ -266,9 +266,9 @@ as it does for the other readers: a store that says "not here" leaves the
|
||||||
file alone and says so, since there is no such thing as a locally valid OIDC
|
file alone and says so, since there is no such thing as a locally valid OIDC
|
||||||
client secret to stand in.
|
client secret to stand in.
|
||||||
|
|
||||||
⚠️ **Service↔store mTLS is its own trust domain.** A credential you must
|
⚠️ **Service↔store mTLS is its own trust domain.** You can't fetch a
|
||||||
already hold to authenticate can't be fetched from the thing it authenticates
|
credential you must already hold to authenticate from the thing it
|
||||||
you to, so the store's identity can't come from an authority the store
|
authenticates you to, so the store's identity can't come from an authority the store
|
||||||
distributes — which excludes the hive CA and the swarm CA both, and has nothing
|
distributes — which excludes the hive CA and the swarm CA both, and has nothing
|
||||||
to do with the gateway's HTTPS certificates either way. `glue-bao-tls.nix`
|
to do with the gateway's HTTPS certificates either way. `glue-bao-tls.nix`
|
||||||
mints a CA that signs exactly two things, the store's server certificate and a
|
mints a CA that signs exactly two things, the store's server certificate and a
|
||||||
|
|
@ -318,8 +318,8 @@ Whatever holds the swarm root is therefore what makes swarm-service certificates
|
||||||
possible at all. Two things follow:
|
possible at all. Two things follow:
|
||||||
|
|
||||||
- **The root's private key is a runtime file and must never enter the nix
|
- **The root's private key is a runtime file and must never enter the nix
|
||||||
store**, so nothing build-time can name it — `security.pki.certificateFiles` is
|
store**, so nothing build-time can name it — `security.pki.certificateFiles`
|
||||||
read when the system is built, and is the wrong tool here. Trust reaches
|
reads at system build time, and is the wrong tool here. Trust reaches
|
||||||
containers through a bind-mounted bundle assembled at boot instead.
|
containers through a bind-mounted bundle assembled at boot instead.
|
||||||
- **On any topology other than all-local, placing that key is an operations
|
- **On any topology other than all-local, placing that key is an operations
|
||||||
decision**, not something this module tree makes for you. A hive that hosts no
|
decision**, not something this module tree makes for you. A hive that hosts no
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue