web-dev-qa-db-fra.com

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

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 que j'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 octroi supplémentaire, 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 m'attendais à ce que l'utilisateur ne soit pas autorisé à faire quoi que ce soit avant de faire explicitement GRANT USAGE Sur le schéma, puis GRANT SELECT Sur les tables.

Où est mon erreur? Qu'est-ce que je fais mal? Comment puis-je réaliser 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 :)

EDIT En suivant les conseils de @ daniel-verite, je révoque maintenant tout de suite après avoir créé 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 avoir émis GRANT ALL PRIVILEGES ON DATABASE project2_core TO project2 Et GRANT ALL PRIVILEGES ON SCHEMA public TO project2, J'obtiens une erreur ERREUR: aucun schéma n'a été sélectionné pour créer dans , et lorsque j'essaie spécifiquement de CREATE TABLE public.WHATEVER ();, j'obtiens ERREUR: autorisation refusée pour le schéma public . Qu'est-ce que je fais mal?

44
andreas-h

Lorsque vous créez une nouvelle base de données, n'importe quel rôle est autorisé à créer des objets dans le schéma public. 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 à l'intérieur du schéma public, ce qui n'est pas pratique. En supposant qu'un non-superutilisateur foo_user Devrait se voir accorder ce privilège, cela devrait être fait avec:

GRANT ALL ON schema public TO foo_user;

Pour savoir ce que ALL signifie pour un schéma, nous devons nous référer à GRANT dans la doc , (dans PG 9.2 il n'y a pas moins de 14 formes d'instructions GRANT qui s'appliquent à différentes choses. ..). Il semble que pour un schéma, cela signifie CREATE et USAGE.

En revanche, GRANT ALL PRIVILEGES ON DATABASE... Accordera CONNECT et CREATE et TEMP, mais CREATE dans ce contexte concerne des schémas, non permanents les tables.

Concernant cette erreur: ERROR: no schema has been selected to create in, Cela se produit lorsque vous essayez de créer un objet sans qualification de schéma (comme dans create table foo(...)) sans l'autorisation de le créer dans n'importe quel schéma de search_path.

41
Daniel Vérité

La chose cruciale à comprendre ici est que les privilèges ne sont pas héritiers et sont non hérités du fait de contenir des objets. ALL signifie tous les privilèges pour cet objet pas tous les privilèges pour cet objet et tous les objets contenus.

Lorsque vous accordez ALL sur une 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 possède par défaut un schéma public créé 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, ALL signifie CREATE, USAGE:

  • CREATE: créer des objets (y compris des tables) dans ce schéma
  • USAGE: répertorier les objets dans le schéma et y accéder si leurs autorisations le permettent

Si vous ne spécifiez pas le schéma pour créer un objet comme une table dans, le moteur de base de données utilise le search_path, et par défaut le schéma public est le premier sur le search_path pour que la table y soit créée. Tout le monde a le droit de public par défaut, donc la création est 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, seulement un schéma en son sein.

Peu importe que vous n'ayez accordé à l'utilisateur aucun droit autre que l'octroi de CONNECT sur la base de données, car le schéma public permet à tous les utilisateurs d'y créer des tables par défaut. Daniel a déjà expliqué comment révoquer ce droit si désiré.

Si vous souhaitez déléguer explicitement tous les droits, révoquez-les tous du public ou supprimez simplement 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. Vous pouvez également l'appliquer à template1, mais cela cassera probablement beaucoup de code tiers qui suppose que public existe et est accessible en écriture.


Cela pourrait être plus logique si vous regardez une analogie du système de fichiers.

Si j'ai la structure du répertoire (mode simplifié pour ne montrer que le mode qui s'applique à l'utilisateur actuel):

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

alors je ne peux rien créer dans /dir1, car je n'ai pas de droit d'écriture. Donc, si je touch /dir1/somefile J'obtiendrai une erreur d'autorisation refusée.

Cependant, je fais ai la permission de regarder à l'intérieur /dir1 et pour accéder aux fichiers et répertoires contenus, y compris /dir1/dir2. J'ai la permission d'écrire sur dir2. Donc touch /dir1/dir2/somefile va réussir, même si je n'ai pas la permission d'écrire sur dir1.

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

19
Craig Ringer

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 d'autres réponses le suggèrent), vous empêcherez également les utilisateurs d'avoir des autorisations USAGE. USAGE signifie que les utilisateurs peuvent utiliser les autorisations qui leur sont attribuées, donc si vous supprimez cela, vos utilisateurs ne pourront pas lister ou accéder aux tables auxquelles ils ont accès.

Alternativement, vous pouvez également REVOKE CREATE pour un utilisateur spécifique:

REVOKE CREATE ON schema public FROM myuser;

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

7
Adrian Macneil