Меню

Ошибка нужно быть владельцем схемы public

For people using Google Cloud Platform, any error will stop the import process.
Personally I encountered two different errors depending on the pg_dump command I issued :

1- The input is a PostgreSQL custom-format dump. Use the pg_restore command-line client to restore this dump to a database.

Occurs when you’ve tried to dump your DB in a non plain text format. I.e when the command lacks the -Fp or —format=plain parameter. However, if you add it to your command, you may then encounter the following error :

2- SET SET SET SET SET SET CREATE EXTENSION ERROR: must be owner of extension plpgsql

This is a permission issue I have been unable to fix using the command provided in the GCP docs, the tips from this current thread, or following advice from Google Postgres team here. Which recommended to issue the following command :

pg_dump -Fp --no-acl --no-owner -U myusername myDBName > mydump.sql

The only thing that did the trick in my case was manually editing the dump file and commenting out all commands relating to plpgsql.

I hope this helps GCP-reliant souls.

Update :

It’s easier to dump the file commenting out extensions, especially since some dumps can be huge :
pg_dump ... | grep -v -E '(CREATE EXTENSION|COMMENT ON)' > mydump.sql

Which can be narrowed down to plpgsql :
pg_dump ... | grep -v -E '(CREATE EXTENSION IF NOT EXISTS plpgsql|COMMENT ON EXTENSION plpgsql)' > mydump.sql

For people using Google Cloud Platform, any error will stop the import process.
Personally I encountered two different errors depending on the pg_dump command I issued :

1- The input is a PostgreSQL custom-format dump. Use the pg_restore command-line client to restore this dump to a database.

Occurs when you’ve tried to dump your DB in a non plain text format. I.e when the command lacks the -Fp or —format=plain parameter. However, if you add it to your command, you may then encounter the following error :

2- SET SET SET SET SET SET CREATE EXTENSION ERROR: must be owner of extension plpgsql

This is a permission issue I have been unable to fix using the command provided in the GCP docs, the tips from this current thread, or following advice from Google Postgres team here. Which recommended to issue the following command :

pg_dump -Fp --no-acl --no-owner -U myusername myDBName > mydump.sql

The only thing that did the trick in my case was manually editing the dump file and commenting out all commands relating to plpgsql.

I hope this helps GCP-reliant souls.

Update :

It’s easier to dump the file commenting out extensions, especially since some dumps can be huge :
pg_dump ... | grep -v -E '(CREATE EXTENSION|COMMENT ON)' > mydump.sql

Which can be narrowed down to plpgsql :
pg_dump ... | grep -v -E '(CREATE EXTENSION IF NOT EXISTS plpgsql|COMMENT ON EXTENSION plpgsql)' > mydump.sql

В PostgreSQL для работы с объектами роль должна иметь привилегии к этим объектам (таблицам, функциям). В этой статье разберёмся с привилегиями PostgreSQL.

Привилегий для разных объектов

Каждый вид объектов имеет разный набор привилегий, таблицы например имеют самый большой набор:

  • SELECT – чтение данных;
  • INSERT – вставка данных;
  • UPDATE – изменение строк;
  • REFERENCES – внешний ключ (право ссылаться на таблицу);
  • DELETE – удаление строк;
  • TRUNCATE – очистка таблицы;
  • TRIGGER – создание триггеров.

Представления имеют всего две привилегии:

  • SELECT – право читать представление;
  • TRIGGER – право создавать триггеры.

Последовательности:

  • SELECT – право читать последовательность;
  • UPDATE – право изменять последовательность;
  • USAGE – право использовать последовательность.

Табличные пространства:

  • CREATE – разрешает создавать объекты внутри табличного пространства.

Базы данных имеют три привилегии:

  • CREATE – разрешает создавать схемы внутри базы данных;
  • CONNECT – даёт возможность подключаться к базе данных;
  • TEMPORARY – разрешает создавать в базе данных временные таблицы.

У схем есть две привилегии:

  • CREATE – разрешает создавать объекты внутри конкретной схемы;
  • USAGE – позволяет использовать объекты в конкретной схеме.

У функций есть только одна привилегия:

  • EXECUTE – даёт право выполнять функцию.

Категории ролей

С точки зрения управления доступом роли можно разбить на несколько групп:

  • Суперпользователи – полный доступ ко всем объектам – проверки не выполняются;
  • Владельцы – владельцем становиться тот, кто создал объект. Но право владения можно передать. Владелец имеет все привилегии на принадлежащий ему объект;
  • Остальные роли – доступ только в рамках выданных привилегий на определённый объект. Такие привилегии могут выдать владельцы на свои объекты. Или может выдать суперпользователь на любой другой объект.

Выдача и отзыв привилегий

Выдать привилегию можно с помощью команды GRANT:

GRANT <привилегии> ON <объект> to <роль>;

Забрать привилегию можно с помощью команды REVOKE:

REVOKE <привилегии> ON <объект> FROM <роль>;

Выданной привилегией можно пользоваться, но нельзя передавать другим ролям. Но владелец или суперпользователь может вместе с привилегией выдать дополнительную опцию, которая разрешит передавать привилегию другим ролям. Выдача привилегии с правом её передачи выполняется с помощью WITH GRAND OPTION:

GRANT <привилегии> ON <объект> to <роль> WITH GRAND OPTION;

Если мы дали привилегию вместе с правом её передачи. А затем роль воспользовалась своим правом и передала привилегию другим ролям. То забрать эту привилегию можно только каскадно у этой роли и у других ролей с помощью CASCADE:

REVOKE <привилегии> ON <объект> FROM <роль> CASCADE;

