fix(proxy): enforce sandbox — proxy_net internal, cf-proxy dual-homed
Some checks failed
CI / lint (push) Successful in 36s
Deploy / notebooks (push) Has been skipped
Deploy / zotero (push) Has been skipped
Deploy / docs (push) Has been skipped
Deploy / api (push) Has been skipped
Deploy / mc (push) Has been skipped
Deploy / report (push) Successful in 18s
CI / test (push) Failing after 12m53s
Some checks failed
CI / lint (push) Successful in 36s
Deploy / notebooks (push) Has been skipped
Deploy / zotero (push) Has been skipped
Deploy / docs (push) Has been skipped
Deploy / api (push) Has been skipped
Deploy / mc (push) Has been skipped
Deploy / report (push) Successful in 18s
CI / test (push) Failing after 12m53s
Before this change HTTPS_PROXY was a polite recommendation, not a boundary: proxy_net was a regular bridge with NAT, so anything inside the claude container could open a direct socket to the internet and silently bypass squid's allowlist. Now proxy_net is internal (no NAT, no outbound). cf-proxy joins a second bridge egress_net to dial the Cloudflare edge. claude stays on proxy_net only, so its only route off-host is through cf-proxy → CF Access → tunnel → squid → allowlisted CONNECTs. Verified: from a sibling container on proxy_net, curl https://1.1.1.1 fails immediately ("Could not connect to server"); the same container through cf-proxy gets HTTP 401 from api.anthropic.com (the smoke-test success code).
This commit is contained in:
@@ -1,12 +1,20 @@
|
||||
# Run Claude Code through proxy.fhirworx.io from inside containers.
|
||||
# Run Claude Code in a sandboxed container whose only outside path is the
|
||||
# allowlisted forward proxy at proxy.fhirworx.io.
|
||||
#
|
||||
# Two services on a self-contained 192.168.10.0/24 bridge:
|
||||
# cf-proxy cloudflared access TCP shim — terminates the Cloudflare tunnel
|
||||
# on 192.168.10.2:18443. Equivalent to the systemd --user unit
|
||||
# that dev/scripts/setup-proxy-client.sh installs on a WSL host.
|
||||
# claude Claude Code CLI. Reaches cloudflared via the bridge; extra_hosts
|
||||
# pins proxy.fhirworx.io -> 192.168.10.2 so TLS SNI/cert match
|
||||
# without poisoning cf-proxy's own DNS view.
|
||||
# Network topology (the point of this compose):
|
||||
# proxy_net internal bridge, 192.168.10.0/24. No NAT, no internet egress.
|
||||
# claude lives only here, so it physically cannot reach anything
|
||||
# outside the host except by going through cf-proxy.
|
||||
# egress_net regular bridge. Only cf-proxy is dual-homed: it sits on
|
||||
# proxy_net to be reachable by claude, and on egress_net so
|
||||
# cloudflared can dial the Cloudflare edge.
|
||||
#
|
||||
# Services:
|
||||
# cf-proxy cloudflared access TCP shim. Terminates the Cloudflare tunnel
|
||||
# at 192.168.10.2:18443. The only door out for claude.
|
||||
# claude Claude Code CLI. HTTPS_PROXY points at proxy.fhirworx.io:18443,
|
||||
# which extra_hosts pins to 192.168.10.2 so the TLS SNI/cert
|
||||
# match without poisoning cf-proxy's own DNS view.
|
||||
#
|
||||
# Usage:
|
||||
# cp .env.example .env && $EDITOR .env # set PROXY_PASSWORD and
|
||||
@@ -18,7 +26,7 @@
|
||||
# - claude-home is a named volume so login state persists across runs.
|
||||
# - Bind mounts use identical host/container paths so Claude never sees a
|
||||
# translated path: /home/care/acoharmony, /opt/s3/data/workspace,
|
||||
# /opt/s3/data/notebooks.
|
||||
# /opt/s3/data/notebooks. Claude only has filesystem access to these.
|
||||
|
||||
services:
|
||||
cf-proxy:
|
||||
@@ -31,6 +39,7 @@ services:
|
||||
networks:
|
||||
proxy_net:
|
||||
ipv4_address: 192.168.10.2
|
||||
egress_net: {}
|
||||
restart: unless-stopped
|
||||
|
||||
claude:
|
||||
@@ -58,9 +67,12 @@ services:
|
||||
networks:
|
||||
proxy_net:
|
||||
driver: bridge
|
||||
internal: true
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 192.168.10.0/24
|
||||
egress_net:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
claude-home:
|
||||
|
||||
Reference in New Issue
Block a user