Перейти к основному содержимому

Лекция 11. Авторизация и аутентификация

В этой главе:

  • Роли
  • Свойства ролей
  • Атрибуты
  • Владельцы объектов
  • Привилегии
  • Членство в групповых ролях
  • Права на функции и процедуры
  • Ограничение доступа

Роли

postgres=# CREATE ROLE grp_students NOLOGIN;
CREATE ROLE
postgres=# CREATE ROLE student LOGIN PASSWORD 'student' IN ROLE grp_students; CREATE ROLE
postgres=# \du
Список ролей
Имя роли | Атрибуты | Член ролей
--------------+-------------------------------------------------------------------------+----------------
grp_students | Cannot login | {}
postgres | Superuser, Create role, Create DB, Replication, Bypass RLS student | {}
student | | {grp_students}

В PostgreSQL любой сеанс является подключением зарегистрированной в СУБД роли к конкретной базе данных. В ранних версиях PostgreSQL были понятия пользователя и группы, как в Unix-подобных ОС. Однако сейчас имеются лишь роли, которые могут представлять конкретного пользователя базы данных или абстрактного владельца объектов, а в случае, если в роль входят несколько членов, то и целую группу. Роль - глобальный объект кластера баз данных.

При создании кластера, которое выполняется средствами команды initdb от имени некоторого пользователя ОС (обычно postgres), создается исходный суперпользователь. Он обладает полными правами на все объекты кластера баз данных и может выполнять любые действия в СУБД.

В примере на слайде зарегистрирована групповая роль grp_students, которая не имеет права входа в сеанс. Также зарегистрирована обычная роль для пользователя student, который таким правом обладает, а также ему установлен пароль.

Для получения списка ролей удобно использовать метакоманду \du psql. Членство в группе отражено в отдельном столбце. В PostgreSQL 16 это не так, там система ролей претерпела значительные изменения.

Список зарегистрированных ролей выводит \du.


List of roles
Role name | Attributes | Member of
--------------+------------------------------------------------------------+----------------
grp_students | Cannot login | {}
postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {}
student | | {grp_students}

Атрибуты выводятся в отдельном столбце. Атрибут LOGIN не выводится, а NOLOGIN, наоборот, выводится. Членство в групповых ролях в 15й версии и более ранних видно в выводе \du.

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

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

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

https://www.postgresql.org/docs/15/database-roles.html.

Атрибуты

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

  • SUPERUSER | NOSUPERUSER - суперпользователь или нет
  • CREATEDB | NOCREATEDB - может создавать БД или нет
  • LOGIN | NOLOGIN - может или нет входить в сеанс
  • BYPASSRLS | NOBYPASSRLS - игнорирует RLS или нет
  • CONNECTION LIMIT - ограничение количества сессий
  • PASSWORD - пароль
  • VALID UNTIL - срок действия

После создания кластера баз данных имеется исходный суперпользователь (bootstrap superuser) и больше ролей нет. Зарегистрировать роль можно командой CREATE ROLE. https://www.postgresql.org/docs/15/sql-createrole.html.

При регистрации роли или уже потом командой ALTER ROLE можно установить атрибуты, указанные на слайде. Например, атрибут SUPERUSER позволяет роли иметь все возможности суперпользователя, но исходным суперпользователем он не будет. Отличие исходного суперпользователя в том, что у него невозможно отобрать права, так как он необходим в системе.

Атрибут BYPASSRLS позволяет игнорировать фильтрующие политики RLS (Row Level Security), предназначенные для скрытой фильтрации строк в таблицах, выполняющейся по заданным правилам. Пароль и ограничение на количество открытых от имени этой роли сеансов также являются атрибутами ролей. После момента времени, указанного атрибутом VALID UNTIL пароль роли не считается более действительным. https://www.postgresql.org/docs/15/role-attributes.html.

Атрибут CONNECTION LIMIT в PostgreSQL ограничивает количество разрешенных подключений для данной роли. В Pangolin реализована возможность резервирования количества доступных подключений для ролей, что гарантирует пользователю наличие свободных подключений. Настроить резервирование соединения можно для конфигурации standalone, изменяя параметры в файле pg_quota.conf. После редактирования этого файла требуется выполнить перезагрузку СУБД.

Запрет входа в сеанс

postgres=# \c - grp_students
connection to server on socket "/tmp/.s.PGSQL.5432" failed: FATAL:
role "grp_students" is not permitted to log in Previous connection kept
  • Атрибут NOLOGIN роли grp_students не позволяет зайти в сеанс непосредственно от имени этой роли.
  • Групповые роли НЕ обязаны иметь запрет на вход в сеанс.
  • Обычное применение групповых ролей состоит в назначении им атрибутов и привилегий, наследуемых их членами.

Главное предназначение групповых ролей в упрощении администрирования прав, имеющихся у обычных ролей. Так, привилегии проще назначать конкретным ролям, которым эти права потребовались. Если этих ролей тысячи, то управлять этим коллективом крайне затруднительно. Гораздо проще классифицировать все роли по разновидностям выполняемых ими действиям, сгруппировать роли в категорийные групповые роли. Достаточно назначить необходимые привилегии групповым ролям, а все члены роли МОГУТ эти права наследовать. Действительно ли произойдет наследование привилегии зависит от атрибута INHERIT/NOINHERIT.

https://www.postgresql.org/docs/15/role-attributes.html. Если члену групповой роли требуется воспользоваться атрибутом, то ему придется воспользоваться командой SET ROLE.

Проверка атрибутов

postgres=# ALTER ROLE grp_students CREATEDB; ALTER ROLE
postgres=# \du *student*
Role name | Attributes | Member of
--------------+---------------------------+----------------
grp_students | Create DB, Cannot login | {}
student | | {grp_students}
postgres=# \c - student
You are now connected to database "postgres" as user "student". postgres=> CREATE DATABASE my_db;
ERROR: permission denied to create database
  • Групповой роли grp_students установлен атрибут, позволяющий создавать базы данных.
  • Не смотря на вхождение в группу, student не унаследовал атрибут.

Роли легко назначить или изъять у нее какой-либо атрибут командой ALTER ROLE. https://www.postgresql.org/docs/15/sql-alterrole.html.

Если эта роль групповая, то хотелось бы для ролей - членов группы иметь возможность воспользоваться возможностями, которые предоставляет атрибут. Например, команда на слайде устанавливает атрибут CREATEDB групповой роли grp_students. Членом этой роли является student, но при входе в его сеанс выясняется, что он этим атрибутом (а он имеется у его групповой роли) воспользоваться не может. Дело в том, что атрибуты НЕ наследуются и для того, чтобы ими воспользоваться, необходимо стать ролью, в которую входит роль - член групповой роли. Делается это с помощью команды SET ROLE. https://www.postgresql.org/docs/15/sql-set-role.html.

Команда SET ROLE

postgres=> \c - student
You are now connected to database "postgres" as user "student".
postgres=> SET ROLE grp_students;
SET
postgres=> SELECT current_user;
current_user
--------------
grp_students
(1 строка)
postgres=> SELECT session_user;
session_user
--------------
student
(1 строка)
postgres=> CREATE DATABASE my_db;
CREATE DATABASE
postgres=> \l *db
Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access privil
-------+--------------+-----------+------------+------------+------------+-----------------+---------------
my_db | grp_students | UTF8 | en_US.UTF8 | en_US.UTF8 | | libc |
(1 row)

При выполнении команды SET ROLE <целевая_роль> пользователь в сеансе получает права целевой роли, если он в нее входит. Проверить эффективные права, какой роли имеются сейчас в сеансе, можно функцией current_user. Но если исходно сеанс был открыт другой ролью, то это никак не повлияет на выводимую функцией session_user информацию. Она всегда выводит имя роли, открывшей сеанс. Вернуться к исходной роли можно командой RESET ROLE.

postgres=> RESET ROLE;
RESET
postgres=> SELECT session_user, current_user;
session_user | current_user
--------------+--------------
student | student
(1 строка)

https://www.postgresql.org/docs/15/functions-info.html.

Владельцы объектов

Владелец объекта

postgres=# \c - student
You are now connected to database "postgres" as user "student". postgres=> \l my*
Список баз данных
Имя | Владелец | Кодировка | LC_COLLATE | LC_CTYPE | локаль ICU | Провайдер локали | Права доступа
-------+--------------+-----------+------------+------------+----------+------------------+---------------
my_db | grp_students | UTF8 | en_US.UTF8 | en_US.UTF8 | | libc |
(1 row)
postgres=> \c my_db
You are now connected to database "my_db" as user "student".

Любой объект в базе данных, включая саму базу данных, имеет владельца. Владелец - особый пользователь: он обладает полными правами на объект. Включая его удаление. Поменять владельца объекта может одной из команд ALTER владелец объекта, либо суперпользователь. В примере на слайде с помощью метакоманды \l получены сведения о базе данных my_db. Заметно, что владельцем ее является роль grp_students. Напомним, что эта БД была создана в сеансе, который был исходно запущен для роли student, но далее в этом сеансе была выполнена команда SET ROLE grp_students. Напрямую роль grp_students в сеанс зайти не может в силу наличия атрибута NOLOGIN, но после SET ROLE эффективным владельцем сеанса стала роль grp_students. Эта роль и стала владельцем БД my_db.

Смена владельца

my_db=> CREATE TABLE studentab(id int, str text); 
CREATE TABLE
my_db=> \d
List of relations
Schema | Name | Type | Owner
--------+-----------+---------+---------- public | studentab | таблица | student
(1 row)
my_db=> ALTER TABLE studentab OWNER TO grp_students;
ALTER TABLE
my_db=> \d
List of relations
Schema | Name | Type | Owner
--------+-----------+---------+--------------
public | studentab | таблица | grp_students
(1 row)
  • В сеансе student создана таблица studentab, владелец - student.
  • Владелец может передать объект другой роли, членом которой он является.
  • Все роли, входящие в групповую роль, являются владельцами объектов, принадлежащих этой групповой роли.

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

my_db=> ALTER TABLE studentab OWNER TO student;
ALTER TABLE
my_db=> \d
List of relations
Schema | Name | Type | Owner
--------+-----------+---------+----------
public | studentab | таблица | student
(1 строка)
my_db=> ALTER TABLE studentab OWNER TO grp_students;
ALTER TABLE
my_db=> \d
List of relations
Schema | Name | Type | Owner
--------+-----------+---------+--------------
public | studentab | таблица | grp_students
(1 строка)
my_db=> ALTER TABLE studentab OWNER TO postgres;
ERROR: must be member of role "postgres"

В PostgreSQL 16 это поведение изменено в сторону ужесточения требований.

Привилегии

Назначение привилегий

postgres=# CREATE USER aspirant;
CREATE ROLE
postgres=# \c my_db student
You are now connected to database "my_db" as user "student". my_db=> GRANT SELECT ON studentab TO aspirant ;
GRANT
my_db=> \c - aspirant
You are now connected to database "my_db" as user "aspirant".
my_db=> SELECT * FROM studentab ;
id | str
----+-----
(0 rows)
  • Роли требуются привилегии для выполнения действий с объектами.
  • Привилегии доступа устанавливаются в метаданных объектов.
  • При выполнении команды GRANT привилегия на объект или группу объектов устанавливается для конкретной роли, отзыв - команда REVOKE.
  • Кроме суперпользователя назначить привилегии может лишь владелец.

Для получения доступа к объекту роли, не обладающей атрибутом суперпользователя и не являющейся владельцем объекта, необходимы привилегии. Привилегии устанавливаются на объекты в их метаданных и запоминаются в форме ACL (Access Control List) следующим образом: grantee=privilege-abbreviation[*].../grantor, где grantee - роль, которой были назначены привилегии, а grantor - роль, предоставившая эту привилегию. Привилегии отображаются в виде буквенных аббревиатур, которые будут показаны далее. Назначить привилегию на объект или несколько объектов можно командой GRANT, в которой после ключевого слова TO указывается роль, которой привилегия предоставлена. После аббревиатуры может присутствовать символ звездочки *, который означает возможность передачи привилегии, о которой будет рассказано далее. В примере на слайде зарегистрирован новый пользователь, которому владелец таблицы предоставил право чтения, то есть, возможность выполнять SELECT для всех колонок таблицы.

https://www.postgresql.org/docs/15/ddl-priv.html.

https://www.postgresql.org/docs/15/sql-grant.html.

https://www.postgresql.org/docs/15/sql-revoke.html.

Привилегий для таблиц и представлений

  • SELECT - чтение таблицы, представления, столбца (r - read);
  • INSERT - вставка в таблицу или представление (a -append);
  • UPDATE - изменение значений столбцов таблиц или представлений (w - write);
  • DELETE - удаление строк в таблицах или представлениях (d - delete);
  • TRUNCATE - опустошение таблицы (D);
  • REFERENCES - создание ссылки на столбец внешним ключом (x);
  • TRIGGER - создание триггера для таблицы или представления (t).

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

my_db=> GRANT SELECT(n),INSERT(n,t) ON ptab TO aspirant; GRANT
my_db=> \dp ptab
Access privileges
Schema | Name | Type |Access privileges| Column privileges | Policies
--------+------+---------+-----------------+-----------------------+----------
public | ptab | таблица | | n: +|
| | | | aspirant=ar/student+|
| | | | t: +|
| | | | aspirant=a/student |
(1 строка)

Просмотр привилегий на доступ к таблице

my_db=> \dp studentab
Access privileges
Schema | Name | Type | Access privileges | Column privileges | Policies
--------+-----------+---------+-----------------------------------+--------------------+----------
public | studentab | таблица | grp_students=arwdDxt/grp_students+| |
| | | aspirant=r/grp_students | |
(1 row)

Получить установленные привилегий на таблицу можно метакомандой \dp psql. Привилегии по умолчанию для владельца - все права на объект не отображаются до тех пор пока ACL не будет изменен любым способом.

Получить информацию о привилегиях, установленных на таблицу или подобный таблице объект, можно метакомандой psql \dp. Причем, если на объект установлены привилегии по умолчанию - полные права для владельца, то в они просто не отображаются. Например:

my_db=> CREATE TABLE def_privs(n int);
CREATE TABLE
my_db=> \dp def_privs
Access privileges
Schema | Name | Type |Access privileges|Column privileges|Policies
--------+-----------+---------+-----------------+-----------------+----------
public | def_privs | таблица | | |
(1 строка)

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

  • CREATE (C):

    • создание новых схем;
    • создание публикаций;
    • разрешение подключать расширения;
  • CONNECT (c) - разрешает подключение к базе данных;

  • TEMPORARY (T) - создание временных объектов в базе данных.

Привилегии, устанавливаемые по умолчанию на базы данных - Tc, то есть возможность подключаться и создавать временные объекты. Подключение к базе данных требует наличия не только наличия соответствующей привилегии, но и разрешения на подключение в файле pg_hba.conf, о котором будет рассказано далее. Если у роли имеется привилегия на создание объектов в базе данных, то эта роль может создать, например, схему. У обычных ролей, не владельцев базы, есть права на подключение и создание временных объектов. Однако эту привилегию, конечно, можно назначить индивидуально. https://www.postgresql.org/docs/15/ddl-priv.html.

Привилегий для схем

my_db=> CREATE SCHEMA my_schema;
CREATE SCHEMA
my_db=> GRANT USAGE ON SCHEMA my_schema TO aspirant; GRANT
my_db=> \dn+ my_schema
List of schemas
Name | Owner | Access privileges | Description
-----------+----------+--------------------+----------
my_schema | student | student=UC/student+|
| | aspirant=U/student |
(1 row)

В примере на слайде в сеансе student создана схема my_schema. Так как student входит в групповую роль grp_students, владеющей базой, он также является владельцем. Соответственно, право на создание объектов имеется. Для схем существуют лишь две привилегии: Usage (U) и Create (C). После того, как привилегия U была предоставлена роли aspirant, в выводе метакоманды \dn+, информирующей о схемах, появилась соответствующая запись: aspirant=U/student То есть, роли aspirant предоставлена привилегия U, а предоставил ее student.

Привилегии на установку параметров

my_db=# \dconfig+ commit_delay
List of configuration parameters
Parameter | Value | Type | Context |Access privileges
--------------+----------+---------+-----------+--------------------
commit_delay | 0 | integer | superuser |
my_db=# GRANT SET ON PARAMETER commit_delay TO student ; my_db=# \dconfig+ commit_delay
List of configuration parameters
Parameter | Value | Type | Context |Access privileges
--------------+----------+---------+-----------+----------------------
commit_delay | 0 | integer | superuser | postgres=sA/postgres+
| | | | student=s/postgres
  • SET (s) - право на установку параметра в текущей сессии;
  • ALTER SYSTEM (A) - право на установку параметра сервера.

Суперпользователь может предоставить право изменять конкретные сессионные параметры с контекстом, не позволяющим менять их обычным ролям. Это позволяет делать привилегия SET с аббревиатурой s. Более того, можно даже предоставить привилегию на изменение параметров на уровне экземпляра командой ALTER SYSTEM - привилегия с аббревиатурой (A). В примере установлено разрешение для роли student влиять на значение параметра commit_delay, позволяющего дожидаться в течении разрешенного времени фиксации сразу нескольких активных транзакций для снижения нагрузки на журнал предзаписи. Этот параметр имеет контекст superuser, что не позволяет обычным пользователям его менять. Получить подробности о параметре удобно метакомандой \dconfig+ .

Другие привилегии

  • CREATE (C) - для табличных пространств позволяет создавать в них объекты;

  • EXECUTE (X) - право выполнения функций и процедур;

  • USAGE (U):

    • использование процедурных языков;
    • для последовательность право выполнять функции currval и nextval;
    • для оберток внешних данных (FDW foreign-data wrappers) право создания нового сервера;
    • для внешних серверов позволяет создавать внешние таблицы.

Привилегии, установленные на табличные пространства, можно увидеть с помощью команды \db+. Для функций и процедур определена единственная привилегия на право исполнения EXECUTE с аббревиатурой X. Привилегии на функции и процедуры показывает метакоманда \df+. Расширения для подключения внешних источников данных (FDW - Foreign Data Wrapper) будут обсуждаться в главе 14. Привилегии на последовательности SEQUENCE:

  • SELECT(r)-правовызыватьфункцияcurrvalдляполученияранее сгенерированного значения;
  • UPDATE(w)-правонавыполнениефункцийnextvalдляполучения нового значения последовательности и setval для установки начального значения последовательности;
  • USAGE (U) - право выполнять функции currval и nextval.

Право передачи

my_db=# CREATE TABLE suptab (s date);
CREATE TABLE
my_db=# GRANT SELECT ON suptab TO student WITH GRANT OPTION;
GRANT
my_db=# \c - student
You are now connected to database "my_db" as user "student". my_db=> \dp suptab
Schema | Name | Type | Access privileges | Column privileges | Policies
--------+--------+---------+---------------------------+--------------------+----------
public | suptab | table | postgres=arwdDxt/postgres+| |
| | | student=r*/postgres | |

my_db=> GRANT SELECT ON suptab TO aspirant;
GRANT
my_db=> \dp suptab
Schema | Name | Type | Access privileges | Column privileges | Policies
--------+--------+---------+---------------------------+--------------------+----------
public | suptab | table | postgres=arwdDxt/postgres+| |
| | | student=r*/postgres + | |
| | | aspirant=r/student | |

Команда GRANT предоставляет опцию GRANT OPTION, которая позволяет роли-получателю передавать полученные полномочия другим ролям. В примере суперпользователь создал таблицу и предоставил на нее право чтения роли student с правом передачи, а student предоставил привилегию чтения роли aspirant. Команда REVOKE позволяет изъять право передачи. Отнимать права командой REVOKE необходимо в том порядке, в котором осуществлялась передача прав.

my_db=# REVOKE SELECT ON suptab FROM aspirant ;
REVOKE
my_db=# \dp suptab
Access privileges
Schema | Name | Type | Access privileges | Column privileges |
--------+--------+---------+---------------------------+--------------------+-
public | suptab | таблица | postgres=arwdDxt/postgres+| |
| | | student=r*/postgres +| |
| | | aspirant=r/student | |
(1 строка)

Право чтения не изъято, так как postgres не выдавал его aspirant.

my_db=# REVOKE GRANT OPTION FOR SELECT ON suptab FROM student CASCADE;
REVOKE
my_db=# \dp suptab
Access privileges
Schema | Name | Type | Access privileges | Column privileges |
--------+--------+---------+---------------------------+--------------------+-
public | suptab | таблица | postgres=arwdDxt/postgres+| |
| | | student=r/postgres | |

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

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

my_db=> \c - student
You are now connected to database "my_db" as user "student".
my_db=> CREATE SCHEMA def_sch;
CREATE SCHEMA
my_db=> ALTER DEFAULT PRIVILEGES IN SCHEMA def_sch GRANT SELECT ON TABLES TO aspirant ;
ALTER DEFAULT PRIVILEGES
my_db=> \ddp
Default access privileges
Owner | Schema | Type | Access privileges
----------+---------+-------+--------------------
student | def_sch | table | aspirant=r/student
(1 rows)
  • Привилегии по умолчанию будут использоваться при создании новых объектов.
  • Привилегии по умолчанию устанавливает команда ALTER DEFAULT PRIVILEGES.

PostgreSQL позволяет заранее задать права для объектов, которые еще не существуют. При создании этих объектов на них будут автоматически установлены именно эти права. В примере создана схема def_sch, она принадлежит роли, создавшей ее - student. Объекты, которые student будет создавать в этой схеме (или иной пользователь, имеющий на это право), будут автоматически получать ACL с установленными привилегиями для пользователя aspirant с правами на чтение.

my_db=> CREATE TABLE def_sch.new_tab();
CREATE TABLE
my_db=> \dp def_sch.new_tab
Access privileges
Schema | Name | Type | Access privileges | Column privileges |
---------+---------+---------+-------------------------+--------------------+-
def_sch | new_tab | таблица | student=arwdDxt/student+| |
| | | aspirant=r/student | |
(1 строка)

Проверить привилегии, установленные по умолчанию, можно метакомандой \ddp. https://www.postgresql.org/docs/15/sql-alterdefaultprivileges.html.

Членство в групповых ролях

Предоставление членства в группе

my_db=# CREATE USER abiturient NOINHERIT; CREATE ROLE
my_db=# GRANT grp_students TO abiturient ; GRANT ROLE
my_db=# \du *ent*
List of roles
Role name | Attributes | Member of
--------------+-------------------------------+----------------
abiturient | No inheritance | {grp_students}
grp_students | Create DB, Cannot login | {}
student | | {grp_students}
  • Команда GRANT <группа> TO <роль> предоставляет членство роли в группе.
  • Удаление роли из группы: REVOKE <группа> FROM <роль>.

Членством ролей в других ролях также управляют команды GRANT и REVOKE. Отдельного понятия для роли, включающей в себя другие роли, в PostgreSQL нет, но для простоты будем называть такие роли групповыми или же просто группами. Напомним, что если роль владеет какими-либо объектами, то все роли, входящие в групповую роль, также являются владельцами этих объектов на равноправных условиях. Вплоть до 15-й версии PostgreSQL членство роли в группах отображала метакоманда \du (с 16-й версии это не так). В примере на слайде создана новая роль abiturient (можно было бы использовать CREATE ROLE ... LOGIN, что эквивалентно CREATE USER). Обратите внимание на атрибут NOINHERIT, который запрещает наследование привилегий от групповой роли. По умолчанию для вновь регистрируемых ролей включен атрибут INHERIT, предоставляющий роли те же привилегии, что и групповая роль. Роли без наследования с атрибутом NOINHERIT могут использовать SET ROLE, как это было продемонстрировано ранее в примере с созданием базы данных my_db. Подробнее о наследовании привилегий далее. https://www.postgresql.org/docs/15/role-attributes.html. Далее в примере командой GRANT роль abiturient предоставлено участие в группе grp_students. Это можно также было сделать самой командой CREATE ROLE. https://www.postgresql.org/docs/15/sql-grant.html.

https://www.postgresql.org/docs/15/sql-createrole.html.

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

my_db=# GRANT INSERT ON suptab TO grp_students ;
GRANT
my_db=# \c - student
You are now connected to database "my_db" as user "student".
my_db=> \dp suptab
Access privileges
Schema | Name | Type | Access privileges | Column privileges | Policies
--------+--------+---------+---------------------------+--------------------+----------
public | suptab | table | postgres=arwdDxt/postgres+| |
| | | student=r/postgres +| |
| | | grp_students=a/postgres | |
(1 row)
my_db=> INSERT INTO suptab VALUES (now());
INSERT 0 1
my_db=> SELECT * FROM suptab ;
s
------------
2024-10-26
(1 row)

Роль student обладает атрибутом INHERIT. Поэтоу автоматически наследуются привилегии, предоставленные групповой роли grp_students. Она, в свою очередь, имеет привилегию выполнять вставку (аббревиатура a - append) командой INSERT в таблицу suptab. Без каких-либо дополнительных действий вставка была выполнена успешно. Также роль student обладает привилегией выполнять SELECT.

Без наследования привилегий

my_db=> \c - abiturient
You are now connected to database "my_db" as user "abiturient".
my_db=> INSERT INTO suptab VALUES (now());
ERROR: permission denied for table suptab
my_db=> SET ROLE grp_students;
SET
my_db=> INSERT INTO suptab VALUES (now());
INSERT 0 1
my_db=> SELECT session_user, current_user;
session_user | current_user
-------------+--------------
abiturient | grp_students
(1 row)
  • Атрибут NOINHERIT роли abiturient запрещает наследование привилегий групповой роли grp_student.
  • Можно лишь выполнить команду SET ROLE для смены текущего пользователя в сессии.

Установленный на роль abiturient атрибут NOINHERIT исключает автоматическое наследование привилегий, поэтому первая попытка выполнить вставку не удалась с сообщением об отсутствии разрешения на это действие. Лишь после выполнения SET ROLE, когда текущим пользователем в сессии (что подтверждает результат функции current_user) стал grp_students, операция вставки прошла успешно. https://www.postgresql.org/docs/15/role-membership.html.

Отметим, что с 16-й версии PostgreSQL возможность выполнения команды SET ROLE членом групповой роли контролируется более жестко. Атрибуты INHERIT и NOINHERIT в PostgreSQL используются для реализации ролевых моделей, предназначенных для реализации принципа наименьших привилегий, исключающего появление у роли излишнего доступа к объектам в связи с наследованием. В Pangolin имеется собственная ролевая модель, скрипты для реализации которой имеются в составе дистрибутива. При наличии установленной документации Pangolin, в ней можно получить подробности о ролевой модели: [file:///home/student/Distrib/documentation/PSQ/6.2.0/html/documents/admin istration-guide/role-model.html](file:///home/student/Distrib/documentation/PSQ/6.2.0/html/documents/admin istration-guide/role-model.html).

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

  • pg_read_all_data/pg_write_all_data - чтение/изменение любых данных.
  • pg_read_all_settings - чтение любых параметров настройки.
  • pg_read_all_stats - чтение любых представлений pg_stat_* .
  • pg_stat_scan_tables - возможность выполнения длительной блокировки функциями мониторинга.
  • pg_monitor - чтение представлений и выполнение функций мониторинга.
  • pg_database_owner - роль владельца базы данных.
  • pg_signal_backend - передача сигналов серверам экземпляра.
  • pg_read_server_files/pg_write_server_files - чтение/запись файлов на стороне сервера.
  • pg_execute_server_program - выполнение программного кода на стороне сервера.
  • pg_checkpoint - право выполнять контрольную точку.

PostgreSQL предоставляет несколько предопределенных ролей, предоставляющих доступ к возможностям, доступным обычно для суперпользователя. Они необходимы для ограничения круга задач, требующих применять привилегии суперпользователя. Предоставлять доступ к этим ролям могут (помимо суперпользователя) административные роли с атрибутом CREATEROLE. Предопределенная роль монитор включает возможности ролей pg_read_all_settings, pg_read_all_stats и pg_stat_scan_tables. Предопределенная роль pg_database_owner относится к владельцу текущей базы данных и может владеть объектами, а также этой роли можно предоставлять привилегии с помощью GRANT. Однако есть и ограничения для этой роли: она не может входить в любую другую роль и не может включать в себя другие роли. Исходно эта роль владеет особой схемой PUBLIC, о которой рассказано далее. https://www.postgresql.org/docs/15/predefined-roles.html.

В Pangolin могут быть созданы роли, если они созданы утилитой initprotection:

  • sec_admin - администратор безопасности;
  • sec_admin_role - групповая роль администраторов безопасности.

[file:///home/student/Distrib/documentation/PSQ/6.2.0/html/documents/admin istration-guide/administration-scenarios.html](file:///home/student/Distrib/documentation/PSQ/6.2.0/html/documents/admin istration-guide/administration-scenarios.html).

Псевдороль public и схема public

dontduitdb=# \dn+
Name | Owner | Access privileges | Description
--------+-------------------+-----------------------------------------+------------------------
public | pg_database_owner | pg_database_owner=UC/pg_database_owner+ | standard public schema
| | =U/pg_database_owner |
dontduitdb=# GRANT CREATE ON SCHEMA public TO public;
GRANT
dontduitdb=# \dn+
Name | Owner | Access privileges | Description
--------+-------------------+----------------------------------------+------------------------
public | pg_database_owner | pg_database_owner=UC/pg_database_owner | standard public schema
| | |
  • Псевдороль public неявно включает в себя все роли.
  • В каждой базе данных есть схема public для общего размещения объектов.
  • В ранних версиях PostgreSQL права на создание объектов (C) в схеме public были у псевдороли public, сейчас только право использовать объекты (U).

Псевдороль public неявным образом включает в себя все остальные роли. Зарегистрированной роли public не существует, но ей можно назначать и отзывать привилегии командами GRANT и REVOKE. Это надо делать с известной долей осторожности. Вплоть до 14-й версии PostgreSQL схема public принадлежала псевдороли public, что давало возможность ЛЮБОМУ пользователю создавать объекты в этой схеме. Исходя из требований безопасности предлагалось удалять привилегию создания объектов: REVOKE CREATE ON SCHEMA public FROM PUBLIC; Начиная с 15-й версии PostgreSQL схема public принадлежит роли pg_database_owner. Но в унаследованных с более ранних версий PostgreSQL базах данных права на схему public до сих пор могут принадлежать псевдороли public, что нельзя признать безопасным. В примере на слайде демонстрируется вновь созданная база данных, в которой на схему public установлен владелец pg_database_owner, а для псевдороли public исходно имеются лишь права на использование объектов (U - usage). Командой GRANT псевдороли public предоставлено право создавать объекты в схеме public исключительно в целях демонстрации. https://www.postgresql.org/docs/15/ddl-schemas.html#DDL-SCHEMAS-PUBLIC.

Одной из особенностей ролевой модели в Pangolin является отключение роли public.

Права на функции и процедуры

Пример функции

my_db=> \c - student
You are now connected to database "my_db" as user "student".
my_db=> CREATE FUNCTION suptab_1st() RETURNS date AS $$
SELECT s FROM suptab LIMIT 1;
$$ LANGUAGE sql;
CREATE FUNCTION
my_db=> SELECT suptab_1st();
suptab_1st
------------
2024-10-26
(1 row)

Для создания функции применяется команда CREATE FUNCTION. Тело функции определено строкой, заключенной между символами $$. Функция в примере возвращает значение поля s в первой строке таблицы suptab. https://www.postgresql.org/docs/15/sql-createfunction.html.

Привилегии для процедур и функций

my_db=> \c - student
You are You are now connected to database "my_db" as user "student".
my_db=> CREATE FUNCTION my_date() RETURNS date AS $$
my_db$> SELECT now()::date;
my_db$> $$ LANGUAGE sql;
CREATE FUNCTION
my_db=> \c - abiturient
You are You are now connected to database "my_db" as user "abiturient".
my_db$> SELECT my_date();
my_date
------------
2024-10-26
(1 row)
  • abiturient неявно входит в псевдороль public, по умолчанию для public привилегия EXECUTE.
  • По умолчанию на новые функции и процедуры псевдороль public получает привилегию EXECUTE (X), других привилегий для функций и процедур нет.

Для функций и процедур предусмотрена единственная привилегия EXECUTE. Причем при создании функции или процедуры эта привилегия устанавливается по умолчанию для псевдороли public. Следовательно, все роли могут выполнять функции или процедуры, если право EXECUTE не было отозвано. В примере в сеансе student была создана простая функция, возвращающая текущую календарную дату. Никаких манипуляций с привилегиями не выполнялось, поэтому в сеансе abiturient удалось успешно выполнить эту функцию. https://www.postgresql.org/docs/15/sql-createfunction.html.

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

my_db=> \c - student
You are now connected to database "my_db" as user "student".
my_db=> REVOKE EXECUTE ON FUNCTION suptab_1st FROM public;
REVOKE
my_db=> GRANT EXECUTE ON FUNCTION suptab_1st TO aspirant;
GRANT
my_db=> SELECT proacl FROM pg_proc WHERE proname = 'suptab_1st';
proacl
---------------------------------------- {student=X/student,aspirant=X/student}
(1 строка)
  • Привилегии, установленные на функцию или процедуру удобно узнать, используя метакоманду psql \df+
  • ACL прав на функцию или процедуру хранится в системном каталоге pg_catalog.pg_proc в поле proacl.

Пример, показанный на слайде, демонстрирует, каким образом у псевдороли public изъять привилегию на выполнение функции. Далее на эту функцию были предоставлены права на выполнение для роли abiturient. Удобно вывести права доступа к функции, используя метакоманду \df+, однако можно и просто обратиться к полю proacl системного каталога pg_catalog.pg_proc.

Свойства функций и процедур

my_db=# \x \df+ *1st \x
Expanded display is on.
List of functions
-[ RECORD 1 ]-------+----------------------------------
Schema | public
Name | suptab_1st
Result data type | date
Argument data types |
Type | func
Volatility | volatile
Parallel | unsafe
Owner | student
Security | definer
Access privileges | student=x/student +
| aspirant=x/student
Language | sql
Source code | +
| SELECT s FROM suptab LIMIT 1;+
|
Description |
Expanded display is off.

Метакоманда \df+ предоставляет подробные сведения о функции или процедуре, в частности, установленные привилегии.

Помимо этого выводится характеристика безопасности функции:

  • SECURITY INVOKER (устанавливается по умолчанию) - выполнение кода с правами вызвавшего;
  • SECURITY DEFINER - работа кода от имени владельца функции или процедуры.

Помимо установленного на функцию ACL с привилегиями ролей, метакоманда \df+ информирует о важнейшем аспекте безопасности функций и процедур - от имени какого пользователя она выполняется:

  • от именивызывающего - SECURITYINVOKER;
  • от именивладельца функции или процедуры - SECURITYDEFINER.

В первом случае (SECURITY INVOKER) при выполнении кода необходим доступ ко всем упомянутым в нем объектам с правами роли, вызвавшей функцию или процедуру. Характеристика безопасности SECURITY DEFINER позволяет выполнять код от имени роли, которой принадлежит код. И, конечно, при такой характеристике обращения ко всем объектам в этом коде будет производиться так, как будто владелец функции этот код запустил. https://www.postgresql.org/docs/15/sql-createfunction.html.

Вызов функции с правами вызывающего

my_db=> \du aspirant 
List of roles
Role name|Attributes| Member of
----------+----------+------------
aspirant | | {}
my_db=> SELECT suptab_1st();
ERROR: permission denied for table suptab
CONTEXT: SQL function "suptab_1st" statement 1
  • В сеансе aspirant, причем эта роль не входит в какие-либо группы и не имеет никаких прав на таблицу suptab.
  • В функции suptab_1st() читается первая строка таблицы suptab.
  • У aspirant есть право на запуск функции, но нет прав на объект, требуемый в коде функции.

При определении функции ролью student все требуемые права на объекты, упомянутые в теле функции, были в наличии (для student). Для того чтобы избежать проблемы нехватки привилегий при вызове функции другими пользователями можно использовать характеристику безопасности функции SECURITY DEFINER, как это будет показано далее. Но по умолчанию, при создании функции на нее устанавливается характеристика SECURITY INVOKER. И, поскольку у aspirant нет прав на таблицу, то при вызове функции, на которое он имеет право, возникает ошибка из-за отсутствия прав на таблицу. Естественно, установить характеристику безопасности SECURITY DEFINER можно было бы еще на этапе ее создания командой CREATE FUNCTION.

Вызов функции с правами владельца

my_db=> \c - student
You are now connected to database "my_db" as user "student".
my_db=> ALTER FUNCTION suptab_1st SECURITY DEFINER;
ALTER FUNCTION
my_db=> \c - aspirant
You are now connected to database "my_db" as user "aspirant".
my_db=> SELECT suptab_1st();
suptab_1st
------------
2024-10-26
(1 row)
  • В сеансе aspirant, причем эта роль не входит в какие-либо группы и не имеет никаких прав на таблицу suptab.
  • В функции suptab_1st() читается первая строка таблицы suptab.
  • У aspirant есть право на запуск функции, но нет прав на объект, требуемый в коде функции.

После того, как на функцию с помощью команды ALTER FUNCTION была установлена характеристика SECURITY DEFINER, роль aspirant смогла выполнять функцию без ошибок. https://www.postgresql.org/docs/15/sql-alterfunction.html.

Ограничение доступа

Файл pg_hba.conf

  • Задает правила, разрешающие или запрещающие подключение клиента к серверу на основе аутентификации.
  • Содержит строки правил, которые читаются сверху-вниз при проверке аутентичности клиента до того момента, когда будет найдено первое правило, которому удовлетворяет запрос клиента для соединения.
  • Если клиентский запрос на соединение не подошел ни одному правилу, соединение отклоняется.
  • Разновидности правил покрывают все возможные способы клиентских соединений.

Помимо привилегии на подключение к базе данных необходимо также пройти процедуру аутентификации, которая настраивается правилами в файле pg_hba.conf (HBA - host-based authentication).

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

В качестве комментария используется #. Длинные строки правил можно разбивать на несколько строк, ставя в конце строки знак обратной косой черты \ перед переводом строки.

Например:

  • local \
  • all \
  • all \
  • peer

https://www.postgresql.org/docs/15/auth-pg-hba-conf.html.

Структура записей в pg_hba.conf

Все строки имеют пять полей, за исключением типа подключения local, для которого четвертое поле пропускается.

  1. Тип соединения.
  2. База данных, к которой выполняется подключение.
  3. Роль, от имени которой выполняется подключение.
  4. Адрес узла или сети или их имена источника соединения.
  5. Метод аутентификации и, возможно, дополнительные опции.

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

local all all peer
host samerole +grp_students samenet scram-sha-256
host replication postgres 127.0.0.1 trust

https://www.postgresql.org/docs/15/auth-pg-hba-conf.html.

Типы соединений

Первое поле указывает тип соединения:

  • local-этосоединенияпосредствомUnix-сокетов(файлособоготипа);
  • host - соединение через любой сетевой адаптер, в том числе через закольцовывающий сетевой интерфейс (loopback), будет ли при этом использоваться SSL/TLS (в документации SSL, так и будем далее называть), зависит от настроек сервера и клиента.
  • hostssl - то же самое, что host, но обязательно с поддержкой SSL.
  • hostnossl - наоборот, без SSL.
  • hostgssenc - шифрованные соединения керберизированных клиентов по протоколу GSSAPI.
  • hostnogssenc - то же самое, но без шифрования.

https://www.postgresql.org/docs/15/auth-pg-hba-conf.html.

База данных

В этом поле указывается, к какой базе данных устанавливается клиентское соединение.

  • Имя базы данных или несколько имен через запятую.
  • @файл - имя отдельного файла со списком баз данных.
  • sameuser - база, названная по имени пользователя, который пытается установить соединение.
  • samerole - база, названная по имени группы пользователя, в которую должен входит пользователь, устанавливающий соединение.
  • replication - не является именем базы данных, это - особый тип записей для репликации.

Во втором поле правил pg_hba.conf указывают либо имя базы данных, либо replication. В последнем случае - это особый тип записей, указывающий правила аутентификации в случае, если клиент запрашивает соединение для репликации. Примером такого клиента является pg_basebackup.

Если же запись относится к обычному клиентскому подключению, то в поле может быть:

  • имя базы данных или несколько баз, имена которых разделены запятыми;
  • @файл-дополнительныйфайл,содержащийсписокбаз;
  • sameuser-базаданныхдолжнавтакомслучаеиметьтакоежеимя, как и пользователь, устанавливающий соединение;
  • samerole - база данных должна называться так, как имя группы, в которую входит пользователь, который устанавливает соединение.

Роль

Указывает, кто устанавливает соединение.

  • имя или имена через запятую;
  • +имя - группа, в которую входит пользователь;
  • @файл - файл со списком имен пользователей.

В третьем поле записей в pg_hba.conf указывают информацию о пользователе, который пытается установить соединение. В поле можно указывать:

  • имя пользователя;
  • список имен через запятую;
  • +группа - группа, членом которой должен являться пользователь, устанавливающий соединение;
  • @файл-внешнийфайлсоспискомпользователей.

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

host samerole +grp_students samenet md5

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

Источник соединения

В четвертом поле для соединений типа local стоит пропуск, так как это - соединения через файл Unix-сокет. Такие соединения могут устанавливаться только на локальном компьютере, поскольку Unix- сокет никак не связан с сетевыми адаптерами. Любые типы сетевых соединений (host и тому подобное) обязательно имеют информацию об источнике соединения, которая и служит критерием проверки, подходит ли правило в pg_hba.conf запросу на соединение. В этом поле можно указывать IPv4, IPv6 адреса хостов или сетей, а также можно указывать имена хостов и их доменную часть. В случае, если указано имя, СУБД выполняет разрешение имени (resolve), используя штатный механизм ОС. https://www.postgresql.org/docs/15/auth-pg-hba-conf.html.

  • Для типа соединения local это поле всегда пустое.
  • IPv4 адрес, пробел сетевая маска: 192.168.0.0 255.255.255.0 - IPv4 адрес сети.
  • IP адреса в форме CIDR с длиной префикса через /
    • 192.168.0.0/24 - IPv4 адрес сети;
    • 192.168.0.1.32 - IPv4 адрес хоста;
    • ::1/128 - IPv6 адрес хоста, соответствующий имени localhost.
  • имя_хоста - имя узла сети server.dbs.local
  • имя_хоста - суффикс имени хоста с доменной частью .dbs.local
  • samehost - соединение с того же адреса, что и любой из адресов интерфейсов сервера;
  • samenet - соединение из любых сетей, которым принадлежат IP адреса интерфейсов сервера.

Некоторые методы аутентификации

  • trust - разрешает соединение без проверки.
  • reject - запрещает соединение.
  • scram-sha-256 - шифрованные пароли хранятся в СУБД.
  • md5 - шифрованные пароли хранятся в СУБД.
  • password - пароли хранятся в СУБД без шифрования.
  • gss - внешняя аутентификация GSSAPI Kerberos v5.
  • peer - внешняя аутентификация в ОС.
  • cert - внешняя аутентификация SSL сертификатами.
  • pam - внешняя аутентификация в ОС библиотекой PAM.
  • radius - внешняя аутентификация в системе RADIUS.
  • ldap - внешняя аутентификация в дереве каталогов LDAP.

Методы trust и reject аутентичность не проверяют, а просто, соответственно, сразу разрешают соединение, или его запрещают. Внутренние методы аутентификации scram-sha-256, md5 и password хранят пароли в системном каталоге pg_authid. При входе в сеанс при такой аутентификации необходимо вводить пароль. Клиентская библиотека libpq может работать с файлом сохраненных паролей ~/.pgpass для автоматизации входа в сеанс (небезопасно). https://www.postgresql.org/docs/15/libpq-pgpass.html.

В Pangolin по умолчанию включены не все методы аутентификации, однако работает аутентификация по SSL сертификатам - метод cert. Дополнительные метода аутентификации, доступные для администраторов, не связанных с безопасностью (non security administrators) определяется параметром конфигурации enabled_extra_auth_methods:

postgres@student=# SHOW enabled_extra_auth_methods;
enabled_extra_auth_methods
----------------------------
scram-sha-256, peer, cert
(1 row)

По умолчанию разрешены методы scram-sha-256, ldap и radius. В примере выше видно, что добавлен peer - метод, базирующийся на имени пользователя, полученного из ОС. Это имя должно совпадать с именем зарегистрированной роли в СУБД. https://www.postgresql.org/docs/15/client-authentication.html.

Файл отображения имен pg_ident.conf

  • Применяется для внешних систем аутентификации, использующих нетипичную для PostgreSQL идентификацию пользователей.

  • В правилах pg_hba.conf, требующих отображения имени пользователя, должна быть опция map=map-name.

  • Содержит строки вида: map-name system-username database-username где:

  • map-name - имя отображения в опции map=map-name правила аутентификации;

  • system-username - имя пользователя во внешней системе аутентификации;

  • database-username - имя зарегистрированной в СУБД роли, на которую отображается внешнее имя.

При использовании внешних систем аутентификации, например, Kerberos, серверу PostgreSQL необходимо отобразить имя пользователя во внешней системе на роль. В Kerberos для идентификации пользователей используются "принципалы" вида: user1@DOMAIN.COM. Для PostgreSQL из этого важно лишь имя роли - user1, а имя области (Realm) необходимо отбросить. Для подобных манипуляций предназначен файл pg_ident.conf, позволяющий отобразить имя пользователя во внешней системе аутентификации на роль в PostgreSQL. В простейшем случае имя пользователя во внешней системе - это просто строка символов, например, user1 (system-name), которую надо отобразить на роль student. Тогда получится отображение:

mapname user1 student.

Имя mapname здесь должно соответствовать заданным опцией map=... имени отображения. Например, так:

local student student peer map=mapname

Для сложных манипуляций с отображениями используют регулярные выражения. https://www.postgresql.org/docs/15/auth-username-maps.html.

Итоги

  • Роль - пользователь СУБД или целая группа.
  • Действия, которые роль может выполнять в системе, определяются привилегиями, атрибутами и членством в других ролях.
  • Роли могут владеть объектами, владельцы имеют полные права на свои объекты.
  • Если роль не владеет данным объектом и не имеет атрибута суперпользователя, то разрешенные с этим объектом действия определяются привилегиями.
  • Аутентификация нужна для проверки, является ли пользователь тем, за кого себя выдает.
  • Настраивается аутентификация файлом pg_hba.conf.