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
7 changes: 5 additions & 2 deletions pmoves/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ ensure-networks: ## Materialize the shared compose-owned networks (idempotent) s
@docker network inspect pmoves_bus >/dev/null 2>&1 || docker network create --driver bridge --internal --subnet 172.30.3.0/24 --gateway 172.30.3.1 --label com.docker.compose.network=pmoves_bus --label com.docker.compose.project=$(PROJECT) pmoves_bus >/dev/null 2>&1 || true
@docker network inspect pmoves_data >/dev/null 2>&1 || docker network create --driver bridge --internal --subnet 172.30.4.0/24 --gateway 172.30.4.1 --label com.docker.compose.network=pmoves_data --label com.docker.compose.project=$(PROJECT) pmoves_data >/dev/null 2>&1 || true
@docker network inspect pmoves_monitoring >/dev/null 2>&1 || docker network create --driver bridge --internal --subnet 172.30.5.0/24 --gateway 172.30.5.1 --label com.docker.compose.network=pmoves_monitoring --label com.docker.compose.project=$(PROJECT) pmoves_monitoring >/dev/null 2>&1 || true
@docker network inspect pmoves_db_egress >/dev/null 2>&1 || docker network create --driver bridge --subnet 172.30.8.0/24 --gateway 172.30.8.1 pmoves_db_egress >/dev/null 2>&1 || true
@docker network inspect pmoves-net >/dev/null 2>&1 || docker network create --driver bridge --label com.docker.compose.network=pmoves --label com.docker.compose.project=$(PROJECT) pmoves-net >/dev/null 2>&1 || true
@echo "✔ shared networks ensured"

Expand Down Expand Up @@ -4983,12 +4984,14 @@ overlay-up-full: ## Start ALL services via overlay files (base + all tiers)
# files declare networks `external: true` (so each overlay parses standalone), so they
# must EXIST at runtime; docker-compose.base.yml owns them but only materializes them
# in a full `up`. Subnets here MUST match docker-compose.base.yml.
ensure-overlay-networks: ## Create the bus overlay networks (pmoves_bus, pmoves_external) if missing
ensure-overlay-networks: ## Create the bus overlay networks (pmoves_bus, pmoves_external, pmoves_db_egress) if missing
@docker network inspect pmoves_bus >/dev/null 2>&1 || \
docker network create --internal --driver bridge --subnet 172.30.3.0/24 --gateway 172.30.3.1 pmoves_bus >/dev/null
@docker network inspect pmoves_external >/dev/null 2>&1 || \
docker network create --driver bridge --subnet 172.30.6.0/24 --gateway 172.30.6.1 pmoves_external >/dev/null
@echo "✅ overlay bus networks present (pmoves_bus, pmoves_external)"
@docker network inspect pmoves_db_egress >/dev/null 2>&1 || \
docker network create --driver bridge --subnet 172.30.8.0/24 --gateway 172.30.8.1 pmoves_db_egress >/dev/null
@echo "✅ overlay bus networks present (pmoves_bus, pmoves_external, pmoves_db_egress)"