Можно не отбирать привилегию, а только отобрать право её передачи. Это делается следующим способом:

REVOKE GRANT OPTION FOR <привилегии> ON <объект> FROM <роль>;

Групповые привилегии

Роль получает привилегии своих групповых ролей. Нужно ли ей будет для получения привилегий выполнять SET ROLE зависит от атрибута роли, который мы можем указать при создании роли, как было показано на предыдущем уроке:

  • INHERIT – атрибут роли, который включает автоматическое наследование привилегий;
  • NOINHERIT – атрибут роли, который требует явное выполнение SET ROLE.

В 13 PostgreSQL при инициализации кластера создаются следующие роли вместе с суперпользователем postgres:

  • pg_signal_backend – право посылать сигналы обслуживающим процессам, например можно вызвать функцию pg_reload_conf() или завершить процесс с помощью функции pg_terminate_backend();
  • pg_read_all_settings – право читать все конфигурационные параметры, даже те, что обычно видны только суперпользователям;
  • pg_read_all_stats – право читать все представления pg_stat_* и использовать различные расширения, связанные со статистикой, даже те, что обычно видны только суперпользователям;
  • pg_stat_scan_tables – право выполнять функции мониторинга, которые могут устанавливать блокировки в таблицах, возможно, на длительное время;
  • pg_monitor – право читать и выполнять различные представления и функции для мониторинга. Эта роль включена в роли pg_read_all_settingspg_read_all_stats и pg_stat_scan_tables;
  • pg_read_server_files – право читать файлы в любом месте файловой системы, куда имеет доступ postgres на сервере. А также выполняя копирование и другие функции работы с файлами;
  • pg_write_server_files – право записывать файлы в любом месте файловой системы, куда имеет доступ postgres на сервере. А также выполнять копирование и другие функции работы с файлами.
  • pg_execute_server_program – право выполнять программы на сервере (от имени пользователя, запускающего СУБД).

Псевдо роль public

Псевдо роль public не видна, но про неё следует знать. Это групповая роль, в которую включены все остальные роли. Это означает, что все роли по умолчанию будут иметь привилегии наследуемые от public. Поэтому иногда у public отбирают некоторые привилегии, чтобы отнять их у всех пользователей.

Роль public по умолчанию имеет следующие привилегии:

  • для всех баз данных:
    • CONNECT – это означает что любая созданная роль сможет подключаться к базам данных, но не путайте с привилегией LOGIN;
    • TEMPORARY – любая созданная роль сможет создавать временные объекты во всех база данных и объекты эти могут быть любого размера;
  • для схемы public:
    • CREATE (создание объектов) – любая роль может создавать объекты в этой схеме;
    • USAGE (доступ к объектам) – любая роль может использовать объекты в этой схеме;
  • для схемы pg_catalog и information_schema:
    • USAGE (доступ к объектам) – любая роль может обращаться к таблицам системного каталога;
  • для всех функций:
    • EXECUTE (выполнение) – любая роль может выполнять любую функцию. Ещё нужны ещё права USAGE на ту схему, в которой функция находится, и права к объектам к которым обращается функция.

Это сделано для удобства, но снижает безопасность сервера баз данных.

Привилегии по умолчанию

Привилегии по умолчанию – это такие привилегии, которые добавятся к каким-то ролям на объект при его создании. Например роль Алиса хочет чтобы при создании новой таблицы доступ к ней сразу же получала роль Боб.

Привилегии по умолчанию создаются командой ALTER DEFAULT PRIVILEGES:

ALTER DEFAULT PRIVILEGES [IN SCHEMA <схема>] GRANT <привилегии> ON <класс_объектов> TO <роль>;

В примере выше <класс_объектов> это может быть, например таблица, функция, представление и т.п. То есть создаём мы какой-то объект из этого класса и сразу срабатывает команда выдачи привилегий: GRANT <привилегии> ON ... .

Аналогично можно удалять такие привилегии:

ALTER DEFAULT PRIVILEGES [IN SCHEMA <схема>] REVOKE <привилегии> ON <класс_объектов> FROM <роль>;

Например сделаем так, чтобы при создании функций (любым пользователем), право их выполнять забиралось у роли public:

ALTER DEFAULT PRIVILEGES REVOKE EXECUTE ON FUNCTIONS FROM public;

Затем вам придется отдельным ролям давать эту привилегию вручную. Или можете сделать отдельную групповую роль, которая сможет выполнять функции, и включать неё другие роли.

Практика

Выдаем различные привилегии на объекты

Подключимся к базе данных postgres под ролью postgres. Затем создадим роль alice и создадим схему alice. Дальше дадим Алисе привилегии создавать и использовать объекты в схеме alice. И наконец подключимся под Алисой:

postgres@s-pg13:~$ psql
Timing is on.
psql (13.3)
Type "help" for help.

postgres@postgres=# CREATE ROLE alice LOGIN;
CREATE ROLE
Time: 0,792 ms

postgres@postgres=# CREATE SCHEMA alice;
CREATE SCHEMA
Time: 0,853 ms

postgres@postgres=# GRANT CREATE, USAGE ON SCHEMA alice to alice;
GRANT
Time: 0,647 ms

postgres@postgres=# c - alice
You are now connected to database "postgres" as user "alice".

alice@postgres=>

Дальше нужно вспомнить что если мы для роли создали одноимённую схему, то по умолчанию для этой роли будет использоваться эта схема.

Под Алисой создадим 2 таблицы, затем переключимся на роль postgres и дадим Бобу право подключаться к базам:

