Application: LDAP, NSS, PAM.
Задача: добавить возможность аутентификации через LDAP локальному пользователю операционной системы.
Представим себе небольшой набор linux-серверов, управляемых вручную (производство невелико и затраты на тотальную автоматизацию неоправданны), на которых должно быть всего два-три системных администратора. Традиционно посредством утилиты "useradd" в несущей операционной системе добавляется учётная запись, ей выделяется некий уровень привилегий посредством "sudo", создаётся пароль и таковой передаётся лично пользователю. Можно ли избежать последней компрометирующей процедуры, если в сети предприятия уже имеется сервис централизованной аутентификации - LDAP (или AD)?
Рассмотрим частный случай использования модуля подсистемы PAM, в самой минимальной его конфигурации, для решения поставленной задачи, следуя принципу минимально необходимой достаточности.
Обычно аутентификация в "Linux" реализуется посредством связки NSS (NSLCD, SSSD) и PAM. Подсистема NSS встраивается прослойкой между типовым интерфейсом (утилитами "useradd", "getent", etc.) и хранилищами сведений о пользователях (файлы конфигураций "passwd", "group", "shadow", etc.), предоставляя при этом дополнительные возможности вроде синхронизации атрибутов между разными хранилищами и автоматизации управления учётными записями. Подсистема PAM играет скромную и важную роль конечного аутентификатора как такового, а как раз только это нам и требуется для решения поставленной задачи.
Установка модулей PAM и настройка NSS.
В "Linux Ubuntu" при установке LDAP-модуля для PAM из системного APT-репозитория за единственно нужным пакетом "libpam-ldap" потянется большое количество вспомогательных скриптов ("auth-client-config", "ldap-auth-client", "ldap-auth-config"), нам не требующихся, но находящихся в строгой зависимости - как я ни пытался, корректно избавиться от них не получилось:
# apt-get install --no-install-recommends libpam-ldap ldap-utils
После развёртывания APT-дистрибутива автоматически запустится интерактивный конфигуратор и запросит подробности подключения к LDAP серверу - практической пользы от этого этапа нет, всё необходимое мы настроим далее вручную - так что отказываемся от всего предлагаемого и выбрасываем это из головы:
LDAP server Uniform Resource Identifier: ldapi:///
....
Distinguished name of the search base: dc=example,dc=net
....
LDAP version to use: 3
...
Make local root Database admin: no
....
Does the LDAP database require login?: no
....
....
Distinguished name of the search base: dc=example,dc=net
....
LDAP version to use: 3
...
Make local root Database admin: no
....
Does the LDAP database require login?: no
....
Как выше упоминалось, в современном "Linux" аутентификация реализована через связку подсистем NSS и PAM. Наверное потому установка LDAP-модуля для PAM сборщиками APT-дистрибутивов была неразрывно связана с установкой LDAP-модуля и для NSS. Мы же здесь настраиваем лишь вспомогательную аутентификацию через LDAP посредством модулей PAM для уже имеющихся локальных пользователей, и не нуждаемся в помощи NSS при взаимодействии с LDAP.
Проследим, чтобы NSS не перехватывал запросы при обращении к LDAP, отрабатывая лишь в рамках типовых хранилищ "compat/files" и "systemd":
# cat /etc/nsswitch.conf
passwd: compat systemd
group: compat systemd
shadow: compat
gshadow: files
....
group: compat systemd
shadow: compat
gshadow: files
....
Настройка аутентификации через LDAP.
LDAP-модуль подсистемы PAM работает через библиотеки "OpenLDAP". По умолчанию в "Linux Ubuntu" все настройки LDAP-модуля собраны в одном конфигурационном файле (в "Linux Debian" это файл конфигурации называется "/etc/pam_ldap.conf"):
# vi /etc/ldap.conf
# Параметры подключения к LDAP-сервису
uri ldaps://ldap0.example.net
port 636
ldap_version 3
# Указываем не проверять подпись SSL-сертификата сервера
tls_checkpeer no
# (опционально) Сервисная учётная запись для запроса атрибутов пользователя
#binddn uid=linux-auth,ou=accounts,ou=services,dc=example,dc=net
#bindpw ***
# Отправная точка и параметр глубины поиска
base ou=people,dc=example,dc=net
scope sub
# Фильтр в дополнение к встроенному "uid=%s"
#pam_filter objectclass=account
# Указываем атрибут, с которым сопоставляется имя пользователя
pam_login_attribute uid
# Отключаем запросы дополнительных атрибутов
pam_lookup_policy no
pam_check_host_attr no
pam_check_service_attr no
# Указываем не обрабатывать запросы для пользователей с "системными UID"
pam_min_uid 1000
uri ldaps://ldap0.example.net
port 636
ldap_version 3
# Указываем не проверять подпись SSL-сертификата сервера
tls_checkpeer no
# (опционально) Сервисная учётная запись для запроса атрибутов пользователя
#binddn uid=linux-auth,ou=accounts,ou=services,dc=example,dc=net
#bindpw ***
# Отправная точка и параметр глубины поиска
base ou=people,dc=example,dc=net
scope sub
# Фильтр в дополнение к встроенному "uid=%s"
#pam_filter objectclass=account
# Указываем атрибут, с которым сопоставляется имя пользователя
pam_login_attribute uid
# Отключаем запросы дополнительных атрибутов
pam_lookup_policy no
pam_check_host_attr no
pam_check_service_attr no
# Указываем не обрабатывать запросы для пользователей с "системными UID"
pam_min_uid 1000
Запрещаем чтение возможно содержащего пароль файла посторонними:
# chown root:root /etc/ldap.conf
# chmod go-rwx /etc/ldap.conf
# chmod go-rwx /etc/ldap.conf
При установке из дистрибутива LDAP-модуль для PAM включается автоматически, но для расширения кругозора можно сделать это повторно, указав подсистеме PAM использовать LDAP-модуль для аутентификации, помимо прочих возможных методов:
# pam-auth-update
PAM profiles to enable:
[*] Unix authentication
[*] LDAP Authentication
[*] Register user sessions in the systemd control group hierarchy
[ ] Create home directory on login
[*] Inheritable Capabilities Management
[*] Unix authentication
[*] LDAP Authentication
[*] Register user sessions in the systemd control group hierarchy
[ ] Create home directory on login
[*] Inheritable Capabilities Management
После этого в файлах конфигурации "/etc/pam.d/common-account", "/etc/pam.d/common-auth", "/etc/pam.d/common-password", "/etc/pam.d/common-session" и "/etc/pam.d/common-session-noninteractive" появятся дополнительные строки указания на модуль LDAP-аутентификации, вроде нижеследующей:
# cat /etc/pam.d/common-auth
# here are the per-package modules (the "Primary" block)
auth [success=2 default=ignore] pam_unix.so nullok_secure
auth [success=1 default=ignore] pam_ldap.so use_first_pass
....
auth [success=2 default=ignore] pam_unix.so nullok_secure
auth [success=1 default=ignore] pam_ldap.so use_first_pass
....
Для успешной аутентификации локального пользователя через удалённый LDAP достаточно включения соответствующего модуля только для этапов "common-account" и "common-auth" - а во всех остальных конфигурациях PAM её можно отключить, просто деактивировав строку с описанием модуля:
# vi /etc/pam.d/common-password
# here are the per-package modules (the "Primary" block)
password [success=2 default=ignore] pam_unix.so obscure sha512
#password [success=1 user_unknown=ignore default=die] pam_ldap.so use_authtok try_first_pass
....
password [success=2 default=ignore] pam_unix.so obscure sha512
#password [success=1 user_unknown=ignore default=die] pam_ldap.so use_authtok try_first_pass
....
Ограничение доступа перечнем локальных пользователей.
По умолчанию в операционную систему может зайти любой пользователь, успешно аутентифицировавшийся через LDAP посредством связки NSS и PAM. Однако нам требуется чёткий контроль за перечнем пользователей в локальной системе. Традиционно нежелательные пользователи отсеиваются списками доступа PAM или фильтрами LDAP-клиента, но самый простой, на мой взгляд, способ - запрет входа в систему для всех "нелокальных" пользователей.
Идея в том, что для обслуживания пользователя его учётную запись вначале потребуется создать явно, зарегистрировав в файле "/etc/passwd", и только после этого подсистема PAM станет с ним работать.
Достигается это добавлением строки указания загрузки модуля "pam_localuser.so", единственная роль которого - требовать наличия пользователя в локальной базе таковых:
# vi /etc/pam.d/common-account
....
# Require the presence of the user in the local list.
account required pam_localuser.so
# Require the presence of the user in the local list.
account required pam_localuser.so
После изменения параметров загрузки модулей PAM желательно запустить утилиту выстраивания взаимосвязей с учётом предустановленных профилей:
# pam-auth-update --force
Теперь даже при успешном прохождении аутентификации через LDAP вход в целевую операционную систему будет пресечён, если пользователь отсутствует в "/etc/passwd".
Соответственно, для обеспечения доступа в систему нужно явно создать локального пользователя:
# useradd -m user
Разрешаем пользователю переходить в роль суперпользователя:
# echo "user ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/user
# visudo -cf /etc/sudoers.d/user
# visudo -cf /etc/sudoers.d/user
Практика использования созданной схемы аутентификации.
Первый (и последующие, без ограничений) вход в целевую систему пользователь осуществляет с логином и паролем его учётной записи в LDAP:
$ ssh user@10.20.30.45
Сразу после первого входа желательно наладить аутентификацию по SSH-ключам, для чего потребуется создать соответствующую директорию, файл и разместить в последнем публичную часть SSH-ключа пользователя:
$ mkdir ~/.ssh
$ vi ~/.ssh/authorized_keys
$ chmod go-rwx ~/.ssh/authorized_keys
$ vi ~/.ssh/authorized_keys
$ chmod go-rwx ~/.ssh/authorized_keys
Теперь при последующем входе уже не понадобиться вводить пароль.
Если пользователю предоставлена возможность повышения полномочий до суперпользователя, то ему легко будет задать отличный от используемого в LDAP пароль для локальной учётной записи в целевой системе:
$ sudo su
# passwd user
# passwd user
Таким образом, пользователь как минимум имеет возможность войти в целевую систему с аутентификацией через внешний LDAP-сервис. При размещении публичной части SSH-ключа у пользователя появляется возможность входа без указания какого-либо пароля. А задав пароль для локальной учётной записи в целевой системе у пользователя появляется возможность входить в неё как с аутентификацией через внешний LDAP, так и с указанием локального пароля.
Пароль локальной учётной записи можно удалить:
# passwd -d user
Пользователь тоже может быть удалён, разумеется (в таком случае аутентификация через LDAP для него может быть успешной, но в систему вход будет закрыт из-за отсутствия пользователя в локальном перечне таковых в файле "/etc/passwd"):
# userdel user
Об атрибутах класса "posixAccount" в LDAP-записи.
В случае применения сервисов NSLCD или SSSD, а также типовой конфигурации NSS, для аутентификации пользователя linux-системы через LDAP в записях "каталога" требуется определение атрибутов класса "posixAccount".
Но, если синхронизация посредством NSS не используется, а задействована только аутентификация посредством PAM, то и атрибуты вроде "uidNumber" не являются обязательными (хотя и запрашиваются в процессе). Таким образом, описываемая в этой заметке схема аутентификации не нуждается в атрибутах "posixAccount".
Ссылки на используемые материалы.