swarm-controller: restrict its socket directory to nginx's access group
This commit is contained in:
parent
5bb9d7c7e5
commit
51cc093465
4 changed files with 63 additions and 16 deletions
|
|
@ -93,8 +93,8 @@ queue, so both survive a restart.
|
|||
|
||||
## Why a unix socket, not a port
|
||||
|
||||
The hive-gateway's nginx is the only intended client and reaches the socket
|
||||
through a bind-mount. A listener that is never bound to an address cannot be
|
||||
The hive-gateway's nginx is the only intended client (`swarmctl` runs as root).
|
||||
A listener that is never bound to an address cannot be
|
||||
reached from off-host by mistake.
|
||||
|
||||
The socket path is `services.hyperhive.deploy.swarm-controller.socketPath`, default
|
||||
|
|
@ -108,7 +108,12 @@ The socket is `0666`. It has to be: nginx runs as a different user and
|
|||
sockets, and rests on the same argument — _"the bind source dir is per-agent on
|
||||
host so blast radius is unchanged."_
|
||||
|
||||
What keeps that safe is that the directory holds **one** socket. So:
|
||||
What keeps that safe is that the directory is `0750`, owned by the
|
||||
`swarm-controller-clients` group, and holds **one** socket. nginx is in that
|
||||
group through its unit's `SupplementaryGroups`; root bypasses mode bits, so
|
||||
`swarmctl` needs no membership. Every other local user gets `EACCES` at the
|
||||
directory. The group is not `swarm-controller`'s own, which also owns the
|
||||
state directory. So:
|
||||
|
||||
> **Never point `socketPath` at a directory that carries anything else.**
|
||||
> `/run/hyperhive` above all — it holds `host.sock`, the host **admin** socket.
|
||||
|
|
@ -116,7 +121,9 @@ What keeps that safe is that the directory holds **one** socket. So:
|
|||
> socket within its reach too.
|
||||
|
||||
nginx is a host service, so nothing narrows what it can reach except the
|
||||
directory itself — that is the whole of the access control. A unit test pins
|
||||
directory itself — that is the whole of the access control. The unit sets the
|
||||
group with a root `ExecStartPre` (`chgrp`), because systemd chowns the runtime
|
||||
directory to the unit's own group on every start. A unit test pins
|
||||
the default path so a tidying edit fails instead of reviewing cleanly.
|
||||
|
||||
`RuntimeDirectoryPreserve=yes` and the daemon's stale-socket unlink on start are
|
||||
|
|
|
|||
|
|
@ -3468,10 +3468,11 @@ async fn main() -> Result<()> {
|
|||
// 0666 matches how hive-c0re publishes the per-agent sockets
|
||||
// (`socket_server::start`), and rests on the same argument: **the
|
||||
// containing directory is the access control, not the socket mode.**
|
||||
// This directory holds one socket and is bind-mounted into exactly
|
||||
// one container. That is also why it must not be shared with
|
||||
// hive-c0re's `/run/hyperhive` — with a 0666 socket, a directory
|
||||
// that carries more than it should is the whole vulnerability.
|
||||
// The unit makes the directory `0750`, group `swarm-controller-clients`,
|
||||
// so only nginx and root reach the socket. The directory holds one
|
||||
// socket, which is also why it must not be shared with hive-c0re's
|
||||
// `/run/hyperhive` — with a 0666 socket, a directory that carries
|
||||
// more than it should is the whole vulnerability.
|
||||
std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o666))
|
||||
.with_context(|| format!("chmod {}", path.display()))?;
|
||||
tracing::info!(socket = %path.display(), "swarm-controller listening");
|
||||
|
|
|
|||
Loading…
Reference in a new issue