alice@postgres=> CREATE TABLE t1(n integer);
CREATE TABLE
Time: 1,903 ms

alice@postgres=> CREATE TABLE t2(n integer, m integer);
CREATE TABLE
Time: 0,715 ms

alice@postgres=> c - postgres
You are now connected to database "postgres" as user "postgres".

postgres@postgres=# ALTER ROLE bob LOGIN;
ALTER ROLE
Time: 0,613 ms

Теперь переключимся на роль Боб и под ним попытаемся прочитать табличку t1 в схеме alice:

postgres@postgres=# c - bob;
You are now connected to database "postgres" as user "bob".

bob@postgres=> SELECT * FROM alice.t1;
ERROR:  permission denied for schema alice
LINE 1: SELECT * FROM alice.t1;
                      ^
Time: 0,300 ms

Возникла ошибка, так как у Боба нет привилегии USAGE на схему alice.

Посмотрим какие есть привилегии у схемы alice с помощью команды dn+:

bob@postgres=> dn+ alice
                    List of schemas
 Name  |  Owner   |  Access privileges   | Description
-------+----------+----------------------+-------------
 alice | postgres | postgres=UC/postgres+|
       |          | alice=UC/postgres    |
(1 row)

В поле “Access privileges” написаны построчно привилегии в следующем формате: роль=привилегии/кем_выданы.

Привилегии сокращаются по первой букве:

  • U = Usage;
  • C = Create.

Подключимся под Алисой и попробуем от неё выдать права Бобу:

bob@postgres=> c - alice
You are now connected to database "postgres" as user "alice".

alice@postgres=> GRANT CREATE, USAGE ON SCHEMA alice TO bob;
WARNING:  no privileges were granted for "alice"
GRANT
Time: 0,710 ms

Ошибка появилась потому-что Алиса не является владельцем этой схемы и не имеет право передавать привилегии.

Переключимся на роль postgres и сделаем Алису владельцем схемы alice:

alice@postgres=> c - postgres
You are now connected to database "postgres" as user "postgres".

postgres@postgres=# ALTER SCHEMA alice OWNER TO alice;
ALTER SCHEMA
Time: 0,800 ms

postgres@postgres=# dn+ alice
                 List of schemas
 Name  | Owner | Access privileges | Description
-------+-------+-------------------+-------------
 alice | alice | alice=UC/alice    |
(1 row)

Снова переключимся на Алису и выдадим права Бобу:

postgres@postgres=# c - alice
You are now connected to database "postgres" as user "alice".

alice@postgres=> GRANT CREATE, USAGE ON SCHEMA alice TO bob;
GRANT
Time: 0,905 ms

Попробуем под Бобом снова прочитать табличку Алисы:

alice@postgres=> c - bob
You are now connected to database "postgres" as user "bob".

bob@postgres=> SELECT * FROM alice.t1;
ERROR:  permission denied for table t1
Time: 0,663 ms

Снова не получилось, так как у Боба нет привилегии читать (SELECT) эту таблицу.

Посмотрим привилегии на эту таблицу с помощью команды dp:

bob@postgres=> dp alice.t1
                            Access privileges
 Schema | Name | Type  | Access privileges | Column privileges | Policies
--------+------+-------+-------------------+-------------------+----------
 alice  | t1   | table |                   |                   |
(1 row)

Привилегии записаны в колонке “Access privileges“. Здесь пока пусто, это означает что владелец может всё, остальные ничего. А для суперпользователя проверки не выполняются, поэтому он тоже может всё. В этой колонке появится информация, если мы выдадим или заберём привилегии у кого-нибудь для этой таблицы.

Переключимся опять на Алису, под которой выдадим привилегию SELECT на таблицу t1 для Боба. И снова проверим привилегии:

bob@postgres=> c - alice
You are now connected to database "postgres" as user "alice".

alice@postgres=> GRANT SELECT ON t1 TO bob;
GRANT
Time: 0,920 ms

alice@postgres=> dp t1
                             Access privileges
 Schema | Name | Type  |  Access privileges  | Column privileges | Policies
--------+------+-------+---------------------+-------------------+----------
 alice  | t1   | table | alice=arwdDxt/alice+|                   |
        |      |       | bob=r/alice         |                   |
(1 row)

Теперь мы видим 2 строки: для Алисы и для Боба. Привилегии сокращаются таким образом:

  • a – insert;
  • r – select;
  • w – update;
  • d – delete;
  • D – truncate;
  • x – reference;
  • t – trigger.

Наконец Боб может выполнить запрос:

alice@postgres=> c - bob
You are now connected to database "postgres" as user "bob".

bob@postgres=> SELECT * FROM alice.t1;
 n
---
(0 rows)
Time: 0,470 ms

Но вставить в эту таблицу он ничего не может, так как привилегии INSERT у Боба нет:

bob@postgres=> INSERT INTO alice.t1 VALUES (42);
ERROR:  permission denied for table t1
Time: 0,395 ms

Привилегии на отдельные столбцы

Некоторые привилегии (INSERT и SELECT) можно выдавать на столбцы.

Переключимся на Алису, и дадим бобу INSERT на колонки m и n, и SELECT на колонку m. Затем просмотрим привилегии на таблицу t2:

bob@postgres=> c - alice
You are now connected to database "postgres" as user "alice".

alice@postgres=> GRANT INSERT(m,n) ON t2 TO bob;
GRANT
Time: 0,869 ms

alice@postgres=> GRANT SELECT(m) ON t2 TO bob;
GRANT
Time: 0,432 ms

alice@postgres=> dp t2
                            Access privileges
 Schema | Name | Type  | Access privileges | Column privileges | Policies
