разрешения: почему в этом случае требуется обновление владельцем таблицы?

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

Это немного запутанно,поэтому я привел пример моей проблемы.

createuser -U postgres testowner -DIRS --pwprompt
createdb -U postgres -O testowner testdb
createuser -U postgres testupdater -DIRS --pwprompt

psql -d testdb -U testowner
CREATE TABLE a ( id serial PRIMARY KEY );
CREATE TABLE b ( a_id integer REFERENCES a(id) );
GRANT SELECT,INSERT ON ALL TABLES IN SCHEMA public TO testupdater;
GRANT USAGE,UPDATE ON SEQUENCE a_id_seq TO testupdater;
REVOKE INSERT, UPDATE ON ALL TABLES IN SCHEMA public FROM testowner;
INSERT INTO a VALUES (DEFAULT);  -- as expected: ERROR:  permission denied for relation a
q

psql -d testdb -U testupdater
INSERT INTO a VALUES (DEFAULT);
SELECT id FROM a LIMIT 1;  -- selects the first id (1)
INSERT INTO b VALUES (1); -- unexpected error: see below
q

ERROR: permission denied for relation a

CONTEXT: SQL statement "SELECT 1 FROM ONLY "public"."a" x WHERE "id" OPERATOR(pg_catalog.=) FOR SHARE OF x"

однако вышеуказанная вставка работает, если я возвращаю testowner привилегию обновления (GRANT UPDATE ON a TO testowner;). Почему testowner нуждается в обновлении в этом случае?

Примечание: GRANT UPDATE ON a TO testupdater; не помогает; кажется, что я должен предоставить обновление роли testowner.

1 ответов


Я предполагаю, что проблема заключается в "For SHARE OF" В этом операторе select - для того, чтобы иметь возможность создать эту блокировку строк, вам нужен хотя бы какой-то доступ для записи в таблицу.

например, если я создаю таблицу и только предоставляю себе доступ к ней:

postgres@testdb=# create table t(t1_id serial primary key, value text);
NOTICE:  CREATE TABLE will create implicit sequence "t_t1_id_seq" for serial column "t.t1_id"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "t_pkey" for table "t"
CREATE TABLE
postgres@testdb=# insert into t(value) values('foo');
INSERT 0 1
postgres@testdb=# grant select on t to steve;
GRANT

Теперь, хотя я могу читать строки из таблицы, я не могу их заблокировать:

steve@testdb@[local] => select * from t;
 t1_id | value 
-------+-------
     1 | foo
(1 row)

steve@testdb@[local] => select * from t for share;
ERROR:  permission denied for relation t

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

Я предполагаю, что это происходит потому что вы не хотите, чтобы учетная запись, которая имеет доступ ко всем таблицам, просто потому, что они их создали? Я бы предложил:

  • выполните изменения схемы как "postgres" или какой-либо другой суперпользователь, который имеет ограниченный доступ в файл pg_hba.conf
  • кроме того, выполните изменения схемы как некоторый пользователь (например, владелец базы данных), который не имеет доступа для входа, используя set session authorization из "postgres" или другого суперпользователя