aurganize-backend/infrastructure/docker/init-scripts/06-grant-bypassrls.sql

111 lines
3.7 KiB
PL/PgSQL

-- ==========================================
-- 06: GRANT BYPASSRLS TO BACKEND USER
-- ==========================================
-- This script grants Row-Level Security bypass privilege
-- Required for registration flow (tenant + user creation in same transaction)
-- Runs as: postgres (superuser)
\echo '🔓 Granting BYPASSRLS privilege...'
-- ==========================================
-- WHY BYPASSRLS IS NECESSARY
-- ==========================================
-- During registration, we create tenant and user in a single transaction:
--
-- BEGIN;
-- INSERT INTO tenants (...) VALUES (...); -- Creates tenant
-- INSERT INTO users (tenant_id, ...) VALUES (...); -- References tenant
-- COMMIT;
--
-- PROBLEM WITHOUT BYPASSRLS:
-- - PostgreSQL validates foreign key (users.tenant_id → tenants.id)
-- - Foreign key check runs: SELECT 1 FROM tenants WHERE id = ?
-- - RLS policy blocks this SELECT (no tenant context during registration)
-- - Foreign key check fails: "violates foreign key constraint"
-- - Transaction rolls back
--
-- SOLUTION WITH BYPASSRLS:
-- - Backend user can see ALL rows during registration
-- - Foreign key check succeeds (tenant visible immediately)
-- - Transaction commits successfully
-- - Regular operations still protected by RLS (when app.current_tenant_id is set)
-- ==========================================
-- Grant BYPASSRLS to backend API user
ALTER USER aurganize_backend_api WITH BYPASSRLS;
\echo ' ✅ BYPASSRLS privilege granted to aurganize_backend_api'
-- ==========================================
-- VERIFY PRIVILEGE GRANTED
-- ==========================================
DO $$
DECLARE
has_bypassrls BOOLEAN;
user_privileges TEXT;
BEGIN
-- Check if BYPASSRLS was granted
SELECT rolbypassrls INTO has_bypassrls
FROM pg_roles
WHERE rolname = 'aurganize_backend_api';
IF has_bypassrls THEN
RAISE NOTICE ' ✅ Verification: BYPASSRLS is active';
ELSE
RAISE WARNING ' ❌ Verification: BYPASSRLS not active!';
RAISE EXCEPTION 'Failed to grant BYPASSRLS privilege';
END IF;
-- Build privilege summary
SELECT CASE
WHEN rolsuper THEN '🔴 SUPERUSER'
WHEN rolbypassrls THEN '🟡 RLS BYPASS'
ELSE '🟢 STANDARD'
END INTO user_privileges
FROM pg_roles
WHERE rolname = 'aurganize_backend_api';
RAISE NOTICE ' 🔐 Privilege Level: %', user_privileges;
END $$;
-- ==========================================
-- DISPLAY FINAL USER CONFIGURATION
-- ==========================================
\echo ''
\echo '📋 Final user configuration:'
SELECT
rolname AS "Username",
rolcanlogin AS "Can Login",
rolsuper AS "Superuser",
rolbypassrls AS "Bypass RLS",
rolconnlimit AS "Conn Limit",
CASE
WHEN rolsuper THEN '🔴 Full Access'
WHEN rolbypassrls THEN '🟡 RLS Bypass (for registration)'
ELSE '🟢 Standard (RLS enforced)'
END AS "Access Level"
FROM pg_roles
WHERE rolname = 'aurganize_backend_api';
-- ==========================================
-- SECURITY NOTES
-- ==========================================
\echo ''
\echo '=========================================='
\echo '🔒 SECURITY NOTES'
\echo '=========================================='
\echo ''
\echo '✅ SAFE USAGE:'
\echo ' - Backend sets app.current_tenant_id for regular operations'
\echo ' - RLS still protects all normal CRUD operations'
\echo ' - Only registration flow runs without tenant context'
\echo ' - Audit logs capture all operations'
\echo ''
\echo '⚠️ IMPORTANT:'
\echo ' - BYPASSRLS only needed for registration endpoint'
\echo ' - All other operations MUST set tenant context'
\echo ' - Readonly user does NOT have BYPASSRLS'
\echo ''
\echo '✅ BYPASSRLS configuration complete!'
\echo ''