--------+------+-------+-------------------+-------------------+----------
 alice  | t2   | table |                   | n:               +|
        |      |       |                   |   bob=a/alice    +|
        |      |       |                   | m:               +|
        |      |       |                   |   bob=ar/alice    |
(1 row)

В колонке “Column privileges” видны привилегии для отдельных столбцов. Видно что для столбца n Боб может только вставлять строки, а для столбца m вставлять и читать.

Проверим привилегии Боба на практике:

alice@postgres=> c - bob
You are now connected to database "postgres" as user "bob".

bob@postgres=> INSERT INTO alice.t2(n,m) VALUES (1,2);
INSERT 0 1
Time: 0,929 ms

bob@postgres=> SELECT * FROM alice.t2;
ERROR:  permission denied for table t2
Time: 0,355 ms

bob@postgres=> SELECT m FROM alice.t2;
 m
---
 2
(1 row)
Time: 0,278 ms

Из этого следует, что Боб смог вставить данные и в столбец n и в столбец m. А прочитать всё он не смог, так как нет прав на чтения для столбца n. Зато отдельно столбец m Боб прочитать смог.

Если необходимо Алиса может выдать все привилегии Бобу с помощью слова all:

bob@postgres=> c - alice
You are now connected to database "postgres" as user "alice".

alice@postgres=> GRANT ALL ON t1 TO bob;
GRANT
Time: 0,806 ms

alice@postgres=> dp t1
                             Access privileges
 Schema | Name | Type  |  Access privileges  | Column privileges | Policies
--------+------+-------+---------------------+-------------------+----------
 alice  | t1   | table | alice=arwdDxt/alice+|                   |
        |      |       | bob=arwdDxt/alice   |                   |
(1 row)

Теперь Бобу доступны все действия, например, удаление строк:

alice@postgres=> c - bob
You are now connected to database "postgres" as user "bob".

bob@postgres=> DELETE FROM alice.t1;
DELETE 0
Time: 0,709 ms

Но саму таблицу Боб удалить не сможет, так как удалить таблицу может только её владелец или суперпользователь:

bob@postgres=> DROP TABLE alice.t1;
ERROR:  must be owner of table t1
Time: 0,364 ms

Работа с ролью public

Алиса может выдать некоторые привилегии групповой роли public, чтобы эти привилегии появились у всех остальных:

bob@postgres=> c - alice
You are now connected to database "postgres" as user "alice".

alice@postgres=> GRANT UPDATE ON t2 TO public;
GRANT
Time: 0,746 ms

alice@postgres=> dp t2
                             Access privileges
 Schema | Name | Type  |  Access privileges  | Column privileges | Policies
--------+------+-------+---------------------+-------------------+----------
 alice  | t2   | table | alice=arwdDxt/alice+| n:               +|
        |      |       | =w/alice            |   bob=a/alice    +|
        |      |       |                     | m:               +|
        |      |       |                     |   bob=ar/alice    |
(1 row)

При выполнении команды dp, роль public не пишется, поэтому получается такая запись =w/alice.

Теперь Боб попробует воспользоваться привилегией UPDATE для этой таблице:

alice@postgres=> c - bob
You are now connected to database "postgres" as user "bob".

bob@postgres=> UPDATE alice.t2 SET n = n + 1;
ERROR:  permission denied for table t2
Time: 0,658 ms

Команде UPDATE для того чтобы что-то изменить нужно вначале это прочитать. А привилегии на чтение у Боба нет. Дадим с помощью Алисы ему это право и попробуем выполнить UPDATE ещё раз:

bob@postgres=> c - alice
You are now connected to database "postgres" as user "alice".

alice@postgres=> GRANT SELECT ON t2 TO bob;
GRANT
Time: 0,983 ms

alice@postgres=> dp t2
                             Access privileges
 Schema | Name | Type  |  Access privileges  | Column privileges | Policies
--------+------+-------+---------------------+-------------------+----------
 alice  | t2   | table | alice=arwdDxt/alice+| n:               +|
        |      |       | =w/alice           +|   bob=a/alice    +|
        |      |       | bob=r/alice         | m:               +|
        |      |       |                     |   bob=ar/alice    |
(1 row)

alice@postgres=> c - bob
You are now connected to database "postgres" as user "bob".

bob@postgres=> UPDATE alice.t2 SET n = n + 1;
UPDATE 1
Time: 1,256 ms

Выдача права передавать привилегии

Переключимся на пользователя postgres и создадим ещё одну роль “Чарли”:

bob@postgres=> c - postgres
You are now connected to database "postgres" as user "postgres".

postgres@postgres=# CREATE ROLE charlie LOGIN;
CREATE ROLE
Time: 0,653 ms

Боб имеет полный набор привилегий для таблицы t1. Но передать эти привилегии не может:

postgres@postgres=# c - bob
You are now connected to database "postgres" as user "bob".

bob@postgres=> dp alice.t1
                             Access privileges
 Schema | Name | Type  |  Access privileges  | Column privileges | Policies
--------+------+-------+---------------------+-------------------+----------
 alice  | t1   | table | alice=arwdDxt/alice+|                   |
        |      |       | bob=arwdDxt/alice   |                   |
(1 row)

bob@postgres=> GRANT SELECT ON alice.t1 TO charlie;
WARNING:  no privileges were granted for "t1"
GRANT
Time: 0,723 ms

Алиса может дать Бобу право передачи некоторых привилегий:

bob@postgres=> c - alice
You are now connected to database "postgres" as user "alice".

alice@postgres=> GRANT SELECT, UPDATE ON t1 TO bob WITH GRANT OPTION;
GRANT
Time: 0,873 ms

alice@postgres=> dp t1
                             Access privileges
 Schema | Name | Type  |  Access privileges  | Column privileges | Policies
--------+------+-------+---------------------+-------------------+----------
 alice  | t1   | table | alice=arwdDxt/alice+|                   |
        |      |       | bob=ar*w*dDxt/alice |                   |
(1 row)

В выводе выше звёздочки возле привилегий означают, что эти привилегии роль может передавать другим.

Теперь Боб может передать эти привилегии для Чарли и даже дать ему также право передавать эти привилегии другим:

alice@postgres=> c - bob
You are now connected to database "postgres" as user "bob".

bob@postgres=> GRANT SELECT ON alice.t1 TO charlie WITH GRANT OPTION;
GRANT
Time: 1,126 ms

bob@postgres=> GRANT UPDATE ON alice.t1 TO charlie;
GRANT
Time: 0,454 ms

bob@postgres=> dp alice.t1
                             Access privileges
 Schema | Name | Type  |  Access privileges  | Column privileges | Policies
--------+------+-------+---------------------+-------------------+----------
 alice  | t1   | table | alice=arwdDxt/alice+|                   |
        |      |       | bob=ar*w*dDxt/alice+|                   |
        |      |       | charlie=r*w/bob     |                   |
(1 row)

Если привилегию выдаёт суперпользователь, то вместо него команда dp выводит владельца:

bob@postgres=> c - postgres
You are now connected to database "postgres" as user "postgres".

postgres@postgres=# GRANT UPDATE ON alice.t1 to charlie;
GRANT
Time: 0,679 ms

postgres@postgres=# dp alice.t1
                             Access privileges
 Schema | Name | Type  |  Access privileges  | Column privileges | Policies
--------+------+-------+---------------------+-------------------+----------
 alice  | t1   | table | alice=arwdDxt/alice+|                   |
        |      |       | bob=ar*w*dDxt/alice+|                   |
        |      |       | charlie=r*w/bob    +|                   |
        |      |       | charlie=w/alice     |                   |
(1 row)

Роль может отнимать привилегии только те, которые она и выдавала. Поэтому информация о том, кто что выдавал сохраняется. Таким образом если Боб отнимет привилегии у Чарли, то у Чарли останутся те привилегии, которые ему дала Алиса (или суперпользователь).

А если роль не выдавала какую-то привилегию, то при удалении этой привилегии никакой ошибки не будет, просто привилегии не изменятся. Например, Алиса может попытаться отобрать у Чарли право передачи привилегий на SELECT (GRANT OPTION FOR SELECT). Но это право для Чарли выдавал Боб, а не Алиса. Запрос выполнится без ошибок, но ничего не изменится:

postgres@postgres=# c - alice
You are now connected to database "postgres" as user "alice".

alice@postgres=> REVOKE GRANT OPTION FOR SELECT ON alice.t1 FROM charlie;
REVOKE
Time: 0,976 ms

alice@postgres=> dp alice.t1
                             Access privileges
 Schema | Name | Type  |  Access privileges  | Column privileges | Policies
--------+------+-------+---------------------+-------------------+----------
 alice  | t1   | table | alice=arwdDxt/alice+|                   |
        |      |       | bob=ar*w*dDxt/alice+|                   |
        |      |       | charlie=r*w/bob    +|                   |
        |      |       | charlie=w/alice     |                   |
(1 row)

Ситуация описанная выше может ввести в заблуждение. Вроде право передачи привилегий отняли, а на самом деле не отняли.

Алиса может попытаться отобрать у Боба право передачи привилегий. Но так как Боб уже воспользовался своим правом и передал право передачи привилегий ещё одному пользователю, то у Алисы ничего не получится:

alice@postgres=> SELECT current_role;
 current_role
--------------
 alice
(1 row)
Time: 0,182 ms

alice@postgres=> REVOKE GRANT OPTION FOR SELECT ON alice.t1 FROM bob;
ERROR:  dependent privileges exist
HINT:  Use CASCADE to revoke them too.
Time: 0,368 ms

Алиса забрать это право может только каскадно, что мы и сделаем:

alice@postgres=> REVOKE GRANT OPTION FOR SELECT ON alice.t1 FROM bob CASCADE;
REVOKE
Time: 0,469 ms

alice@postgres=> dp alice.t1
                             Access privileges
 Schema | Name | Type  |  Access privileges  | Column privileges | Policies
--------+------+-------+---------------------+-------------------+----------
 alice  | t1   | table | alice=arwdDxt/alice+|                   |
        |      |       | bob=arw*dDxt/alice +|                   |
        |      |       | charlie=w/bob      +|                   |
        |      |       | charlie=w/alice     |                   |
(1 row)

В выводе можем заметить, что у Боба право передачи для SELECT исчезло, но сама привилегия SELECT осталась. А у Чарли привилегия SELECT и право её передавать исчезли.

Дополнительно под Алисой отнимем привилегию UPDATE у Боба, тоже каскадно:

alice@postgres=> REVOKE UPDATE ON alice.t1 FROM bob CASCADE;
REVOKE
Time: 0,639 ms

alice@postgres=> dp alice.t1
                             Access privileges
 Schema | Name | Type  |  Access privileges  | Column privileges | Policies
--------+------+-------+---------------------+-------------------+----------
 alice  | t1   | table | alice=arwdDxt/alice+|                   |
        |      |       | bob=ardDxt/alice   +|                   |
        |      |       | charlie=w/alice     |                   |
(1 row)

Работа с функциями

