Files
portal/db/02_grants.sql
T
Дмитрий 1b5316b2c8 feat/db-path-a: anon(152-ФЗ)+схема+изоляция проверены на боевом Managed PG; 02_grants портирован под управляемую базу
- anon 1.3.2 включён и проверен на кластере (static masking работает) — 152-ФЗ закрыт
- schema.sql v8.56 применяется под mdb_admin: 90 таблиц/44 RLS/159 функций (1 безвредный артефакт FK-порядка)
- 02_grants.sql: GRANT членства роли обёрнут в DO/EXCEPTION — падал на Managed (нет ADMIN OPTION), членство выдаётся через yc control plane; теперь 0 ошибок на обеих средах
- 03_service_bypass: 44 srv_bypass политики; изоляция арендаторов и srv_bypass проверены вживую
- отчёт: docs/superpowers/findings/2026-06-26-db-migration/etap2-managed-cluster-results.md

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 11:24:30 +03:00

186 lines
12 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- =============================================================================
-- 02_grants.sql — GRANT/REVOKE для 4 ролей Лидерры
-- =============================================================================
-- Версия: 1.0 (08.05.2026, фаза 1 backend multi-tenant фундамент)
-- Источник: schema.sql v8.5 §13 «Роли БД (CTO-5)» + §14 «АУДИТ APPEND-ONLY»
-- =============================================================================
--
-- НАЗНАЧЕНИЕ: deployment-скрипт для production. Запускается ПОСЛЕ:
-- 1. db/00_create_roles.sql — роли созданы
-- 2. db/schema.sql — таблицы/индексы/RLS-политики созданы (через `php artisan migrate`)
--
-- ЗАПУСК:
-- psql -U postgres -h <host> -d liderra -f db/02_grants.sql
-- (требуется superuser, т.к. GRANT/REVOKE на чужие объекты)
--
-- ВНИМАНИЕ: на **dev-машине** этот файл НЕ запускается — schema.sql §13 разрешает
-- использовать суперпользователя `postgres` для разработки. RLS-политики работают
-- через `current_setting('app.current_tenant_id')::bigint` — независимо от роли.
-- =============================================================================
-- =============================================================================
-- 1. crm_app_user — tenant-уровень приложения (RLS активна)
-- =============================================================================
GRANT USAGE ON SCHEMA public TO crm_app_user;
-- SELECT/INSERT/UPDATE/DELETE на ВСЕ таблицы (RLS-политики ограничат доступ
-- к чужим tenant-данным; saas-таблицы дополнительно закрыты REVOKE ниже)
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO crm_app_user;
-- USAGE на sequences (для BIGSERIAL nextval)
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO crm_app_user;
-- Default privileges для будущих таблиц/sequences (после миграций)
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO crm_app_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT USAGE, SELECT ON SEQUENCES TO crm_app_user;
-- v8.5 (OPEN-И-14) defense-in-depth: REVOKE ALL на 6 saas-таблицах.
-- К этим таблицам tenant-приложение НЕ должно иметь доступа даже теоретически
-- (RLS + REVOKE = 2 барьера).
REVOKE ALL ON saas_admin_users FROM crm_app_user;
REVOKE ALL ON saas_admin_sessions FROM crm_app_user;
REVOKE ALL ON saas_admin_audit_log FROM crm_app_user;
REVOKE ALL ON incidents_log FROM crm_app_user;
REVOKE ALL ON pd_subject_requests FROM crm_app_user;
REVOKE ALL ON impersonation_tokens FROM crm_app_user;
-- =============================================================================
-- 2. crm_admin_user — администрирование SaaS (BYPASSRLS)
-- =============================================================================
GRANT USAGE ON SCHEMA public TO crm_admin_user;
-- ВСЕ права crm_app_user + доступ к saas_admin_*, supplier_*, system_settings,
-- tariff_plans, legal_entities, payment_gateways
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO crm_admin_user;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO crm_admin_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO crm_admin_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT USAGE, SELECT ON SEQUENCES TO crm_admin_user;
-- Запрет DELETE на финансовых таблицах (только soft markers через UPDATE):
REVOKE DELETE ON balance_transactions FROM crm_admin_user;
REVOKE DELETE ON supplier_invoices FROM crm_admin_user;
REVOKE DELETE ON supplier_lead_costs FROM crm_admin_user;
-- (tenant_subscriptions удалена из продукта — REVOKE убран, шов E 26.06.2026)
-- =============================================================================
-- 3. crm_audit_writer — append-only audit (INSERT-only)
-- =============================================================================
-- UPDATE/DELETE дополнительно блокируются триггерами audit_block_mutation
-- (schema.sql §14). Двухслойная защита от tampering.
GRANT USAGE ON SCHEMA public TO crm_audit_writer;
GRANT INSERT ON auth_log TO crm_audit_writer;
GRANT INSERT ON activity_log TO crm_audit_writer;
GRANT INSERT ON pd_processing_log TO crm_audit_writer;
GRANT INSERT ON saas_admin_audit_log TO crm_audit_writer;
GRANT INSERT ON balance_transactions TO crm_audit_writer;
GRANT USAGE ON SEQUENCE auth_log_id_seq TO crm_audit_writer;
GRANT USAGE ON SEQUENCE activity_log_id_seq TO crm_audit_writer;
GRANT USAGE ON SEQUENCE pd_processing_log_id_seq TO crm_audit_writer;
GRANT USAGE ON SEQUENCE saas_admin_audit_log_id_seq TO crm_audit_writer;
GRANT USAGE ON SEQUENCE balance_transactions_id_seq TO crm_audit_writer;
-- crm_audit_writer НЕ имеет SELECT/UPDATE/DELETE/TRUNCATE — это специально.
-- Явно отзываем дефолтные привилегии PUBLIC, если такие есть:
REVOKE SELECT, UPDATE, DELETE, TRUNCATE ON auth_log FROM crm_audit_writer;
REVOKE SELECT, UPDATE, DELETE, TRUNCATE ON activity_log FROM crm_audit_writer;
REVOKE SELECT, UPDATE, DELETE, TRUNCATE ON pd_processing_log FROM crm_audit_writer;
REVOKE SELECT, UPDATE, DELETE, TRUNCATE ON saas_admin_audit_log FROM crm_audit_writer;
REVOKE SELECT, UPDATE, DELETE, TRUNCATE ON balance_transactions FROM crm_audit_writer;
-- =============================================================================
-- 4. crm_migrator — runtime миграций (BYPASSRLS, CREATEDB)
-- =============================================================================
-- Для запуска `php artisan migrate` в production без ослабления RLS.
GRANT USAGE, CREATE ON SCHEMA public TO crm_migrator;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO crm_migrator;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO crm_migrator;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT ALL PRIVILEGES ON TABLES TO crm_migrator;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT ALL PRIVILEGES ON SEQUENCES TO crm_migrator;
-- =============================================================================
-- 5. crm_supplier_worker — backend queue worker (BYPASSRLS) — Plan 2.6 fix #iv
-- =============================================================================
-- Для запуска `php artisan queue:work` под отдельным .env (отдельным от web).
-- Cross-tenant операции: sharing-flow webhook routing (RouteSupplierLeadJob),
-- global crons (projects:reset-delivered-today, supplier:check-webhook-secret).
-- Web worker остаётся под crm_app_user (RLS-enforce). WHERE(tenant_id=) фильтры
-- в коде сохраняются как defense-in-depth даже под BYPASSRLS-ролью.
--
-- Brainstorm decision (10.05.2026 поздняя ночь): вариант C из 3 опций
-- (A=elevated DB-connection / B=RLS WITH-CHECK exception / C=BYPASSRLS-роль).
GRANT USAGE ON SCHEMA public TO crm_supplier_worker;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO crm_supplier_worker;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO crm_supplier_worker;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO crm_supplier_worker;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT USAGE, SELECT ON SEQUENCES TO crm_supplier_worker;
-- =============================================================================
-- v8.19 (Plan 4): supplier_csv_reconcile_log — SaaS-уровневый журнал CSV recon.
-- Используется CsvReconcileJob под crm_supplier_worker (BYPASSRLS).
-- =============================================================================
GRANT SELECT, INSERT, UPDATE ON TABLE supplier_csv_reconcile_log TO crm_supplier_worker;
GRANT USAGE, SELECT ON SEQUENCE supplier_csv_reconcile_log_id_seq TO crm_supplier_worker;
-- =============================================================================
-- 23.05.2026 (post hole #2): partition-maintenance privilege model
-- =============================================================================
-- `partitions:create-months` / `partitions:drop-expired` теперь идут через
-- `pgsql_supplier` connection (MonthlyPartitionManager::DDL_CONNECTION). Чтобы
-- `crm_supplier_worker` мог CREATE/DROP партиции партиционированных родителей,
-- нужны два условия:
-- 1. Единый владелец всех 9 партиционированных родителей — `crm_migrator`.
-- По умолчанию `schema.sql` создаёт audit-таблицы под `postgres` (load
-- выполняется суперпользователем при `migrate:fresh`); явный ALTER OWNER
-- ниже выравнивает прод (где это уже сделано вживую 23.05.2026) и
-- гарантирует, что fresh-deploy не разойдётся.
-- 2. `crm_supplier_worker` — член `crm_migrator` (INHERIT TRUE), чтобы
-- ownership-операции (CREATE TABLE ... PARTITION OF, DROP TABLE) проходили
-- проверку владельца. Web-роль `crm_app_user` остаётся least-privilege —
-- она НЕ получает crm_migrator-членство и НЕ может делать partition DDL.
--
-- Идемпотентно — повторный запуск 02_grants.sql после первого применения
-- безопасен.
-- =============================================================================
ALTER TABLE auth_log OWNER TO crm_migrator;
ALTER TABLE activity_log OWNER TO crm_migrator;
ALTER TABLE tenant_operations_log OWNER TO crm_migrator;
-- (webhook_log удалена в v8.35 legacy-webhook removal — ALTER OWNER убран, шов E 26.06.2026)
ALTER TABLE balance_transactions OWNER TO crm_migrator;
ALTER TABLE pd_processing_log OWNER TO crm_migrator;
ALTER TABLE saas_admin_audit_log OWNER TO crm_migrator;
-- NB (Путь А, Managed PG, проверено вживую 26.06.2026): на УПРАВЛЯЕМОЙ базе Yandex
-- этот GRANT членства в роли падает с 'permission denied to grant role "crm_migrator"'
-- — даже владелец-mdb_admin не имеет ADMIN OPTION на кастомную роль. На Managed членство
-- выдаётся через control plane (выполняется привилегированно самим Yandex):
-- yc managed-postgresql user update crm_supplier_worker --cluster-id <id> --grants crm_migrator
-- DO-обёртка делает скрипт безопасным на ОБЕИХ средах: self-managed prod (postgres superuser)
-- проходит штатно; на Managed — мягко пропускается с NOTICE (членство уже выдано через yc).
DO $$
BEGIN
EXECUTE 'GRANT crm_migrator TO crm_supplier_worker WITH INHERIT TRUE';
EXCEPTION WHEN insufficient_privilege THEN
RAISE NOTICE 'GRANT crm_migrator TO crm_supplier_worker пропущен (Managed PG: выдать через yc ... --grants crm_migrator)';
END$$;