PostgreSQL
Roles, ownership y permisos
Modelo de autorización con roles, ownership, GRANT, REVOKE, role membership y default privileges para separar administración, migraciones y runtime.
- Última actualización
- Actualizada
- Nivel
- Fundamentos
PostgreSQL
Modelo de autorización con roles, ownership, GRANT, REVOKE, role membership y default privileges para separar administración, migraciones y runtime.
La seguridad de PostgreSQL empieza por separar identidades, ownership y privilegios. El runtime de una aplicación no debe poseer el esquema que utiliza ni tener capacidad para redefinirlo.
Un role puede representar una persona, aplicación o grupo de privilegios. LOGIN determina si puede autenticarse:
CREATE ROLE app_runtime LOGIN PASSWORD '...';
CREATE ROLE app_readonly NOLOGIN;
GRANT app_readonly TO analyst_user;PostgreSQL usa roles tanto para usuarios como grupos.
Modelo recomendado:
migration_owner
→ posee schema, tablas, functions y migrations
app_runtime
→ SELECT/INSERT/UPDATE/DELETE necesarios
→ no crea ni altera objetos
reporting_role
→ lectura limitada
backup_role
→ privilegios específicos de backupEl owner puede modificar o eliminar el objeto aunque no tenga un GRANT explícito. Por eso ownership es más potente que permisos ordinarios.
Database:
GRANT CONNECT ON DATABASE appdb TO app_runtime;Schema:
GRANT USAGE ON SCHEMA app TO app_runtime;Tablas:
GRANT SELECT, INSERT, UPDATE, DELETE
ON ALL TABLES IN SCHEMA app
TO app_runtime;Sequences:
GRANT USAGE, SELECT
ON ALL SEQUENCES IN SCHEMA app
TO app_runtime;Functions:
GRANT EXECUTE ON FUNCTION app.reserve_stock(bigint,bigint,numeric)
TO app_runtime;USAGE en schema permite resolver nombres, no concede acceso automático a sus tablas.
Afectan objetos futuros creados por un role específico:
ALTER DEFAULT PRIVILEGES
FOR ROLE migration_owner
IN SCHEMA app
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_runtime;Error frecuente: configurar default privileges como admin, mientras las migraciones crean objetos con otro role. Los grants no se aplican.
PUBLIC representa todos los roles. Revisa defaults:
REVOKE CREATE ON SCHEMA public FROM PUBLIC;
REVOKE ALL ON DATABASE appdb FROM PUBLIC;No apliques comandos sin entender dependencias existentes, pero evita schemas escribibles por cualquiera cuando funciones sensibles dependen de search_path.
GRANT app_readonly TO analyst_user;Con INHERIT, el usuario obtiene privilegios automáticamente. SET ROLE permite asumir un role miembro en contextos autorizados.
No construyas jerarquías tan profundas que nadie pueda explicar el privilegio efectivo.
Cambiar owner:
ALTER TABLE app.orders OWNER TO migration_owner;Un role owner no debería ser usado por la aplicación. Puede ser NOLOGIN y las migraciones lo asumen mediante SET ROLE.
GRANT SELECT (id, name, created_at)
ON app.customers TO support_role;Útil para ocultar columnas sensibles, pero views suelen dar un contrato más mantenible. Column grants no sustituyen RLS para filas.
GRANT SELECT ON app.orders TO team_lead WITH GRANT OPTION;Permite delegar ese privilegio. Úsalo con cautela: amplía quién puede extender acceso.
Una función puede exponer una operación limitada sin conceder acceso directo:
GRANT EXECUTE ON FUNCTION security.close_order(uuid) TO app_runtime;Pero debe usar owner mínimo, search path seguro y validación. No conviertas SECURITY DEFINER en bypass general.
Una migración debe crear objetos bajo el owner previsto. Si un framework conecta como superuser, todos los objetos pueden terminar con ownership incorrecto y complicar restores, grants y operación.
Usa:
\du
\dn+
\dp app.*Y funciones como:
has_table_privilege('app_runtime','app.orders','SELECT')Prueba conectándote como el role real; leer ACLs no siempre revela la interacción completa de membership, ownership, RLS y functions.
REVOKE UPDATE ON app.orders FROM app_runtime;Los privilegios pueden provenir de otra membership. Verifica el acceso efectivo después.
REASSIGN OWNED y DROP OWNED ayudan al retirar roles, pero pueden afectar muchos objetos; inventaría primero.
FORCE ROW LEVEL SECURITY y reglas aplicables.public escribible.USAGE en schema?Row-Level Security y multi-tenancy aplica políticas por fila sin convertirlas en la única capa de aislamiento.