fix: RLS auth bypass for signup/login flows
Some checks failed
CI — P2 Drift (Go + Node) / saas (push) Successful in 26s
CI — P3 Alert / test (push) Successful in 23s
CI — P6 Run / build-push (push) Failing after 15s
CI — P2 Drift (Go + Node) / agent (push) Successful in 38s
CI — P4 Portal / test (push) Successful in 34s
CI — P5 Cost / test (push) Successful in 35s
CI — P6 Run / saas (push) Successful in 33s
CI — P2 Drift (Go + Node) / build-push (push) Failing after 50s
CI — P3 Alert / build-push (push) Failing after 5s
CI — P4 Portal / build-push (push) Failing after 51s
CI — P5 Cost / build-push (push) Failing after 15s
Some checks failed
CI — P2 Drift (Go + Node) / saas (push) Successful in 26s
CI — P3 Alert / test (push) Successful in 23s
CI — P6 Run / build-push (push) Failing after 15s
CI — P2 Drift (Go + Node) / agent (push) Successful in 38s
CI — P4 Portal / test (push) Successful in 34s
CI — P5 Cost / test (push) Successful in 35s
CI — P6 Run / saas (push) Successful in 33s
CI — P2 Drift (Go + Node) / build-push (push) Failing after 50s
CI — P3 Alert / build-push (push) Failing after 5s
CI — P4 Portal / build-push (push) Failing after 51s
CI — P5 Cost / build-push (push) Failing after 15s
- Add set_config('app.tenant_id') before user INSERT in signup tx
- Add 004_auth_rls_fix.sql: permissive SELECT on users/api_keys for
auth lookups, INSERT on users with tenant context check
- db-setup now runs migrations on every up (idempotent)
This commit is contained in:
@@ -0,0 +1,18 @@
|
|||||||
|
-- Fix RLS for auth operations (login/signup)
|
||||||
|
-- Login needs to SELECT users by email before tenant context is known.
|
||||||
|
-- Signup needs to check for duplicate emails and INSERT new users.
|
||||||
|
|
||||||
|
-- Allow SELECT on users without tenant context (for login email lookup + signup dupe check)
|
||||||
|
CREATE POLICY auth_select_users ON users
|
||||||
|
FOR SELECT
|
||||||
|
USING (true);
|
||||||
|
|
||||||
|
-- Allow INSERT on users when tenant context is set (signup sets it via set_config)
|
||||||
|
CREATE POLICY auth_insert_users ON users
|
||||||
|
FOR INSERT
|
||||||
|
WITH CHECK (tenant_id::text = current_setting('app.tenant_id', true));
|
||||||
|
|
||||||
|
-- Allow SELECT on api_keys without tenant context (for API key auth lookup)
|
||||||
|
CREATE POLICY auth_select_api_keys ON api_keys
|
||||||
|
FOR SELECT
|
||||||
|
USING (true);
|
||||||
@@ -222,6 +222,9 @@ export function registerAuthRoutes(app: FastifyInstance, jwtSecret: string, pool
|
|||||||
role = 'owner';
|
role = 'owner';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set tenant context for RLS before inserting user
|
||||||
|
await client.query("SELECT set_config('app.tenant_id', $1, true)", [tenantId]);
|
||||||
|
|
||||||
const user = await client.query(
|
const user = await client.query(
|
||||||
`INSERT INTO users (tenant_id, email, password_hash, role) VALUES ($1, $2, $3, $4) RETURNING id`,
|
`INSERT INTO users (tenant_id, email, password_hash, role) VALUES ($1, $2, $3, $4) RETURNING id`,
|
||||||
[tenantId, body.email, passwordHash, role],
|
[tenantId, body.email, passwordHash, role],
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
-- Fix RLS for auth operations (login/signup)
|
||||||
|
-- Login needs to SELECT users by email before tenant context is known.
|
||||||
|
-- Signup needs to check for duplicate emails and INSERT new users.
|
||||||
|
|
||||||
|
-- Allow SELECT on users without tenant context (for login email lookup + signup dupe check)
|
||||||
|
CREATE POLICY auth_select_users ON users
|
||||||
|
FOR SELECT
|
||||||
|
USING (true);
|
||||||
|
|
||||||
|
-- Allow INSERT on users when tenant context is set (signup sets it via set_config)
|
||||||
|
CREATE POLICY auth_insert_users ON users
|
||||||
|
FOR INSERT
|
||||||
|
WITH CHECK (tenant_id::text = current_setting('app.tenant_id', true));
|
||||||
|
|
||||||
|
-- Allow SELECT on api_keys without tenant context (for API key auth lookup)
|
||||||
|
CREATE POLICY auth_select_api_keys ON api_keys
|
||||||
|
FOR SELECT
|
||||||
|
USING (true);
|
||||||
@@ -222,6 +222,9 @@ export function registerAuthRoutes(app: FastifyInstance, jwtSecret: string, pool
|
|||||||
role = 'owner';
|
role = 'owner';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set tenant context for RLS before inserting user
|
||||||
|
await client.query("SELECT set_config('app.tenant_id', $1, true)", [tenantId]);
|
||||||
|
|
||||||
const user = await client.query(
|
const user = await client.query(
|
||||||
`INSERT INTO users (tenant_id, email, password_hash, role) VALUES ($1, $2, $3, $4) RETURNING id`,
|
`INSERT INTO users (tenant_id, email, password_hash, role) VALUES ($1, $2, $3, $4) RETURNING id`,
|
||||||
[tenantId, body.email, passwordHash, role],
|
[tenantId, body.email, passwordHash, role],
|
||||||
|
|||||||
18
products/04-lightweight-idp/migrations/004_auth_rls_fix.sql
Normal file
18
products/04-lightweight-idp/migrations/004_auth_rls_fix.sql
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
-- Fix RLS for auth operations (login/signup)
|
||||||
|
-- Login needs to SELECT users by email before tenant context is known.
|
||||||
|
-- Signup needs to check for duplicate emails and INSERT new users.
|
||||||
|
|
||||||
|
-- Allow SELECT on users without tenant context (for login email lookup + signup dupe check)
|
||||||
|
CREATE POLICY auth_select_users ON users
|
||||||
|
FOR SELECT
|
||||||
|
USING (true);
|
||||||
|
|
||||||
|
-- Allow INSERT on users when tenant context is set (signup sets it via set_config)
|
||||||
|
CREATE POLICY auth_insert_users ON users
|
||||||
|
FOR INSERT
|
||||||
|
WITH CHECK (tenant_id::text = current_setting('app.tenant_id', true));
|
||||||
|
|
||||||
|
-- Allow SELECT on api_keys without tenant context (for API key auth lookup)
|
||||||
|
CREATE POLICY auth_select_api_keys ON api_keys
|
||||||
|
FOR SELECT
|
||||||
|
USING (true);
|
||||||
@@ -223,6 +223,9 @@ export function registerAuthRoutes(app: FastifyInstance, jwtSecret: string, pool
|
|||||||
role = 'owner';
|
role = 'owner';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set tenant context for RLS before inserting user
|
||||||
|
await client.query("SELECT set_config('app.tenant_id', $1, true)", [tenantId]);
|
||||||
|
|
||||||
const user = await client.query(
|
const user = await client.query(
|
||||||
`INSERT INTO users (tenant_id, email, password_hash, role) VALUES ($1, $2, $3, $4) RETURNING id`,
|
`INSERT INTO users (tenant_id, email, password_hash, role) VALUES ($1, $2, $3, $4) RETURNING id`,
|
||||||
[tenantId, body.email, passwordHash, role],
|
[tenantId, body.email, passwordHash, role],
|
||||||
|
|||||||
18
products/05-aws-cost-anomaly/migrations/004_auth_rls_fix.sql
Normal file
18
products/05-aws-cost-anomaly/migrations/004_auth_rls_fix.sql
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
-- Fix RLS for auth operations (login/signup)
|
||||||
|
-- Login needs to SELECT users by email before tenant context is known.
|
||||||
|
-- Signup needs to check for duplicate emails and INSERT new users.
|
||||||
|
|
||||||
|
-- Allow SELECT on users without tenant context (for login email lookup + signup dupe check)
|
||||||
|
CREATE POLICY auth_select_users ON users
|
||||||
|
FOR SELECT
|
||||||
|
USING (true);
|
||||||
|
|
||||||
|
-- Allow INSERT on users when tenant context is set (signup sets it via set_config)
|
||||||
|
CREATE POLICY auth_insert_users ON users
|
||||||
|
FOR INSERT
|
||||||
|
WITH CHECK (tenant_id::text = current_setting('app.tenant_id', true));
|
||||||
|
|
||||||
|
-- Allow SELECT on api_keys without tenant context (for API key auth lookup)
|
||||||
|
CREATE POLICY auth_select_api_keys ON api_keys
|
||||||
|
FOR SELECT
|
||||||
|
USING (true);
|
||||||
@@ -222,6 +222,9 @@ export function registerAuthRoutes(app: FastifyInstance, jwtSecret: string, pool
|
|||||||
role = 'owner';
|
role = 'owner';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set tenant context for RLS before inserting user
|
||||||
|
await client.query("SELECT set_config('app.tenant_id', $1, true)", [tenantId]);
|
||||||
|
|
||||||
const user = await client.query(
|
const user = await client.query(
|
||||||
`INSERT INTO users (tenant_id, email, password_hash, role) VALUES ($1, $2, $3, $4) RETURNING id`,
|
`INSERT INTO users (tenant_id, email, password_hash, role) VALUES ($1, $2, $3, $4) RETURNING id`,
|
||||||
[tenantId, body.email, passwordHash, role],
|
[tenantId, body.email, passwordHash, role],
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
-- Fix RLS for auth operations (login/signup)
|
||||||
|
-- Login needs to SELECT users by email before tenant context is known.
|
||||||
|
-- Signup needs to check for duplicate emails and INSERT new users.
|
||||||
|
|
||||||
|
-- Allow SELECT on users without tenant context (for login email lookup + signup dupe check)
|
||||||
|
CREATE POLICY auth_select_users ON users
|
||||||
|
FOR SELECT
|
||||||
|
USING (true);
|
||||||
|
|
||||||
|
-- Allow INSERT on users when tenant context is set (signup sets it via set_config)
|
||||||
|
CREATE POLICY auth_insert_users ON users
|
||||||
|
FOR INSERT
|
||||||
|
WITH CHECK (tenant_id::text = current_setting('app.tenant_id', true));
|
||||||
|
|
||||||
|
-- Allow SELECT on api_keys without tenant context (for API key auth lookup)
|
||||||
|
CREATE POLICY auth_select_api_keys ON api_keys
|
||||||
|
FOR SELECT
|
||||||
|
USING (true);
|
||||||
@@ -222,6 +222,9 @@ export function registerAuthRoutes(app: FastifyInstance, jwtSecret: string, pool
|
|||||||
role = 'owner';
|
role = 'owner';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set tenant context for RLS before inserting user
|
||||||
|
await client.query("SELECT set_config('app.tenant_id', $1, true)", [tenantId]);
|
||||||
|
|
||||||
const user = await client.query(
|
const user = await client.query(
|
||||||
`INSERT INTO users (tenant_id, email, password_hash, role) VALUES ($1, $2, $3, $4) RETURNING id`,
|
`INSERT INTO users (tenant_id, email, password_hash, role) VALUES ($1, $2, $3, $4) RETURNING id`,
|
||||||
[tenantId, body.email, passwordHash, role],
|
[tenantId, body.email, passwordHash, role],
|
||||||
|
|||||||
@@ -59,6 +59,12 @@ services:
|
|||||||
restart: "no"
|
restart: "no"
|
||||||
depends_on:
|
depends_on:
|
||||||
postgres: { condition: service_healthy }
|
postgres: { condition: service_healthy }
|
||||||
|
volumes:
|
||||||
|
- ./02-iac-drift-detection/saas/migrations:/migrations/02-drift:ro
|
||||||
|
- ./03-alert-intelligence/migrations:/migrations/03-alert:ro
|
||||||
|
- ./04-lightweight-idp/migrations:/migrations/04-portal:ro
|
||||||
|
- ./05-aws-cost-anomaly/migrations:/migrations/05-cost:ro
|
||||||
|
- ./06-runbook-automation/saas/migrations:/migrations/06-run:ro
|
||||||
environment:
|
environment:
|
||||||
PGHOST: postgres
|
PGHOST: postgres
|
||||||
PGUSER: ${POSTGRES_USER:-dd0c}
|
PGUSER: ${POSTGRES_USER:-dd0c}
|
||||||
@@ -88,6 +94,22 @@ services:
|
|||||||
create_user dd0c_portal dd0c_portal "$$DB_PORTAL_PASSWORD"
|
create_user dd0c_portal dd0c_portal "$$DB_PORTAL_PASSWORD"
|
||||||
create_user dd0c_cost dd0c_cost "$$DB_COST_PASSWORD"
|
create_user dd0c_cost dd0c_cost "$$DB_COST_PASSWORD"
|
||||||
create_user dd0c_run dd0c_run "$$DB_RUN_PASSWORD"
|
create_user dd0c_run dd0c_run "$$DB_RUN_PASSWORD"
|
||||||
|
# Run any new migrations (idempotent — CREATE IF NOT EXISTS / DO blocks)
|
||||||
|
run_migrations() {
|
||||||
|
local db=$$1 dir=$$2
|
||||||
|
if [ -d "$$dir" ]; then
|
||||||
|
for sql in "$$dir"/*.sql; do
|
||||||
|
[ -f "$$sql" ] || continue
|
||||||
|
echo " $$db ← $$(basename $$sql)"
|
||||||
|
psql -d "$$db" -f "$$sql" 2>/dev/null || true
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
run_migrations dd0c_drift /migrations/02-drift
|
||||||
|
run_migrations dd0c_alert /migrations/03-alert
|
||||||
|
run_migrations dd0c_portal /migrations/04-portal
|
||||||
|
run_migrations dd0c_cost /migrations/05-cost
|
||||||
|
run_migrations dd0c_run /migrations/06-run
|
||||||
echo "db-setup complete"
|
echo "db-setup complete"
|
||||||
|
|
||||||
# --- dd0c Products ---
|
# --- dd0c Products ---
|
||||||
|
|||||||
Reference in New Issue
Block a user