05-row-level-security.sql 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. -- =====================================================
  2. -- Row Level Security (RLS) Policies
  3. -- =====================================================
  4. -- This migration adds row-level security policies to protect data access
  5. -- based on user roles and ownership
  6. -- Enable Row Level Security on all system tables
  7. ALTER TABLE __sys_users ENABLE ROW LEVEL SECURITY;
  8. ALTER TABLE __sys_sessions ENABLE ROW LEVEL SECURITY;
  9. ALTER TABLE __sys_api_keys ENABLE ROW LEVEL SECURITY;
  10. ALTER TABLE __sys_applications ENABLE ROW LEVEL SECURITY;
  11. ALTER TABLE __sys_deployments ENABLE ROW LEVEL SECURITY;
  12. ALTER TABLE __sys_audit_logs ENABLE ROW LEVEL SECURITY;
  13. ALTER TABLE __sys_email_queue ENABLE ROW LEVEL SECURITY;
  14. ALTER TABLE __sys_smtp_settings ENABLE ROW LEVEL SECURITY;
  15. -- Add role column to users table if it doesn't exist
  16. DO $$
  17. BEGIN
  18. IF NOT EXISTS (SELECT 1 FROM information_schema.columns
  19. WHERE table_name='__sys_users' AND column_name='role') THEN
  20. ALTER TABLE __sys_users ADD COLUMN role VARCHAR(50) DEFAULT 'user';
  21. END IF;
  22. END $$;
  23. -- Update existing users to have admin role (for the first user)
  24. UPDATE __sys_users SET role = 'admin' WHERE role IS NULL LIMIT 1;
  25. -- Create function to get current user ID from JWT claims
  26. CREATE OR REPLACE FUNCTION current_user_id() RETURNS UUID AS $$
  27. BEGIN
  28. -- Try to get user_id from current_setting
  29. -- This will be set by the application layer
  30. RETURN current_setting('app.current_user_id', true)::UUID;
  31. EXCEPTION
  32. WHEN OTHERS THEN
  33. RETURN NULL;
  34. END;
  35. $$ LANGUAGE plpgsql STABLE;
  36. -- Create function to check if current user is admin
  37. CREATE OR REPLACE FUNCTION is_admin() RETURNS BOOLEAN AS $$
  38. DECLARE
  39. user_role VARCHAR(50);
  40. BEGIN
  41. SELECT role INTO user_role
  42. FROM __sys_users
  43. WHERE id = current_user_id();
  44. RETURN user_role = 'admin';
  45. EXCEPTION
  46. WHEN OTHERS THEN
  47. RETURN false;
  48. END;
  49. $$ LANGUAGE plpgsql STABLE;
  50. -- =====================================================
  51. -- USERS TABLE POLICIES
  52. -- =====================================================
  53. -- Users can see their own profile, admins can see all users
  54. CREATE POLICY users_select_policy ON __sys_users
  55. FOR SELECT
  56. USING (id = current_user_id() OR is_admin());
  57. -- Users can update their own profile, admins can update any user
  58. CREATE POLICY users_update_policy ON __sys_users
  59. FOR UPDATE
  60. USING (id = current_user_id() OR is_admin());
  61. -- Only admins can insert users
  62. CREATE POLICY users_insert_policy ON __sys_users
  63. FOR INSERT
  64. WITH CHECK (is_admin());
  65. -- Only admins can delete users
  66. CREATE POLICY users_delete_policy ON __sys_users
  67. FOR DELETE
  68. USING (is_admin());
  69. -- =====================================================
  70. -- SESSIONS TABLE POLICIES
  71. -- =====================================================
  72. -- Users can see their own sessions, admins can see all
  73. CREATE POLICY sessions_select_policy ON __sys_sessions
  74. FOR SELECT
  75. USING (user_id = current_user_id() OR is_admin());
  76. -- Users can insert their own sessions
  77. CREATE POLICY sessions_insert_policy ON __sys_sessions
  78. FOR INSERT
  79. WITH CHECK (user_id = current_user_id() OR is_admin());
  80. -- Users can delete their own sessions, admins can delete any
  81. CREATE POLICY sessions_delete_policy ON __sys_sessions
  82. FOR DELETE
  83. USING (user_id = current_user_id() OR is_admin());
  84. -- =====================================================
  85. -- API KEYS TABLE POLICIES
  86. -- =====================================================
  87. -- Users can see their own API keys, admins can see all
  88. CREATE POLICY api_keys_select_policy ON __sys_api_keys
  89. FOR SELECT
  90. USING (created_by = current_user_id() OR is_admin());
  91. -- Users can create their own API keys
  92. CREATE POLICY api_keys_insert_policy ON __sys_api_keys
  93. FOR INSERT
  94. WITH CHECK (created_by = current_user_id() OR is_admin());
  95. -- Users can update their own API keys, admins can update any
  96. CREATE POLICY api_keys_update_policy ON __sys_api_keys
  97. FOR UPDATE
  98. USING (created_by = current_user_id() OR is_admin());
  99. -- Users can delete their own API keys, admins can delete any
  100. CREATE POLICY api_keys_delete_policy ON __sys_api_keys
  101. FOR DELETE
  102. USING (created_by = current_user_id() OR is_admin());
  103. -- =====================================================
  104. -- APPLICATIONS TABLE POLICIES
  105. -- =====================================================
  106. -- Users can see their own applications, admins can see all
  107. CREATE POLICY applications_select_policy ON __sys_applications
  108. FOR SELECT
  109. USING (created_by = current_user_id() OR is_admin());
  110. -- Users can create applications
  111. CREATE POLICY applications_insert_policy ON __sys_applications
  112. FOR INSERT
  113. WITH CHECK (created_by = current_user_id() OR is_admin());
  114. -- Users can update their own applications, admins can update any
  115. CREATE POLICY applications_update_policy ON __sys_applications
  116. FOR UPDATE
  117. USING (created_by = current_user_id() OR is_admin());
  118. -- Users can delete their own applications, admins can delete any
  119. CREATE POLICY applications_delete_policy ON __sys_applications
  120. FOR DELETE
  121. USING (created_by = current_user_id() OR is_admin());
  122. -- =====================================================
  123. -- DEPLOYMENTS TABLE POLICIES
  124. -- =====================================================
  125. -- Users can see deployments of their applications, admins can see all
  126. CREATE POLICY deployments_select_policy ON __sys_deployments
  127. FOR SELECT
  128. USING (
  129. EXISTS (
  130. SELECT 1 FROM __sys_applications
  131. WHERE __sys_applications.id = __sys_deployments.application_id
  132. AND (__sys_applications.created_by = current_user_id() OR is_admin())
  133. )
  134. );
  135. -- Users can create deployments for their applications
  136. CREATE POLICY deployments_insert_policy ON __sys_deployments
  137. FOR INSERT
  138. WITH CHECK (
  139. EXISTS (
  140. SELECT 1 FROM __sys_applications
  141. WHERE __sys_applications.id = application_id
  142. AND (__sys_applications.created_by = current_user_id() OR is_admin())
  143. )
  144. );
  145. -- Users can update deployments of their applications, admins can update any
  146. CREATE POLICY deployments_update_policy ON __sys_deployments
  147. FOR UPDATE
  148. USING (
  149. EXISTS (
  150. SELECT 1 FROM __sys_applications
  151. WHERE __sys_applications.id = __sys_deployments.application_id
  152. AND (__sys_applications.created_by = current_user_id() OR is_admin())
  153. )
  154. );
  155. -- Users can delete deployments of their applications, admins can delete any
  156. CREATE POLICY deployments_delete_policy ON __sys_deployments
  157. FOR DELETE
  158. USING (
  159. EXISTS (
  160. SELECT 1 FROM __sys_applications
  161. WHERE __sys_applications.id = __sys_deployments.application_id
  162. AND (__sys_applications.created_by = current_user_id() OR is_admin())
  163. )
  164. );
  165. -- =====================================================
  166. -- AUDIT LOGS TABLE POLICIES
  167. -- =====================================================
  168. -- Users can see their own audit logs, admins can see all
  169. CREATE POLICY audit_logs_select_policy ON __sys_audit_logs
  170. FOR SELECT
  171. USING (user_id = current_user_id() OR is_admin());
  172. -- Only the system can insert audit logs (through application)
  173. CREATE POLICY audit_logs_insert_policy ON __sys_audit_logs
  174. FOR INSERT
  175. WITH CHECK (true);
  176. -- No one can update audit logs (immutable)
  177. CREATE POLICY audit_logs_update_policy ON __sys_audit_logs
  178. FOR UPDATE
  179. USING (false);
  180. -- Only admins can delete audit logs (for cleanup)
  181. CREATE POLICY audit_logs_delete_policy ON __sys_audit_logs
  182. FOR DELETE
  183. USING (is_admin());
  184. -- =====================================================
  185. -- EMAIL QUEUE TABLE POLICIES
  186. -- =====================================================
  187. -- Only admins can see email queue
  188. CREATE POLICY email_queue_select_policy ON __sys_email_queue
  189. FOR SELECT
  190. USING (is_admin());
  191. -- Only admins can insert into email queue
  192. CREATE POLICY email_queue_insert_policy ON __sys_email_queue
  193. FOR INSERT
  194. WITH CHECK (is_admin());
  195. -- Only admins can update email queue
  196. CREATE POLICY email_queue_update_policy ON __sys_email_queue
  197. FOR UPDATE
  198. USING (is_admin());
  199. -- Only admins can delete from email queue
  200. CREATE POLICY email_queue_delete_policy ON __sys_email_queue
  201. FOR DELETE
  202. USING (is_admin());
  203. -- =====================================================
  204. -- SMTP SETTINGS TABLE POLICIES
  205. -- =====================================================
  206. -- Only admins can see SMTP settings
  207. CREATE POLICY smtp_settings_select_policy ON __sys_smtp_settings
  208. FOR SELECT
  209. USING (is_admin());
  210. -- Only admins can insert SMTP settings
  211. CREATE POLICY smtp_settings_insert_policy ON __sys_smtp_settings
  212. FOR INSERT
  213. WITH CHECK (is_admin());
  214. -- Only admins can update SMTP settings
  215. CREATE POLICY smtp_settings_update_policy ON __sys_smtp_settings
  216. FOR UPDATE
  217. USING (is_admin());
  218. -- Only admins can delete SMTP settings
  219. CREATE POLICY smtp_settings_delete_policy ON __sys_smtp_settings
  220. FOR DELETE
  221. USING (is_admin());
  222. -- =====================================================
  223. -- BYPASS RLS FOR SERVICE ROLE
  224. -- =====================================================
  225. -- Allow the service user to bypass RLS for system operations
  226. -- This is important for the application to function while RLS infrastructure is being built
  227. -- Note: RLS is ENABLED but not FORCED, meaning:
  228. -- - The service role (saas_user) can bypass RLS and access all data
  229. -- - When we set up proper user context in the future, RLS will be enforced
  230. -- - This allows gradual migration to full RLS enforcement
  231. -- If you want to FORCE RLS (enforce for all roles including service role),
  232. -- uncomment the lines below:
  233. -- ALTER TABLE __sys_users FORCE ROW LEVEL SECURITY;
  234. -- ALTER TABLE __sys_sessions FORCE ROW LEVEL SECURITY;
  235. -- ALTER TABLE __sys_api_keys FORCE ROW LEVEL SECURITY;
  236. -- ALTER TABLE __sys_applications FORCE ROW LEVEL SECURITY;
  237. -- ALTER TABLE __sys_deployments FORCE ROW LEVEL SECURITY;
  238. -- ALTER TABLE __sys_audit_logs FORCE ROW LEVEL SECURITY;
  239. -- ALTER TABLE __sys_email_queue FORCE ROW LEVEL SECURITY;
  240. -- ALTER TABLE __sys_smtp_settings FORCE ROW LEVEL SECURITY;
  241. -- Create indexes for better RLS performance
  242. CREATE INDEX IF NOT EXISTS idx_users_role ON __sys_users(role);
  243. CREATE INDEX IF NOT EXISTS idx_sessions_user_id ON __sys_sessions(user_id);
  244. CREATE INDEX IF NOT EXISTS idx_api_keys_created_by ON __sys_api_keys(created_by);
  245. CREATE INDEX IF NOT EXISTS idx_applications_created_by ON __sys_applications(created_by);
  246. CREATE INDEX IF NOT EXISTS idx_deployments_application_id ON __sys_deployments(application_id);
  247. CREATE INDEX IF NOT EXISTS idx_audit_logs_user_id ON __sys_audit_logs(user_id);
  248. -- Grant necessary permissions to the service user
  249. GRANT ALL ON ALL TABLES IN SCHEMA public TO saas_user;
  250. GRANT ALL ON ALL SEQUENCES IN SCHEMA public TO saas_user;
  251. GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO saas_user;
  252. COMMENT ON FUNCTION current_user_id() IS 'Returns the current user ID from session context';
  253. COMMENT ON FUNCTION is_admin() IS 'Returns true if the current user has admin role';