Repository navigation
feat(security): Docker allow-list proxy, isolated Constellation network, key-based SSH, Prefect auth plumbing - #54
Merged
Conversation
…rk, dynamic nginx upstreams
- The dashboard no longer mounts /var/run/docker.sock (":ro" does not limit the Docker
API, so that was root on the host). It uses a small HAProxy allow-list proxy
(server/docker-proxy/haproxy.cfg) that permits only what the dashboard does:
follow the logs of the API and Trevor, and restart the API, Trevor and the dashboard.
Everything else (list, exec, create, rm, other containers) is refused with 403.
Tested against a disposable container, including under the proxy's restricted runtime
(read-only, all capabilities dropped, no-new-privileges, 32 MB).
- Constellation, the most exposed app, moves to its own `constellation` network shared
only with nginx, so it can no longer reach the API, Prefect or the dashboard over the
Docker network. It reaches TravelNet through the public hostname already.
- nginx re-resolves its upstreams through Docker's DNS every 10 s. A literal host in
proxy_pass is resolved once at start-up, so a recreated container with a new IP was
a 502 until a reload (reproduced and fixed in a throwaway test).
- The dashboard receives PREFECT_API_AUTH_STRING for the upcoming Prefect server auth.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
The API reached the compute PC with a password and trusted any host key (AutoAddPolicy). get_ssh_client() now: - offers the private key at COMPUTE_SSH_KEY_PATH first and the password only as a fallback (paramiko's order), so the key can be rolled out before the password is removed; COMPUTE_PASSWORD is now optional; - pins the host key when COMPUTE_KNOWN_HOSTS_PATH points at a known_hosts file, refusing unknown or changed keys before any credentials are sent; without it the previous trust-on-first-use behaviour is unchanged; - no longer tries the ssh-agent or default key locations, and fails with a clear error if no credentials are configured at all. Tested with mocks and against a real in-process SSH server (key auth, password fallback, impostor host key, host missing from known_hosts, no pinning). Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
…e Docker proxy - ingest mounts the compute key directory (a directory, so a missing key can never turn into a root-owned directory created by Docker) at /run/secrets/compute. - .env.example documents COMPUTE_SSH_KEY_PATH, COMPUTE_KNOWN_HOSTS_PATH and PREFECT_API_AUTH_STRING (commented out: CI copies this file to .env). - the host health monitor now expects the travelnet-docker-proxy container. - prefect-server.service draft reads its auth string from a root-only env file instead of putting the credential in the world-readable unit. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
…n stdin
graceful_reboot.sh (gitignored) polls the Prefect API for in-flight flow runs, which now
needs HTTP Basic credentials. They must reach curl as a config line on stdin ("-K -"),
never as an argument, so they cannot be read from the process list. Tests assert both
that the credential is delivered and that it never appears in an argument.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Deploying travelnet with
|
| Latest commit: |
44993d3
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://de08f244.travelnet.pages.dev |
| Branch Preview URL: | https://security-pi-hardening.travelnet.pages.dev |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Hardening pass over the Pi stack. Every change below was tested in isolation first (throwaway containers or an in-process SSH server), and each is backward compatible so the rollout can be staged.
/var/run/docker.sock(:rodoes not limit the Docker API, so it was root on the host). A small HAProxy proxy (server/docker-proxy/haproxy.cfg, 8.6 MB, read-only, all capabilities dropped) permits only what the dashboard does: follow the logs of the API and Trevor, restart the API, Trevor and the dashboard. Listing, exec, create, rm and any other container are refused with 403.travelnetnetwork with the API, Prefect and the dashboard. It now sits on aconstellationnetwork shared only with nginx; it reaches TravelNet through the public hostname like any outside client.proxy_passis resolved once at start-up, so a recreated container with a new IP was a 502 until a reload. Reproduced and fixed (resolver with a 10 s TTL); this also makes the network move above safe.COMPUTE_SSH_KEY_PATHis tried first, the password only as a fallback, so it can be migrated without a flag day;COMPUTE_PASSWORDbecomes optional. WithCOMPUTE_KNOWN_HOSTS_PATHthe host key is pinned (unknown or changed keys refused before credentials are sent). Tested against a real in-process SSH server.PREFECT_API_AUTH_STRING; theprefect-server.servicedraft reads the server's copy from a root-only env file. The Prefect server enforces HTTP Basic auth while keeping/api/healthopen (verified on the pinned server image).curlon stdin, never as an argument.Rollout order (important)
docker compose up -d.nginx(creates theconstellationnetwork) before recreating Constellation.Companion PRs: Dashboard (Prefect credentials), Trevor (key-based SSH), Constellation (network).
🤖 Generated with Claude Code