mirror of
https://github.com/formbricks/formbricks.git
synced 2026-05-18 06:52:01 -05:00
chore: merge with epic/v5
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
---
|
||||
title: "Cube Tenant Isolation"
|
||||
description: "Threat model and controls for XM analytics tenant isolation in Cube"
|
||||
icon: "shield-check"
|
||||
---
|
||||
|
||||
## Context
|
||||
|
||||
XM analytics reads Hub feedback records through Cube. Hub stores all tenants in a shared `feedback_records`
|
||||
table and uses `tenant_id` to separate rows. Workspace access is the application authorization boundary. In the
|
||||
current Hub schema, `tenant_id` stores the authorized FeedbackDirectory ID, so every Cube query must be
|
||||
scoped to a directory that the authenticated workspace can access before data leaves Cube.
|
||||
|
||||
## Threat Model
|
||||
|
||||
The main risk is cross-tenant read access through an unscoped Cube query. The attacker could be a regression in
|
||||
server code, an AI-generated query that includes malicious filters, a copied static token, or a direct request to
|
||||
Cube from inside the deployment network.
|
||||
|
||||
The controls assume query bodies are attacker-influenced. Tenant identity is never trusted from the query JSON.
|
||||
|
||||
## Enforcement Flow
|
||||
|
||||
<Steps>
|
||||
<Step title="Authorize workspace access">
|
||||
Server actions and server components authorize workspace access in the Next.js app.
|
||||
</Step>
|
||||
<Step title="Validate the Cube query">
|
||||
The app validates the Cube query and rejects any `FeedbackRecords.tenantId` member supplied by users,
|
||||
saved charts, or AI output, including filters, dimensions, time dimensions, and order clauses.
|
||||
</Step>
|
||||
<Step title="Mint a short-lived JWT">
|
||||
The app mints a short-lived JWT per Cube request with `tenantId`, `feedbackDirectoryId`,
|
||||
`workspaceId`, `organizationId`, `userId`, `scope`, `iss`, `aud`, `jti`, and `exp` claims.
|
||||
</Step>
|
||||
<Step title="Verify the JWT in Cube">
|
||||
Cube verifies the JWT and exposes the claims through `securityContext`.
|
||||
</Step>
|
||||
<Step title="Enforce the tenant filter">
|
||||
Cube `queryRewrite` rejects missing tenant context, rejects caller-supplied tenant member usage, and
|
||||
appends `FeedbackRecords.tenantId = securityContext.tenantId` to every query.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Audit Evidence
|
||||
|
||||
The app records a sanitized `cubeQuery` audit event for each Cube query attempt, keyed by the JWT `jti`. Cube also
|
||||
emits a structured audit log line from `queryRewrite` with tenant, feedback directory, workspace,
|
||||
organization, user, request ID, source, and queried member names. Raw filter values are intentionally omitted from
|
||||
both logs.
|
||||
|
||||
## Operational Notes
|
||||
|
||||
`CUBEJS_API_SECRET` is a signing secret, not an access token. Do not pass it to clients or reuse it as a bearer
|
||||
token. Set `CUBEJS_JWT_ISSUER` and `CUBEJS_JWT_AUDIENCE` consistently for the web app and Cube so Cube rejects
|
||||
tokens minted for any other audience or issuer. Set `CUBEJS_DEFAULT_API_SCOPES=meta,data` for Cube deployments so
|
||||
GraphQL, SQL, and orchestration APIs are not exposed unless explicitly needed. Network isolation for Cube remains
|
||||
recommended, but JWT-backed `queryRewrite` is the mandatory data boundary.
|
||||
@@ -310,6 +310,7 @@
|
||||
"pages": [
|
||||
"development/technical-handbook/overview",
|
||||
"development/technical-handbook/background-job-processing",
|
||||
"development/technical-handbook/cube-tenant-isolation",
|
||||
"development/technical-handbook/database-model",
|
||||
"development/technical-handbook/tenant-separation"
|
||||
]
|
||||
|
||||
@@ -116,16 +116,23 @@ bundled Docker Compose or Helm assets, the following variables apply:
|
||||
|
||||
XM Suite v5 dashboard and analysis features require a reachable Cube.js instance. Formbricks generates the backend
|
||||
Cube JWT from `CUBEJS_API_SECRET`, so `CUBEJS_API_TOKEN` is not part of the supported setup contract.
|
||||
If you do not use XM Suite v5 analytics, omit the Cube variables and leave the bundled Docker `xm` profile disabled.
|
||||
|
||||
| Variable | Description | Required | Default |
|
||||
| ----------------- | ----------------------------------------------------------------------------------------------------- | ---------------------------------- | ------------------------------------ |
|
||||
| CUBEJS_API_URL | Base URL the Formbricks app uses to call Cube. Use `http://localhost:4000` locally. | required for XM Suite v5 analytics | `http://localhost:4000` in local dev |
|
||||
| CUBEJS_API_SECRET | Shared secret Formbricks uses to sign Cube API JWTs. Generate with `openssl rand -hex 32`. | required for XM Suite v5 analytics | |
|
||||
| CUBEJS_DB_HOST | Database host for the Cube service. Only needed when you run Cube yourself and override defaults. | optional | Depends on your Cube deployment |
|
||||
| CUBEJS_DB_PORT | Database port for the Cube service. Only needed when you run Cube yourself and override defaults. | optional | Depends on your Cube deployment |
|
||||
| CUBEJS_DB_NAME | Database name for the Cube service. Only needed when you run Cube yourself and override defaults. | optional | Depends on your Cube deployment |
|
||||
| CUBEJS_DB_USER | Database user for the Cube service. Only needed when you run Cube yourself and override defaults. | optional | Depends on your Cube deployment |
|
||||
| CUBEJS_DB_PASS | Database password for the Cube service. Only needed when you run Cube yourself and override defaults. | optional | Depends on your Cube deployment |
|
||||
| Variable | Description | Required | Default |
|
||||
| ------------------------- | ------------------------------------------------------------------------------------------------------ | ---------------------------------- | ------------------------------------ |
|
||||
| CUBEJS_API_URL | Base URL the Formbricks app uses to call Cube. Use `http://localhost:4000` locally. | required for XM Suite v5 analytics | `http://localhost:4000` in local dev |
|
||||
| CUBEJS_API_SECRET | Shared secret Formbricks uses to sign Cube API JWTs. Generate with `openssl rand -hex 32`. | required for XM Suite v5 analytics | |
|
||||
| CUBEJS_JWT_ISSUER | JWT issuer expected by Cube and used by Formbricks when signing per-request Cube tokens. | optional | `formbricks-web` |
|
||||
| CUBEJS_JWT_AUDIENCE | JWT audience expected by Cube and used by Formbricks when signing per-request Cube tokens. | optional | `formbricks-cube` |
|
||||
| CUBEJS_DB_HOST | Database host for the Cube service. Only needed when you run Cube yourself and override defaults. | optional | Depends on your Cube deployment |
|
||||
| CUBEJS_DB_PORT | Database port for the Cube service. Only needed when you run Cube yourself and override defaults. | optional | Depends on your Cube deployment |
|
||||
| CUBEJS_DB_NAME | Database name for the Cube service. Only needed when you run Cube yourself and override defaults. | optional | Depends on your Cube deployment |
|
||||
| CUBEJS_DB_USER | Database user for the Cube service. Only needed when you run Cube yourself and override defaults. | optional | Depends on your Cube deployment |
|
||||
| CUBEJS_DB_PASS | Database password for the Cube service. Only needed when you run Cube yourself and override defaults. | optional | Depends on your Cube deployment |
|
||||
|
||||
The bundled Docker Compose Cube service sets `CUBEJS_DEFAULT_API_SCOPES=meta,data` directly on the Cube
|
||||
container. If you run Cube outside the bundled Compose stack, configure the equivalent Cube service environment
|
||||
there rather than adding it to the Formbricks app environment.
|
||||
|
||||
For Helm deployments, Formbricks does not deploy Cube for you in this chart. Provide an external Cube endpoint with
|
||||
`CUBEJS_API_URL` and supply `CUBEJS_API_SECRET` through your existing secret management setup.
|
||||
|
||||
@@ -43,14 +43,19 @@ Make sure Docker and Docker Compose are installed on your system. These are usua
|
||||
curl -o cube/schema/FeedbackRecords.js https://raw.githubusercontent.com/formbricks/formbricks/stable/docker/cube/schema/FeedbackRecords.js
|
||||
```
|
||||
|
||||
1. **Generate Hub and Cube Secrets**
|
||||
1. **Generate Hub Secret and Optional Cube Secret**
|
||||
|
||||
XM Suite v5 analytics requires Formbricks Hub and Cube.js. Create a local `.env` file for the required shared secrets:
|
||||
Formbricks Hub requires an API key. XM Suite v5 analytics also requires Cube.js; set the optional `xm`
|
||||
Compose profile and Cube secret when you want to run the bundled Cube service. For a Hub-only stack, create
|
||||
`.env` with just `HUB_API_KEY` and omit `COMPOSE_PROFILES` and `CUBEJS_API_SECRET`.
|
||||
|
||||
```bash
|
||||
cat <<EOF > .env
|
||||
COMPOSE_PROFILES=xm
|
||||
HUB_API_KEY=$(openssl rand -hex 32)
|
||||
CUBEJS_API_SECRET=$(openssl rand -hex 32)
|
||||
CUBEJS_JWT_ISSUER=formbricks-web
|
||||
CUBEJS_JWT_AUDIENCE=formbricks-cube
|
||||
EOF
|
||||
```
|
||||
|
||||
@@ -127,7 +132,9 @@ Make sure Docker and Docker Compose are installed on your system. These are usua
|
||||
|
||||
1. **Start the Docker Setup**
|
||||
|
||||
Now, you're ready to run Formbricks with Docker. Use the command below to start Formbricks together with PostgreSQL, Redis, Formbricks Hub, and Cube.js:
|
||||
Now, you're ready to run Formbricks with Docker. Use the command below to start Formbricks together with
|
||||
PostgreSQL, Redis, and Formbricks Hub. If the `xm` profile is set in `.env`, Docker Compose also starts Cube.js
|
||||
for XM Suite v5 analytics.
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
@@ -140,8 +147,8 @@ Make sure Docker and Docker Compose are installed on your system. These are usua
|
||||
Once the setup is running, open [**http://localhost:3000**](http://localhost:3000) in your browser to access Formbricks. The first time you visit, you'll see a setup wizard. Follow the steps to create your first user and start using Formbricks.
|
||||
|
||||
<Note>
|
||||
The bundled Docker stack keeps Formbricks Hub and Cube.js internal to the compose network. The app reaches
|
||||
them through `http://hub:8080` and `http://cube:4000`.
|
||||
The bundled Docker stack keeps Formbricks Hub internal to the compose network. When the `xm` profile is
|
||||
enabled, Cube.js is internal too. The app reaches them through `http://hub:8080` and `http://cube:4000`.
|
||||
</Note>
|
||||
|
||||
## Update
|
||||
|
||||
Reference in New Issue
Block a user