Теперь поработаем с функциями. Пусть Алиса создаст функцию, которая будет считать количество строк в таблице t1 и возвращать это значение (в синтаксис функции можете не вникать):

alice@postgres=> CREATE FUNCTION f() RETURNS integer AS $$ SELECT count(*)::integer FROM t2; $$ LANGUAGE SQL;
CREATE FUNCTION
Time: 1,922 ms

alice@postgres=> SELECT f();
 f
---
 1
(1 row)

Time: 0,397 ms

Теперь попробуем выполнить эту функцию под Бобом:

alice@postgres=> c - bob
You are now connected to database "postgres" as user "bob".

bob@postgres=> SELECT alice.f();
ERROR:  relation "t2" does not exist
LINE 1:  SELECT count(*)::integer FROM t2;
                                       ^
QUERY:   SELECT count(*)::integer FROM t2;
CONTEXT:  SQL function "f" during inlining
Time: 0,437 ms

Боб может выполнить эту функцию, так как по умолчанию псевдо роль public может выполнять любые функции. Но так как прав на табличку t2 у Боба нету, то на команде SELECT из функции мы получили ошибку.

Боб может в своей схеме (public) создать свою табличку t2 и выполнить функцию относительно неё. А у Алисы по умолчанию схема alice, поэтому для неё функция будет работать для другой таблицы. Вот пример:

bob@postgres=> CREATE TABLE t2 (n numeric);
CREATE TABLE
Time: 2,296 ms
bob@postgres=> SELECT alice.f();
 f
---
 0
(1 row)
Time: 0,506 ms

bob@postgres=> c - alice
You are now connected to database "postgres" as user "alice".
alice@postgres=> SELECT alice.f();
 f
---
 1
(1 row)
Time: 0,772 ms

Алиса при создании функции может указать, что при выполнении функции она будет работать от имени владельца (Алисы), а не от имени того кто эту функцию выполняет. Для этого используется опция SECURITY DEFINER при создании функции:

alice@postgres=> CREATE OR REPLACE FUNCTION f() RETURNS integer AS $$ SELECT count(*)::integer FROM t2; $$ SECURITY DEFINER LANGUAGE SQL;
CREATE FUNCTION
Time: 0,994 ms

alice@postgres=> c - bob
You are now connected to database "postgres" as user "bob".
bob@postgres=> SELECT alice.f();
 f
---
 1
(1 row)
Time: 0,751 ms

Так как функция сработала от имени Алиса, то и обратилась она к схеме alice и в ней нашла таблицу.

Такие функции обычно создаются для контролируемого доступа. Например Бобу нельзя читать таблицу, но мы хотим дать ему право посчитать количество строк в таблице. Таким образом через функции даём доступ к объектам.

Теперь отнимем у всех (public) привилегию выполнять функции в схеме alice:

bob@postgres=> c - alice
You are now connected to database "postgres" as user "alice".

alice@postgres=> REVOKE EXECUTE ON ALL FUNCTIONS IN SCHEMA alice FROM public;
REVOKE
Time: 0,911 ms

alice@postgres=> c - bob
You are now connected to database "postgres" as user "bob".

bob@postgres=> SELECT alice.f();
ERROR:  permission denied for function f
Time: 0,454 ms

Команда выше удалила привилегию EXECUTE для всех существующих функций. Если Алиса создаст новую, то у public сразу появится возможность её выполнить:

bob@postgres=> c - alice
You are now connected to database "postgres" as user "alice".

alice@postgres=> CREATE FUNCTION f_new() RETURNS integer AS $$ SELECT 1; $$ LANGUAGE SQL;
CREATE FUNCTION
Time: 1,285 ms

alice@postgres=> c - bob
You are now connected to database "postgres" as user "bob".

bob@postgres=> SELECT alice.f_new();
 f_new
-------
     1
(1 row)
Time: 0,395 ms

Привилегии по умолчанию

С помощью привилегий по умолчанию можно автоматически удалять привилегии с новых объектах. Например когда Алиса будет создавать какую-нибудь функцию, то нужно чтобы сразу у роли public отнимались привилегии на её выполнение:

bob@postgres=> c - alice
You are now connected to database "postgres" as user "alice".

alice@postgres=> ALTER DEFAULT PRIVILEGES FOR ROLE alice REVOKE EXECUTE ON FUNCTIONS FROM public;
ALTER DEFAULT PRIVILEGES
Time: 1,155 ms

Команда выше делает так, что когда Алиса создает любую функцию, привилегия FUNCTIONS сразу отнимается у public.

Посмотреть такие привилегии по умолчанию можно с помощью команды ddp:

alice@postgres=> ddp
           Default access privileges
 Owner | Schema |   Type   | Access privileges
-------+--------+----------+-------------------
 alice |        | function | alice=X/alice
(1 row)

В выводе выше мы видим что для функций Алисы будут отниматься привилегии (буква X).

Проверим. Удалим функцию и заново её создадим. И попробуем её вызвать под Бобом:

alice@postgres=> DROP FUNCTION f_new();
DROP FUNCTION
Time: 1,282 ms

alice@postgres=> CREATE FUNCTION f_new() RETURNS integer AS $$ SELECT 1; $$ LANGUAGE SQL;
CREATE FUNCTION
Time: 0,657 ms
alice@postgres=> c - bob
You are now connected to database "postgres" as user "bob".
bob@postgres=> SELECT alice.f_new();
ERROR:  permission denied for function f_new
Time: 0,502 ms

Аналогично, с помощью привилегий по умолчанию, можно настроить чтобы Боб автоматически получал какие-нибудь привилегии. Например при создании таблиц привилегии на их чтение:

