Context
PR #143 switches DinD to rootless mode, which prevents inner containers from flushing outer iptables rules via user namespace isolation. This is the current solution.
However, rootless DinD has known limitations (overlay2 driver restrictions, UID mapping edge cases, compatibility with certain images). This issue documents what would be needed to securely run rootful DinD instead — a Docker API filtering proxy between the opencode container and the DinD sidecar.
Required components
1. Docker API filtering proxy
A reverse proxy (jailoc system dind-proxy hidden subcommand) that intercepts Docker Engine API calls and blocks dangerous operations:
/containers/create — reject Privileged, NetworkMode: host, dangerous CapAdd (NET_ADMIN, NET_RAW, SYS_ADMIN, SYS_PTRACE), bind mounts to sensitive paths (/proc, /sys, host Docker socket)
/containers/{id}/exec and /exec/{id}/start — block entirely (exec can escalate to root inside containers)
/containers/{id}/update — block (can re-add capabilities post-creation)
/containers/{id}/archive PUT — block (can overwrite arbitrary files in containers)
/build — allow, but stream tar context without buffering
- Versioned paths — handle
/v1.47/... prefix stripping
Errors returned as Docker-format JSON: {"message": "blocked by jailoc proxy: ..."}.
2. mTLS on both hops
- opencode ↔ proxy: proxy presents DinD's server cert (extend DinD SAN with
DNS:dind-proxy)
- proxy ↔ DinD: proxy uses DinD client certs for upstream connection
- New
dind-certs-server named volume to persist DinD's /certs/server/ (currently only ca and client are volumes)
3. Network-level bypass prevention
iptables rule in opencode's entrypoint.sh to block direct access to dind:2376, forcing all traffic through the proxy:
iptables -I JAILOC-OUTPUT -d dind -p tcp --dport 2376 -j DROP
iptables -I JAILOC-OUTPUT -d dind -p tcp --dport 2375 -j DROP
4. Compose template changes
- Add
dind-proxy service (runs jailoc system dind-proxy)
- Mount jailoc binary into the proxy container (or build/download a Linux binary)
- Route
DOCKER_HOST from opencode to dind-proxy:2376 instead of dind:2376
- Add
dind-certs-server volume
5. Binary delivery problem
The jailoc binary on the host may be Darwin (macOS). The proxy runs in a Linux container. Options:
- Download Linux binary from GitHub Releases at container start
- Build from source inside the container (slow)
- Publish a separate proxy container image
This is the main unresolved design question.
Blocklist vs allowlist
The proposed approach is blocklist (allow all API calls, block known-dangerous ones). This is pragmatic but has an inherent risk of missing new dangerous endpoints in future Docker API versions. An allowlist approach would be safer but significantly more restrictive and harder to maintain.
References
Context
PR #143 switches DinD to rootless mode, which prevents inner containers from flushing outer iptables rules via user namespace isolation. This is the current solution.
However, rootless DinD has known limitations (overlay2 driver restrictions, UID mapping edge cases, compatibility with certain images). This issue documents what would be needed to securely run rootful DinD instead — a Docker API filtering proxy between the opencode container and the DinD sidecar.
Required components
1. Docker API filtering proxy
A reverse proxy (
jailoc system dind-proxyhidden subcommand) that intercepts Docker Engine API calls and blocks dangerous operations:/containers/create— rejectPrivileged,NetworkMode: host, dangerousCapAdd(NET_ADMIN,NET_RAW,SYS_ADMIN,SYS_PTRACE), bind mounts to sensitive paths (/proc,/sys, host Docker socket)/containers/{id}/execand/exec/{id}/start— block entirely (exec can escalate to root inside containers)/containers/{id}/update— block (can re-add capabilities post-creation)/containers/{id}/archivePUT — block (can overwrite arbitrary files in containers)/build— allow, but stream tar context without buffering/v1.47/...prefix strippingErrors returned as Docker-format JSON:
{"message": "blocked by jailoc proxy: ..."}.2. mTLS on both hops
DNS:dind-proxy)dind-certs-servernamed volume to persist DinD's/certs/server/(currently onlycaandclientare volumes)3. Network-level bypass prevention
iptables rule in opencode's
entrypoint.shto block direct access todind:2376, forcing all traffic through the proxy:4. Compose template changes
dind-proxyservice (runsjailoc system dind-proxy)DOCKER_HOSTfrom opencode todind-proxy:2376instead ofdind:2376dind-certs-servervolume5. Binary delivery problem
The jailoc binary on the host may be Darwin (macOS). The proxy runs in a Linux container. Options:
This is the main unresolved design question.
Blocklist vs allowlist
The proposed approach is blocklist (allow all API calls, block known-dangerous ones). This is pragmatic but has an inherent risk of missing new dangerous endpoints in future Docker API versions. An allowlist approach would be safer but significantly more restrictive and harder to maintain.
References
.sisyphus/plans/docker-socket-proxy.mdinfix-dind-proxybranch