docs: fix 329 Microsoft.Contractions hits with proper safety checks
Apply contraction fixes across ~40 doc files (setup, integrations, lifecycle, networking, scheduler, swarm, tools, trust-boundary, UI, etc.). Skipped 14 hits: - 10 where words appear in ALL CAPS for deliberate emphasis (is NOT, do NOT, etc.) - 4 where text could not be safely located due to markdown formatting or column position Applied via systematic scan with checks for fenced code blocks, inline code spans, and intentional caps. Preserves sentence-initial capitalization throughout.
This commit is contained in:
parent
77296aff35
commit
78021ce982
38 changed files with 320 additions and 320 deletions
|
|
@ -19,9 +19,9 @@ so the store is a perfectly good place for it.
|
|||
|
||||
**The generator and the reader are usually in different containers.** They share
|
||||
the host's network namespace, which makes them feel co-located, but their
|
||||
filesystem roots are separate. That is why delivery is a **host-side copy rather
|
||||
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 does not exist
|
||||
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.
|
||||
|
||||
|
|
@ -30,20 +30,20 @@ container that starts after it.
|
|||
Every row below is read 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_ --- so the two lists do not line up one-to-one, and
|
||||
file being there_ --- so 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 — each secret is generated where it is read, or copied by a host unit |
|
||||
| **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 does not host | the operator provides the file and names it in config |
|
||||
| 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 |
|
||||
| **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 — one of each per swarm
|
||||
|
||||
| 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 is public |
|
||||
| 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 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 |
|
||||
| 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 |
|
||||
|
|
@ -56,31 +56,31 @@ neither is a renaming of the other.
|
|||
| 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` |
|
||||
| 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 is 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 |
|
||||
|
||||
The three keys authelia mints for itself are generated in-container precisely
|
||||
because nothing outside that container ever reads them. **That is the test worth
|
||||
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.
|
||||
|
||||
There are two telemetry collectors and they land on opposite sides of that test.
|
||||
|
||||
The **hive's** collector needs no delivery step. It authenticates to the swarm's
|
||||
collector as its own hive, and it is 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
|
||||
made. On any other topology it is an ordinary "operator provides the file"
|
||||
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
|
||||
`/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 is not the container that reads it.
|
||||
secret isn't the container that reads it.
|
||||
|
||||
The copy is only made when authelia is enabled **on this host** and something
|
||||
published is being scraped; otherwise no secret is needed and none is placed.
|
||||
|
||||
⚠️ **Do not read that delivery unit as the only way this collector is fed.**
|
||||
⚠️ **don't read that delivery unit as the only way this collector is fed.**
|
||||
Whether it authenticates follows the _credential_, never another service's
|
||||
placement: a swarm collector may run on a host that holds neither store and no
|
||||
authelia, and then the secret is an ordinary operator-provided file named in
|
||||
|
|
@ -91,7 +91,7 @@ not the definition of the case.
|
|||
### Minting the queue's callout nkeys
|
||||
|
||||
`deploy.nats.autoGenerateCallout` mints both keypairs on the host before the queue
|
||||
starts. It is on by default only under `singleHostSwarm` — the one
|
||||
starts. It's on by default only under `singleHostSwarm` — the one
|
||||
topology where the queue, its responder and the operator are the same person. On
|
||||
every other topology, mint them yourself:
|
||||
|
||||
|
|
@ -108,12 +108,12 @@ admit anyone to the queue, so it belongs wherever the responder runs and nowhere
|
|||
else.
|
||||
|
||||
A hive that sets neither the public keys nor `autoGenerateCallout` fails at
|
||||
eval, naming the option it wants. That is deliberate: a queue that started
|
||||
eval, naming the option it wants. that's deliberate: a queue that started
|
||||
without them would accept `CONNECT {"user":"auth"}` from anyone sharing the
|
||||
host's network namespace, and nothing would look wrong until somebody connected.
|
||||
|
||||
**All four or none** — the seed paths are required too, not just the public
|
||||
keys. They are two halves of the same pair: the server verifies with the public
|
||||
keys. they're two halves of the same pair: the server verifies with the public
|
||||
half, the responder signs with the private one. Supplying only the public keys
|
||||
used to pass eval and leave the queue with an auth-callout nobody answers, which
|
||||
refuses every client rather than degrading — and a refusal reaches the client as
|
||||
|
|
@ -139,8 +139,8 @@ bounded wait, 120s — and then **fail loudly** rather than skipping. A silent s
|
|||
produces a service whose login button always fails, which is a symptom several
|
||||
layers from its cause.
|
||||
|
||||
The store's **first reader** is the matrix registration token, and it is worth
|
||||
saying why that one: it is an opaque 32-byte value with no second file and no
|
||||
The store's **first reader** is the matrix registration token, and it's worth
|
||||
saying why that one: it's an opaque 32-byte value with no second file and no
|
||||
format. Authelia's OIDC secret needs a `.secret` _and_ a matching `.digest`, so
|
||||
starting there would have meant debugging "can a reader authenticate and get
|
||||
bytes back" and "did we write authelia's file format right" at once, with an
|
||||
|
|
@ -153,8 +153,8 @@ locally minted token in place, so a hive with no store behaves exactly as it
|
|||
did before.
|
||||
|
||||
⚠️ **Service↔store mTLS is its own trust domain.** A credential you must
|
||||
already hold to authenticate cannot be fetched from the thing it authenticates
|
||||
you to, so the store's identity cannot come from an authority the store
|
||||
already hold to authenticate can't be fetched from the thing it 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
|
||||
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
|
||||
|
|
@ -163,14 +163,14 @@ internal CA deletes that file and names its own paths in
|
|||
`deploy.bao.serverCertFile` / `clientCaFile`; the store itself has no opinion.
|
||||
A hive that reads from a store on **another** machine names the reader's half —
|
||||
`clientCertFile`, `clientKeyFile`, `serverCaFile` — and places that leaf by hand.
|
||||
It is the one credential that cannot come out of the store, being what opens it;
|
||||
it's the one credential that can't come out of the store, being what opens it;
|
||||
everything else a hive needs does.
|
||||
|
||||
## The constraint that decides where the root lives
|
||||
|
||||
A hive CA carries `nameConstraints=permitted;DNS:<hive domain>`, and **a swarm
|
||||
service name is a sibling of the hive domain rather than a child** — `forge.<swarm>`
|
||||
next to `<hive>.<swarm>`. So a hive CA cannot issue a certificate for a swarm
|
||||
next to `<hive>.<swarm>`. So a hive CA can't issue a certificate for a swarm
|
||||
service. Not by policy: by construction, and openssl enforces it.
|
||||
|
||||
Whatever holds the swarm root is therefore what makes swarm-service certificates
|
||||
|
|
@ -188,4 +188,4 @@ possible at all. Two things follow:
|
|||
|
||||
State three things, in the row you add above: **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 does not bind.
|
||||
needs a delivery unit, and the unit copies — it doesn't bind.
|
||||
|
|
|
|||
Loading…
Reference in a new issue