Pourquoi un nouvel utilisateur est-il autorisé à créer une table?

41

Je me demande pourquoi un utilisateur nouvellement créé est autorisé à créer une table après s'être connecté à une base de données. J'ai une base de données project2_core:

postgres=# \l
                                          List of databases
     Name      |    Owner     | Encoding  |   Collate   |    Ctype    |       Access privileges       
---------------+--------------+-----------+-------------+-------------+-------------------------------
 postgres      | postgres     | SQL_ASCII | C           | C           | 
 project2_core | atm_project2 | UTF8      | de_DE.UTF-8 | de_DE.UTF-8 | project2=CTc/project2
 template0     | postgres     | SQL_ASCII | C           | C           | =c/postgres                  +
               |              |           |             |             | postgres=CTc/postgres
 template1     | postgres     | SQL_ASCII | C           | C           | =c/postgres                  +
               |              |           |             |             | postgres=CTc/postgres
(5 rows)

Jusqu'ici tout va bien. Maintenant je crée un utilisateur:

postgres=# CREATE ROLE dietrich ENCRYPTED PASSWORD 'md5XXX' LOGIN NOCREATEROLE NOCREATEDB NOSUPERUSER

D'accord. Lorsque j'essaie de me connecter à la base de données, l'utilisateur n'est pas autorisé à le faire:

$ psql -h localhost -p 5432 -U dietrich -W project2_core
Password for user dietrich: 
psql: FATAL:  permission denied for database "project2_core"
DETAIL:  User does not have CONNECT privilege.

C'est ce à quoi je m'attendais. Maintenant, les choses étranges commencent. J'accorde à l'utilisateur CONNECT:

postgres=# GRANT CONNECT ON DATABASE project2_core TO dietrich;
GRANT
postgres=# \l
                                          List of databases
     Name      |    Owner     | Encoding  |   Collate   |    Ctype    |       Access privileges       
---------------+--------------+-----------+-------------+-------------+-------------------------------
 postgres      | postgres     | SQL_ASCII | C           | C           | 
 project2_core | atm_project2 | UTF8      | de_DE.UTF-8 | de_DE.UTF-8 | project2=CTc/project2+
               |              |           |             |             | dietrich=c/project2
 template0     | postgres     | SQL_ASCII | C           | C           | =c/postgres                  +
               |              |           |             |             | postgres=CTc/postgres
 template1     | postgres     | SQL_ASCII | C           | C           | =c/postgres                  +
               |              |           |             |             | postgres=CTc/postgres
(5 rows)

Et sans autre subvention, l'utilisateur est autorisé à créer une table:

$ psql -h localhost -p 5432 -U dietrich -W project2_core
Password for user dietrich: 
psql (9.2.3)
SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256)
Type "help" for help.

project2_core=> create table adsf ();
CREATE TABLE
project2_core=> \d
        List of relations
 Schema | Name | Type  |  Owner   
--------+------+-------+----------
 public | adsf | table | dietrich
(1 row)

Je me serais attendu à ce que l'utilisateur ne soit pas autorisé à faire quoi que ce soit avant que je ne GRANT USAGEle fasse explicitement sur le schéma, puis GRANT SELECTsur les tables.

Où est mon erreur? Qu'est-ce que je fais mal? Comment puis-je obtenir ce que je veux (qu'un nouvel utilisateur ne soit pas autorisé à faire quoi que ce soit avant de lui accorder explicitement les droits appropriés.

Je suis perdu et votre aide est grandement appréciée :)

EDITER Suite aux conseils de @ daniel-verite, je reprends tout immédiatement après la création de la base de données. L'utilisateur dietrich n'est plus autorisé à créer une table. Bien. MAIS : Maintenant, le propriétaire de la base de données, project2 , n'est pas autorisé à créer une table. Même après l’émission GRANT ALL PRIVILEGES ON DATABASE project2_core TO project2et GRANT ALL PRIVILEGES ON SCHEMA public TO project2, j’obtiens une erreur ERROR: aucun schéma n’a été sélectionné pour créer , et lorsque j’essaie précisément de le faire CREATE TABLE public.WHATEVER ();, j’obtiens ERROR: permission refusée pour le schéma public . Qu'est-ce que je fais mal?

andreas-h
la source

Réponses:

38

Lorsque vous créez une nouvelle base de données, tout rôle est autorisé à créer des objets dans le publicschéma. Pour supprimer cette possibilité, vous pouvez émettre immédiatement après la création de la base de données:

REVOKE ALL ON schema public FROM public;

Edit: après la commande ci-dessus, seul un superutilisateur peut créer de nouveaux objets dans le publicschéma, ce qui n’est pas pratique. En supposant qu'un foo_userprivilège soit accordé à un non-superutilisateur , vous devez le faire avec:

GRANT ALL ON schema public TO foo_user;

Pour savoir ce que ALLsignifie un schéma, nous devons faire référence à GRANT dans la doc (dans PG 9.2, il n’existe pas moins de 14 formes d’instructions GRANT qui s’appliquent à différentes choses ...). Il semble que pour un schéma cela signifie CREATEet USAGE.

