Роли в базе данных

QHB управляет правами доступа к базе данных, используя концепцию ролей. Роль может рассматриваться как пользователь базы данных или группа пользователей базы данных, в зависимости от того, как она установлена. Роли могут владеть объектами базы данных (например, таблицами и функциями) и назначать права для этих объектов другим ролям, контролируя то, кто имеет доступ к каким объектам. Кроме того, можно предоставить членство в роли другой роли, что позволяет роли-участнику пользоваться правами, присвоенные другой роли.

Понятие ролей объединяет понятия «пользователи» и «группы». Любая роль может выступать в роли пользователя, группы или и того, и другого.

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


Роли базы данных

Роли базы данных концептуально полностью отделены от пользователей операционной системы. На практике может быть удобно поддерживать соответствие между ними, но это необязательно. Роли базы данных являются глобальными для всей установки кластера баз данных (а не для отдельной базы данных). Чтобы создать роль, используйте команду SQL CREATE ROLE:

CREATE ROLE имя;

Синтаксис имени соответствует правилам для идентификаторов SQL: либо простой, без специальных символов, либо в кавычках. (На практике обычно требуется добавить в команду дополнительные параметры, например LOGIN. Подробнее см. ниже) Чтобы удалить существующую роль, используйте аналогичную команду DROP ROLE:

DROP ROLE имя;

Для удобства в качестве оберток вокруг этих команд SQL предоставляются программы createuser и dropuser, которые можно вызывать из командной строки оболочки:

createuser имя
dropuser имя

Чтобы определить набор существующих ролей, просмотрите системный каталог pg_roles, например:

SELECT rolname FROM pg_roles;

Для просмотра существующих ролей также полезна метакоманда \du программы psql.

Для начальной загрузки СУБД недавно инициализированная система всегда содержит одну предопределенную роль. Эта роль всегда является «суперпользователем», и по умолчанию (если она не изменена при запуске qhb_bootstrap (или initdb)) она будет иметь то же имя, что и пользователь операционной системы, инициализирующий кластер баз данных. Обычно эта роль называется qhb. Чтобы создать больше ролей, сначала необходимо подключиться к базе данных под этой начальной ролью.

Каждое соединение с сервером баз данных выполняется с использованием имени какой-то определенной роли, и эта роль определяет начальные права доступа для команд, выполненных в этом соединении. Имя роли, которое будет использоваться для конкретного подключения к базе данных, указывается клиентом, инициирующим запрос на подключение, причем специфичным для клиентского приложения образом. Например, программа psql использует для указания роли для подключения параметр командной строки -U. Многие приложения по умолчанию принимают имя текущего пользователя операционной системы (включая createuser и psql). Поэтому часто удобно поддерживать соответствие имен между ролями и пользователями операционной системы.

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


Атрибуты ролей

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

Право входа в систему

Только роли с атрибутом LOGIN могут использоваться в качестве начального имени роли для подключения к базе данных. Роль с атрибутом LOGIN может рассматриваться как «пользователь базы данных». Чтобы создать роль с правами входа в систему, используйте:

CREATE ROLE имя LOGIN;
CREATE USER имя;

(Команда CREATE USER равнозначна команде CREATE ROLE за исключением того, что CREATE USER по умолчанию включает атрибут LOGIN, а CREATE ROLE — нет.)

Статус суперпользователя

Суперпользователь базы данных обходит все проверки разрешений, кроме права на вход в систему. Это опасное право, и его не следует использовать небрежно; лучше всего выполнять большую часть работы в роли, которая не является суперпользователем. Чтобы создать нового суперпользователя базы данных, используйте команду CREATE ROLE имя SUPERUSER. Это следует делать под ролью, которая уже является суперпользователем.

Создание базы данных

Роли должно быть явно дано разрешение на создание баз данных (за исключением суперпользователей, поскольку они обходят все проверки разрешений). Чтобы создать такую роль, используйте команду CREATE ROLE имя CREATEDB.

Создание ролей

Роли должно быть явно дано разрешение на создание других ролей (за исключением суперпользователей, поскольку они обходят все проверки разрешений). Чтобы создать такую роль, используйте команду CREATE ROLE имя CREATEROLE. Роль с правом CREATEROLE тоже может изменять и удалять другие роли, а также предоставлять или отзывать членство в них. Изменение роли включает большинство изменений, которые можно сделать командой ALTER ROLE, в том числе, например, смену пароля, а также модификации роли, которые можно сделать с помощью команд COMMENT и SECURITY LABEL.

