feat(#2641): sudoless hivectl via a hive-admin group on the host socket
The host admin socket `/run/hyperhive/host.sock` was `0660 root:root` (no SocketGroup), so hivectl needed sudo. Group-own it by a new `hive-admin` group and add a `services.hyperhive.c0re.adminUsers` allowlist: listed users join `hive-admin` and drive hivectl without root. - `SocketGroup = "hive-admin"`, `SocketMode = "0660"` on the hive-c0re.socket unit. - `/run/hyperhive` -> `0751` (traverse-only, no listing) so the group can reach the socket path; the socket's own `0660 hive-admin` mode gates the connection, and the per-agent subdirs keep their own restrictive perms. - Empty `adminUsers` (the default) leaves `hive-admin` memberless -> root-only, as before. The admin socket is full hive control (spawn/kill/destroy/deploy), so `adminUsers` is an explicit, opt-in trust grant. Documented in docs/boundary.md (host admin socket access) + docs/tools/hivectl.md.
This commit is contained in:
parent
c4deca99db
commit
30a2a2e9de
4 changed files with 68 additions and 7 deletions
|
|
@ -93,3 +93,22 @@ root's primary group rather than `hive-core`, so a `hive-core` client
|
|||
couldn't connect the way the socket unit's `SocketGroup` grant
|
||||
intends. Requiring socket activation everywhere means dev and prod
|
||||
take the exact same path and the group grant always holds.
|
||||
|
||||
### host admin socket access (`hivectl`)
|
||||
|
||||
`hivectl` drives the whole hive — spawn / kill / destroy / rebuild /
|
||||
deploy — over the **host admin socket** `/run/hyperhive/host.sock`,
|
||||
socket-activated by the `hive-c0re.socket` unit. That socket *is* the
|
||||
full-control surface, so who can connect to it is a real trust
|
||||
boundary.
|
||||
|
||||
By default the socket is `0660` group-owned by **`hive-admin`**, an
|
||||
empty group — so it is effectively **root-only** until an operator is
|
||||
explicitly granted access. Grant sudoless `hivectl` by listing login
|
||||
users in `services.hyperhive.c0re.adminUsers`; each is added to
|
||||
`hive-admin`, and members connect without `sudo`. The runtime dir
|
||||
`/run/hyperhive` is `0751` (traverse-only, no listing) so the group can
|
||||
reach the socket path; the socket's own `0660 hive-admin` mode gates
|
||||
the connection, and the per-agent subdirs under it keep their own
|
||||
restrictive perms. Keep `adminUsers` to trusted operators — membership
|
||||
is equivalent to root over the hive.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,12 @@
|
|||
# hivectl
|
||||
|
||||
`hivectl` is the operator-facing host CLI for hyperhive. It lives on the
|
||||
host (not inside any container) and requires root for most operations.
|
||||
host (not inside any container). It talks to `hive-c0re` over the host
|
||||
admin socket `/run/hyperhive/host.sock`, which is root-only by default —
|
||||
so it needs `sudo` unless you grant sudoless access by listing your
|
||||
login user in `services.hyperhive.c0re.adminUsers` (adds you to the
|
||||
`hive-admin` group that owns the socket; see
|
||||
[`docs/boundary.md`](../boundary.md#host-admin-socket-access-hivectl)).
|
||||
Available via the `hive-c0re` package in the host NixOS config.
|
||||
|
||||
Unlike the `hive-c0re` daemon subcommands (which go through the broker),
|
||||
|
|
|
|||
|
|
@ -126,6 +126,15 @@ in
|
|||
};
|
||||
users.groups.hive-core = { };
|
||||
|
||||
# Operators granted sudoless `hivectl`. Members of `hive-admin` can
|
||||
# connect to the host admin socket (group-owned by hive-admin via the
|
||||
# socket unit's `SocketGroup` below) without root. That socket is *full*
|
||||
# hive control (spawn/kill/destroy/deploy, docs/boundary.md), so this is
|
||||
# an explicit opt-in allowlist — empty by default (root-only).
|
||||
users.groups.hive-admin = {
|
||||
members = cfg.adminUsers;
|
||||
};
|
||||
|
||||
# The gateway nginx is always the sole external entry point (it runs
|
||||
# alongside hyperhive), so the per-agent web-port range stays closed on
|
||||
# the host firewall. See `docs/gateway.md::Firewall posture (host-level)`.
|
||||
|
|
@ -189,7 +198,12 @@ in
|
|||
Group = "hive-core";
|
||||
SupplementaryGroups = [ "systemd-journal" ];
|
||||
RuntimeDirectory = "hyperhive";
|
||||
RuntimeDirectoryMode = "0750";
|
||||
# 0751 (traverse-only, no listing) so `hive-admin` operators can reach
|
||||
# the host admin socket (`SocketGroup = "hive-admin"`, 0660) without
|
||||
# root. Others can traverse but not list; the socket + per-agent
|
||||
# subdirs gate access by their own perms. Matches the socket unit's
|
||||
# DirectoryMode.
|
||||
RuntimeDirectoryMode = "0751";
|
||||
RuntimeDirectoryPreserve = "yes";
|
||||
StateDirectory = "hyperhive";
|
||||
StateDirectoryMode = "0750";
|
||||
|
|
@ -251,12 +265,18 @@ in
|
|||
socketConfig = {
|
||||
# Must match the `--socket` arg passed to `hive-c0re serve`.
|
||||
ListenStream = "/run/hyperhive/host.sock";
|
||||
# 0660 root:root — `hivectl` is a host-only tool run as root.
|
||||
# `0660 root:hive-admin` — group-owned by `hive-admin` so operators in
|
||||
# that group (services.hyperhive.c0re.adminUsers) drive `hivectl`
|
||||
# without root; an empty adminUsers list leaves the group memberless,
|
||||
# so it stays effectively root-only. See docs/boundary.md.
|
||||
SocketMode = "0660";
|
||||
# Parent dir inherits the RuntimeDirectory mode (0750) set on the
|
||||
# service unit; DirectoryMode is only consulted when the dir is
|
||||
# absent at socket-unit activation.
|
||||
DirectoryMode = "0750";
|
||||
SocketGroup = "hive-admin";
|
||||
# `0751` (traverse-only, no listing) so hive-admin can reach the socket
|
||||
# path — the socket's own `0660 hive-admin` gates the connection, and
|
||||
# the per-agent subdirs under here keep their own restrictive perms.
|
||||
# Must match the service unit's RuntimeDirectoryMode. DirectoryMode is
|
||||
# only consulted when the dir is absent at socket-unit activation.
|
||||
DirectoryMode = "0751";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -315,5 +315,22 @@
|
|||
serialized by its lifecycle lease regardless.
|
||||
'';
|
||||
};
|
||||
|
||||
adminUsers = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
example = [ "alice" ];
|
||||
description = ''
|
||||
Login users granted **sudoless `hivectl`**. Each is added to the
|
||||
`hive-admin` group, which group-owns the host admin socket
|
||||
(`/run/hyperhive/host.sock`, mode `0660`) — so listed users drive
|
||||
`hivectl` (and thus the whole hive) without `sudo`.
|
||||
|
||||
This is a real privilege grant: the admin socket is *full* hive
|
||||
control — spawn / kill / destroy / deploy — see `docs/boundary.md`.
|
||||
Keep the list to trusted operators. Empty (the default) keeps the
|
||||
socket root-only, as before.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue