103 lines
4.4 KiB
SQL
103 lines
4.4 KiB
SQL
-- Hammy backend bootstrap. Run ONCE, as a superuser, before any migration:
|
|
--
|
|
-- psql -U postgres -f scripts/bootstrap.sql
|
|
--
|
|
-- Deliberately NOT in migrations/. Three reasons:
|
|
--
|
|
-- * CREATE DATABASE cannot run inside a transaction block, and migration
|
|
-- tools wrap each file in one.
|
|
-- * \c is a psql meta-command, not SQL. A migration tool has no idea what it
|
|
-- means.
|
|
-- * Roles are cluster-wide, not per-database, so they are not part of any one
|
|
-- database's schema history.
|
|
--
|
|
-- Order matters: the schemas and ALTER DEFAULT PRIVILEGES must exist BEFORE any
|
|
-- table is created, because default privileges only apply to objects created
|
|
-- afterwards. Get this right here and no migration ever needs a GRANT.
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- Roles (cluster-wide)
|
|
-- ---------------------------------------------------------------------------
|
|
|
|
-- Owns every object and runs migrations. Never connects at runtime.
|
|
CREATE ROLE hammy_owner NOLOGIN;
|
|
|
|
-- What the backend connects as. DML only: it can read and write rows but not
|
|
-- create, alter or drop anything, so a compromised backend cannot drop the
|
|
-- logbook.
|
|
CREATE ROLE hammy_app LOGIN PASSWORD 'CHANGE_ME';
|
|
|
|
-- Bulk loaders for FCC ULS, 44net allocations and the like.
|
|
CREATE ROLE hammy_ingest LOGIN PASSWORD 'CHANGE_ME';
|
|
|
|
-- Analytics and debugging. Deliberately no access to the api schema - a
|
|
-- reporting query has no business reading key material.
|
|
CREATE ROLE hammy_readonly LOGIN PASSWORD 'CHANGE_ME';
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- Database
|
|
-- ---------------------------------------------------------------------------
|
|
|
|
CREATE DATABASE hammy OWNER hammy_owner ENCODING 'UTF8';
|
|
|
|
\c hammy
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- Schemas
|
|
-- ---------------------------------------------------------------------------
|
|
|
|
-- Before PostgreSQL 15, PUBLIC held CREATE on the public schema, so any role
|
|
-- could add objects to it. Revoke it and do not use public for anything.
|
|
REVOKE ALL ON SCHEMA public FROM PUBLIC;
|
|
|
|
CREATE SCHEMA core AUTHORIZATION hammy_owner;
|
|
CREATE SCHEMA api AUTHORIZATION hammy_owner;
|
|
CREATE SCHEMA logbook AUTHORIZATION hammy_owner;
|
|
CREATE SCHEMA ingest AUTHORIZATION hammy_owner;
|
|
|
|
COMMENT ON SCHEMA core IS 'Discord-linked user identity and callsign verification.';
|
|
COMMENT ON SCHEMA api IS 'API tenancy: owners, keys, usage. Most sensitive schema.';
|
|
COMMENT ON SCHEMA logbook IS 'Per-user QSO logs and import batches.';
|
|
COMMENT ON SCHEMA ingest IS 'Bulk-loaded third-party reference data.';
|
|
|
|
GRANT USAGE ON SCHEMA core, api, logbook, ingest TO hammy_app;
|
|
GRANT USAGE ON SCHEMA ingest TO hammy_ingest;
|
|
GRANT USAGE ON SCHEMA core, logbook TO hammy_readonly;
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- Default privileges
|
|
--
|
|
-- Apply to objects hammy_owner creates FROM NOW ON. Every migration runs as
|
|
-- hammy_owner, so tables pick these up automatically.
|
|
-- ---------------------------------------------------------------------------
|
|
|
|
ALTER DEFAULT PRIVILEGES FOR ROLE hammy_owner IN SCHEMA core, api, logbook
|
|
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO hammy_app;
|
|
|
|
ALTER DEFAULT PRIVILEGES FOR ROLE hammy_owner IN SCHEMA core, api, logbook
|
|
GRANT USAGE ON SEQUENCES TO hammy_app;
|
|
|
|
ALTER DEFAULT PRIVILEGES FOR ROLE hammy_owner IN SCHEMA ingest
|
|
GRANT SELECT ON TABLES TO hammy_app;
|
|
|
|
ALTER DEFAULT PRIVILEGES FOR ROLE hammy_owner IN SCHEMA ingest
|
|
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO hammy_ingest;
|
|
|
|
ALTER DEFAULT PRIVILEGES FOR ROLE hammy_owner IN SCHEMA core, logbook
|
|
GRANT SELECT ON TABLES TO hammy_readonly;
|
|
|
|
-- Postgres grants EXECUTE on new functions to PUBLIC by default, which would
|
|
-- make forget_user() callable by anyone who can connect. Revoke it; 005 grants
|
|
-- it back to hammy_app explicitly.
|
|
ALTER DEFAULT PRIVILEGES FOR ROLE hammy_owner IN SCHEMA core, api
|
|
REVOKE EXECUTE ON FUNCTIONS FROM PUBLIC;
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- search_path per role, so queries need not schema-qualify everything.
|
|
-- ---------------------------------------------------------------------------
|
|
|
|
ALTER ROLE hammy_owner SET search_path = core, api, logbook, ingest;
|
|
ALTER ROLE hammy_app SET search_path = core, api, logbook, ingest;
|
|
ALTER ROLE hammy_ingest SET search_path = ingest;
|
|
ALTER ROLE hammy_readonly SET search_path = core, logbook;
|