Phase 4: real per-tenant ClickHouse isolation via a new enterprise-api binary
Closes the threat model's headline finding for the SQL query path:
enterprise/internal/tenantprovision does real CREATE DATABASE/USER/GRANT
against ClickHouse, and enterprise/internal/chrunner is a per-tenant
connection registry implementing api's SQLRunner interface, resolving
the tenant from the authenticated request identity -- never a
caller-suppliable parameter. Both are wired into a new binary,
enterprise/cmd/enterprise-api, alongside the unchanged single-tenant
api/cmd/api, since AGPL core can never import enterprise/ and Go's own
internal/ package visibility rules meant enterprise/ couldn't implement
core's SQLRunner interface without importing the package that defines
it. That required moving api/internal/{authz,queryapi,dashboards,
querylang/executor,searchclient,httpserver} out of internal/ -- the
minimal set enterprise-api needs to import; querylang's compiler
internals (planner/lexer/parser/ast/ir) and api's own config stay
internal, since nothing outside api needs them directly.
Also finally wires enterprise/internal/audit into queryapi.AuditLogger
(nil since Phase 4 task 4) via a new adapter, and adds live-ClickHouse
integration tests for two of the four adversarial probes named in
docs/phase-4-isolation-design.md's verification plan.
Corrected several overclaims in the docs while writing this up: an
earlier claim that rbacstore's CRUD was "verified against a live
Postgres" was never actually true in this environment (only
internal/audit was, earlier in this phase, before Docker access was
lost) -- threat-model.md, phase-4-runbook.md, CLAUDE.md, and
enterprise/README.md all now distinguish "a real integration test
exists" from "this was confirmed against a live database."
Still not built: Tantivy/free-text tenant isolation
(enterprise/internal/searchclient), and any deployment-topology
mechanism that actually routes traffic to enterprise-api instead of
plain api -- both binaries exist side by side today with nothing
enforcing or flagging which one a deployment runs.
This commit is contained in:
@@ -264,6 +264,46 @@ services:
|
||||
timeout: 5s
|
||||
retries: 30
|
||||
|
||||
# Multi-tenant-aware alternative to `api` (Phase 4) -- see
|
||||
# enterprise/cmd/enterprise-api/main.go's doc comment for why this is
|
||||
# a second binary rather than a flag on `api`. NOT part of the default
|
||||
# traffic path: `web`'s VITE_API_BASE_URL still points at `api`
|
||||
# (localhost:8080), and nothing here provisions any tenants (see that
|
||||
# binary's -provision-tenant flag) -- included so it can be
|
||||
# built/run/curled directly, same "available, not defaulted in" shape
|
||||
# as enterprise-auth above. CLICKHOUSE_ADMIN_USERNAME/PASSWORD reuse
|
||||
# the same admin credential `clickhouse-migrate` uses, since
|
||||
# tenantprovision needs access_management, not a tenant-scoped grant.
|
||||
enterprise-api:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: enterprise/cmd/enterprise-api/Dockerfile
|
||||
container_name: sentry-enterprise-api
|
||||
depends_on:
|
||||
clickhouse-migrate:
|
||||
condition: service_completed_successfully
|
||||
metadata-migrate:
|
||||
condition: service_completed_successfully
|
||||
ports:
|
||||
- "8083:8083"
|
||||
environment:
|
||||
CLICKHOUSE_ADDR: "clickhouse:9000"
|
||||
CLICKHOUSE_ADMIN_USERNAME: "default"
|
||||
CLICKHOUSE_ADMIN_PASSWORD: "sentry-dev-only"
|
||||
SEARCH_GRPC_ADDR: "search:50052"
|
||||
POSTGRES_ADDR: "metadata-postgres:5432"
|
||||
POSTGRES_DATABASE: "sentry_metadata"
|
||||
POSTGRES_USERNAME: "sentry"
|
||||
POSTGRES_PASSWORD: "sentry-dev-only"
|
||||
AUDIT_WRITER_USERNAME: "audit_writer"
|
||||
AUDIT_WRITER_PASSWORD: "audit-writer-dev-only"
|
||||
ENTERPRISE_AUTH_URL: "http://enterprise-auth:8082"
|
||||
healthcheck:
|
||||
test: ["CMD", "/enterprise-api", "-healthcheck"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 30
|
||||
|
||||
web:
|
||||
build:
|
||||
context: web
|
||||
|
||||
Reference in New Issue
Block a user