Короткий ответ: как работает LDAP-аутентификация
LDAP-аутентификация подтверждает учетную запись через операцию bind. Приложение получает логин и пароль, подключается к LDAP-серверу, при необходимости находит полный DN пользователя через SearchRequest, затем отправляет BindRequest с этим DN и паролем. Сервер проверяет данные и возвращает BindResponse с кодом результата, например success или invalidCredentials.
Когда пользователь вводит короткий логин, например ivan, приложение обычно не может сразу выполнить bind. Сначала оно подключается сервисной учетной записью, ищет запись по фильтру вроде (uid=ivan), получает DN uid=ivan,ou=people,dc=example,dc=org и повторяет bind уже от имени пользователя. Если DN заранее известен по шаблону, поиск можно пропустить.
Simple bind передает имя учетной записи и пароль внутри LDAP-запроса. Сам механизм simple bind не шифрует пароль, поэтому TLS нужно установить до пользовательского bind. Успешная проверка пароля подтверждает личность, но не выдает права на SSH, sudo, приложение или отдельный ресурс.
Участники запроса: клиент, каталог и приложение
В типовой схеме участвуют три логических компонента:
- LDAP-клиент формирует протокольные операции и принимает ответы сервера. Им может быть веб-приложение, VPN-шлюз, Linux-клиент через SSSD, NAS или утилита
ldapsearch. - LDAP-сервер принимает соединение, выполняет bind, обрабатывает поиск и проверяет учетные данные по данным каталога.
- Приложение принимает решение о входе и доступе. Оно может делегировать проверку SSSD, PAM или встроенному LDAP-модулю.
LDAP-сервер не обязан знать, что запрос пришел от SSH или веб-приложения. Для него это набор операций протокола: подключение, TLS, bind, поиск записей, чтение атрибутов и завершение сеанса.
Полный путь от логина до успешного входа
- Пользователь вводит логин и пароль в приложении или передает их SSH-клиенту.
- Клиент разрешает имя LDAP-сервера через DNS и устанавливает TCP-соединение с портом
389или636. - При LDAPS TLS запускается сразу после TCP-подключения. При StartTLS клиент сначала подключается к LDAP на порту
389, затем выполняет расширенную операцию StartTLS. - Клиент выполняет bind сервисной учетной записи, если ему нужно искать пользователя по короткому логину.
- LDAP-клиент отправляет
SearchRequestс Base DN, областью поиска и фильтром, например(uid=ivan). - Клиент получает DN найденной записи и проверяет, что результат единственный.
- Клиент отправляет пользовательский
BindRequestс найденным DN и введенным паролем. - После успешного bind приложение запрашивает группы, идентификаторы и дополнительные атрибуты.
- Локальная или прикладная политика проверяет, разрешен ли вход этому пользователю.
- После завершения работы клиент отправляет
UnbindRequestили закрывает соединение.
При прямом bind этапы с сервисной учетной записью и поиском отсутствуют. Клиент сразу использует известный DN, например uid=ivan,ou=people,dc=example,dc=org.
Что означает успешный bind
Ответ BindResponse с кодом success означает, что LDAP-сервер принял переданное имя и пароль и установил соответствующий аутентифицированный контекст соединения. Пароль сервер не возвращает.
Успешный bind не означает автоматический доступ к ресурсам. Приложение может отклонить вход из-за отсутствия пользователя в разрешенной группе. SSH может применить AllowGroups, PAM может запретить вход по локальному правилу, а sudo проверит отдельную политику. Подробная схема групп и ролей приведена в статье о настройке LDAP-групп и ролей.
LDAP-каталог, DN и запись пользователя
LDAP хранит информацию в виде иерархии записей, или entry. Каждая запись имеет уникальное полное имя DN, набор атрибутов и один или несколько классов объектов. Клиент использует эти данные, чтобы найти пользователя, проверить его пароль и получить признаки, необходимые для последующего контроля доступа.
Как устроена запись пользователя в LDAP
Запись пользователя может выглядеть так:
dn: uid=ivan,ou=people,dc=example,dc=org objectClass: inetOrgPerson objectClass: posixAccount uid: ivan cn: Ivan Petrov mail: ivan@example.org uidNumber: 10001 gidNumber: 10000 homeDirectory: /home/ivan loginShell: /bin/bash
В этой записи:
dnсодержит полный идентификатор записи в дереве LDAP.objectClassопределяет допустимые и обязательные атрибуты.uidчасто используется как короткий логин в OpenLDAP.cnсодержит отображаемое имя или полное имя пользователя.mailхранит адрес электронной почты, если он предусмотрен схемой.uidNumberиgidNumberнужны Linux-системам, которые используют каталог как источник POSIX-идентификаторов.homeDirectoryиloginShellпомогают создать Linux-сеанс.
Пароль может храниться в атрибуте userPassword, но формат и права чтения зависят от схемы и настроек сервера. Клиенту обычно запрещают читать этот атрибут. При пользовательском bind сервер сам сравнивает переданный пароль с сохраненным представлением.
Группы могут описываться атрибутами member и memberOf. Поддержка вложенных групп, автоматического memberOf и схемы групп зависит от LDAP-сервера.
DN, RDN и Base DN на практическом примере
В DN uid=ivan,ou=people,dc=example,dc=org отдельные части имеют разные роли:
- RDN, относительное имя записи, это первая часть
uid=ivan. Она отличает запись от соседних объектов внутри родительского контейнера. - OU
ou=peopleобозначает подраздел или контейнер пользователей. - Base DN
dc=example,dc=orgзадает корень области поиска. - DN объединяет все компоненты и однозначно адресует запись в дереве.
Поиск может выполняться с разной областью:
baseпроверяет только сам объект, указанный в Base DN;oneпроверяет непосредственные дочерние записи;subобходит Base DN и вложенные ветки.
Если клиент ищет пользователя с Base DN ou=groups,dc=example,dc=org, запись из ou=people не попадет в результат. Ошибка Base DN может дать noSuchObject, а неподходящий фильтр часто возвращает пустой результат при доступном сервере и рабочем bind.
LDAP-фильтр проверяет атрибуты записи. Фильтр (uid=ivan) ищет точное значение атрибута uid. Условия можно комбинировать, например (&(objectClass=person)(uid=ivan)). В реальной команде символ амперсанда может потребовать экранирования как HTML-сущность.
OpenLDAP и Active Directory: что меняется в записи пользователя
Общая последовательность LDAP-операций сохраняется, но схема каталога и имена атрибутов различаются.
| Задача | OpenLDAP, частый вариант | Active Directory, частый вариант |
|---|---|---|
| Логин | uid | sAMAccountName или userPrincipalName |
| Контейнер пользователя | ou=people | OU=Users или другая OU |
| Группы | groupOfNames, member | group, member, вычисляемые связи |
| POSIX-атрибуты | uidNumber, gidNumber, loginShell | Могут отсутствовать или задаваться расширением схемы |
Нельзя переносить фильтр (uid=login) в Active Directory без проверки схемы. Там может использоваться (sAMAccountName=login) или фильтр по userPrincipalName. Сначала получите тестовую запись через поиск и проверьте реальные имена атрибутов.
Как LDAP находит пользователя: прямой bind и search-then-bind
Логин, который вводит человек, часто не совпадает с полным DN. LDAP-сервер проверяет пароль для конкретного имени записи, поэтому клиенту нужно либо знать DN заранее, либо сначала найти его поиском.
Прямой bind по известному DN
При прямом bind клиент формирует запрос, где поле name уже содержит DN пользователя:
BindRequest version: 3 name: uid=ivan,ou=people,dc=example,dc=org authentication: simple password: пароль пользователя
Этот вариант подходит, когда структура DN стабильна и приложение может безопасно построить имя из логина. Пример шаблона: uid={login},ou=people,dc=example,dc=org.
Шаблон нельзя применять без экранирования специальных символов DN. Запятая, знак плюса, обратный слеш, кавычки и некоторые другие символы могут изменить смысл имени. Если логин может содержать такие символы, используйте библиотечную функцию экранирования DN.
Преимущество прямого bind, один LDAP-запрос вместо поиска и пользовательского bind. Ограничение, приложение должно точно знать структуру каталога и не сможет работать с разными OU без дополнительной логики.
Поиск DN через сервисную учетную запись
Сценарий search-then-bind подходит, когда пользователь вводит короткий логин:
- Клиент устанавливает TLS-сеанс.
- Клиент выполняет bind сервисной учетной записи, например
uid=svc-reader,ou=people,dc=example,dc=org. - Клиент отправляет поиск по Base DN
ou=people,dc=example,dc=orgи фильтру(uid=ivan). - Сервер возвращает запись и ее DN.
- Клиент проверяет, что найден ровно один пользователь.
- Клиент закрывает или переиспользует сервисный контекст и выполняет bind найденного DN с паролем пользователя.
Сервисной учетной записи достаточно прав на поиск и чтение нужных атрибутов. Ей не требуется право изменять пользователей, читать userPassword или управлять группами. Если поиск возвращает две записи, приложение должно отказать во входе и сообщить об ошибке конфигурации, а не выбирать первый результат.
Тестовый поиск можно выполнить так:
ldapsearch -H ldaps://ldap.example.org -x -D 'uid=svc-reader,ou=people,dc=example,dc=org' -W -b 'ou=people,dc=example,dc=org' '(uid=ivan)' dn
Ключ -W запрашивает пароль интерактивно. Секрет не попадает в командную строку, историю shell и список процессов.
Почему поиск пользователя не заменяет проверку пароля
SearchRequest только находит доступную запись и возвращает разрешенные атрибуты. Успешный поиск говорит, что сервисная учетная запись может читать объект по заданному фильтру. Пароль пользователя на этом этапе не проверяется.
Подтверждение личности происходит во втором bind. Если приложение принимает найденную запись без пользовательского bind, любой человек, знающий логин, может пройти проверку без знания пароля. Сервисный bind подтверждает права самого сервиса и не подтверждает личность конечного пользователя.
Simple bind LDAP: состав запроса и ответ сервера
Операция bind устанавливает аутентификационный контекст LDAP-сеанса. В протоколе LDAP версии 3 запрос содержит версию протокола, имя учетной записи и способ аутентификации.
Что содержит BindRequest
Логическая структура BindRequest выглядит так:
version, обычно значение3;name, DN пользователя, DN сервисной учетной записи или пустое имя для anonymous bind;authentication, например simple authentication с паролем.
При simple bind пароль передается серверу внутри протокольного поля аутентификации. LDAP-кодировка BER и транспорт TCP не защищают секрет от перехвата. Защита появляется только после успешного TLS-сеанса, если клиент проверяет сертификат и не допускает откат к незашифрованному соединению.
Возможны три распространенных варианта:
- Пользовательский bind: в
nameуказан DN пользователя, а в authentication передан введенный пароль. - Сервисный bind: в
nameуказан технический DN с правами поиска. - Anonymous bind: имя и пароль пустые. Сервер может запретить такой режим или дать ему ограниченный доступ.
Anonymous bind не подтверждает личность клиента. Его использование допустимо только при осознанно открытом чтении публичных данных и с учетом политики конкретного сервера.
Что содержит BindResponse
Сервер возвращает код результата и, при наличии, диагностическое сообщение. Частые значения:
| Код | Смысл | Что проверить |
|---|---|---|
success | Bind выполнен | Переходить к группам и политике доступа |
invalidCredentials | Неверное имя, пароль или недопустимый способ входа | DN, пароль, блокировку учетной записи и формат логина |
unwillingToPerform | Сервер отказался выполнять операцию по политике или из-за состояния каталога | Политику bind, требования к шифрованию и серверные журналы |
confidentialityRequired | Сервер требует защищенный канал | LDAPS или StartTLS и проверку сертификата |
unavailable | Сервис временно недоступен | Состояние сервера, сеть, DNS и балансировщик |
Диагностическое сообщение LDAP помогает администратору, но его не следует без фильтра показывать пользователю. В тексте ошибки могут оказаться DN, имена внутренних узлов или сведения о политике каталога.
Пример последовательности LDAP-операций
Для схемы с поиском пользователя обмен выглядит так:
TCP connect to ldap.example.org:636 TLS handshake and certificate validation BindRequest: service account BindResponse: success SearchRequest: base=ou=people,dc=example,dc=org, filter=(uid=ivan) SearchResultEntry: dn=uid=ivan,ou=people,dc=example,dc=org SearchResultDone: success BindRequest: user DN, simple authentication BindResponse: success SearchRequest: groups and account attributes UnbindRequest
При прямом bind последовательность короче:
TCP connect TLS handshake BindRequest: user DN and password BindResponse: success SearchRequest: groups or attributes UnbindRequest
После завершения bind клиент может выполнять разрешенные операции в контексте этой учетной записи. Объем доступа определяется ACL каталога, а не самим фактом успешной аутентификации.
LDAP авторизация и аутентификация: что происходит после проверки пароля
Аутентификация отвечает на вопрос, кто передал учетные данные. Авторизация решает, что этому пользователю разрешено делать. Эти проверки могут проходить в LDAP, в приложении, в PAM, в SSH или сразу в нескольких компонентах.
Аутентификация подтверждает личность, авторизация определяет доступ
Успешный пользовательский bind подтверждает соответствие пароля конкретному DN. После него приложение должно определить, разрешен ли вход и какие действия доступны пользователю.
Примеры авторизационных правил:
- SSH принимает только членов группы
ssh-users. - Веб-приложение разрешает административную панель группе
app-admins. - Linux проверяет группы через NSS и разрешает sudo только пользователям, перечисленным в отдельной политике.
- LDAP ACL запрещает сервисной учетной записи читать часть атрибутов.
Пользователь может успешно пройти bind и получить отказ на любом из этих этапов. При диагностике нужно разделять ошибку пароля, ошибку поиска групп и отказ прикладной политики.
Какие данные запрашиваются после bind
После проверки пароля клиент может получить:
uid,cn,mailи другие атрибуты профиля;uidNumberиgidNumberдля POSIX-идентификации;homeDirectoryиloginShellдля Linux-сеанса;- членство в группах через
member,memberOfили отдельный поиск групп; - атрибуты, которые приложение использует для ролей и ограничений.
Приложение может выполнять дополнительные LDAP-поиски с DN пользователя в качестве базы. В другой схеме оно ищет группы по фильтру, который содержит DN пользователя. Конкретный способ зависит от каталога и модели групп.
Группы LDAP и доступ к ресурсам
При простой схеме группа содержит атрибут member со списком DN пользователей:
dn: cn=ssh-users,ou=groups,dc=example,dc=org objectClass: groupOfNames cn: ssh-users member: uid=ivan,ou=people,dc=example,dc=org
Обратная связь через memberOf может формироваться сервером автоматически или отсутствовать. Вложенные группы требуют отдельной поддержки и дополнительных запросов. Нельзя считать пользователя членом группы только потому, что похожее имя найдено в каталоге.
Практичная политика начинается с принципа запрета по умолчанию. LDAP-пользователь получает доступ к SSH, sudo или приложению только после прохождения отдельного правила группы, роли или ACL. Проверку нужно тестировать учетной записью без нужной группы, чтобы убедиться в отказе.
Безопасность simple bind: LDAPS или StartTLS
Simple bind без TLS раскрывает пароль на транспортном уровне. Любой компонент, который может наблюдать незашифрованный трафик между клиентом и LDAP-сервером, получает возможность перехватить учетные данные. Для пользовательского bind TLS должен завершиться до отправки пароля.
LDAPS через порт 636
При LDAPS клиент открывает TLS-соединение сразу:
- Клиент подключается к имени сервера на порту
636. - Сервер отправляет сертификат.
- Клиент проверяет цепочку доверия, имя в SAN, срок действия и параметры TLS.
- После успешной проверки клиент отправляет LDAP bind.
В URI клиента используется схема ldaps://. Имя в URI должно совпадать с DNS-именем, указанным в SAN сертификата. Подключение к IP-адресу при сертификате только на DNS-имя вызовет ошибку проверки имени.
StartTLS на порту 389
StartTLS начинается с обычного LDAP-соединения, которое затем переводится в защищенный режим:
- Клиент подключается к порту
389. - Клиент отправляет расширенную операцию StartTLS.
- Сервер отвечает готовностью к TLS.
- Клиент выполняет TLS-рукопожатие и проверяет сертификат.
- Только после успешного TLS клиент отправляет сервисный или пользовательский bind.
Пароль нельзя отправлять между TCP-подключением и завершением StartTLS. Установка TLS после bind не защищает уже переданный секрет.
Что проверить в TLS-сеансе
- Корневой и промежуточные сертификаты доверенного CA установлены на клиенте.
- Имя LDAP endpoint совпадает с SAN сертификата.
- Системные часы клиента и сервера синхронизированы.
- Сертификат не просрочен и не отозван по правилам вашей инфраструктуры.
- Клиент и сервер согласуют разрешенную версию TLS и набор шифров.
- Проверка сертификата включена, а режим доверия к любому сертификату не используется в production.
Отключение проверки сертификата часто создает иллюзию рабочего LDAPS. Трафик может шифроваться, но клиент не подтверждает, с каким сервером установил соединение. Подробная проверка сертификатов, прав bind-аккаунта и TLS-диагностика описаны в материале о безопасности LDAP-аутентификации.
Как LDAP-аутентификация работает в Linux: SSSD, PAM и NSS
В Linux протокол LDAP обычно скрыт за системными компонентами. Приложение SSH передает учетные данные PAM, SSSD выполняет LDAP-запросы и может хранить кэш, а NSS возвращает сведения о пользователях и группах системным утилитам.
Роли SSSD, PAM и NSS в одной схеме
- SSSD подключается к LDAP или Active Directory, выполняет поиск, bind, получение групп и кэширование. Его параметры задаются для конкретного домена в конфигурации SSSD.
- PAM участвует в проверке пароля и правилах входа. Модули PAM передают запрос в SSSD и могут дополнительно применять ограничения.
- NSS отвечает за поиск учетных записей и групп через системные вызовы. Команды
getentиidпоказывают, видит ли система каталог как источник идентификационной информации.
NSS не заменяет проверку пароля. Команда getent passwd ivan может вернуть запись пользователя, но это не доказывает, что пароль верный. За проверку учетных данных отвечает PAM через настроенный провайдер.
Как проходит вход пользователя по SSH
sshdполучает логин и пароль от SSH-клиента.- SSH передает запрос в PAM.
- PAM обращается к SSSD или другому настроенному модулю.
- SSSD устанавливает защищенное LDAP-соединение, при необходимости выполняет поиск DN и проверяет пользовательский пароль bind-операцией.
- SSSD получает группы и идентификаторы пользователя.
- PAM и SSH проверяют локальные ограничения, включая разрешенные группы и запреты.
- Система определяет домашний каталог, shell и окружение, после чего запускает сеанс.
Успешный LDAP bind может завершиться отказом SSH. Причина часто находится в AllowUsers, AllowGroups, PAM-правилах, отсутствии домашнего каталога или запрещенном shell.
Кэш SSSD и локальные учетные записи
SSSD может кэшировать идентификационные данные, группы и результаты аутентификации. Поэтому getent passwd ivan иногда возвращает пользователя при недоступном LDAP-сервере. Это не означает, что каталог отвечает сейчас.
Нужно разделять:
- Кэш идентификации позволяет получить имя, UID, GID и другие сведения.
- Офлайн-аутентификация позволяет войти без связи с каталогом, если политика SSSD разрешает такой режим и в кэше есть подходящие данные.
- Локальная учетная запись хранится в системных файлах и может работать независимо от LDAP.
Сравнивайте результат getent, логи SSSD и доступность LDAP в момент проверки. Для подключения Linux к каталогу через SSSD, PAM и NSS используйте отдельное руководство по настройке LDAP-клиента.
Для лабораторного стенда с Linux-клиентом, LDAP-сервером и отдельной сетью можно использовать виртуальную инфраструктуру, например Timeweb Cloud. Тестовые узлы лучше изолировать, ограничить доступ к LDAP-портам и не применять реальные учетные данные.
Проверка LDAP bind и типовые ошибки
Диагностику выполняйте снизу вверх: сначала сеть и TLS, затем сервисный bind, поиск DN, пользовательский bind, группы и локальная политика. Такой порядок отделяет ошибку подключения от неверного пароля и отказа авторизации.
Проверка соединения, TLS и сервисного bind
- Проверьте разрешение имени LDAP-сервера через DNS.
- Проверьте доступность порта
389или636с узла приложения. - Убедитесь, что клиент доверяет CA и проверяет имя сертификата.
- Выполните
ldapwhoamiс тем же URI и режимом TLS, который использует целевое приложение. - Проверьте сервисный bind отдельно от поиска пользователя.
Пример проверки LDAPS:
ldapwhoami -H ldaps://ldap.example.org -x -D 'uid=svc-reader,ou=people,dc=example,dc=org' -W
Для StartTLS используется порт 389 и ключ -ZZ, который требует успешного TLS:
ldapwhoami -H ldap://ldap.example.org:389 -ZZ -x -D 'uid=svc-reader,ou=people,dc=example,dc=org' -W
Не заменяйте -ZZ на режим, который позволяет продолжить соединение после ошибки TLS. Иначе клиент может перейти к незашифрованному bind.
Проверка поиска пользователя и его DN
Проверьте Base DN, область поиска, атрибут логина и количество результатов. Для OpenLDAP фильтр может выглядеть как (uid=ivan), для Active Directory часто используется (sAMAccountName=ivan).
ldapsearch -H ldaps://ldap.example.org -x -D 'uid=svc-reader,ou=people,dc=example,dc=org' -W -b 'ou=people,dc=example,dc=org' -s sub '(uid=ivan)' dn
Ожидаемый результат содержит один DN. Пустой результат обычно указывает на неверный фильтр, Base DN, область поиска, регистр или отсутствие прав чтения. Несколько записей означают неоднозначный логин. Код noSuchObject чаще связан с отсутствующей веткой Base DN, а insufficientAccessRights указывает на ACL сервера.
Проверка пользовательского bind
После получения DN проверьте bind тестовой учетной записи отдельной командой:
ldapwhoami -H ldaps://ldap.example.org -x -D 'uid=ivan,ou=people,dc=example,dc=org' -W
Если команда возвращает invalidCredentials, проверьте точный DN, пароль, срок действия учетной записи, блокировку и правила смены пароля. Убедитесь, что приложение не отправляет короткий логин вместо DN, если сервер ожидает полное имя записи.
Не включайте пароль в команду, переменные окружения с широким доступом, историю shell, журналы CI и диагностические отчеты. Для проверки используйте интерактивный ввод или механизм секретов, предусмотренный вашим клиентом.
Почему вход не работает после успешного bind
Когда пользовательский bind успешен, проверьте следующие уровни:
- Группы: видит ли клиент нужную группу и совпадает ли DN пользователя с атрибутом
member. - NSS: возвращают ли
getent passwd ivanиid ivanправильные UID, GID и группы. - PAM: разрешает ли стек вход по SSH и не срабатывает ли отдельное ограничение.
- SSH: корректны ли
AllowUsers,AllowGroups, shell и настройки доступа. - Домашний каталог: существует ли путь из
homeDirectoryи может ли система его создать. - Sudo: есть ли пользователь или его группа в разрешенной политике sudo.
- Кэш SSSD: не показывает ли клиент устаревшие группы или старую запись.
Сопоставляйте логи клиента и сервера по времени запроса. Полезно сначала повторить проверку через ldapwhoami и ldapsearch, затем проверить SSSD и PAM, и только после этого менять конфигурацию SSH или приложения.
Пошаговый чек-лист для ошибок LDAP и Active Directory с проверкой DNS, порта, TLS, bind, Base DN, фильтров и групп собран в статье о диагностике ошибок аутентификации.
Рабочая проверка LDAP-аутентификации должна повторять параметры production-клиента: тот же endpoint, имя сервера, режим TLS, Base DN, фильтр и учетную запись. Тест с другим URI или отключенной проверкой сертификата не подтверждает исправность реальной схемы.