# This agent's own credential for the swarm queue, read from the store by the # harness itself. # # The credential beside it in ./queue.nix is keyed per **hive**: one OIDC # client minted at deploy time and handed to every agent container on the # hive, so at the queue's auth callout one agent is indistinguishable from its # co-hived neighbours. This one is keyed per **agent** — `swarm-controller` # mints it at agent creation into `swarm/agents//queue` # (`swarm_secret_client::queue::agent_queue_path`), at swarm level, with no # hive anywhere in the chain. # # The agent authenticates to the store as itself, with the certificate # ./bao.nix already proves it can log in with, and reads its own path. A hive # courier in the path would be the hive vouching for which agent this is, # which is the property the per-agent credential exists to remove. # # Nothing here writes the secret anywhere. The harness reads it into memory # before its first queue connection and again on every reconnect attempt # (`hive-agent`'s `swarm_queue`), so a re-minted secret is picked up without a # restart. What this module hands the harness is the store's address and the # paths of its certificate. # # ⛔ The store certificate is for reaching the store and nothing else. It is # never presented to the queue: what goes to the queue is the secret read # back from this path. { lib, config, ... }: let cfg = config.services.hyperhive.agent.bao; # This container's agent name — the same string `swarm-controller` minted # the credential under, because the agent's unix user is named for the # agent (see ./user.nix). The harness builds the path and the cert-auth # role from it. agentName = config.services.hyperhive.agent.user.name; # The same three ids ./bao.nix loads, because there is one store identity # per agent; the ids are `hive_c0re::lifecycle::agent_identity`'s and a # rename is a rename there too. certCredential = "hive-agent-bao-cert"; keyCredential = "hive-agent-bao-key"; serverCaCredential = "hive-agent-bao-server-ca"; # The store's address is the whole switch, exactly as in ./bao.nix — and # deliberately *not* the queue coordinates in ./queue.nix. Those are the # hive's, and gating a swarm-minted per-agent credential on a hive-level # option would put the hive back in a path whose entire purpose is not # having one. configured = cfg.addr != null; in { config = lib.mkIf configured { systemd.services.hive-agent = { # Bare ids, no paths: the terse `LoadCredential=` form that inherits a # credential the service *manager* received, which is what the container # manager passed in. ./bao.nix and ./queue.nix state the same shape. serviceConfig.LoadCredential = [ certCredential keyCredential serverCaCredential ]; # Paths and a name only. `%d` is this unit's own credentials directory. environment = { HIVE_AGENT_NAME = agentName; BAO_ADDR = cfg.addr; BAO_CLIENT_CERT = "%d/${certCredential}"; BAO_CLIENT_KEY = "%d/${keyCredential}"; # Named even when no CA was delivered: a bare `LoadCredential=` is # non-fatal when absent, and the harness treats a missing or empty file # as "use the container's own trust store". BAO_CACERT = "%d/${serverCaCredential}"; }; }; }; }