bob@postgres=> c - alice
You are now connected to database "postgres" as user "alice".
alice@postgres=> ALTER DEFAULT PRIVILEGES FOR ROLE alice GRANT SELECT ON TABLES TO bob;
ALTER DEFAULT PRIVILEGES
Time: 0,977 ms
alice@postgres=> ddp
            Default access privileges
 Owner | Schema |   Type   |  Access privileges
-------+--------+----------+---------------------
 alice |        | function | alice=X/alice
 alice |        | table    | bob=r/alice        +
       |        |          | alice=arwdDxt/alice
(2 rows)

Теперь если Алиса создаст табличку, то у Боба сразу появится привилегия SELECT на табличку:

alice@postgres=> CREATE TABLE t3(n integer);
CREATE TABLE
Time: 2,084 ms

alice@postgres=> dp t3
                             Access privileges
 Schema | Name | Type  |  Access privileges  | Column privileges | Policies
--------+------+-------+---------------------+-------------------+----------
 alice  | t3   | table | bob=r/alice        +|                   |
        |      |       | alice=arwdDxt/alice |                   |
(1 row)

Сводка

Привилегии в PostgreSQL

Имя статьи

Привилегии в PostgreSQL

Описание

В PostgreSQL для работы с объектами роль должна иметь привилегии к этим объектам (таблицам, функциям). В этой статье разберёмся с привилегиями PostgreSQL

Я запускаю Postgres 10.4 и в настоящее время сбит с толку, поскольку не могу предоставить доступ к схеме другой роли.

Что я хочу сделать:

У меня одна роль с одной схемой, и я хочу получить доступ к схеме и ее таблицам из другой роли. Итак, я сделал как обычно (что работало с другими схемами):

grant usage on schema myschema to newuser;

grant select on all tables in schema myschema to newuser;

Оба этих оператора выполнялись как владелец схемы. При этом я не столкнулся с какими-либо ошибками.

Когда я вхожу в систему как новый пользователь и пытаюсь выбрать некоторые данные:

select * from myschema.table;

Я получаю сообщение об ошибке:

SQL Error [42501]: ERROR: permission denied for schema myschema

Я вижу, что у нового пользователя есть нужные привилегии в таблице «information_schema.role_table_grants»

Он также работал с другой ролью и другой схемой. Я невежественен.


Ответы
2

Это определенно работает, как указано в моем вопросе, проблема заключалась в том, что я не использовал владельца схемы.

Поэтому всегда убедитесь, что вы предоставляете доступ к схеме от роли владельца.

Шаг 1
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA name_schema TO name_user;

Шаг 2
GRANT USAGE ON SCHEMA name_schema TO name_user;

Другие вопросы по теме

I’m trying to view the raw data from the AACT Database in pgAdmin 4. I’m on a Mac computer. When I just try to view the first 100 rows from the ‘complete_oncology’ table, I get the below error:

ERROR: permission denied for schema public
LINE 1: SELECT * FROM public.complete_oncology
                      ^
SQL state: 42501
Character: 15

Do I have insufficient permissions? If yes, how do I grant myself permissions to view this table? I am able to see other tables from different Schemas in the AACT database. I’ve read some users suggest granting myself permissions with something like the below, but no luck:

GRANT SELECT ON complete_oncology TO PUBLIC

This just turns up an error:

ERROR:  relation "complete_oncology" does not exist
SQL state: 42P01

asked Apr 27, 2021 at 2:57

cpburke94's user avatar

If you get a «permission denied» for public.complete_oncology, but a «relation does not exist» for oncology, that can only mean only one thing: you do not have USAGE permissions on the public schema.

Get the owner of the schema to run

GRANT USAGE ON SCHEMA public TO your_user;

Then you should be able to see the table. If you still lack permissions on the table itself, get the owner to grant you SELECT on the table as well.

answered Apr 27, 2021 at 3:19

Laurenz Albe's user avatar

Laurenz AlbeLaurenz Albe

190k17 gold badges175 silver badges229 bronze badges

1

  1. go to preferences setting on popsql
  2. connections
  3. delete connection that you have
  4. add new connection
    fill the form
    -connection name ( up to you)
    -Turn on Connection type «connect directly from my computer»
    -hostname : localhost (before you can type localhost, turn on the connection type «connect directly from mycomputer»)
    -port : 3306
    -database name : same as you create before on cmd sql
    -username : root

answered Oct 9, 2022 at 10:58

Tienho's user avatar

1

Какую опцию / трюк grant мне нужно дать текущему пользователю (« userA «), чтобы он мог изменить владельца объекта, принадлежащего другому пользователю (« userC «)?

Точнее, таблица contact принадлежит userC , и когда я выполняю следующий запрос для смены владельца на userB , связанный с userA :

alter table contact owner to userB;

Я получаю такую ​​ошибку:

ERROR:  must be owner of relation contact

Но userA имеет все необходимые права, чтобы делать это в обычном режиме (параметра предоставления « create on schema » должно быть достаточно):

grant select,insert,update,delete on all tables in schema public to userA; 
grant select,usage,update on all sequences in schema public to userA;
grant execute on all functions in schema public to userA;
grant references, trigger on all tables in schema public to userA;
grant create on schema public to userA;
grant usage on schema public to userA;

Спасибо


Вывод командной строки:

root@server:~# psql -U userA myDatabase
myDataBase=>dt contact
    List of relations
Schema |  Name   |   Type   |  Owner
-------+---------+----------+---------
public | contact | table    | userC
(1 row)
myDataBase=>
myDataBase=>alter table contact owner to userB;
ERROR:  must be owner of relation public.contact
myDataBase=>

