¿Cómo se crea un usuario de solo lectura en PostgreSQL?


Me gustaría crear un usuario en PostgreSQL que solo pueda hacer SELECTs de una base de datos en particular. En MySQL el comando sería:

GRANT SELECT ON mydb.* TO 'xxx'@'%' IDENTIFIED BY 'yyy';

¿Cuál es el comando o serie de comandos equivalente en PostgreSQL?

Lo intenté...

postgres=# CREATE ROLE xxx LOGIN PASSWORD 'yyy';
postgres=# GRANT SELECT ON DATABASE mydb TO xxx;

Pero parece que las únicas cosas que puede conceder en una base de datos son CREAR, CONECTAR, TEMPORAL y TEMPORAL.

 336
Author: Peter Mortensen, 2009-04-17

9 answers

Conceder uso / seleccionar a una sola tabla

Si solo concede la CONEXIÓN a una base de datos, el usuario puede conectarse pero no tiene otros privilegios. Tiene que conceder el USO en los espacios de nombres (esquemas) y SELECCIONAR en las tablas y vistas individualmente así:

GRANT CONNECT ON DATABASE mydb TO xxx;
-- This assumes you're actually connected to mydb..
GRANT USAGE ON SCHEMA public TO xxx;
GRANT SELECT ON mytable TO xxx;

Múltiples tablas / vistas (PostgreSQL 9.0+)

En las últimas versiones de PostgreSQL, puede otorgar permisos en todas las tablas/vistas/etc en el esquema utilizando un solo comando en lugar de tener que escribirlos uno por uno:

GRANT SELECT ON ALL TABLES IN SCHEMA public TO xxx;

Esto solo afecta a las tablas que ya han sido creadas. Más poderosamente, puede tener automáticamente roles predeterminados asignados a nuevos objetos en el futuro:

ALTER DEFAULT PRIVILEGES IN SCHEMA public
   GRANT SELECT ON TABLES TO xxx;

Tenga en cuenta que, por defecto, esto solo afectará a los objetos (tablas) creados por el usuario que emitió este comando: aunque también se puede establecer en cualquier rol del que sea miembro el usuario emisor. Sin embargo, no obtiene privilegios predeterminados para todos los roles de los que es miembro al crear objetos nuevos... tan todavía hay algunos faffing alrededor. Si adopta el enfoque de que una base de datos tiene un rol propietario y los cambios de esquema se realizan como ese rol propietario, debe asignar privilegios predeterminados a ese rol propietario. En mi humilde opinión, todo esto es un poco confuso y es posible que tenga que experimentar para llegar a un flujo de trabajo funcional.

Varias tablas / vistas (versiones de PostgreSQL anteriores a la 9.0)

Para evitar errores en cambios largos y de varias tablas, se recomienda usar el siguiente 'automático' proceso para generar el GRANT SELECT requerido para cada tabla / vista:

SELECT 'GRANT SELECT ON ' || relname || ' TO xxx;'
FROM pg_class JOIN pg_namespace ON pg_namespace.oid = pg_class.relnamespace
WHERE nspname = 'public' AND relkind IN ('r', 'v', 'S');

Esto debería generar los comandos GRANT relevantes para GRANT SELECT en todas las tablas, vistas y secuencias en público, para copiar-n-pegar amor. Naturalmente, esto solo se aplicará a las tablas que ya se han creado.

 513
Author: araqnid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-24 19:58:22

Tenga en cuenta que PostgreSQL 9.0 (hoy en pruebas beta) tendrá una forma sencilla de hacerlo :

test=> GRANT SELECT ON ALL TABLES IN SCHEMA public TO joeuser;
GRANT
 34
Author: bortzmeyer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-19 21:21:01

Esta es la mejor manera que he encontrado para agregar usuarios de solo lectura (usando PostgreSQL 9.0 o posterior):

$ sudo -upostgres psql postgres
postgres=# CREATE ROLE readonly WITH LOGIN ENCRYPTED PASSWORD '<USE_A_NICE_STRONG_PASSWORD_PLEASE';
postgres=# GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly;

Luego inicie sesión en todas las máquinas relacionadas (master + read-slave(s)/hot-standby(s), etc..) y ejecutar:

