124 lines
5.9 KiB
SQL
124 lines
5.9 KiB
SQL
-- ============================================================
|
|
-- Omika Diagnostic Center -- 003_diagnostics_roles.sql (Phase 5B2B.3)
|
|
-- PostgreSQL hardening : least privilege (Worker / Web / Owner).
|
|
-- ============================================================
|
|
-- TO RUN ON SRV-OMIKA as PostgreSQL superuser (e.g. psql -U postgres),
|
|
-- BEFORE Phase 5C. DO NOT run from the development PC.
|
|
--
|
|
-- Guarantees :
|
|
-- - PostgreSQL 18 compatible.
|
|
-- - Idempotent : re-running is a no-op.
|
|
-- - Non destructive : NO DROP, no role/object/data removal.
|
|
-- - NO password, NO secret (LOGIN role passwords are set manually via
|
|
-- \password, never in this file).
|
|
--
|
|
-- Role model :
|
|
-- omika_diagnostics_owner NOLOGIN : owner of DB/schema/tables/sequences/indexes.
|
|
-- omika_diagnostics_worker LOGIN : Worker runtime (JSONL import).
|
|
-- omika_diagnostics_web LOGIN : Web runtime (read only).
|
|
-- omika_diagnostics_app (existing) : KEPT (controlled transition),
|
|
-- NOT disabled here.
|
|
--
|
|
-- Server apply order : 001 (schema) -> 002 (actor_key) -> 003 (roles).
|
|
-- ============================================================
|
|
|
|
-- ------------------------------------------------------------
|
|
-- 1. Create roles if absent (NO password here).
|
|
-- ------------------------------------------------------------
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'omika_diagnostics_owner') THEN
|
|
CREATE ROLE omika_diagnostics_owner;
|
|
END IF;
|
|
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'omika_diagnostics_worker') THEN
|
|
CREATE ROLE omika_diagnostics_worker;
|
|
END IF;
|
|
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'omika_diagnostics_web') THEN
|
|
CREATE ROLE omika_diagnostics_web;
|
|
END IF;
|
|
END
|
|
$$;
|
|
|
|
-- ------------------------------------------------------------
|
|
-- 2. Secure attributes (idempotent).
|
|
-- All: NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION NOBYPASSRLS.
|
|
-- ------------------------------------------------------------
|
|
ALTER ROLE omika_diagnostics_owner NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION NOBYPASSRLS NOLOGIN;
|
|
ALTER ROLE omika_diagnostics_worker NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION NOBYPASSRLS LOGIN;
|
|
ALTER ROLE omika_diagnostics_web NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION NOBYPASSRLS LOGIN;
|
|
|
|
-- ------------------------------------------------------------
|
|
-- 3. Ownership transfer (explicit -- no global REASSIGN OWNED).
|
|
-- Only Omika Diagnostics objects are targeted.
|
|
-- ------------------------------------------------------------
|
|
ALTER DATABASE omika_diagnostics OWNER TO omika_diagnostics_owner;
|
|
ALTER SCHEMA public OWNER TO omika_diagnostics_owner;
|
|
|
|
ALTER TABLE diagnostic_event OWNER TO omika_diagnostics_owner;
|
|
ALTER TABLE telemetry_metric_hourly OWNER TO omika_diagnostics_owner;
|
|
|
|
ALTER SEQUENCE diagnostic_event_id_seq OWNER TO omika_diagnostics_owner;
|
|
ALTER SEQUENCE telemetry_metric_hourly_id_seq OWNER TO omika_diagnostics_owner;
|
|
|
|
-- PostgreSQL 18:
|
|
-- Index ownership follows table ownership.
|
|
-- No ALTER INDEX OWNER is required.
|
|
-- (Sequences are NOT auto-transferred by ALTER TABLE: the ALTER SEQUENCE
|
|
-- OWNER commands above are therefore kept and required.)
|
|
|
|
-- ------------------------------------------------------------
|
|
-- 4. Schema "public" hardening.
|
|
-- Decision : YES, REVOKE CREATE -- the database is dedicated to the
|
|
-- Diagnostic Center; only the owner/admin should create objects.
|
|
-- (PostgreSQL 15+ already revokes it for new databases; this is an
|
|
-- idempotent belt-and-suspenders.)
|
|
-- ------------------------------------------------------------
|
|
REVOKE CREATE ON SCHEMA public FROM PUBLIC;
|
|
|
|
-- ------------------------------------------------------------
|
|
-- 5. MINIMUM runtime privileges (from real code audit).
|
|
--
|
|
-- WORKER (omika_diagnostics_worker):
|
|
-- * diagnostic_event : INSERT only
|
|
-- (INSERT ... ON CONFLICT (event_id) DO NOTHING -- dedup).
|
|
-- * sequence diagnostic_event_id_seq : USAGE (id BIGSERIAL).
|
|
-- * NO SELECT/UPDATE/DELETE (60-day retention is NOT implemented;
|
|
-- telemetry_metric_hourly upsert is registered but has NO caller).
|
|
--
|
|
-- WEB (omika_diagnostics_web): SELECT ONLY on diagnostic_event
|
|
-- (QueryAsync count+page, GetByTraceId, GetByOperationId, IsAvailableAsync).
|
|
--
|
|
-- NO privilege granted on telemetry_metric_hourly while no code uses it
|
|
-- (least privilege).
|
|
-- ------------------------------------------------------------
|
|
|
|
-- Explicit connection intent (PUBLIC keeps default CONNECT; documented only,
|
|
-- not hardened beyond requested scope).
|
|
GRANT CONNECT ON DATABASE omika_diagnostics TO omika_diagnostics_worker, omika_diagnostics_web;
|
|
|
|
GRANT USAGE ON SCHEMA public TO omika_diagnostics_worker, omika_diagnostics_web;
|
|
|
|
-- Worker : JSONL import -> diagnostic_event.
|
|
GRANT INSERT ON TABLE diagnostic_event TO omika_diagnostics_worker;
|
|
GRANT USAGE ON SEQUENCE diagnostic_event_id_seq TO omika_diagnostics_worker;
|
|
|
|
-- Web : read only.
|
|
GRANT SELECT ON TABLE diagnostic_event TO omika_diagnostics_web;
|
|
|
|
-- ------------------------------------------------------------
|
|
-- 6. Legacy role omika_diagnostics_app : KEPT (no DROP, no NOLOGIN here).
|
|
-- After transfer it owns no Diagnostics object and has no object privilege;
|
|
-- disabling it (ALTER ROLE ... NOLOGIN) is an EXPLICIT administrator action
|
|
-- AFTER validating the new roles.
|
|
-- ------------------------------------------------------------
|
|
|
|
-- ============================================================
|
|
-- END 003. Manual next steps (outside this script):
|
|
-- 1. Set passwords: psql -> \password omika_diagnostics_worker
|
|
-- then \password omika_diagnostics_web (never in script/log/history).
|
|
-- 2. Point Worker: Username=omika_diagnostics_worker ; Web:
|
|
-- Username=omika_diagnostics_web (ConnectionStrings__DiagnosticsDatabase).
|
|
-- 3. Validate Worker (INSERT) and Web (SELECT), then only after,
|
|
-- disable omika_diagnostics_app (ALTER ROLE ... NOLOGIN) if desired.
|
|
-- ============================================================
|