Watch
0
0
Fork
You've already forked hyperhive
0

say that the backend env leaf and file are agent-writable, and why that is accepted

This commit is contained in:
atlas 2026-10-27 22:12:52 +01:00
commit be3a3af093
4 changed files with 22 additions and 4 deletions

View file

@ -305,7 +305,11 @@ The file lives in the agent's bind-mounted **harness** dir, not `state/`
— `harness/` survives container rebuilds exactly like `state/` does, but — `harness/` survives container rebuilds exactly like `state/` does, but
(unlike `state/`) is never bind-mounted into a parent agent's container (unlike `state/`) is never bind-mounted into a parent agent's container
(see `docs/agent-lifecycle/persistence.md`'s "Parent access to child state"), so an API (see `docs/agent-lifecycle/persistence.md`'s "Parent access to child state"), so an API
key placed here is reachable by nothing but this agent and the host. key placed here is reachable by nothing but this agent and the host. The
file doesn't stay root-owned, though: the container's activation chowns the
whole harness dir to the agent, so after the next boot the file is agent-owned
whatever owner you installed it with, and the agent can rewrite it. That holds
until the swarm secret store replaces the file.
<!-- vale write-good.Passive = NO --> <!-- vale write-good.Passive = NO -->

View file

@ -192,7 +192,10 @@ in
read-write for recovery — see `docs/agent-lifecycle/persistence.md`'s "Cross-agent access to read-write for recovery — see `docs/agent-lifecycle/persistence.md`'s "Cross-agent access to
state"), so this credential is reachable by nothing but this agent state"), so this credential is reachable by nothing but this agent
and the host. Permissions should be `0600`, owned by the agent's and the host. Permissions should be `0600`, owned by the agent's
unix user. Loaded with a leading `-` (optional `EnvironmentFile`), unix user. Whatever owner it was installed with, the file becomes
agent-owned at the container's next boot, so the agent can rewrite it;
it is no boundary the agent can't cross until the swarm secret store
replaces the file. Loaded with a leading `-` (optional `EnvironmentFile`),
so a path that doesn't exist yet — an operator setting this option so a path that doesn't exist yet — an operator setting this option
before creating the file, or a fresh host rebuild before state is before creating the file, or a fresh host rebuild before state is
restored — makes systemd skip it rather than refuse to start the restored — makes systemd skip it rather than refuse to start the

View file

@ -18,6 +18,12 @@
# systemd lets a later file override an earlier one, so the store's value wins # systemd lets a later file override an earlier one, so the store's value wins
# when there is one, and the file carries the agent when the store is down. # when there is one, and the file carries the agent when the store is down.
# #
# The leaf's create grant cannot constrain content, so while the leaf is empty
# the agent's own process can also create it with any text, and the store's
# value then wins over the file. That is no wider than the file the agent
# already owns: `./user.nix`'s `heal_own_dir` chowns the harness dir to the
# agent at every activation, a gap the issue tracker has an open bug for.
#
# The unit runs as root because the file is root-owned `0600` where an operator # The unit runs as root because the file is root-owned `0600` where an operator
# placed it. Root can still read the agent's `0400` store identity. # placed it. Root can still read the agent's `0400` store identity.
{ {

View file

@ -205,8 +205,13 @@ const ENTITY_NAME_TEMPLATE: &str = "{{identity.entity.name}}";
/// ///
/// The one write is `create` on the agent's own [`backend_env`] leaf, without /// The one write is `create` on the agent's own [`backend_env`] leaf, without
/// `update`: the agent seeds it from the file it has today, once, and cannot /// `update`: the agent seeds it from the file it has today, once, and cannot
/// replace it. Any other write would let an agent hand itself an identity it /// replace it. The stanza cannot constrain the content, and the agent's own
/// was never issued. An agent has no business with another agent's /// process holds the identity, so while the leaf is empty it can also create it
/// with any text, and the store's value then wins over the file. That is no
/// wider than the harness-dir file the agent already owns:
/// `nix/agent-modules/user.nix`'s `heal_own_dir` chowns that dir to the agent at
/// every activation, a gap the issue tracker has an open bug for. Any other
/// write would let an agent hand itself an identity it was never issued. An agent has no business with another agent's
/// credentials, a hive's, a service's, or the controller's, so none of /// credentials, a hive's, a service's, or the controller's, so none of
/// [`render_shared_hives`]'s breadth applies. A hive still reads this /// [`render_shared_hives`]'s breadth applies. A hive still reads this
/// agent's secrets, and closing that is its own decision. /// agent's secrets, and closing that is its own decision.