Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ volumes:
portwing-stacks:
```

By design, the `sockguard.yaml` preset above (a copy of sockguard's `portwing.yaml`) denies all exec β€” `POST /containers/*/exec` returns a 403 with an `exec denied: no commands are allowlisted` reason. If Drydock's edge exec feature is in play, use [`examples/docker-compose.edge-with-exec.yml`](examples/docker-compose.edge-with-exec.yml) instead, which pairs edge mode with sockguard's `portwing-with-exec.yaml` preset (`examples/sockguard-with-exec.yaml`) so exec is actually allowed through the proxy. Either way, denial reasons like `exec denied: no commands are allowlisted` now surface in the controller's exec error instead of a bare status code.
By design, the `sockguard.yaml` preset above (a copy of sockguard's `portwing.yaml`) denies all exec β€” `POST /containers/*/exec` matches no allow rule and hits the catch-all deny, returning a 403 with a `not allowed by portwing preset` reason. If Drydock's edge exec feature is in play, use [`examples/docker-compose.edge-with-exec.yml`](examples/docker-compose.edge-with-exec.yml) instead, which pairs edge mode with sockguard's `portwing-with-exec.yaml` preset (`examples/sockguard-with-exec.yaml`) so exec is actually allowed through the proxy; under that preset, policy denials carry specific reasons instead, like `exec denied: privileged exec is not allowed`. Either way, the denial reason now reaches Portwing's exec error and is forwarded in the `exec_end` frame's reason to the controller (drydock-side display of it is still pending).

**Upgrade to Ed25519 key auth (zero shared secrets):** generate a keypair with `portwing keygen`, mount the `authorized_keys` file, and set `AUTHORIZED_KEYS=/etc/portwing/authorized_keys` β€” see [Authentication](#authentication). Use `PRIVATE_KEY_FILE` for signed edge-mode hellos.

Expand Down
20 changes: 20 additions & 0 deletions docs/content/docs/drydock-integration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,26 @@ When `PRIVATE_KEY_FILE` is set, the hello carries the `pubKeyId`, `timestamp`, `
| `ping` / `pong` | Either | Keepalive (30s default) |
| `error` | Either | Error with optional `code` |

**Exec (interactive `docker exec` sessions):**

| Type | Direction | Purpose |
|---|---|---|
| `exec_start` | Controller β†’ Agent | Start an exec session (`execId`, `containerId`, `cmd`, `user`, `cols`, `rows`, `tty`) |
| `exec_ready` | Agent β†’ Controller | Exec session started and attached; safe to send input |
| `exec_input` | Controller β†’ Agent | Base64 stdin chunk for a live session |
| `exec_output` | Agent β†’ Controller | Base64 stdout/stderr chunk from a live session |
| `exec_resize` | Controller β†’ Agent | TTY resize (`cols`, `rows`) for a live session |
| `exec_end` | Either | Session ended, with an optional `reason` |

If a session fails to start (for example, a sockguard exec-policy denial),
the agent's failStart path sends `exec_end` immediately instead of
`exec_ready`. Its `reason` field now carries the underlying Docker/sockguard
error body β€” e.g. `not allowed by portwing preset` or `exec denied:
privileged exec is not allowed` β€” rather than a bare status code. Drydock's
edge agent adapter does not yet surface that reason to the user; today it
receives the frame but discards `reason` before it reaches Drydock's own
exec error display.

**Drydock-specific (`dd:` namespace):**

| Type | Direction | Purpose |
Expand Down
2 changes: 2 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Ready-to-run Docker Compose and Kubernetes examples, hardened by default (`read_
| [`docker-compose.standard.yml`](docker-compose.standard.yml) | Standard (inbound HTTP on :3000) | Drydock or any client can reach the host directly |
| [`docker-compose.edge.yml`](docker-compose.edge.yml) | Edge (outbound WebSocket, no inbound ports) | Agent is behind NAT/firewall; it dials out to your Drydock instance |
| [`docker-compose.with-sockguard.yml`](docker-compose.with-sockguard.yml) | Standard + [sockguard](https://github.com/CodesWhat/sockguard) socket filter | Two-layer defense: even a compromised agent is constrained to an explicit Docker API allowlist |
| [`docker-compose.edge-with-exec.yml`](docker-compose.edge-with-exec.yml) | Edge + sockguard, exec enabled | Same two-layer defense as above, but pairs with [`sockguard-with-exec.yaml`](sockguard-with-exec.yaml) so Drydock's edge exec feature is actually allowed through the proxy |
| [`sockguard-with-exec.yaml`](sockguard-with-exec.yaml) | Sockguard preset (with-exec) | The policy file `docker-compose.edge-with-exec.yml` mounts; pairs with it, not used standalone |
| [`observability/docker-compose.yml`](observability/docker-compose.yml) | Standard or edge + Prometheus + Fluent Bit | Complete TLS/auth, metrics, readiness, and audit-shipping topology selected with a Compose profile |

Before starting any of them, generate a token and export the Docker socket's group ID (the images run as the non-root `portwing` user, UID 65532, and need `group_add` to reach the socket):
Expand Down
16 changes: 10 additions & 6 deletions examples/docker-compose.edge-with-exec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@
# stack uses sockguard-with-exec.yaml, not sockguard.yaml.
#
# sockguard.yaml (the plain preset used by docker-compose.with-sockguard.yml)
# denies all exec paths by design β€” POST /containers/*/exec comes back 403
# "exec denied: no commands are allowlisted". If drydock is going to drive
# interactive exec through this agent's edge tunnel, sockguard has to be
# running the portwing-with-exec.yaml preset (sockguard-with-exec.yaml here)
# instead, or every exec attempt is denied at the proxy before it ever
# reaches Portwing.
# denies all exec paths by design β€” POST /containers/*/exec matches no allow
# rule and hits the catch-all deny, coming back 403 "not allowed by portwing
# preset". If drydock is going to drive interactive exec through this
# agent's edge tunnel, sockguard has to be running the portwing-with-exec.yaml
# preset (sockguard-with-exec.yaml here) instead, or every exec attempt is
# denied at the proxy before it ever reaches Portwing.
#
# For an audited, version-pinned variant of this same stack, see sockguard's
# examples/compose/tri-tool/ bundle (pins SOCKGUARD_VERSION/PORTWING_VERSION/
# DRYDOCK_VERSION with override env vars).
#
# Edge mode against Drydock 1.6 is Ed25519-only: the controller's
# /api/portwing/ws endpoint rejects token-based hellos. Generate a keypair
Expand Down
Loading