Однако право CREATEROLE не позволяет создавать или каким-то образом влиять на уже существующие роли SUPERUSER. Более того, право CREATEROLE не позволяет ни создавать пользователей REPLICATION, ни предоставлять или отзывать право REPLICATION, ни изменять свойства ролей таких пользователей. Тем не менее, оно позволяет использовать команды ALTER ROLE ... SET и ALTER ROLE ... RENAME, а также COMMENT ON ROLE, SECURITY LABEL ON ROLE и DROP ROLE к ролям REPLICATION. Наконец, право CREATEROLE не дает возможности предоставлять или отзывать право BYPASSRLS.

Поскольку право CREATEROLE позволяет пользователю предоставлять или отзывать членство даже в тех ролях, к которым он (пока) не имеет доступа, пользователь CREATEROLE может получить доступ к возможностям каждой предопределенной роли в системе, включая роли со множеством прав, такие как pg_execute_server_program и pg_write_server_files.

Инициирование репликации

Роли должно быть явно дано разрешение на инициирование потоковой репликации (за исключением суперпользователей, поскольку они обходят все проверки разрешений). Роль, используемая для потоковой репликации, также должна иметь разрешение LOGIN. Чтобы создать такую роль, используйте команду CREATE ROLE имя REPLICATION LOGIN.

Пароль

Пароль имеет значение только в том случае, если метод аутентификации клиента требует от пользователя ввода пароля при подключении к базе данных. Пароли используются в методах аутентификации password и md5. Пароли базы данных отделены от паролей операционной системы. Укажите пароль при создании роли с помощью команды CREATE ROLE имя PASSWORD 'string'.

Наследование прав

По умолчанию роли дается разрешение наследовать права той роли, членом которой она является. Тем не менее, чтобы создать роль без этого разрешения, достаточно выполнить CREATE ROLE имя NOINHERIT.

Обход защиты на уровне строк

Разрешение обходить все политики защиты на уровне строк (RLS, row-level security) нужно давать роли явно (за исключением суперпользователей, поскольку они обходят все проверки разрешений). Чтобы создать такую роль, выполните CREATE ROLE имя BYPASSRLS от имени суперпользователя.

Ограничение соединений

Ограничение соединение позволяет указать, сколько именно одновременных соединений может создать роль. -1 (значение по умолчанию) означает отсутствие ограничения. Задайте ограничение соединений при создании роли, выполнив CREATE ROLE имя CONNECTION LIMIT 'integer'.

Атрибуты роли можно изменить после ее создания, воспользовавшись командой ALTER ROLE. Подробную информацию см. на справочных страницах команд CREATE ROLE и ALTER ROLE.

Роль также может иметь специфичные для нее значения по умолчанию для многих параметров конфигурации времени выполнения, описанных в главе Конфигурация сервера. Например, если по какой-то причине необходимо выключить сканирование индекса (намек: не очень хорошая идея) при каждом подключении, можно использовать:

ALTER ROLE myname SET enable_indexscan TO off;

Это сохранит настройку (но не установит ее сразу). В последующих соединениях с этой ролью будет казаться, будто команда SET enable_indexscan TO off была выполнена непосредственно перед началом сеанса. Этот параметр по-прежнему можно изменить в рамках сеанса; это только значение по умолчанию. Чтобы удалить настройку по умолчанию для конкретной роли, используйте команду ALTER ROLE имя_роли RESET имя_переменной. Обратите внимание, что специфичные для роли значения по умолчанию, закрепленные за ролями без права LOGIN, довольно бесполезны, поскольку они никогда не будут применены.


Членство в роли

Зачастую бывает удобно группировать пользователей, чтобы упростить управление правами: таким образом, права могут быть предоставлены или отозваны для группы в целом. В QHB это достигается созданием роли, представляющей группу, а затем предоставлением членства в групповой роли отдельным ролям пользователей.

Чтобы настроить групповую роль, сначала создайте эту роль:

CREATE ROLE имя;

Обычно роль, используемая в качестве группы, не имеет атрибута LOGIN, хотя при желании его можно установить.

Когда групповая роль уже существует, в нее можно добавлять и удалять участников, используя команды GRANT и REVOKE:

GRANT групповая_роль TO роль1, ... ;
REVOKE групповая_роль FROM роль1, ... ;

Вы можете предоставить членство и другим групповым ролям (поскольку на самом деле между групповыми и не групповыми ролями никакой разницы нет). База данных не позволит настроить замыкание членства в круг. Кроме того, не разрешено предоставлять роли PUBLIC членство в других ролях.

Члены групповой роли могут использовать права этой роли двумя способами. Во-первых, каждый член группы может явно выполнить SET ROLE, чтобы временно «стать» групповой ролью. В этом состоянии сеанс базы данных имеет доступ к правам групповой роли, а не исходной роли входа в систему, и любые созданные объекты базы данных считаются принадлежащими групповой роли, а не роли входа. Во-вторых, роли-участники, имеющие атрибут INHERIT, автоматически используют права ролей, членами которых они являются, включая любые права, унаследованные этими ролями. В качестве примера предположим, что мы выполнили:

CREATE ROLE joe LOGIN INHERIT;
CREATE ROLE admin NOINHERIT;
CREATE ROLE wheel NOINHERIT;
GRANT admin TO joe;
GRANT wheel TO admin;

Сразу после подключения под ролью joe сеанс базы данных будет использовать права, предоставленные непосредственно joe, а также любые права, предоставленные admin, поскольку joe «наследует» права admin. Однако права, предоставленные wheel, ему недоступны, потому что, хотя joe опосредованно является членом wheel, членство осуществляется через роль admin, имеющую атрибут NOINHERIT. После:

SET ROLE admin;

сеанс будет использовать только права, предоставленные admin, но не те, которые предоставлены joe. После:

SET ROLE wheel;

сеанс будет использовать только права, предоставленные wheel, но не те, которые предоставлены joe или admin. Исходное состояние прав можно восстановить любым из следующих способов:

SET ROLE joe;
SET ROLE NONE;
RESET ROLE;

Примечание
Команда SET ROLE всегда позволяет выбрать любую роль, членом которой непосредственно или опосредованно является исходная роль входа в систему. Таким образом, в приведенном выше примере нет необходимости становиться admin, прежде чем стать wheel.

Примечание
В стандарте SQL существует четкое различие между пользователями и ролями, и пользователи не наследуют права автоматически, в то время как роли наследуют. Такое поведение можно получить в QHB, если ролям, используемым в качестве ролей SQL, дать атрибут INHERIT, а ролям, используемым в качестве пользователей SQL, — атрибут NOINHERIT. По умолчанию в QHB всем ролям предоставляется атрибут INHERIT.

Атрибуты роли LOGIN, SUPERUSER, CREATEDB и CREATEROLE могут рассматриваться как специальные права, но они никогда не наследуются, в отличие от обычных прав для объектов базы данных. Чтобы использовать такой атрибут, нужно действительно выполнить SET ROLE для конкретной роли, имеющей один из этих атрибутов. Продолжая приведенный выше пример, мы можем предоставить атрибуты CREATEDB и CREATEROLE роли admin. Тогда подключение к сеансу под ролью joe получит эти права не сразу, а только после выполнения SET ROLE admin.

Чтобы уничтожить групповую роль, используйте команду DROP ROLE:

DROP ROLE имя;

Любое членство в групповой роли автоматически отзывается (но иным образом на роли-участники это не повлияет).


Удаление ролей

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

Права собственности на объекты можно передавать по одному с помощью команд ALTER, например:

ALTER TABLE bobs_table OWNER TO alice;

Как вариант, можно воспользоваться командой REASSIGN OWNED для переназначения другой роли владения всеми объектами, принадлежащими удаляемой роли. Поскольку REASSIGN OWNED не может обращаться к объектам в других базах данных, необходимо запускать ее в каждой базе данных, содержащей объекты, принадлежащие этой роли. (Обратите внимание, что первая такая REASSIGN OWNED изменит владельца любых совместно используемых между базами данных объектов, то есть баз данных или табличных пространств, принадлежащих удаляемой роли.)

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

Команда DROP OWNED также удаляет все права, предоставленные целевой роли для объектов, которые ей не принадлежат. Поскольку REASSIGN OWNED не затрагивает такие объекты, как правило, для полного удаления зависимостей удаляемой роли нужно выполнить и REASSIGN OWNED, и DROP OWNED (именно в таком порядке!).

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

REASSIGN OWNED BY doomed_role TO successor_role;
DROP OWNED BY doomed_role;
-- повторить вышеуказанные команды в каждой базе данных кластера
DROP ROLE doomed_role;

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

Если попытка выполнить DROP ROLE происходит, пока у роли еще остались зависимые объекты, эта команда выдаст сообщения, указывающие, какие объекты необходимо переназначить или удалить.


Предопределенные роли

QHB предоставляет набор предопределенных ролей, которые обеспечивают доступ к определенным, обычно востребованным, конфиденциальным возможностям и информации. Администраторы (в том числе роли, имеющие право CREATEROLE) могут назначать (командой GRANT) эти роли пользователям и/или другим ролям в их среде, предоставляя этим пользователям доступ к указанным возможностям и информации.

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

Таблица 1. Предопределенные роли

РольРазрешенный доступ
pg_read_all_dataЧитать все данные (таблицы, представления, последовательности), как будто роль имеет права SELECT для этих объектов и права USAGE для всех схем, даже если эти права не назначены ей явно. У этой роли не установлен атрибут BYPASSRLS. Если используется технология RLS, администратору может понадобиться задать BYPASSRLS ролям, которым назначена эта роль.
pg_write_all_dataЗаписывать все данные (таблицы, представления, последовательности), как будто роль имеет права INSERT, UPDATE и DELETE для этих объектов и права USAGE для всех схем, даже если эти права не назначены ей явно. У этой роли не установлен атрибут BYPASSRLS. Если используется технология RLS, администратору может понадобиться задать BYPASSRLS ролям, которым назначена эта роль.
pg_read_all_settingsЧитать все переменные конфигурации, даже те, которые обычно видны только суперпользователям.
pg_read_all_statsЧитать все представления pg_stat_* и использовать различные расширения, связанные со статистикой, даже те, которые обычно видны только суперпользователям.
pg_stat_scan_tablesВыполнять функции мониторинга, которые могут устанавливать блокировки ACCESS SHARE в таблицах, возможно, на долгое время.
pg_monitorЧитать/выполнять различные представления и функции для мониторинга. Эта роль является членом ролей pg_read_all_settings, pg_read_all_stats и pg_stat_scan_tables.
pg_database_ownerНикакого. Членство неявно включает в себя текущего владельца базы данных.
pg_signal_backendПодавать другому обслуживающему процессу сигнал, чтобы отменить запрос или завершить сеанс.
pg_read_server_filesРазрешить чтение файлов из любого места, к которому база данных может получить доступ на сервере с помощью команды COPY и других функций обращения к файлам.
pg_write_server_filesРазрешить запись в файлы в любом месте, к которому база данных может получить доступ на сервере с помощью команды COPY и других функций обращения к файлам.
pg_execute_server_programРазрешить выполнение программ на сервере баз данных от имени пользователя, запускающего базу данных, так же, как это делает команда COPY и другие функции, позволяющие выполнять программу на стороне сервера.

Роли pg_monitor, pg_read_all_settings, pg_read_all_stats и pg_stat_scan_tables предназначены для того, чтобы администраторы могли легко сконфигурировать роль для мониторинга сервера баз данных. Они предоставляют набор общих прав, позволяющих такой роли читать различные полезные параметры конфигурации, статистику и другую системную информацию, обычно доступную только суперпользователям.

У роли pg_database_owner имеется только один неявный, определяемый сложившейся ситуацией член, а именно — владелец текущей базы данных. Изначально эта роль не предоставляет никаких прав. Как и любая роль, она может владеть объектами или получать права доступа. Следовательно, как только pg_database_owner приобретет права в базе-шаблоне, каждый владелец базы данных, созданной из этого шаблона, получит эти права. Роль pg_database_owner не может быть членом какой-либо роли и не может явно включать членов.

Роль pg_signal_backend предназначена для того, чтобы администраторы могли давать доверенным, но не суперпользовательским ролям право отправлять сигналы другим обслуживающим процессам. В настоящее время эта роль позволяет отправлять сигналы для отмены запроса на другом сервере или завершения его сеанса. Однако пользователь, которому предоставлена эта роль, не может отправлять сигналы процессу, принадлежащему суперпользователю. См. подраздел Функции для передачи сигналов серверу.

Роли pg_read_server_files, pg_write_server_files и pg_execute_server_program предназначены для того, чтобы администраторы могли иметь доверенные, но не суперпользовательские роли, которые могут обращаться к файлам и запускать программы на сервере баз данных от имени пользователя, запускающего базу данных. Поскольку эти роли могут обращаться к любому файлу в файловой системе сервера, то при прямом обращении они обходят все проверки разрешений на уровне базы данных и могут использоваться для получения доступа на уровне суперпользователя, поэтому при назначении этих ролей пользователям следует соблюдать особую осторожность.

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

Администраторы могут предоставить пользователям доступ к этим ролям с помощью команды GRANT, например:

GRANT pg_signal_backend TO admin_user;

Безопасность функций

Функции, триггеры и политики защиты на уровне строк позволяют пользователям добавлять во внутренний сервер код, который могут непреднамеренно выполнить другие пользователи. Следовательно, эти механизмы позволяют пользователям относительно легко запускать другим «троянских коней». Самая сильная защита — жесткий контроль над тем, кто может определять объекты. Там, где это невозможно, пишите запросы, относящиеся только к объектам, имеющим доверенных владельцев. Удалите из search_path общедоступную схему и любые другие схемы, которые позволяют не доверенным пользователям создавать объекты.

Функции выполняются внутри процесса внутреннего сервера с разрешениями операционной системы служебного процесса сервера баз данных. Если язык программирования, используемый для функции, допускает неконтролируемый доступ к памяти, появляется возможность изменить внутренние структуры данных сервера. Следовательно, среди прочего, такие функции могут обойти любые системы контроля доступа. Языки функций, разрешающих такой доступ, считаются «ненадежными», а QHB позволяет создавать функции, написанные на этих языках, только суперпользователям.