3 ответа

Лучший ответ

Благодаря комментарию Майка я перечитал документ и понял, что мой текущий пользователь (т.е. userA, у которого уже есть привилегия create ) не был прямым / косвенным членом новой роли владельца

Итак, решение было довольно простым — я только что выполнил грант:

grant userB to userA;

Это все, ребята 😉


Обновить:

Другое требование состоит в том, что объект должен принадлежать пользователю userA до его изменения …


107

Marcus Campbell
15 Мар 2019 в 19:03

Это решило мою проблему: пример оператора alter table для смены владельца.

ALTER TABLE databasechangelog OWNER TO arwin_ash;
ALTER TABLE databasechangeloglock OWNER TO arwin_ash;


9

Vivek
18 Янв 2020 в 20:40

Из прекрасного руководства.

Вы должны владеть таблицей, чтобы использовать ALTER TABLE.

Или станьте суперпользователем базы данных.

ОШИБКА: должно быть владельцем контакта

Сообщения об ошибках PostgreSQL обычно появляются точно. Это место на высоте.


16

Mike Sherrill ‘Cat Recall’
18 Фев 2015 в 13:44

Я использую Postgres для проекта django, и в настоящее время я реализую систему резервного копирования/восстановления базы данных, которая как можно проще выполняет pg_dump, когда пользователь нажимает backup, а затем pg_restore, когда они нажимают restore backup.

все кажется прекрасным и денди, пока он не попытается выполнить pg_restore, в котором он дает эту ошибку:

pg_restore: [архиватор (db)] ошибка из записи TOC 3206; 0 0 комментарий
Расширение plpgsql pg_restore: [архиватор (db)] не удалось выполнить запрос:
Ошибка: должен быть владельцем команды расширения plpgsql: COMMENT ON
Расширение plpgsql — это «процедурный язык PL / pgSQL»;

Я посмотрел, что такое plpgsql и т. д., И я понимаю это, и что касается ошибки, я попытался вручную установить «владельца расширения» пользователю, который выполняет скрипт и владеет самой базой данных, но это ничего не изменило, его действительно раздражает, так как его ошибка при попытке установить комментарий всех вещи!—1—>

все это создается автоматически pg_dump, поэтому строка комментария не может быть удалена, и нет флагов для отключения комментариев (которые я знаю), поэтому я действительно застрял в том, как решить эту проблему.

5 ответов


похоже, что pg_restore пытается восстановить некоторые дополнительные данные, которыми вы не владеете. Попробуйте добавить -n public опция командной строки pg_restore. Он сообщит pg_restore восстановить только содержимое общедоступной схемы. Ваша командная строка должна выглядеть как

pg_restore -U username -c -n public -d database_name

Я нашел следующий обходной путь на этой странице:

http://archives.postgresql.org/pgsql-general/2011-10/msg00826.php

идея состоит в том, чтобы использовать pg_restore-l для списка содержимого архива, grep из расширения, которое пользователь не имеет разрешения на восстановление, и использовать pg_restore-L для использования этого elided списка при восстановлении.

например:

pg_restore -l ~/database.dump | grep -v "EXTENSION - plpgsql" > ~/restore_elements
pg_restore -L ~/restore_elements ~/database.dump

Если возможно, я рекомендую вам удалить комментарий, который не удается восстановить перед созданием дампов.

можно сделать так:

COMMENT ON EXTENSION plpgsql IS null;

Если вы не хотите делать это для каждой вновь созданной базы данных, удалите комментарий из БД template1 (CREATE DATABASE… копирует эту базу данных.)

дампы, созданные после этого, должны восстанавливаться без ошибок.


вы загружаете в БД, которая была создана другим пользователем? Если возможно, попробуйте восстановить с помощью того же пользователя, который создал БД и ее существующие объекты.


работает для меня после этой команды —

Deepak@deepak:~$ sudo -i -u postgres
postgres@deepak:~$ psql 
psql (9.3.5)
Type "help" for help.

postgres=# GRANT ALL PRIVILEGES ON DATABASE database_name TO user;
postgres=# GRANT

Когда я создаю базу данных с моим пользователем, общедоступная схема создается с пользователем «postgres». Я могу создавать и удалять таблицы в этой схеме, но не могу удалить схему или изменить владельца.

Я устанавливаю миграцию Phinx для проекта php. Это зрелый проект, который имеет много таблиц. Для первой миграции по методу up() я загружаю файл sql со схемой базы данных, а по методу down() я бы отбрасывал схему (таблицы, триггеры, процедуры…)

class FirstMigration extends AbstractMigration
{
public function up()
{
$schema= file_get_contents('./database/migrations/schemaDB.sql');
$this->execute($schema);
}

public function down()
{
$this->execute("DROP SCHEMA public CASCADE");
$this->execute("CREATE SCHEMA public");
}
}

Когда я делаю откат, у меня появляется ошибка:

Недостаточно прав: 7 ОШИБКА: Вы должны быть владельцем общедоступной схемы.

image

Когда я создаю базу данных, я выбираю пользователя «citest»

image

Но владельцем общедоступной схемы по умолчанию является «postgres»!

и я не могу это изменить.

Мой пользователь является владельцем базы данных, но не является владельцем общедоступной схемы, которая является пользователем «postgres».

0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии

А вот еще интересные материалы:

  • Яшка сломя голову остановился исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного где ошибка
  • Ошибка обнаруживающаяся при повторном измерении называется
  • Ошибка номер 8 на ниве шевроле что означает