$ echo "hostssl <PUT_DBNAME_HERE> <PUT_READONLY_USERNAME_HERE> 0.0.0.0/0 md5" | sudo tee -a /etc/postgresql/9.2/main/pg_hba.conf
$ sudo service postgresql reload
 22
Author: Jay Taylor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-20 23:00:39

Referencia tomada de este blog:

Script para Crear usuario de Solo lectura:

CREATE ROLE Read_Only_User WITH LOGIN PASSWORD 'Test1234' 
NOSUPERUSER INHERIT NOCREATEDB NOCREATEROLE NOREPLICATION VALID UNTIL 'infinity';

Asignar permiso a este usuario de solo lectura:

GRANT CONNECT ON DATABASE YourDatabaseName TO Read_Only_User;
GRANT USAGE ON SCHEMA public TO Read_Only_User;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO Read_Only_User;
GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO Read_Only_User;
 14
Author: Anvesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-04 19:51:34

Por defecto, los nuevos usuarios tendrán permiso para crear tablas. Si está planeando crear un usuario de solo lectura, probablemente esto no sea lo que desea.

Para crear un usuario verdadero de solo lectura con PostgreSQL 9.0+, ejecute los siguientes pasos:

# This will prevent default users from creating tables
REVOKE CREATE ON SCHEMA public FROM public;

# If you want to grant a write user permission to create tables
# note that superusers will always be able to create tables anyway
GRANT CREATE ON SCHEMA public to writeuser;

# Now create the read-only user
CREATE ROLE readonlyuser WITH LOGIN ENCRYPTED PASSWORD 'strongpassword';
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonlyuser;

Si su usuario de solo lectura no tiene permiso para listar tablas (es decir, \d no devuelve resultados), probablemente sea porque no tiene permisos USAGE para el esquema. USAGE es un permiso que permite a los usuarios utilizar realmente los permisos han sido asignados. ¿Qué sentido tiene esto? No estoy seguro. Para arreglar:

# You can either grant USAGE to everyone
GRANT USAGE ON SCHEMA public TO public;

# Or grant it just to your read only user
GRANT USAGE ON SCHEMA public TO readonlyuser;
 9
Author: Adrian Macneil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-20 23:03:05

He creado un script conveniente para eso; pg_grant_read_to_db.sh . Este script otorga privilegios de solo lectura a un rol especificado en todas las tablas, vistas y secuencias en un esquema de base de datos y los establece como predeterminados.

 8
Author: Jakub Jirutka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-14 20:27:36

Si su base de datos está en el esquema público, es fácil (esto asume que ya ha creado el readonlyuser)

db=> GRANT SELECT ON ALL TABLES IN SCHEMA public to readonlyuser;
GRANT
db=> GRANT CONNECT ON DATABASE mydatabase to readonlyuser;
GRANT
db=> GRANT SELECT ON ALL SEQUENCES IN SCHEMA public to readonlyuser;
GRANT

Si su base de datos está usando customschema, ejecute lo anterior pero agregue un comando más:

db=> ALTER USER readonlyuser SET search_path=customschema, public;
ALTER ROLE
 2
Author: josephmisiti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-28 17:07:55

La forma no sencilla de hacerlo sería otorgar select en cada tabla de la base de datos:

postgres=# grant select on db_name.table_name to read_only_user;

Podría automatizar eso generando sus declaraciones de subvención a partir de los metadatos de la base de datos.

 1
Author: Pablo Santa Cruz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-17 12:35:08

Tomado de un enlace publicado en respuesta a despesz' enlace.

Postgres 9.x parece tener la capacidad de hacer lo que se solicita. Ver el párrafo Grant On Database Objects de:

Http://www.postgresql.org/docs/current/interactive/sql-grant.html

Donde dice: "También hay una opción para otorgar privilegios a todos los objetos del mismo tipo dentro de uno o más esquemas. Esta funcionalidad se admite actualmente solo para tablas, secuencias y funciones (pero tenga en cuenta que TODAS las TABLAS se considera que incluyen vistas y tablas extranjeras)."

Esta página también discute el uso de roles y un PRIVILEGIO llamado "TODOS LOS PRIVILEGIOS".

También está presente información sobre cómo se comparan las funcionalidades de GRANT con los estándares SQL.

 0
Author: kbulgrien,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-27 16:22:09