D'un autre côté, GRANT ALL PRIVILEGES ON DATABASE...accordera CONNECTet CREATEet TEMP, mais CREATEdans ce contexte, concerne des schémas, pas des tables permanentes.

En ce qui concerne cette erreur: ERROR: no schema has been selected to create incela se produit lorsque vous essayez de créer un objet sans qualification de schéma (comme dans create table foo(...)) sans la permission de le créer dans n’importe quel schéma de search_path.

Daniel Vérité
la source
fonctionne :) Mais je ne comprends toujours pas: j’ai déjà essayé REVOKE ALL ON DATABASE project2_core FROM PUBLIC;. pourquoi cela n'a-t-il eu aucun effet?
andreas-h
mhh. maintenant, le propriétaire de la base de données n'est plus autorisé CREATE TABLE. voir mon édition ci-dessus.
andreas-h
@ andreas-h: a modifié la réponse avec plus de détails
Daniel Vérité le
En ce qui concerne l’erreur, il est facile de la reproduire en lançant les commandes de la question et votre REVOKE dans l’ordre :)
dezso
@ DanielVérité J'ai développé les concepts sous-jacents dans une nouvelle réponse pour compléter le vôtre. Un contrôle de santé serait apprécié.
Craig Ringer
19

La chose cruciale à comprendre ici est que les privilèges ne sont pas hérités et ne sont pas hérités des objets contenant . ALLsignifie tous les privilèges pour cet objet, pas tous les privilèges pour cet objet et tous les objets qu'il contient .

Lorsque vous accordez ALLune base de données, vous accordez CREATE, CONNECT, TEMP. Ce sont des actions sur l'objet de base de données lui-même:

  • CONNECT: Se connecter à la base de données
  • CREATE: Créer un schéma ( pas une table)
  • TEMP: Créer des objets temporaires, y compris, mais sans s'y limiter, des tables temporaires

Désormais, chaque base de données PostgreSQL a un publicschéma créé par défaut lors de la création de la base de données. Ce schéma a tous les droits accordés au rôle public, dont tout le monde est implicitement membre. Pour un schéma, ALLsignifie CREATE, USAGE:

  • CREATE: Créer des objets (y compris des tables) dans ce schéma
  • USAGE: Liste les objets du schéma et y accède si leurs autorisations le permettent

Si vous ne spécifiez pas le schéma pour créer un objet comme une table, le moteur de base de données utilise le search_path, et par défaut, le publicschéma est le premier sur search_pathla table, de sorte que la table y est créée. Tout le monde a les droits publicpar défaut, la création est donc autorisée. Les droits des utilisateurs sur la base de données ne sont pas pertinents à ce stade, car l'utilisateur n'essaie pas de faire quoi que ce soit à l'objet de base de données lui-même, mais seulement un schéma en son sein.

Peu importe que vous n'ayez accordé à l'utilisateur aucun autre droit que celui accordé CONNECTà la base de données, car le publicschéma permet à tous les utilisateurs de créer des tables par défaut. Daniel a déjà expliqué comment révoquer ce droit s'il le souhaitait.

Si vous souhaitez déléguer chaque droit explicitement, révoquer tout du public ou simplement supprimer le schéma public. Vous pouvez créer une nouvelle base de données de modèles avec cette modification appliquée si vous le souhaitez. Alternativement, vous pouvez l'appliquer à template1, mais cela cassera probablement beaucoup de code tiers qui suppose qu'il publicexiste et est inscriptible.


Cela peut sembler plus logique si vous regardez une analogie avec un système de fichiers.

Si j'ai la structure de répertoire (mode simplifié pour afficher uniquement le mode qui s'applique à l'utilisateur actuel):

/dir1           mode=r-x
/dir1/dir2      mode=rwx

alors je ne peux rien créer à l'intérieur /dir1, car je n'ai pas de permission en écriture. Donc, si je touch /dir1/somefilevais obtenir une erreur d’autorisation refusée.

Cependant, je n'ont la permission de regarder à l' intérieur et à l' accès contenu des fichiers et répertoires, y compris . J'ai l'autorisation d'écriture sur . Alors va réussir , même si je n'ai pas l'autorisation d'écrire pour ./dir1/dir1/dir2dir2touch /dir1/dir2/somefiledir1

Même chose avec les bases de données et les schémas.

Craig Ringer
la source
7

Si vous souhaitez uniquement empêcher les nouveaux utilisateurs de créer des tables, vous devez exécuter la commande suivante:

REVOKE CREATE ON SCHEMA public FROM public;

Si vous REVOKE ALL(comme le suggèrent d’autres réponses), vous empêcherez également les utilisateurs d’avoir des USAGEautorisations. USAGECela signifie que les utilisateurs peuvent utiliser les autorisations qui leur sont attribuées. Par conséquent, si vous les supprimez, vos utilisateurs ne pourront ni répertorier ni accéder aux tables auxquelles ils ont accès.

Alternativement, vous pouvez aussi REVOKE CREATEpour un utilisateur spécifique:

REVOKE CREATE ON schema public FROM myuser;

Voir aussi: Comment créer un utilisateur en lecture seule avec PostgreSQL .

Adrian Macneil
la source