harden(explore): root socat bridge for docker socket access instead of group-grant (ward#315) #319

Closed
opened 2026-06-25 08:05:41 +00:00 by coilyco-ops · 2 comments
Member

Deferred from the ward#315 explore dispatch landing.

To let the read-only explore session dispatch a sibling warded #N, the host docker socket is bind-mounted into the box and grant_docker_socket_access adds the dropped agent to the socket's owning group (created in-container if absent). No chmod/chown touches the socket, because the bind mount shares the host inode and mutating it is a lingering host side-effect.

The group-grant covers the common Linux root:docker 0660 socket. It does not cover a root:root 0660 socket (some Docker Desktop setups) where there is no usable group - dispatch fails there with a permission error.

A root-owned socat bridge fronting the socket (agent talks to a UNIX socket the bridge owns, bridge relays to the real docker socket) would grant access regardless of socket ownership, with no host-inode mutation. More moving parts, stronger coverage. Tracked separately so #315 can land the group-grant path now.

Deferred from the ward#315 explore dispatch landing. To let the read-only explore session dispatch a sibling `warded #N`, the host docker socket is bind-mounted into the box and `grant_docker_socket_access` adds the dropped agent to the socket's **owning group** (created in-container if absent). No `chmod`/`chown` touches the socket, because the bind mount shares the host inode and mutating it is a lingering host side-effect. The group-grant covers the common Linux `root:docker 0660` socket. It does **not** cover a `root:root 0660` socket (some Docker Desktop setups) where there is no usable group - dispatch fails there with a permission error. A **root-owned socat bridge** fronting the socket (agent talks to a UNIX socket the bridge owns, bridge relays to the real docker socket) would grant access regardless of socket ownership, with no host-inode mutation. More moving parts, stronger coverage. Tracked separately so #315 can land the group-grant path now.
Author
Member

Landed on main as e626d60. For a root:root docker socket (no group to join, e.g. Docker Desktop), the entrypoint now runs a root socat bridge exposing an agent-group-owned socket (group=$AGENT_GID,mode=0660) forwarding to the real host socket; the dropped agent reaches it via DOCKER_HOST. No chmod/chown touches the shared host inode, so the no-host-mutation guarantee holds. Mirrored in the bash entrypoint and the Go bootstrap, with an entrypoint-embed test and docs. Needs socat in the dev-base image (agentic-os 207f5b7). The group-grant from ward#315 stays the path for group-owned sockets.

Landed on main as `e626d60`. For a `root:root` docker socket (no group to join, e.g. Docker Desktop), the entrypoint now runs a root `socat` bridge exposing an agent-group-owned socket (`group=$AGENT_GID,mode=0660`) forwarding to the real host socket; the dropped agent reaches it via `DOCKER_HOST`. No chmod/chown touches the shared host inode, so the no-host-mutation guarantee holds. Mirrored in the bash entrypoint and the Go bootstrap, with an entrypoint-embed test and docs. Needs `socat` in the dev-base image (agentic-os `207f5b7`). The group-grant from ward#315 stays the path for group-owned sockets.
Owner

Reproduced from a warded explore session running on the pre-v0.125.0 image, after manually installing the docker static client into the container to isolate the two walls:

  • Client side is now fine: docker --version -> Docker version 28.5.1, and the client talks (docker version prints the client block). So with agentic-os v0.125.0 shipping the docker CLI in the image, the ward#321 "no client" wall is closed.
  • The socket wall remains exactly as described here. The mounted socket is srw-rw---- 1 root root /var/run/docker.sock, the dropped agent is uid=1000(ubuntu) with groups adm dialout cdrom floppy sudo audio dip video plugdev - no root/docker group. Result:
docker -H unix:///var/run/docker.sock version
permission denied while trying to connect to the Docker daemon socket at
unix:///var/run/docker.sock: ... connect: permission denied
  • No self-rescue available from inside: sudo is not installed (sudo: command not found), so the dropped agent cannot run the client as root, cannot chmod/chown the socket (and must not - the bind mount shares the host inode), and cannot stand up the root socat bridge this issue proposes. socat is also absent on this pre-v0.125.0 image (it ships in v0.125.0 alongside the client).

So on a root:root 0660 socket, dispatch from explore is hard-blocked with no in-container workaround: the grant or the root socat bridge has to be set up before the agent drops. This is the confirmed end-to-end repro for the bridge ward#319 tracks.

Reproduced from a `warded explore` session running on the **pre-v0.125.0** image, after manually installing the docker static client into the container to isolate the two walls: - Client side is now fine: `docker --version` -> `Docker version 28.5.1`, and the client talks (`docker version` prints the client block). So with agentic-os v0.125.0 shipping the docker CLI in the image, the ward#321 "no client" wall is closed. - The socket wall remains exactly as described here. The mounted socket is `srw-rw---- 1 root root /var/run/docker.sock`, the dropped agent is `uid=1000(ubuntu)` with groups `adm dialout cdrom floppy sudo audio dip video plugdev` - no `root`/`docker` group. Result: ``` docker -H unix:///var/run/docker.sock version permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: ... connect: permission denied ``` - No self-rescue available from inside: `sudo` is not installed (`sudo: command not found`), so the dropped agent cannot run the client as root, cannot `chmod`/`chown` the socket (and must not - the bind mount shares the host inode), and cannot stand up the root socat bridge this issue proposes. socat is also absent on this pre-v0.125.0 image (it ships in v0.125.0 alongside the client). So on a `root:root 0660` socket, dispatch from explore is hard-blocked with no in-container workaround: the grant or the root socat bridge has to be set up before the agent drops. This is the confirmed end-to-end repro for the bridge ward#319 tracks.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
coilyco-flight-deck/ward#319
No description provided.