Estoy creando una API JSON en Ruby on Rails. Quiero tener cuentas de usuario de solo escritura que se supone que alimentan datos al sistema pero que no deberían poder leer de él.
Para lograr una capa adicional de seguridad, me gustaría aplicar esta regla en el nivel de la base de datos.
La idea es tener un tipo de usuario "escritor" que use una conexión separada a la base de datos. A esta conexión se le debe permitir insertar/actualizar/eliminar pero no seleccionar.
Tengo todo configurado muy bien, pero desafortunadamente Rails genera esta consulta al insertar:
INSERT INTO "default"."products" ("id", "name", "sku") VALUES ($1, $2, $3) RETURNING "id"La parte "ID DE RETORNO" está haciendo que falle porque el usuario no tiene permisos SELECCIONAR:
ActiveRecord::StatementInvalid: PG::InsufficientPrivilege: ERROR: permission denied for relation products: INSERT INTO "default"."products" ("id", "name", "sku") VALUES ($1, $2, $3) RETURNING "id"¿Hay alguna forma de evitar esto en PG o Rails? Las dos opciones que veo son:
Encontré un artículo de alguien que tuvo el mismo problema y terminé simplemente otorgando derechos SELECT a los usuarios escritores:
https://til.hashrocket.com/posts/0c83645c03-postgres-permisos-para-insertar-pero-no-devolver
¿Hay alguna posibilidad de que haya una solución real para que la configuración anterior funcione?
Hay una forma de usar la función de seguridad de nivel de fila disponible desde PostgreSQL 9.5:
create table products(id serial primary key, name text not null, sku text not null); grant select,insert on products to tometzky; grant usage on sequence products_id_seq to tometzky; alter table products enable row level security; create policy products_tometzky on products to tometzky using (id=currval('products_id_seq')); tometzky=> select * from products; ERROR: currval of sequence "products_id_seq" is not yet defined in this session tometzky=> insert into products (name, sku) values ('a','a') returning id; 1 tometzky=> select * from products; 1|a|a tometzky=> insert into products (name, sku) values ('b','b') returning id; 2 tometzky=> select * from products; 2|b|bUn usuario solo ve la última fila que puso en la base de datos. Él sabe lo que es de todos modos.