docs: fix genuine passive-voice hits in docs/swarm
Read all 94 write-good.Passive hits across docs/swarm/ (ca.md, README.md, secrets.md, services.md, sso.md, ui.md) in context. 44 are genuine catches with a nameable, usually already-established actor (swarm-controller, authelia, swarmctl, the controller, the gateway, this module, hyperhive itself, or 'the operator' for manual actions) — rewritten to active. 50 are legitimate passives or false catches, left alone: predicate-adjective state descriptions (is expected/misconfigured/ broken), negative-capability idioms (no X is needed/placed, can't be Yed/listed/fetched), config-state conditionals (whenever/when X is enabled/configured/set), requirement-list labels (is required), 'is tracked as' idiom, backward-looking changelog facts with no actor (was removed/verified/introduced), ambiguous-actor statements left conservatively alone (agents are created and destroyed — could be hive-c0re or swarm-controller, doc doesn't say), and a couple of deliberately-parallel idiom pairs. Several sibling-inconsistency fixes: a passive clause sitting next to an already-active sibling describing the same fact/mechanism (ca.md's two-bullet consumer list, README's 4-item WireGuard-mesh bullet list, README's controller-registers-hooks paragraph, sso.md's followed-a-302 sentence). Verified via vale on the whole directory, diffed against main's exact baseline (not just the Passive count): write-good.Passive 94 -> 50 exactly, every other category unchanged (1 pre-existing Microsoft.Contractions error at services... at secrets.md:182, 8 TooWordy, 1 Microsoft.We, 1 Microsoft.FirstPerson — same counts, same locations).
This commit is contained in:
parent
e9d59f3d10
commit
fab2a0dedc
6 changed files with 79 additions and 78 deletions
|
|
@ -41,7 +41,7 @@ services.hyperhive = {
|
|||
```
|
||||
|
||||
`swarm.domain` and `hiveName` are **required** whenever hyperhive is
|
||||
enabled; eval fails with a hint naming each. Neither is defaulted,
|
||||
enabled; eval fails with a hint naming each. Neither defaults,
|
||||
because a guessed value here is a wrong hostname that evaluates cleanly
|
||||
and deploys — an eval failure asking the operator to write the address
|
||||
down is the cheaper outcome. **Upgrading past this release means setting
|
||||
|
|
@ -55,9 +55,9 @@ the other hives read — `swarm.hives.edge.domain = "edge.elsewhere.example";`.
|
|||
|
||||
Setting `services.hyperhive.domain` directly still works and still wins,
|
||||
with a **deprecation warning**. The reason it's deprecated isn't tidiness:
|
||||
that option is local to one host, the directory is copied to every host,
|
||||
so a value written only there leaves every peer pointing somewhere else
|
||||
with nothing detecting the disagreement.
|
||||
that option is local to one host, and the operator copies the directory
|
||||
to every host, so a value written only there leaves every peer pointing
|
||||
somewhere else with nothing detecting the disagreement.
|
||||
|
||||
⚠️ **Upgrading:** a hive that has been running on `swarm.domain` +
|
||||
`hiveName` alone now needs its own directory entry —
|
||||
|
|
@ -81,8 +81,8 @@ and `qualify()` / `qualified_label()` semantics.
|
|||
## Swarm CA
|
||||
|
||||
A hive's internal TLS chains to a **swarm root CA**, so a peer that
|
||||
trusts the root validates every hive in the swarm rather than being
|
||||
pinned to each one by hand. Provisioning modes, what to hand a peer
|
||||
trusts the root validates every hive in the swarm rather than pinning
|
||||
to each one by hand. Provisioning modes, what to hand a peer
|
||||
(`trust-bundle.pem`, never `ca.pem`), the name constraints on a hive
|
||||
CA, and how an existing hive adopts the hierarchy: [`ca.md`](ca.md).
|
||||
|
||||
|
|
@ -107,8 +107,8 @@ which of the three topologies makes it the operator's job to place:
|
|||
## Swarm UI
|
||||
|
||||
The operator-only web surface on the swarm apex, why reaching it needs
|
||||
the `admins` group rather than just a session, and the four sites a
|
||||
swarm service name has to be wired into: [`ui.md`](ui.md).
|
||||
the `admins` group rather than just a session, and the four sites you
|
||||
wire a swarm service name into: [`ui.md`](ui.md).
|
||||
|
||||
## The swarm's hive directory
|
||||
|
||||
|
|
@ -249,15 +249,15 @@ services.hyperhive = {
|
|||
|
||||
### What the mesh does
|
||||
|
||||
- `networking.wireguard.interfaces.wg-hive` is configured on the host
|
||||
(not inside agent containers; containers reach peers via the host's
|
||||
routing table).
|
||||
- UDP port 51820 (or `listenPort`) is opened on the host firewall.
|
||||
- hyperhive configures `networking.wireguard.interfaces.wg-hive` on the
|
||||
host (not inside agent containers; containers reach peers via the
|
||||
host's routing table).
|
||||
- It opens UDP port 51820 (or `listenPort`) on the host firewall.
|
||||
- `swarm-wireguard.nix` reads each entry's `wireguardAddress` directly
|
||||
from `services.hyperhive.swarm.peerHives` to build `wg-hive`'s
|
||||
`allowedIPs`, so intra-swarm traffic can route over the mesh address
|
||||
rather than the public domain.
|
||||
- `persistentKeepalive = 25` is set by default; override or null to
|
||||
- It sets `persistentKeepalive = 25` by default; override or null to
|
||||
disable (not needed when both sides have public IPs and no NAT).
|
||||
|
||||
### NAT / one-sided endpoints
|
||||
|
|
@ -310,7 +310,7 @@ below. A hive without them reads
|
|||
| `fresh` | nothing — reported within `staleAfterSeconds` |
|
||||
| `stale` | the hive stopped reporting. Its last payload is still shown, so check `age_seconds` and the payload for what it managed to say |
|
||||
| `never_reported` | this hive has never reported at all — normally a deployment that hasn't happened, not an outage |
|
||||
| `unknown` | something is publishing under a name that's not in `swarm.hives` — a typo in the roster, or a hive that was removed and is still running |
|
||||
| `unknown` | something is publishing under a name that's not in `swarm.hives` — a typo in the roster, or a hive removed from the roster but still running |
|
||||
|
||||
Every row also carries `last_seen_unix` and `age_seconds` if you want to
|
||||
apply your own threshold. The timestamp is the one the queue recorded on
|
||||
|
|
@ -382,10 +382,11 @@ controller's — and **both are expected; don't delete either.** Removing
|
|||
a hive's stops it acting on config PRs; removing the controller's just
|
||||
gets recreated on its next start.
|
||||
|
||||
Nothing to configure. The hooks are registered only when this host also
|
||||
serves the swarm UI vhost — that's what publishes the endpoint, and a
|
||||
hook the forge can't reach would collect failed deliveries while
|
||||
looking healthy. The HMAC secret is generated on first start and kept
|
||||
Nothing to configure. The controller registers the hooks only when this
|
||||
host also serves the swarm UI vhost — that's what publishes the
|
||||
endpoint, and a hook the forge can't reach would collect failed
|
||||
deliveries while looking healthy. The controller generates the HMAC
|
||||
secret on first start and keeps it
|
||||
(see [`docs/agent-lifecycle/persistence.md`](../agent-lifecycle/persistence.md)).
|
||||
|
||||
To check it's working, push to `internal/knowledge` and look for
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
A hive's internal TLS chains to a **swarm root CA**: the root signs each
|
||||
hive's own CA, and that hive CA signs the gateway leaf. A peer that
|
||||
trusts the root once validates every hive in the swarm, present and
|
||||
future, instead of being pinned to each one by hand.
|
||||
future, instead of pinning to each one by hand.
|
||||
|
||||
That's the whole point of the hierarchy — it turns per-peer trust from
|
||||
O(n²) hand-pinning into one anchor per swarm.
|
||||
|
|
@ -55,8 +55,8 @@ able to issue, but not an operator-installed sub-CA in
|
|||
by any other means. If you have arranged one, the warning is expected
|
||||
and can be ignored. Otherwise either install the sub-CA, or pin the
|
||||
names back under the hive domain — a supported migration, since the
|
||||
sub-CA is constrained to the _configured_ names and the swarm root
|
||||
carries no name constraints at all.
|
||||
sub-CA carries a name constraint on the _configured_ names and the
|
||||
swarm root carries no name constraints at all.
|
||||
|
||||
## Constraints on the material
|
||||
|
||||
|
|
@ -89,9 +89,9 @@ host:
|
|||
scp /var/lib/swarm-ca/root.pem <peer-host>:/var/lib/swarm-ca/root.pem
|
||||
```
|
||||
|
||||
That's the point of the hierarchy: the root is installed **once per
|
||||
swarm host**, not once per peer, so a hive joining later needs no edit on
|
||||
the hives already running. A hive whose cert already chains to a public
|
||||
That's the point of the hierarchy: the operator installs the root
|
||||
**once per swarm host**, not once per peer, so a hive joining later
|
||||
needs no edit on the hives already running. A hive whose cert already chains to a public
|
||||
CA has nothing to install — `peer-config` says so instead.
|
||||
|
||||
Handing a peer this hive's own `ca.pem` would not work even as a
|
||||
|
|
@ -114,8 +114,8 @@ two cases.**
|
|||
|
||||
Adoption happens by itself, once. `hive-tls-ca.service` notices that
|
||||
`ca.pem` doesn't chain to the root, keeps the old certificate as
|
||||
`ca-previous.pem`, and re-issues under the root; the next leaf is signed
|
||||
by the new CA.
|
||||
`ca-previous.pem`, and re-issues under the root; the new CA signs the
|
||||
next leaf.
|
||||
|
||||
It's safe to automate here precisely because this is the
|
||||
all-on-one-host shape: every consumer is on this box, so "when will they
|
||||
|
|
@ -142,7 +142,7 @@ systemctl restart hive-tls-ca.service
|
|||
```
|
||||
|
||||
Failing rather than warning is deliberate: a hive whose CA doesn't
|
||||
chain to the root it has been given is misconfigured, and a warning in a
|
||||
chain to the root it received is misconfigured, and a warning in a
|
||||
build log isn't something anyone reads twice.
|
||||
|
||||
To keep the current CA on purpose — a hive that deliberately stays
|
||||
|
|
@ -162,12 +162,12 @@ beside the key under `swarm.ca.stateDir` — and that has a cost worth
|
|||
naming, because it's subtle and it bites at a distance:
|
||||
|
||||
> **Nothing whose trust store is assembled at build time can reference
|
||||
> the swarm root.** `security.pki.certificateFiles` is read inside the
|
||||
> derivation; the root doesn't exist there.
|
||||
> the swarm root.** The derivation reads `security.pki.certificateFiles`
|
||||
> inside itself; the root doesn't exist there.
|
||||
|
||||
Two consumers, and only one of them is fine:
|
||||
|
||||
- **Agents are covered.** `hive-tls.nix` folds the root into this hive's
|
||||
- **`hive-tls.nix` covers agents.** It folds the root into this hive's
|
||||
`trust-bundle.pem`, hive-c0re receives that path as
|
||||
`HIVE_TLS_CA_PATH`, and the meta-flake renderer embeds that one file
|
||||
next to every agent's flake. The bundle is the runtime-to-build-time
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ 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 is rendered into the nix store — world-readable and permanent. No
|
||||
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.
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ container that starts after it.
|
|||
|
||||
## Topologies, by who places secrets
|
||||
|
||||
Every row below is read against one of these. This is a different cut
|
||||
Read every row below 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
|
||||
|
|
@ -58,7 +58,7 @@ neither is a renaming of the other.
|
|||
| 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 three keys authelia mints for itself are generated 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
|
||||
applying to any secret added here** — and the client secret's plaintext half is
|
||||
the one row that fails it, which is the entire reason a delivery step exists.
|
||||
|
|
@ -71,8 +71,8 @@ an all-local swarm it reads authelia's file where it lies and no second copy is
|
|||
made. On any other topology it's an ordinary "operator provides the file"
|
||||
case — see `services.hyperhive.otel.clientSecretFile`.
|
||||
|
||||
The **swarm's** collector does need one. It runs in a container, so its copy is
|
||||
placed by `swarm-otel-oidc-secret.service` and lands at
|
||||
The **swarm's** collector does need one. It runs in a container, so
|
||||
`swarm-otel-oidc-secret.service` places its copy, landing at
|
||||
`/var/lib/swarm-otel-oidc/<client-id>.secret` — the same shape as the forge and
|
||||
homeserver rows below, and for the same reason: the container that mints the
|
||||
secret isn't the container that reads it.
|
||||
|
|
@ -120,7 +120,7 @@ refuses every client rather than degrading — and a refusal reaches the client
|
|||
a timeout, so the symptom is every consumer hanging with nothing logged.
|
||||
|
||||
One consequence of the generated path worth knowing before you debug it: with
|
||||
`autoGenerateCallout` set, the queue's config is assembled at boot rather than at
|
||||
`autoGenerateCallout` set, the queue assembles its config at boot rather than at
|
||||
build time, so a malformed one surfaces when the container starts instead of
|
||||
when the system builds. The server names the offending file and refuses to run.
|
||||
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ sections below don't repeat it, so a service that stops deriving is a
|
|||
visible difference rather than one more paragraph saying the same thing.
|
||||
|
||||
`singleHostSwarm` is the all-on-one-box switch above it: it defaults
|
||||
both `deploy.allSwarmServices` and `swarm.ca.autoConfigure` (the swarm CA
|
||||
is generated here). Each derived toggle can still be set on its own,
|
||||
both `deploy.allSwarmServices` and `swarm.ca.autoConfigure` (this host
|
||||
generates the swarm CA here). Each derived toggle can still be set on its own,
|
||||
which wins, so "all local except X" needs no further option.
|
||||
|
||||
**Both default to off**, and that's deliberate: a host can't tell
|
||||
|
|
@ -45,8 +45,8 @@ the shapes worth naming are the ones they produce:
|
|||
- **Fully spread out.** One container / VM / machine per service,
|
||||
somewhere.
|
||||
|
||||
**These are a set, not a ladder with a correct top, and in-between
|
||||
shapes are supported.** Each derived toggle can be set on its own (see
|
||||
**These are a set, not a ladder with a correct top, and hyperhive
|
||||
supports in-between shapes.** Each derived toggle can be set on its own (see
|
||||
above), which is what makes "all local except X" a configuration rather
|
||||
than an unsupported edge case. Nothing in hyperhive prescribes a
|
||||
deployment model, so a doc that treats one shape as the real one and
|
||||
|
|
@ -69,21 +69,21 @@ provider, differentiated by roles and claims rather than by mechanism —
|
|||
there is one IdP and one auth path.
|
||||
|
||||
- **`deploy.authelia`** — run the container here.
|
||||
- **`swarm.authelia.url`** — where clients are sent to authenticate.
|
||||
- **`swarm.authelia.url`** — where clients go to authenticate.
|
||||
Present on **every** hive, defaulting to this host's own instance only
|
||||
when this module is the thing running it; otherwise `null`, and a hive
|
||||
joining someone else's swarm sets it explicitly. Null means "no SSO
|
||||
configured", and consumers say so rather than guessing an address.
|
||||
|
||||
The users database is written by swarm-controller, not by hand: agents
|
||||
swarm-controller writes the users database, not by hand: agents
|
||||
are created and destroyed continuously, so the subject set is dynamic.
|
||||
This module only guarantees the file exists and parses, so authelia
|
||||
starts with nobody in it rather than failing to start — a provider with
|
||||
no subjects yet is the correct state before anything has provisioned
|
||||
them. Session and storage keys are generated in the container on first
|
||||
boot and never rotated automatically; replacing one invalidates data
|
||||
already written (sessions, the encrypted store), so that's an operator
|
||||
action.
|
||||
them. Authelia generates session and storage keys in the container on
|
||||
first boot and never rotates them automatically; replacing one
|
||||
invalidates data already written (sessions, the encrypted store), so
|
||||
that's an operator action.
|
||||
|
||||
Storage is local sqlite and the notifier writes to a file. Both are
|
||||
small-deployment choices, and the scope is the justification: redis
|
||||
|
|
@ -91,13 +91,13 @@ buys shared session state across replicas and there is one instance;
|
|||
SMTP exists to mail humans, and provisioning here is programmatic.
|
||||
|
||||
See [`sso.md`](sso.md) for bootstrapping the first user and the OIDC
|
||||
relying-party flow, and [`secrets.md`](secrets.md) for where each of
|
||||
authelia's keys is generated and read.
|
||||
relying-party flow, and [`secrets.md`](secrets.md) for where authelia
|
||||
generates and reads each of its keys.
|
||||
|
||||
### Metrics (VictoriaMetrics + Grafana)
|
||||
|
||||
The swarm's telemetry lands in one VictoriaMetrics and is read through
|
||||
one Grafana, in two containers at `metrics.<swarm-domain>` and
|
||||
The swarm's telemetry lands in one VictoriaMetrics, and one Grafana
|
||||
reads it, in two containers at `metrics.<swarm-domain>` and
|
||||
`grafana.<swarm-domain>`. Two containers rather than one so Grafana can
|
||||
be restarted or broken without taking the time-series database with it.
|
||||
|
||||
|
|
@ -119,8 +119,8 @@ See `retentionPeriod` below before leaving it at its default.
|
|||
| `deploy.grafana.datasourceUrl` | Only if you front VictoriaMetrics with something else. It defaults to the store on this host, which is the only thing it can reach. |
|
||||
|
||||
**Logging in.** Grafana is behind swarm SSO, so the accounts are the
|
||||
authelia ones — there is no separate Grafana password, and the local
|
||||
login form is switched off whenever SSO is configured. If you enable
|
||||
authelia ones — there is no separate Grafana password, and this module
|
||||
switches off the local login form whenever SSO is configured. If you enable
|
||||
Grafana on a host with no authelia, the form stays on and Grafana's
|
||||
default `admin`/`admin` applies; change it before exposing that host.
|
||||
|
||||
|
|
@ -178,9 +178,9 @@ gateway either way.
|
|||
| `swarm.otel.domain` | Only to rename it — the default already resolves correctly for every hive in the swarm. |
|
||||
| `swarm.otel.port` | Only if something else on the services host already claims `4319`. |
|
||||
|
||||
With neither `otel.endpoint` nor the store enabled, this collector is
|
||||
refused at eval — a tier that receives samples and drops them looks
|
||||
healthy while losing data.
|
||||
With neither `otel.endpoint` nor the store enabled, this module refuses
|
||||
the collector at eval — a tier that receives samples and drops them
|
||||
looks healthy while losing data.
|
||||
|
||||
Agent-side configuration, and what a hive's own collector does, are in
|
||||
[`../scheduler/observability.md`](../scheduler/observability.md).
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ provider** every protected vhost checks (`auth_request`), and — once any
|
|||
client is declared — an **OIDC provider** issuing tokens to relying
|
||||
parties: the forge and the matrix homeserver.
|
||||
|
||||
The second role is derived rather than switched:
|
||||
The second role derives rather than switches:
|
||||
`services.hyperhive.swarm.authelia.oidc.clients` being non-empty turns it
|
||||
on. authelia refuses to start with a provider that has no clients, so a
|
||||
separate `enable` would be a second fact free to disagree with the first.
|
||||
|
|
@ -18,10 +18,10 @@ name all follow `deploy.authelia`, so there is nothing to turn on
|
|||
separately. (Details, including why a client hive must not declare that
|
||||
vhost: [`../networking/gateway.md`](../networking/gateway.md).)
|
||||
|
||||
**Authelia doesn't start until at least one user exists.** The user
|
||||
store is generated empty — deliberately, since seeding a default account
|
||||
would put a credential in a config file — but authelia validates it at
|
||||
startup and treats "no users" as fatal:
|
||||
**Authelia doesn't start until at least one user exists.** This module
|
||||
generates the user store empty — deliberately, since seeding a default
|
||||
account would put a credential in a config file — but authelia validates
|
||||
it at startup and treats "no users" as fatal:
|
||||
|
||||
```
|
||||
error reading the authentication database: could not validate the schema:
|
||||
|
|
@ -47,8 +47,8 @@ password: <generated>
|
|||
this password is stored nowhere — record it now
|
||||
```
|
||||
|
||||
The password is generated, hashed, and printed once; only the hash is
|
||||
kept. `swarmctl` reads and writes authelia's `users.yml` directly — it's
|
||||
`swarmctl` generates, hashes, and prints the password once, keeping only
|
||||
the hash. It reads and writes authelia's `users.yml` directly — it's
|
||||
the one user store, shared with `swarm-authelia-bridge`, which creates
|
||||
agent identities in the same file. No restart: authelia watches it. Full
|
||||
reference: [`../tools/swarmctl-cli.md`](../tools/swarmctl-cli.md).
|
||||
|
|
@ -84,7 +84,7 @@ Two behaviours worth knowing before you rely on them:
|
|||
already was. Revocation is the exception on purpose: a typo'd group
|
||||
name that reported success would leave an account holding access you
|
||||
believe you took away, and that's the one outcome nobody re-checks.
|
||||
- **The resulting group list is printed** because group names have no
|
||||
- **`swarmctl` prints the resulting group list** because group names have no
|
||||
registry anywhere. A misspelled `--add-group` creates a real group that
|
||||
no access-control rule mentions, so the user gains nothing and no error
|
||||
is possible — reading the line back is the only check there is.
|
||||
|
|
@ -115,8 +115,8 @@ authelia's first boot to mint that client's secret and copies it into the
|
|||
service's container, and the service's own module contributes its client
|
||||
entry — callback URL included — to authelia's client list.
|
||||
|
||||
The callback is built once and read twice, so the redirect URI authelia is
|
||||
told to allow and the one the service actually sends can't drift apart. A
|
||||
The callback is built once and read twice, so the redirect URI authelia
|
||||
accepts and the one the service actually sends can't drift apart. A
|
||||
mismatch there is a rejected login with no error text worth reading.
|
||||
|
||||
⚠️ The delivery is a copy, not a `bindMounts` entry, and deliberately so:
|
||||
|
|
@ -147,7 +147,7 @@ services.hyperhive.swarm = {
|
|||
};
|
||||
```
|
||||
|
||||
**Both are asserted at eval.** A hive that boots with SSO
|
||||
**This module asserts both at eval.** A hive that boots with SSO
|
||||
half-configured shows a login button that always fails — a symptom
|
||||
many layers from its cause, and far worse to diagnose than an
|
||||
evaluation error.
|
||||
|
|
@ -173,9 +173,9 @@ Two consequences worth stating plainly:
|
|||
host-side ownership arrangement to maintain.
|
||||
- **Matrix SSO lives inside the homeserver.** The client-server API is
|
||||
spoken by non-browser clients holding matrix access tokens — every
|
||||
agent's own daemon — as well as by federation, so `/_matrix/` is served
|
||||
directly and authenticates itself. The forward-auth vhosts protect
|
||||
browser surfaces; this isn't one of them.
|
||||
agent's own daemon — as well as by federation, so the homeserver
|
||||
serves `/_matrix/` directly and authenticates it itself. The
|
||||
forward-auth vhosts protect browser surfaces; this isn't one of them.
|
||||
|
||||
## Machine clients
|
||||
|
||||
|
|
@ -197,7 +197,7 @@ thing to keep in step, and it drifts silently — a mismatch presents as a
|
|||
valid token refused at the target, which reads like a broken credential
|
||||
rather than a broken name.
|
||||
|
||||
**Tokens are signed (`RS256`), not opaque**, because a resource server
|
||||
**Authelia signs tokens (`RS256`), not opaque ones**, because a resource server
|
||||
that can't call the provider back is a real case here: the telemetry
|
||||
collector verifies offline against `/jwks.json`, and an opaque token gives
|
||||
it nothing to verify. The queue's responder introspects instead — a
|
||||
|
|
@ -218,15 +218,15 @@ HTML instead of the failure that actually happened:
|
|||
- `/api/oidc/token`, `/.well-known/openid-configuration` — a client
|
||||
parsing an error page as its JSON document
|
||||
|
||||
Authelia's `/api/` and `/.well-known/` prefixes are routed **without**
|
||||
error interception. The split is by _audience_, not by an enumerated path
|
||||
The gateway routes authelia's `/api/` and `/.well-known/` prefixes
|
||||
**without** error interception. The split is by _audience_, not by an enumerated path
|
||||
list: a human gets the page, every machine caller gets the status.
|
||||
Enumerating endpoints individually would leave the next one added
|
||||
silently intercepted.
|
||||
|
||||
The same shape bites any machine route behind a browser-shaped gate: a
|
||||
`302` to a login page is followed, the login page answers `200`, and the
|
||||
caller reports success while nothing happened. Log ingest hit exactly this
|
||||
The same shape bites any machine route behind a browser-shaped gate: the
|
||||
caller follows a `302` to a login page, the login page answers `200`,
|
||||
and the caller reports success while nothing happened. Log ingest hit exactly this
|
||||
and lost eleven hours of delivery in silence.
|
||||
|
||||
**Checking it, if you change this routing.** Point the vhost at a dead
|
||||
|
|
|
|||
|
|
@ -56,8 +56,8 @@ between "an operator's page" and "anyone with a session."
|
|||
|
||||
## What it costs to be reachable
|
||||
|
||||
The apex is published to the hive's resolver like every other swarm
|
||||
service, so agent containers can resolve it. That's deliberate and it's
|
||||
hyperhive publishes the apex to the hive's resolver like every other
|
||||
swarm service, so agent containers can resolve it. That's deliberate and it's
|
||||
not a hole: **reachability isn't the access control here.** An agent
|
||||
that resolves the name and connects still has no operator session, and
|
||||
the subrequest denies it.
|
||||
|
|
@ -74,7 +74,7 @@ a container":
|
|||
| **certificate name** | `nix/host-modules/swarm.nix` (`serviceDomains`) |
|
||||
|
||||
The DNS record and the local-dev `/etc/hosts` entry need no separate
|
||||
edit: both are derived from `services.hyperhive.gateway.localNames`,
|
||||
edit: both derive from `services.hyperhive.gateway.localNames`,
|
||||
which a service's own module already has to push its domain into to be
|
||||
resolvable — see `nix/host-modules/hive-gateway/dnsmasq.nix` and
|
||||
`.../default.nix`'s `networking.hosts`. `vhosts.nix` itself is scoped to
|
||||
|
|
|
|||
Loading…
Reference in a new issue