What I'd like to be able to express
A way to say "this schema is owned by this role" directly in the policy YAML, analogous to how default_owner sets the global default today:
default_owner: pgloader_pg
schemas:
- name: cdc
owner: cdc_owner # <-- new, per-schema override
profiles: [editor, viewer, subscriber]
- name: awa
owner: awa_owner
profiles: [editor, viewer]
On apply, pgroles would:
- Ensure the schema exists with the correct
AUTHORIZATION (using CREATE SCHEMA ... AUTHORIZATION on first create, ALTER SCHEMA ... OWNER TO on converge).
- Set
ALTER DEFAULT PRIVILEGES FOR ROLE {owner} per profile, so the editor/viewer grants keep applying to objects the owner creates afterwards.
Out of scope
Bulk reassignment of existing schema-scoped objects (tables, functions, sequences, types) to the new owner. Reasons to leave this out:
- Blast radius. Changing the declared owner would rewrite ownership of potentially hundreds of objects on the next apply. Bigger consequence than any of pgroles' current converge steps.
- Edge cases. Partitioned parents + children, enum array types, function overloads, materialised views, extension-owned objects. Each solvable, each a source of bugs.
- Overlap with migrations. Migrations sometimes intentionally reassign ownership for specific reasons (RLS, replication, FDW). Silently re-overriding that on converge is the kind of trap that's hard to debug.
- Incompleteness. Services that create objects at runtime (e.g. a cdc-relay calling
CREATE TABLE IF NOT EXISTS) produce objects owned by the connecting role, not necessarily the schema owner, unless they SET ROLE first. pgroles can't enforce that from outside, so the invariant is never fully pgroles'.
Object-level ownership reassignment stays a one-time migration concern when adopting the pattern. Optionally pgroles could ship a CLI helper (pgroles reassign --schema cdc) that does the walk, but it's not part of the converge loop.
Why
A handful of services at work own a schema that they manage themselves at runtime — their startup code does CREATE OR REPLACE FUNCTION, CREATE TABLE IF NOT EXISTS, dynamic CREATE TRIGGER, etc. Those statements either require ownership or (for replace-style DDL) require the caller to be a member of the owning role.
Concretely, in one of our services:
- A change-data-capture relay owns a
cdc schema whose DDL it generates at boot.
- An async-worker framework owns an
awa schema and uses awa_owner (NOLOGIN) as the owning role, with service login roles granted membership.
With the current policy shape the only way I've found to express this is:
- Let
pgroles apply create the schema under default_owner.
- Run a post-apply SQL step that does
ALTER SCHEMA … OWNER TO and sets ALTER DEFAULT PRIVILEGES FOR ROLE for the new owner.
That works but moves a small piece of the policy out of the declarative file and into a side-car SQL script, which is awkward to keep consistent.
What I've considered
- Just making the service login role the owner. Works but conflates ownership with the connecting identity, and rules out having multiple login roles (old + new during a rollout) both act as owner via membership — which is the obvious zero-downtime story.
- A dedicated
{schema}_owner NOLOGIN role with login roles granted membership. This is a clean pattern and works fine at the SQL level; I'd just like pgroles to know about it so the ownership and its default privileges are part of the converged state.
Shape of the feature
Either:
owner: field on each schema entry (as sketched above). Falls back to default_owner if omitted.
- Ownership expressed on the owning role instead, e.g.
owns_schemas: [cdc, awa] on a role entry.
Either would let pgroles also set ALTER DEFAULT PRIVILEGES FOR ROLE {owner} per profile so editor/viewer grants keep applying to future objects without a separate SQL step.
What I'd like to be able to express
A way to say "this schema is owned by this role" directly in the policy YAML, analogous to how
default_ownersets the global default today:On
apply, pgroles would:AUTHORIZATION(usingCREATE SCHEMA ... AUTHORIZATIONon first create,ALTER SCHEMA ... OWNER TOon converge).ALTER DEFAULT PRIVILEGES FOR ROLE {owner}per profile, so the editor/viewer grants keep applying to objects the owner creates afterwards.Out of scope
Bulk reassignment of existing schema-scoped objects (tables, functions, sequences, types) to the new owner. Reasons to leave this out:
CREATE TABLE IF NOT EXISTS) produce objects owned by the connecting role, not necessarily the schema owner, unless theySET ROLEfirst. pgroles can't enforce that from outside, so the invariant is never fully pgroles'.Object-level ownership reassignment stays a one-time migration concern when adopting the pattern. Optionally pgroles could ship a CLI helper (
pgroles reassign --schema cdc) that does the walk, but it's not part of the converge loop.Why
A handful of services at work own a schema that they manage themselves at runtime — their startup code does
CREATE OR REPLACE FUNCTION,CREATE TABLE IF NOT EXISTS, dynamicCREATE TRIGGER, etc. Those statements either require ownership or (for replace-style DDL) require the caller to be a member of the owning role.Concretely, in one of our services:
cdcschema whose DDL it generates at boot.awaschema and usesawa_owner(NOLOGIN) as the owning role, with service login roles granted membership.With the current policy shape the only way I've found to express this is:
pgroles applycreate the schema underdefault_owner.ALTER SCHEMA … OWNER TOand setsALTER DEFAULT PRIVILEGES FOR ROLEfor the new owner.That works but moves a small piece of the policy out of the declarative file and into a side-car SQL script, which is awkward to keep consistent.
What I've considered
{schema}_ownerNOLOGIN role with login roles granted membership. This is a clean pattern and works fine at the SQL level; I'd just like pgroles to know about it so the ownership and its default privileges are part of the converged state.Shape of the feature
Either:
owner:field on each schema entry (as sketched above). Falls back todefault_ownerif omitted.owns_schemas: [cdc, awa]on a role entry.Either would let pgroles also set
ALTER DEFAULT PRIVILEGES FOR ROLE {owner}per profile so editor/viewer grants keep applying to future objects without a separate SQL step.