move the squid host options to deploy.hive-controller.squid
This commit is contained in:
parent
c9b5705ad8
commit
da16487800
2 changed files with 168 additions and 57 deletions
|
|
@ -225,7 +225,7 @@ host. It never decrypts TLS, so it holds no signing key. It caches nothing.
|
|||
credential (HTTP Basic, the agent's name and its secret). `swarm-controller`
|
||||
mints one per agent at `swarm/agents/<agent>/proxy-credential`, and never
|
||||
replaces it. `hive-c0re` hashes the credentials of this hive's agents, and
|
||||
one more for the self-check, into `services.hyperhive.squid.usersFile`
|
||||
one more for the self-check, into `services.hyperhive.deploy.hive-controller.squid.usersFile`
|
||||
every 30 seconds. Squid's `basic_ncsa_auth` helper re-reads the file when it
|
||||
changes. A stopped agent stays in the file. Squid caches a good login for a
|
||||
minute. Nothing rotates a credential: to replace one, delete its leaf in the
|
||||
|
|
@ -238,7 +238,7 @@ host. It never decrypts TLS, so it holds no signing key. It caches nothing.
|
|||
- **Agents and the proxy.** An agent uses the proxy only when its hive says
|
||||
this host's squid is ready for it. `hive-c0re` puts two facts in every
|
||||
container's `/etc/hyperhive-hive-facts`, only on a hive that holds a store
|
||||
identity: `HIVE_SQUID_PROXY` (`services.hyperhive.squid.listen`, the bridge IP
|
||||
identity: `HIVE_SQUID_PROXY` (`services.hyperhive.deploy.hive-controller.squid.listen`, the bridge IP
|
||||
and port) and `HIVE_EGRESS_NO_PROXY` (the direct hosts below). A hive that
|
||||
predates them writes neither, and its agents go direct.
|
||||
`hive-agent-proxy-credential.service` (`nix/agent-modules/egress-proxy.nix`)
|
||||
|
|
@ -272,7 +272,7 @@ host. It never decrypts TLS, so it holds no signing key. It caches nothing.
|
|||
has no CIDR support, so the list holds the bridge as an address.
|
||||
|
||||
- **Two lists.** The credential decides the policy. `hive-c0re` writes a
|
||||
second file beside the users file, `services.hyperhive.squid.unrestrictedFile`
|
||||
second file beside the users file, `services.hyperhive.deploy.hive-controller.squid.unrestrictedFile`
|
||||
(`/var/lib/hive-squid/unrestricted`, `hive-core:squid`, `0640`): the names of
|
||||
the users whose agent holds the `unrestricted_internet` flag in the
|
||||
permissions the hive last read from the swarm, one per line, rewritten when
|
||||
|
|
@ -289,7 +289,7 @@ host. It never decrypts TLS, so it holds no signing key. It caches nothing.
|
|||
restricted. Agents must not start sending credentials until every hive runs
|
||||
the `hive-c0re` that writes it, or a legacy agent loses general internet.
|
||||
|
||||
- **Base list.** `services.hyperhive.squid.baseAllowedDomains` is open to every
|
||||
- **Base list.** `services.hyperhive.deploy.hive-controller.squid.baseAllowedDomains` is open to every
|
||||
authenticated user, whatever its flag: what the agent harness needs off the
|
||||
swarm. The default is the hosts Claude Code requires
|
||||
(<https://code.claude.com/docs/en/network-config>): `api.anthropic.com` for
|
||||
|
|
@ -300,8 +300,8 @@ host. It never decrypts TLS, so it holds no signing key. It caches nothing.
|
|||
agent's own swarm entries (see _Swarm allow-list_ below). The list omits the plugin marketplace clone from `github.com`, since a failed add
|
||||
isn't fatal. The rules below still refuse an entry that resolves to a
|
||||
private address.
|
||||
- **Allow-list.** `services.hyperhive.squid.allowedDomains` defaults to empty,
|
||||
plus the self-check canary (`services.hyperhive.squid.selfcheck.canary`), so
|
||||
- **Allow-list.** `services.hyperhive.deploy.hive-controller.squid.allowedDomains` defaults to empty,
|
||||
plus the self-check canary (`services.hyperhive.deploy.hive-controller.squid.selfcheck.canary`), so
|
||||
the canary widens the restricted list by that one name. The swarm's own
|
||||
service names aren't on it: they resolve to the bridge or a private address,
|
||||
which the rules below refuse, and agents reach them directly. Each entry
|
||||
|
|
@ -313,8 +313,8 @@ host. It never decrypts TLS, so it holds no signing key. It caches nothing.
|
|||
([allowed domains](../swarm/ui.md#allowed-domains)); the swarm controller
|
||||
keeps them in one value of the `egress-allow` bucket, each for every agent
|
||||
or for one agent. Every 30 seconds `hive-c0re` reads it and writes two files
|
||||
beside the users file, `services.hyperhive.squid.allowedFile`
|
||||
(`/var/lib/hive-squid/allowed`) and `services.hyperhive.squid.agentAllowFile`
|
||||
beside the users file, `services.hyperhive.deploy.hive-controller.squid.allowedFile`
|
||||
(`/var/lib/hive-squid/allowed`) and `services.hyperhive.deploy.hive-controller.squid.agentAllowFile`
|
||||
(`/var/lib/hive-squid/agent-allow.conf`), `hive-core:squid`, `0640`, and
|
||||
logs `squid allow list: 2 swarm, 3 agent entries` when they change. The
|
||||
swarm-wide names join the allow ACL, so a restricted user reaches them. A
|
||||
|
|
@ -387,12 +387,12 @@ host. It never decrypts TLS, so it holds no signing key. It caches nothing.
|
|||
client's source address.
|
||||
- **Self-check.** `squid-selfcheck.timer` runs `squid-selfcheck.service`
|
||||
every minute from the bridge IP, logging in as `selfcheck.squid`: `CONNECT`
|
||||
to `services.hyperhive.squid.selfcheck.canary` (default: `cache.nixos.org`,
|
||||
to `services.hyperhive.deploy.hive-controller.squid.selfcheck.canary` (default: `cache.nixos.org`,
|
||||
a public name that's also on the allow-list)
|
||||
must answer 200, to `deny-canary.invalid` 403, and to the canary without a
|
||||
credential 407. It then logs in as `selfcheck-unrestricted.squid`, which has
|
||||
the same secret and is always on the unrestricted list, and a `CONNECT` to
|
||||
`services.hyperhive.squid.selfcheck.unrestrictedCanary` (default:
|
||||
`services.hyperhive.deploy.hive-controller.squid.selfcheck.unrestrictedCanary` (default:
|
||||
`example.com`, a name outside the allow-list) must answer 200. It writes one
|
||||
`squid-selfcheck ok=… allow_status=… deny_status=… anon_status=…
|
||||
credential=present|absent unrestricted_canary=… unrestricted_status=…` line
|
||||
|
|
|
|||
|
|
@ -149,16 +149,16 @@ pieces fit, and the reasoning behind them, is in [`credentials.md`](credentials.
|
|||
|
||||
### Hive-level — one of each per hive
|
||||
|
||||
| secret | generated by | lives at |
|
||||
| ---------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| hive leaf certs | `hive-tls.nix`, issued by the secret store's `pki` mount | `<deploy.hive-controller.tls.stateDir>/<name>.pem` |
|
||||
| the hive's own store identity | `glue-bao-tls.nix` on the store's host; placed by hand on every other host ([`ca.md`](ca.md#the-gateway-leaf-comes-from-the-secret-store)) | `deploy.hive-controller.tls.baoHiveIdentityCertFile` / `baoHiveIdentityKeyFile` |
|
||||
| the cache's public key and pull token, for hive-priv | `swarm-controller` copies them to `swarm/hives/<hive>/attic/{public-key,pull-token}` (see the cache-facts row above) | `hive-priv-cache-facts` (root) reads those two under the hive's own store identity every ten minutes and writes `/run/hyperhive-priv/attic/public-key` and `netrc` (tmpfs, root, each `0600`, directory `0700`); the cache's address comes from `services.hyperhive.swarm.attic.domain` and `cache`, not from the store. A store that holds no facts, or that doesn't answer, leaves the files as they stand, and a hive that never got them has `hive-priv` answer `not available`. |
|
||||
| the forge's copy of its OIDC secret | `swarm-bao-forge-oidc.service` reads it out of the swarm secret store under the forge publisher's leaf, wherever authelia runs | `/run/hive-forge-oidc/<id>.secret` on the host (tmpfs), bound into the forge container, handed to `forgejo-sso-source` through `LoadCredential` |
|
||||
| the homeserver's copy of its OIDC secret | `swarm-bao-matrix-oidc.service` reads it out of the swarm secret store under matrix-ctl's leaf, wherever authelia runs | `/run/hive-matrix-oidc/<id>.secret` on the host (tmpfs), bound into the homeserver container, handed to tuwunel through `LoadCredential` |
|
||||
| this hive's forge read token | `swarm-controller`, into the secret store at `swarm/hives/<hive>/forge/token`, for the `hive-<hive>` account; a pass at start and every five minutes re-mints a missing or stale token | `hive-c0re` reads it under the hive's own store identity, and copies it (account on the first line, token on the second) to `/run/hyperhive/forge-hive-token` (tmpfs, `0600` `hive-core`) for nix's `git`, which `hive-priv` also runs. Each `internal/meta` read and each boot rewrites the copy when it differs; where they differ after a rotation, a build that starts before the next read fails to authenticate, and a retry reads the new token |
|
||||
| squid's users file | `hive-c0re` (`workers::squid_users`), every 30 seconds, from the proxy credentials of its agents and the self-check | `services.hyperhive.squid.usersFile` (`/var/lib/hive-squid/users`, `hive-core:squid`, `0640`): `<user>:<hash>` lines, SHA-512 crypt hashes only, renamed into place when it changed. `unrestricted` beside it lists the users whose agent holds the swarm's `unrestricted_internet` flag, names only; it lists every agent the hive never read as off `systemd-tmpfiles` creates it empty so squid's helper never sees a missing file. A hive whose agents have no credential yet (an older controller) has an empty file: every login fails and the self-check reports `ok=false`; an agent without one sends none, so it goes direct |
|
||||
| the squid self-check's password | `swarm-controller` mints `swarm/hives/<hive>/squid-selfcheck`; `squid-selfcheck-credential` (root, every 10 minutes) reads it as the hive | `/run/credstore/hive-squid.selfcheck` (tmpfs, root, `0400`), imported by `squid-selfcheck.service` as a systemd credential and handed to `curl` on its stdin. Both self-check users (`selfcheck.squid` and the always-unrestricted `selfcheck-unrestricted.squid`) use it, so whoever holds it has unrestricted egress through this squid Missing, or different from the users file: the self-check logs `credential=absent` or a 407 and fails, and nothing else breaks |
|
||||
| secret | generated by | lives at |
|
||||
| ---------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| hive leaf certs | `hive-tls.nix`, issued by the secret store's `pki` mount | `<deploy.hive-controller.tls.stateDir>/<name>.pem` |
|
||||
| the hive's own store identity | `glue-bao-tls.nix` on the store's host; placed by hand on every other host ([`ca.md`](ca.md#the-gateway-leaf-comes-from-the-secret-store)) | `deploy.hive-controller.tls.baoHiveIdentityCertFile` / `baoHiveIdentityKeyFile` |
|
||||
| the cache's public key and pull token, for hive-priv | `swarm-controller` copies them to `swarm/hives/<hive>/attic/{public-key,pull-token}` (see the cache-facts row above) | `hive-priv-cache-facts` (root) reads those two under the hive's own store identity every ten minutes and writes `/run/hyperhive-priv/attic/public-key` and `netrc` (tmpfs, root, each `0600`, directory `0700`); the cache's address comes from `services.hyperhive.swarm.attic.domain` and `cache`, not from the store. A store that holds no facts, or that doesn't answer, leaves the files as they stand, and a hive that never got them has `hive-priv` answer `not available`. |
|
||||
| the forge's copy of its OIDC secret | `swarm-bao-forge-oidc.service` reads it out of the swarm secret store under the forge publisher's leaf, wherever authelia runs | `/run/hive-forge-oidc/<id>.secret` on the host (tmpfs), bound into the forge container, handed to `forgejo-sso-source` through `LoadCredential` |
|
||||
| the homeserver's copy of its OIDC secret | `swarm-bao-matrix-oidc.service` reads it out of the swarm secret store under matrix-ctl's leaf, wherever authelia runs | `/run/hive-matrix-oidc/<id>.secret` on the host (tmpfs), bound into the homeserver container, handed to tuwunel through `LoadCredential` |
|
||||
| this hive's forge read token | `swarm-controller`, into the secret store at `swarm/hives/<hive>/forge/token`, for the `hive-<hive>` account; a pass at start and every five minutes re-mints a missing or stale token | `hive-c0re` reads it under the hive's own store identity, and copies it (account on the first line, token on the second) to `/run/hyperhive/forge-hive-token` (tmpfs, `0600` `hive-core`) for nix's `git`, which `hive-priv` also runs. Each `internal/meta` read and each boot rewrites the copy when it differs; where they differ after a rotation, a build that starts before the next read fails to authenticate, and a retry reads the new token |
|
||||
| squid's users file | `hive-c0re` (`workers::squid_users`), every 30 seconds, from the proxy credentials of its agents and the self-check | `services.hyperhive.deploy.hive-controller.squid.usersFile` (`/var/lib/hive-squid/users`, `hive-core:squid`, `0640`): `<user>:<hash>` lines, SHA-512 crypt hashes only, renamed into place when it changed. `unrestricted` beside it lists the users whose agent holds the swarm's `unrestricted_internet` flag, names only; it lists every agent the hive never read as off `systemd-tmpfiles` creates it empty so squid's helper never sees a missing file. A hive whose agents have no credential yet (an older controller) has an empty file: every login fails and the self-check reports `ok=false`; an agent without one sends none, so it goes direct |
|
||||
| the squid self-check's password | `swarm-controller` mints `swarm/hives/<hive>/squid-selfcheck`; `squid-selfcheck-credential` (root, every 10 minutes) reads it as the hive | `/run/credstore/hive-squid.selfcheck` (tmpfs, root, `0400`), imported by `squid-selfcheck.service` as a systemd credential and handed to `curl` on its stdin. Both self-check users (`selfcheck.squid` and the always-unrestricted `selfcheck-unrestricted.squid`) use it, so whoever holds it has unrestricted egress through this squid Missing, or different from the users file: the self-check logs `credential=absent` or a 407 and fails, and nothing else breaks |
|
||||
|
||||
### Store identities, one per principal
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue