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

07 Занятие 07: Методы аутентификации / Внешняя аутентификация

Исходная страница в нативном Markdown: Методы аутентификации / Внешняя аутентификация
Примечание

Эта страница извлечена из официального PDF в нативный Markdown. Текст слайдов, код и комментарии сохранены в порядке чтения; исходные PDF и HTML остаются эталоном макета. HTML source: dbs_07_auth_external.html Archive: DBS-handouts-16.zip Страниц PDF: 29

Page 1: Методы аутентификации / Внешняя аутентификация

Авторские права

© Postgres Professional, 2017–2026 Авторы: Егор Рогов, Павел Лузанов, Илья Баштанов, Алексей Береснев Фото: Олег Бартунов (монастырь Пху и пик Бхрикути, Непал)

Использование материалов курса

Некоммерческое использование материалов курса (презентации, демонстрации) разрешается без ограничений. Коммерческое использование возможно только с письменного разрешения компании Postgres Professional. Запрещается внесение изменений в материалы курса.

Обратная связь

Отзывы, замечания и предложения направляйте по адресу: edu@postgrespro.ru

Отказ от ответственности

Компания Postgres Professional не несет никакой ответственности за любые повреждения и убытки, включая потерю дохода, нанесенные прямым или непрямым, специальным или случайным использованием материалов курса. Компания Postgres Professional не предоставляет каких-либо гарантий на материалы курса. Материалы курса предоставляются на основе принципа «как есть» и компания Postgres Professional не обязана предоставлять сопровождение, поддержку, обновления, расширения и изменения.

Page 2: Темы

  • Внешняя аутентификация
  • Аутентификация LDAP
  • Аутентификация GSSAPI
  • Аутентификация PAM

Page 3: Внешняя аутентификация

peer [параметры]

  • проверка в операционной системе ldap [параметры]
    • проверка в службе каталогов LDAP
  • gssapi [параметры]
    • использование GSSAPI, обычно Kerberos
  • sspi [параметры]
  • проверка средствами аутентификации Windows pam [параметры]
    • проверка посредством подключаемых модулей PAM

Комментарии преподавателя

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

Метод аутентификации peer, рассмотренный в теме «Подключение и аутентификация», относится к внешним, так как запрашивает имя текущего пользователя у ядра ОС.

При использовании метода ldap PostgreSQL обращается к службе каталогов LDAP.

GSSAPI (Generic Security Service Application Program Interface) — универсальный интерфейс для служб аутентификации, соответствующий спецификации RFC 2743. На практике используется для аутентификации в UNIX/Linux средах Kerberos, где в PostgreSQL используется метод аутентификации gssapi.

В аналогичных средах Windows, реализующих подход одноразовой аутентификации (single sign-on), используется метод sspi.

Метод pam использует подключаемые модули аутентификации (Pluggable Authentication Modules) — стандартный механизм Linux, предоставляющий приложениям высокоуровневый API для аутентификации с помощью внешних модулей.

Page 4: Аутентификация LDAP

Служба каталогов

  • Простое связывание
  • Поиск + связывание

Page 5: Служба каталогов

Source slide page 5: Служба каталогов{#source-figure-005 caption=“Source slide page 5: Служба каталогов”}

Комментарии преподавателя

LDAP (Lightweight Directory Access Protocol) — протокол для доступа к службе каталогов. Каталог представляет собой иерархию записей, которые состоят из различных атрибутов и описывают какой-либо объект: учетную запись пользователя, группу пользователей, организацию, доменное имя, сетевую службу и т. п. В учетной записи может храниться пароль, обычно в виде хеш-кода в атрибуте userPassword.

Запись идентифицируется уникальным именем (DN, distinguished name), составленным из DN родительской записи и, как правило, некоторого атрибута текущей. Например, DN учетной записи Алисы на слайде — «uid=alice,ou=BioLab,dc=course,dc=local»:

  • uid — идентификатор пользователя (user ID);

  • ou — подразделение (organization unit);

  • dc — домен (domain component).

https://ru.wikipedia.org/wiki/LDAP

Page 6: Простое связывание

Source slide page 6: Простое связывание{#source-figure-006 caption=“Source slide page 6: Простое связывание”}

Комментарии преподавателя

В простом варианте СУБД связывается с сервером LDAP по уникальному имени, составленному из префикса, имени подключающейся роли и суффикса. Например, при подключении клиента под ролью alice с параметрами метода ldap

● префикс ldapprefix = «uid=»,

● суффикс ldapsuffix = «,ou=BioLab,dc=course,dc=local»

PostgreSQL пошлет запрос аутентификации (bind) к серверу LDAP, используя DN «uid=alice,ou=BioLab,dc=course,dc=local» и переданный клиентом пароль. Адрес и порт сервера LDAP задаются параметрами ldapserver и ldapport.

Если запрос выполняется успешно, аутентификация считается пройденной.

https://postgrespro.ru/docs/postgresql/16/auth-ldap

Page 7: LDAP: простое связывание

При аутентификации в LDAP роли должны быть зарегистрированы в PostgreSQL, а пароли хранятся на сервере LDAP.

student=# CREATE ROLE alice LOGIN;
CREATE ROLE
student=# CREATE ROLE bob LOGIN;
CREATE ROLE
student=# CREATE ROLE charlie LOGIN;
CREATE ROLE

Учетные записи пользователей alice и bob уже заведены в дереве LDAP, их можно посмотреть с помощью утилиты:

student$ ldapsearch \
  -x                              `# аутентификация по DN и паролю` \
  -LLL                            `# краткая информация` \
  -H ldaps://$(hostname)          `# сервер LDAP` \
  -b ou=BioLab,dc=course,dc=local `# ветвь дерева` \
  "(uid=*)"                       `# фильтр` \
  cn                              `# выводить только common name`
dn: uid=bob,ou=BioLab,dc=course,dc=local
cn: Bob
dn: uid=alice,ou=BioLab,dc=course,dc=local
cn: Alice

Для PostgreSQL мы хотим использовать аутентификацию LDAP без шифрования (PostgreSQL и сервер LDAP обмениваются сообщениями в открытом виде). Добавим правило с методом аутентификации ldap для Алисы. В параметрах метода указываем префикс и суффикс:

/etc/postgresql/16/main/pg_hba.conf.d/ext.conf
# TYPE  DATABASE  USER   ADDRESS  METHOD
host    all       alice  samehost ldap ldapserver=course.local ldapprefix="uid="
ldapsuffix=",ou=BioLab,dc=course,dc=local"

Попросим PostgreSQL принимать подключения со всех сетевых интерфейсов и записывать информацию о соединениях в журнал сообщений:

student=# ALTER SYSTEM SET listen_addresses = '*';
ALTER SYSTEM
student=# ALTER SYSTEM SET log_connections = on;
ALTER SYSTEM

Изменение первого параметра требует перезапуска сервера.

student$ sudo pg_ctlcluster 16 main restart

Подключимся от имени Алисы. В строке соединения передаем те же параметры, что и при парольной аутентификации:

student$ psql "host=localhost user=alice password=alice dbname=student" -c "\conninfo"
You are connected to database "student" as user "alice" on host "localhost" (address
"127.0.0.1") at port "5432".

Проверим журнал сообщений:

student$ tail -3 /var/log/postgresql/postgresql-16-main.log
2026-07-30 16:35:46.062 MSK [58393] [unknown]@[unknown] LOG:  connection received:
host=127.0.0.1 port=45556
2026-07-30 16:35:46.069 MSK [58393] alice@student LOG:  connection authenticated:
identity="uid=alice,ou=BioLab,dc=course,dc=local" method=ldap
(/etc/postgresql/16/main/pg_hba.conf.d/ext.conf:2)
2026-07-30 16:35:46.069 MSK [58393] alice@student LOG:  connection authorized: user=alice
database=student application_name=psql

Page 8: Поиск + связывание

Source slide page 8: Поиск + связывание{#source-figure-008 caption=“Source slide page 8: Поиск + связывание”}

Комментарии преподавателя

Если пользователи хранятся в разных поддеревьях, суффиксы уникальных имен записей будут разными и возможностей простого связывания не хватит. Например, записи alice и charlie заведены в разных лабораториях: суффикс Алисы будет ‘ou=BioLab’, а Чарли — ‘ou=ChemLab’.

Для таких случаев есть возможность провести аутентификацию в два этапа.

Сначала выполняется поиск нужной записи (search). Для этого PostgreSQL подключается к серверу LDAP под фиксированным именем и паролем (ldapbinddn, ldapbindpasswd) и ищет в поддереве ldapbasedn запись, у которой атрибут ldapsearchattribute равен имени подключающейся роли.

Например, для роли charlie с настройками

● ldapbasedn = ‘dc=course,dc=local’,

● ldapsearchattribute = ‘uid’

PostgreSQL обнаружит запись «uid=charlie,ou=ChemLab,dc=course,dc=local».

Page 9: Поиск + связывание

Source slide page 9: Поиск + связывание{#source-figure-009 caption=“Source slide page 9: Поиск + связывание”}

Комментарии преподавателя

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

Page 10: LDAP: поиск + связывание

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

student$ ldapsearch \
  -x                              `# аутентификация по DN и паролю` \
  -LLL                            `# краткая информация` \
  -H ldaps://$(hostname)          `# сервер LDAP` \
  -b dc=course,dc=local           `# ветвь дерева` \
  -D cn=admin,dc=course,dc=local  `# от кого запрос` \
  -w admin                        `# пароль` \
  "(uid=*)"                       `# фильтр` \
  cn                              `# выводить только common name`
dn: uid=alice,ou=BioLab,dc=course,dc=local
cn: Alice
dn: uid=bob,ou=BioLab,dc=course,dc=local
cn: Bob
dn: uid=charlie,ou=ChemLab,dc=course,dc=local
cn: Charlie

Изменим правило аутентификации. Значения отдельных параметров можно указать в более компактном виде (ldapurl): ldaps — аутентификация LDAP, в данном случае — с шифрованием SSL; course.local — адрес сервера (ldapserver); dc=course,dc=local — поддерево для поиска (ldapbasedn); uid — атрибут для поиска (ldapsearchattribute); sub — указание искать в указанном поддереве. Параметры ldapbinddn и ldapbindpasswd не указываем: в этом случае происходит анонимный запрос, который разрешен конфигурацией нашего LDAP-сервера.

/etc/postgresql/16/main/pg_hba.conf.d/ext.conf
# TYPE  DATABASE  USER     ADDRESS   METHOD
host    all       charlie  samehost  ldap
ldapurl="ldaps://course.local/dc=course,dc=local?uid?sub"
student$ sudo pg_ctlcluster 16 main reload

Пробуем.

student$ psql "host=$(hostname) user=charlie password=charlie dbname=student" -c "\conninfo"
You are connected to database "student" as user "charlie" on host "course.local" (address
"127.0.1.1") at port "5432".
student$ tail -3 /var/log/postgresql/postgresql-16-main.log
2026-07-30 16:35:47.150 MSK [58624] [unknown]@[unknown] LOG:  connection received:
host=127.0.0.1 port=41714
2026-07-30 16:35:47.171 MSK [58624] charlie@student LOG:  connection authenticated:
identity="uid=charlie,ou=ChemLab,dc=course,dc=local" method=ldap
(/etc/postgresql/16/main/pg_hba.conf.d/ext.conf:2)
2026-07-30 16:35:47.172 MSK [58624] charlie@student LOG:  connection authorized:
user=charlie database=student application_name=psql

Page 11: Аутентификация GSSAPI

Kerberos и GSSAPI

  • Настройка клиента
  • Настройка сервера
  • Аутентификация
  • Запрос сеансового ключа
  • Передача ключа сервису
  • Коммуникация с сервисом

Page 12: Kerberos и GSSAPI

Kerberos — протокол аутентификации

  • надежный обмен ключами и взаимная аутентификация
  • между клиентом и сервисом
  • симметричные ключи, доверенная третья сторона
  • разграничение доступа по областям (realm)
  • GSSAPI — универсальный интерфейс безопасности
    • поддерживает разные протоколы, в том числе Kerberos

Комментарии преподавателя

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

Клиент один раз аутентифицируется службой Kerberos, а затем получает билеты-разрешения, с которыми обращается к сервисам. Билет гарантирует клиенту, что он подключится именно к запрошенному сервису, а сервису — что клиент имеет право на подключение.

Kerberos рассчитан на большое количество пользователей и сервисов, и не каждому пользователю нужно разрешать подключаться к любому сервису. Для разграничения доступа существуют области (realm): пользователь может получать билет для сервиса, только если они входят в одну область. В нашем примере это область COURSE.LOCAL.

PostgreSQL работает с протоколом Kerberos не напрямую, а через универсальный прикладной интерфейс GSSAPI (Generic Security Services API), который, помимо Kerberos, поддерживает NTLM и другие протоколы.

Page 13: Настройки клиента

Параметр gssencmode

  • disable
  • не использовать шифрование GSSAPI
  • prefer
  • попытка использовать шифрование GSSAPI,
  • при неудаче — попытка соединиться без него
  • (по умолчанию)
  • require
  • потребовать шифрование GSSAPI
  • Параметр krbsrvname
    • имя службы Kerberos для аутентификации

Комментарии преподавателя

Аналогично тому, как при подключении клиент может попросить или потребовать SSL-соединение с помощью параметра sslmode библиотеки libpq, пожелания по использованию шифрования GSSAPI определяются значением параметра gssencmode.

Клиент может запретить (disable) или потребовать (require) соединение с шифрованием GSSAPI. Если сервер не разрешает желаемое соединение, оно не будет установлено.

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

https://postgrespro.ru/docs/postgresql/16/gssapi-enc

https://postgrespro.ru/docs/postgresql/16/libpq-connect#LIBPQ-CONNECT-GSSENCMODE

Также клиент может указать имя службы Kerberos, которая должна использоваться для аутентификации (по умолчанию — postgres).

https://postgrespro.ru/docs/postgresql/16/libpq-connect#LIBPQ-CONNECT-KRBSRVNAME

Page 14: Настройки сервера

Параметры

  • krb_server_keyfile
  • имя keytab-файла с ключом PostgreSQL
  • Типы сетевых подключений в pg_hba.conf
    • host
    • любое сетевое подключение
    • hostgssenc
    • подключение с шифрованием GSSAPI
    • hostnogssenc
    • подключение без шифрования GSSAPI
  • Метод аутентификации
    • gss
    • аутентификация с помощью GSSAPI
    • sspi
    • аутентификация SSPI для Windows

Комментарии преподавателя

Для аутентификации с помощью Kerberos необходимо указать метод аутентификации gss. (В ОС Windows для работы с Kerberos используется собственный интерфейс SSPI и соответствующий ему метод аутентификации sspi, которые мы здесь не рассматриваем.)

В параметре krb_server_keyfile указывается расположение файла с ключом PostgreSQL. Такие файлы, содержащие ключ Kerberos определенного сервиса или клиента, называются keytab-файлами.

В качестве типа подключения при этом можно указать как простой тип host, так и явно разделить соединения на использующие шифрование GSSAPI (hostgssenc) и не использующие (hostnogssenc).

https://postgrespro.ru/docs/postgresql/16/gssapi-auth

Page 15: Аутентификация

Source slide page 15: Аутентификация{#source-figure-015 caption=“Source slide page 15: Аутентификация”}

Комментарии преподавателя

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

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

Клиент Алисы обращается к службе аутентификации Kerberos AS (Authentication Service). Если Алиса ввела правильный пароль, ключи совпадут. Тогда Kerberos генерирует временный ключ, предназначенный для сеанса общения клиента и самого Kerberos, и отправляет клиенту два сообщения:

● Временный ключ, зашифрованный ключом Алисы. Клиент сможет его расшифровать.

● Временный ключ (плюс дополнительная служебная информация), зашифрованный ключом Kerberos. Это сообщение называется TGT, Ticket Granting Ticket — билет на получение билетов. Клиент не может его расшифровать, но будет предъявлять его Kerberos в доказательство того, что пользователь уже прошел аутентификацию.

Page 16: Аутентификация в Kerberos

Kerberos установлен и настроен в виртуальной машине курса, учетные записи (principals) зарегистрированы.

student$ sudo kadmin.local list_principals | grep '^[abc]'
alice@COURSE.LOCAL
bob@COURSE.LOCAL
charlie@COURSE.LOCAL

alice@COURSE.LOCAL — Алиса хранит пароль в специальном файле alice.keytab. bob@COURSE.LOCAL — Боб — в файле bob.keytab. charlie@COURSE.LOCAL — Чарли не хранит пароль в файле и должен вводить его вручную. Вы можете использовать его для собственных экспериментов. Сначала Алисе нужно аутентифицироваться и получить билет, дающий возможность получать билеты сервисов (TGT, Ticket Granting Ticket). Аутентификацию в Kerberos можно пройти с помощью команды kinit. Она запрашивает у пользователя пароль, из которого генерируется ключ, подтверждающий право на получение TGT. Мы воспользуемся заранее подготовленным ключом Алисы (в виртуальной машине он находится в файле alice.keytab), чтобы не вводить пароль интерактивно:

student$ kinit -kt alice.keytab alice

В результате Kerberos сформировал TGT и сохранил его в кеше:

student$ klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: alice@COURSE.LOCAL
Valid starting       Expires              Service principal
30.07.2026 16:35:47  31.07.2026 02:35:47  krbtgt/COURSE.LOCAL@COURSE.LOCAL
renew until 31.07.2026 16:35:47

Билет ограничен по времени действия (valid starting, expires/renew until); Термин principal означает учетную запись Kerberos: это может быть как клиент, так и сервис; COURSE.LOCAL — название области Kerberos, которая используется в этом примере.

Page 17: Запрос сеансового ключа

Source slide page 17: Запрос сеансового ключа{#source-figure-017 caption=“Source slide page 17: Запрос сеансового ключа”}

Комментарии преподавателя

Теперь Алиса хочет подключиться к PostgreSQL. Для этого ее клиент отправляет запрос на получение доступа к сервису, подтверждая аутентификацию Алисы с помощью полученного ранее TGT. Это позволяет Алисе не вводить пароль каждый раз при подключении к другим сервисам — то, что называется single sign-on.

Служба Kerberos TGS (Ticket Granting Service) генерирует сеансовый ключ, которым должны обладать как клиент, так и сервис. Клиенту снова передаются два сообщения:

● Сеансовый ключ, зашифрованный временным ключом (который уже есть у клиента).

● Сеансовый ключ, зашифрованный ключом сервиса (которого у клиента, конечно, нет). Это сообщение называется ST, Service Ticket — билет сервиса, и предназначено для сервиса.

Page 18: Передача ключа сервису

Source slide page 18: Передача ключа сервису{#source-figure-018 caption=“Source slide page 18: Передача ключа сервису”}

Комментарии преподавателя

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

Из расшифрованного билета PostgreSQL извлекает сеансовый ключ для общения с клиентом.

Page 19: Коммуникация с сервисом

Source slide page 19: Коммуникация с сервисом{#source-figure-019 caption=“Source slide page 19: Коммуникация с сервисом”}

Комментарии преподавателя

Теперь сеансовый ключ имеется и у клиента, и у сервиса. Он используется для шифрования данных, пересылаемых по клиент-серверному протоколу.

Билет TGT остается у клиента и будет использован для запросов на подключения к другим сервисам, если они понадобятся пользователю.

Page 20: Подключение к PostgreSQL

Включим в дополнительный файл аутентификации правило, разрешающее Алисе аутентифицироваться в Kerberos:

/etc/postgresql/16/main/pg_hba.conf.d/ext.conf
# TYPE      DATABASE  USER   ADDRESS   METHOD
hostgssenc  student   alice  samehost  gss include_realm=0

Параметр include_realm=0 убирает из имени учетной записи пользователя название области Kerberos. Например, alice@COURSE.LOCAL преобразуется в alice, то есть в обычное имя учетной записи PostgreSQL. Перечитаем конфигурацию.

student$ sudo pg_ctlcluster 16 main reload

При подключении к PostgreSQL psql запрашивает у Kerberos билет сервиса и передает его PostgreSQL. Имя сервиса задается в строке подключения libpq в параметре krbsrvname; в нашем случае годится значение по умолчанию — postgres. Проверим, сможет ли Алиса начать защищенный сеанс:

student$ psql "host=$(hostname) user=alice dbname=student" -c "\conninfo"
You are connected to database "student" as user "alice" on host "course.local" (address
"127.0.1.1") at port "5432".
GSSAPI-encrypted connection
student$ tail -3 /var/log/postgresql/postgresql-16-main.log
2026-07-30 16:35:48.479 MSK [58922] [unknown]@[unknown] LOG:  connection received:
host=127.0.0.1 port=41730
2026-07-30 16:35:48.485 MSK [58922] alice@student LOG:  connection authenticated:
identity="alice@COURSE.LOCAL" method=gss
(/etc/postgresql/16/main/pg_hba.conf.d/ext.conf:2)
2026-07-30 16:35:48.485 MSK [58922] alice@student LOG:  connection authorized: user=alice
database=student application_name=psql GSS (authenticated=yes, encrypted=yes,
delegated_credentials=no, principal=alice@COURSE.LOCAL)

Теперь в кеше будет и билет сервиса PostgreSQL:

student$ klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: alice@COURSE.LOCAL
Valid starting       Expires              Service principal
30.07.2026 16:35:47  31.07.2026 02:35:47  krbtgt/COURSE.LOCAL@COURSE.LOCAL
renew until 31.07.2026 16:35:47
30.07.2026 16:35:48  31.07.2026 02:35:47  postgres/course.local@
renew until 31.07.2026 16:35:47
Ticket server: postgres/course.local@COURSE.LOCAL

Кроме учетной записи Алисы, в Kerberos зарегистрирована и учетная запись Боба: bob@COURSE.LOCAL. В случае Алисы мы просто отбросили из имени учетной записи название области, пользуясь тем, что оставшаяся часть совпадает с именем роли в PostgreSQL. Можно использовать более универсальный подход: превращать имена учетных записей Kerberos в имена пользователей PostgreSQL с помощью сопоставлений имен, с которыми мы уже встречались в теме «Подключение и аутентификация». Заменим правило аутентификации для Алисы универсальным правилом с именем сопоставления krb:

/etc/postgresql/16/main/pg_hba.conf.d/ext.conf
# TYPE      DATABASE  USER   ADDRESS   METHOD
hostgssenc  student   all    samehost  gss map=krb

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

/etc/postgresql/16/main/pg_ident.conf.d/ext.conf
krb /^(.+)@ \1

Перечитаем конфигурацию:

student$ sudo pg_ctlcluster 16 main reload

Page 21: Page 21

Аутентифицируем Боба в Kerberos:

student$ kinit -kt bob.keytab bob

Боб начинает сеанс:

student$ psql "host=$(hostname) user=bob dbname=student" -c "\conninfo"
You are connected to database "student" as user "bob" on host "course.local" (address
"127.0.1.1") at port "5432".
GSSAPI-encrypted connection
student$ tail -3 /var/log/postgresql/postgresql-16-main.log
2026-07-30 16:35:49.624 MSK [59170] [unknown]@[unknown] LOG:  connection received:
host=127.0.0.1 port=41746
2026-07-30 16:35:49.630 MSK [59170] bob@student LOG:  connection authenticated:
identity="bob@COURSE.LOCAL" method=gss (/etc/postgresql/16/main/pg_hba.conf.d/ext.conf:2)
2026-07-30 16:35:49.631 MSK [59170] bob@student LOG:  connection authorized: user=bob
database=student application_name=psql GSS (authenticated=yes, encrypted=yes,
delegated_credentials=no, principal=bob@COURSE.LOCAL)

Билеты, полученные Бобом:

student$ klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: bob@COURSE.LOCAL
Valid starting       Expires              Service principal
30.07.2026 16:35:49  31.07.2026 02:35:49  krbtgt/COURSE.LOCAL@COURSE.LOCAL
renew until 31.07.2026 16:35:49
30.07.2026 16:35:49  31.07.2026 02:35:49  postgres/course.local@
renew until 31.07.2026 16:35:49
Ticket server: postgres/course.local@COURSE.LOCAL

Page 22: Аутентификация PAM

Source slide page 22: Аутентификация PAM{#source-figure-022 caption=“Source slide page 22: Аутентификация PAM”}

pam [параметры]

  • проверяет пары «имя пользователя — пароль»

Комментарии преподавателя

Система PAM (Pluggable Authentication Modules — подключаемые модули аутентификации) является стандартной инфраструктурой в Linux и многих UNIX системах. Модули этой системы представляют собой разделяемые библиотеки, реализующие четыре сервиса PAM:

● библиотеки аутентификации (Authentication Service Modules), посредством которых выполняется проверка подлинности;

● библиотеки учетных записей (Account Service Modules), выполняющих такие задачи, как проверка устаревания учетных записей;

● библиотеки сеансов (Session Service Modules), отвечающие за действия, выполняемые при входе в сеанс;

● библиотеки управления паролями (Password Service Modules).

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

В PostgreSQL аутентификация PAM работает подобно методу password, используя пары «имя пользователя — пароль». Сам же механизм аутентификации может быть реализован, например, с помощью LDAP, к которому будет обращаться модуль PAM.

Page 23: Итоги

При аутентификации PostgreSQL может полагаться на сторонние средства

  • Метод ldap запрашивает у клиента пароль и проверяет его с помощью службы каталогов
  • Методы gss и sspi аутентифицируют соединения через протокол Kerberos
  • Метод pam позволяет использовать для аутентификации внешнюю библиотеку

Page 24: Практика

  1. Настройте аутентификацию ldap по методу «поиск + связывание», как в демонстрации. Поддеревом для поиска укажите ou=BioLab. Проверьте, что Алиса и Боб могут подключиться к серверу, а Чарли — нет.
    1. Измените настройку так, чтобы все сетевые соединения использовали шифрование GSSAPI, но аутентификация по-прежнему происходила с помощью LDAP.

Комментарии преподавателя

  1. Такая настройка не имеет большого практического смысла, поскольку для шифрования GSSAPI клиент все равно должен пройти аутентификацию сервисом Kerberos.

Page 25: 1. Аутентификация LDAP

Создаем роли:

student=# CREATE ROLE alice LOGIN;
CREATE ROLE
student=# CREATE ROLE bob LOGIN;
CREATE ROLE
student=# CREATE ROLE charlie LOGIN;
CREATE ROLE

Попросим PostgreSQL принимать подключения со всех сетевых интерфейсов:

student=# ALTER SYSTEM SET listen_addresses = '*';
ALTER SYSTEM
student=# ALTER SYSTEM SET log_connections = on;
ALTER SYSTEM

Настройка аутентификации:

/etc/postgresql/16/main/pg_hba.conf.d/ext.conf
# TYPE  DATABASE  USER  ADDRESS   METHOD
host    all       all   all       ldap ldapserver=course.local
ldapbasedn="ou=BioLab,dc=course,dc=local"
student$ sudo pg_ctlcluster 16 main restart
student$ psql student

Пробуем.

student$ psql "host=$(hostname) user=alice password=alice dbname=student" -c "\conninfo"
You are connected to database "student" as user "alice" on host "course.local" (address
"127.0.1.1") at port "5432".
student$ psql "host=$(hostname) user=bob password=bob dbname=student" -c "\conninfo"
You are connected to database "student" as user "bob" on host "course.local" (address
"127.0.1.1") at port "5432".

Алиса и Боб подключаются. А Чарли — нет:

student$ psql "host=$(hostname) user=charlie password=charlie dbname=student" -c "\conninfo"
psql: error: connection to server at "course.local" (127.0.1.1), port 5432 failed: SSL
error: certificate verify failed
connection to server at "course.local" (127.0.1.1), port 5432 failed: FATAL:  LDAP
authentication failed for user "charlie"

2. Шифрование GSSAPI

Первым правилом запрещаем все соединения без шифрования GSSAPI. Второе правило аналогично правилу из предыдущего задания:

/etc/postgresql/16/main/pg_hba.conf.d/ext.conf
# TYPE        DATABASE  USER   ADDRESS   METHOD
hostnogssenc  all       all    all       reject
host          all       all    all       ldap ldapserver=course.local
ldapbasedn="ou=BioLab,dc=course,dc=local"
student=# SELECT pg_reload_conf();

Page 26: Page 26

 pg_reload_conf
----------------
 t
(1 row)

Пробуем подключиться:

student$ psql "host=$(hostname) user=alice password=alice dbname=student" -c "\conninfo"
psql: error: connection to server at "course.local" (127.0.1.1), port 5432 failed: SSL
error: certificate verify failed
connection to server at "course.local" (127.0.1.1), port 5432 failed: FATAL:  pg_hba.conf
rejects connection for host "127.0.0.1", user "alice", database "student", no encryption

Что произошло: Утилита psql не пытается установить соединение с шифрованием GSSAPI: Алиса не аутентифицирована в Керберос, у нее нет билета на подключение к сервисам. Сначала psql попытался установить SSL-соединение (параметр sslmode по умолчанию равен prefer). Затем psql попытался установить открытое соединение. Ни одна попытка не увенчалась успехом, поскольку сервер принимает только соединение с шифрованием GSSAPI. Теперь Алиса получает билет на соединение с сервисами:

student$ kinit -kt alice.keytab alice

На этот раз подключение срабатывает: параметр gssencmode по умолчанию равен prefer и у Алисы есть билет.

student$ psql "host=$(hostname) user=alice password=alice dbname=student" -c "\conninfo"
You are connected to database "student" as user "alice" on host "course.local" (address
"127.0.1.1") at port "5432".
GSSAPI-encrypted connection

В журнале сообщений видно, что для аутентификации использовался LDAP.

student$ tail -2 /var/log/postgresql/postgresql-16-main.log
2026-07-30 16:40:26.302 MSK [74724] alice@student LOG:  connection authenticated:
identity="uid=alice,ou=BioLab,dc=course,dc=local" method=ldap
(/etc/postgresql/16/main/pg_hba.conf.d/ext.conf:3)
2026-07-30 16:40:26.302 MSK [74724] alice@student LOG:  connection authorized: user=alice
database=student application_name=psql GSS (authenticated=no, encrypted=yes,
delegated_credentials=no)

Уборка

Очистим кеш Керберос:

student$ kdestroy
student$ sudo rm /etc/postgresql/16/main/pg_hba.conf.d/*
student$ sudo pg_ctlcluster 16 main reload
student=# \c student
You are now connected to database "student" as user "student".
student=# DROP ROLE alice, bob, charlie;
DROP ROLE

Page 27: Практика+

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

    1. Настройте журналирование подключений PostgreSQL. 2. Зарегистрируйте средствами операционной системы пользователя pamuser и назначьте ему пароль. Зарегистрируйте одноименную роль pamuser в СУБД. 3. В pg_hba.conf настройте для pamuser аутентификацию PAM с помощью сервиса login. 4. Обеспечьте доступ на чтение файла /etc/shadow пользователю postgres, добавив его в группу shadow. 5. Перезапустите СУБД и проверьте возможность подключения пользователем pamuser.

Комментарии преподавателя

  1. Для регистрации пользователя в операционной системе используйте команду: sudo useradd pamuser

Назначить пароль можно следующей командой (предложит ввести пароль и подтвердить его): sudo passwd pamuser

Также пароль для пользователя можно установить так: echo ‘pamuser:пароль’ | sudo chpasswd

  1. Вариант настройки аутентификации PAM для сервиса login:
# TYPE DATABASE USER    ADDRESS  METHOD
local  all      pamuser          pam pamservice=login
  1. Для предоставления доступа на чтение файла /etc/shadow для пользователя postgres, добавьте его в группу shadow: sudo gpasswd -a postgres shadow

После выполнения задания удалите postgres из группы: sudo gpasswd -d postgres shadow

Доступ пользователей к /etc/shadow не рекомендуется в реальной эксплуатации по соображениям безопасности.

Page 28: 1. Журналирование подключений

Включим запись в журнал отчета о подключениях:

student=# ALTER SYSTEM SET log_connections TO on;
ALTER SYSTEM

2. Регистрация пользователя

Создадим в PostgreSQL роль pamuser и зарегистрируем одноименного пользователя операционной системы.

student=# CREATE ROLE pamuser LOGIN;
CREATE ROLE
student$ sudo useradd pamuser

Установим пароль пользователю pamuser, совпадающий с его именем:

student$ echo 'pamuser:pamuser' | sudo chpasswd

Проверим, что пароль установлен:

student$ sudo passwd -S pamuser
pamuser P 2026-07-30 0 99999 7 -1

Символ P в выводе означает, что пароль установлен и не заблокирован.

3. Настройка аутентификации

/etc/postgresql/16/main/pg_hba.conf.d/ext.conf
# TYPE  DATABASE  USER    ADDRESS  METHOD
local   all       pamuser          pam pamservice=login

4. Права доступа для пользователя ОС postgres

Проверим права доступа на /etc/shadow

student$ ls -l /etc/shadow
-rw-r----- 1 root shadow 1286 июл 30 16:40 /etc/shadow

Пользователи операционной системы, входящие в группу shadow, могут читать файл. В этом файле находятся зашифрованные пароли, необходимые PostgreSQL для локальной аутентификации PAM. Добавим пользователя ОС postgres в группу shadow:

student$ sudo gpasswd -a postgres shadow
Adding user postgres to group shadow
student$ id postgres
uid=116(postgres) gid=124(postgres) groups=124(postgres),42(shadow),105(ssl-cert)
postgres$ grep pamuser /etc/shadow
pamuser:$y$j9T$miZzcSUuy/Ra5ogTFGGvO/$nidLLgPMXeG3NMStu1HHny.JYh.d5Ngsn0EIdhjZzSA:20664:0:
99999:7:::

5. Перезапуск СУБД и подключение

Перезапустим экземпляр.

student$ sudo pg_ctlcluster 16 main restart
student$ psql student

Проверим, сможет ли pamuser подключиться.

student$ psql "user=pamuser password=pamuser dbname=student" -c "\conninfo"

Page 29: Page 29

You are connected to database "student" as user "pamuser" via socket in
"/var/run/postgresql" at port "5432".
student$ tail -3 /var/log/postgresql/postgresql-16-main.log
2026-07-30 16:40:39.541 MSK [75516] [unknown]@[unknown] LOG:  connection received:
host=[local]
2026-07-30 16:40:39.614 MSK [75516] pamuser@student LOG:  connection authenticated:
identity="pamuser" method=pam (/etc/postgresql/16/main/pg_hba.conf.d/ext.conf:2)
2026-07-30 16:40:39.614 MSK [75516] pamuser@student LOG:  connection authorized:
user=pamuser database=student application_name=psql

Уборка

Выведем пользователя ОС postgres из группы shadow и удалим пользователя pamuser:

student$ sudo gpasswd -d postgres shadow
Removing user postgres from group shadow
student$ sudo userdel pamuser
student$ sudo rm /etc/postgresql/16/main/pg_hba.conf.d/*
student$ sudo pg_ctlcluster 16 main restart
student=# \c student
You are now connected to database "student" as user "student".
student=# DROP ROLE pamuser;
DROP ROLE