# overlay-up-bus brings up ONLY the NATS event bus via the split overlays
# (OVERLAY_DC = base+core), NOT the monolith via DC/STACK_FILES. The monolith's
Expand Down
10 changes: 10 additions & 0 deletions pmoves/docker-compose.base.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 31 additions & 1 deletion pmoves/docker-compose.core.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 41 additions & 1 deletion pmoves/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@ services:
- TOPOLOGY_MODE=${TOPOLOGY_MODE:-docked}
- PARENT_SYSTEM=${PARENT_SYSTEM:-PMOVES.AI}
- PARENT_VERSION=${PARENT_VERSION:-1.0.0-hardened}
- PMOVES_NETWORKS=pmoves_data,pmoves_api
- PMOVES_NETWORKS=pmoves_data,pmoves_api,pmoves_db_egress
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
interval: 20s
Expand All @@ -617,6 +617,36 @@ services:
networks:
- pmoves_data
- pmoves_api # Services on pmoves_api need DB access
# Step 4 of the juicefs cross-node lane. pmoves_data and pmoves_api are both
# `internal: true`, and a published port on a container attached only to
# internal networks is not reachable -- the port maps, nothing can dial it.
# A non-internal bridge is what actually plumbs it.
#
# DEDICATED bridge, NOT the shared egress network (review P1): joining
# pmoves_external would hand every internet-facing container on that bridge
# a direct route to supabase-db:5432, and the pg_hba catch-all accepts every
# role from 172.16.0.0/12 (docker bridges included) -- the tailnet scoping
# never sees those sources. pmoves_db_egress (172.30.8.0/24, internal:
# false) carries ONLY this database, and its pg_hba ruleset admits nothing
# from that subnet except juicefs_meta.
#
# This does NOT put the database on the open internet. Reachability is
# governed by:
# 1. SUPABASE_DB_BIND -- set to the node's TAILNET address, not 0.0.0.0, so
# the listener exists only on the tailnet interface. Default stays
# 127.0.0.1, so a node that does not set it publishes nothing new.
# 2. pg_hba (supabase/config/pg_hba.conf) -- tailnet sources
# (100.64.0.0/10, which DNAT preserves end-to-end) admit ONLY
# juicefs_meta and reject every other role; the dedicated bridge subnet
# carries the same juicefs_meta-only rule so a container that somehow
# joined it gains nothing either.
#
# sslmode: the cross-node DSN carries sslmode=disable. JuiceFS's PostgreSQL
# best-practices doc advises against it. Recorded decision rather than an
# inherited default: WireGuard encrypts the tailnet transport, so the session
# is not on the wire in plaintext, and the metadata role is non-superuser and
# pg_hba-scoped. Revisit if the DB is ever reachable off-tailnet.
- pmoves_db_egress

deploy:
resources:
Expand Down Expand Up @@ -5871,3 +5901,13 @@ networks:
pmoves_external:
external: true
name: pmoves_external
# DEDICATED non-internal bridge for the supabase-db tailnet port publish
# (juicefs cross-node lane, PR #2728). Deliberately NOT pmoves_external:
# that bridge is shared with internet-facing containers, and pg_hba's
# 172.16.0.0/12 catch-all would accept every role from any of them. This
# network carries ONLY the database; pg_hba scopes its subnet
# (172.30.8.0/24) to juicefs_meta alone. External for the same
# cross-stack-adoption reason as pmoves_external.
pmoves_db_egress:
external: true
name: pmoves_db_egress
2 changes: 1 addition & 1 deletion pmoves/docs/operations/PORT_REGISTRY.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ Central registry of all service ports to prevent conflicts and ensure consistenc

| Port | Service | Description | Network |
|------|---------|-------------|---------|
| 5432 | Supabase DB | PostgreSQL 17 (internal only) | pmoves_data |
| 5432 | Supabase DB | PostgreSQL 17 (tailnet-bound on the juicefs meta host; internal elsewhere) | pmoves_data, pmoves_api, pmoves_db_egress (dedicated, pg_hba-scoped) |
| 3010 | PostgREST | Supabase REST API — **host** port (container port stays 3000) | pmoves_api, pmoves_data |
| 9999 | GoTrue | JWT authentication service | pmoves_api, pmoves_data |
| 4010 | Realtime | WebSocket for real-time subscriptions (remapped from 4000) | pmoves_api, pmoves_data |
Expand Down
12 changes: 12 additions & 0 deletions pmoves/supabase/config/pg_hba.conf
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,18 @@ host all all 100.64.0.0/10 reject
host all juicefs_meta fd7a:115c:a1e0::/48 scram-sha-256
host all all fd7a:115c:a1e0::/48 reject

# Dedicated DB-egress bridge (172.30.8.0/24, docker-compose.base.yml
# pmoves_db_egress). The DB joins this non-internal bridge solely so its
# tailnet-published port is actually plumbed (PR #2728). Legitimate inbound
# traffic DNATs in with its real 100.x source and matches the rules above;
# the only packets bearing a 172.30.7.x source are containers that joined
# this bridge -- which is supposed to carry the database alone. Scope them
# identically to the tailnet: juicefs_meta only, everything else rejected,
# ABOVE the 172.16.0.0/12 catch-all (which otherwise accepts every role from
# any docker bridge).
host all juicefs_meta 172.30.8.0/24 scram-sha-256
host all all 172.30.8.0/24 reject

# IPv4 external connections
host all all 10.0.0.0/8 scram-sha-256
host all all 172.16.0.0/12 scram-sha-256
Expand Down
Loading