Метод ldap auth позволяет выполнять аутентификацию с использованием существующего сервера LDAP и учетных данных - имени пользователя и пароля. Это позволяет интегрировать Stronghold в среды, использующие LDAP.
Сопоставление групп и пользователей в LDAP с политиками Stronghold осуществляется с помощью путей users/ и groups/.
Аутентификация
С помощью CLI
$ d8 stronghold login -method=ldap username=mitchellh
Password (will be hidden):
Successfully authenticated! The policies that are associated
with this token are listed below:
admins
С помощью API
$ curl \
--request POST \
--data '{"password": "foo"}' \
http://127.0.0.1:8200/v1/auth/ldap/login/mitchellh
Ответ будет представлен в формате JSON. Например:
{
"lease_id": "",
"renewable": false,
"lease_duration": 0,
"data": null,
"auth": {
"client_token": "c4f280f6-fdb2-18eb-89d3-589e2e834cdb",
"policies": [
"admins"
],
"metadata": {
"username": "mitchellh"
},
"lease_duration": 0,
"renewable": false
}
}
Конфигурация
Перед тем как пользователи смогут проходить аутентификацию, необходимо предварительно настроить методы аутентификации. Эти шаги обычно выполняются оператором или средством управления конфигурацией.
- Включить метод аутентификации LDAP:
d8 stronghold auth enable ldap
- Настройте параметры подключения к серверу LDAP, а также информацию о том, как аутентифицировать пользователей, и как запрашивать членство в группах.
Параметры подключения
url(строка, обязательно) - Сервер LDAP, к которому необходимо подключиться. Примеры:ldap://ldap.myorg.com,ldaps://ldap.myorg.com:636. Это также может быть список URL через запятую, например,ldap://ldap.myorg.com,ldaps://ldap.myorg.com:636, в этом случае серверы будут использованы в порядке очереди, если в процессе соединения возникнут ошибки.starttls(bool, необязательно) - Если значение параметра true, то после установления незашифрованного соединения выдается командаStartTLS.insecure_tls- (bool, необязательно) - Если true, пропускает проверку SSL-сертификата LDAP-сервера - небезопасно, используйте с осторожностью!certificate- (строка, необязательно) - сертификат CA, который будет использоваться при проверке сертификата LDAP-сервера, должен быть в кодировке x509 PEM.client_tls_cert- (строка, необязательно) - Сертификат клиента для предоставления серверу LDAP, должен быть в кодировке x509 PEM.client_tls_key- (строка, необязательно) - Ключ сертификата клиента для предоставления серверу LDAP, должен быть закодирован в формате x509 PEM.
Параметры поиска
Существуют два разных способа определения объекта пользователя для аутентификации конечного пользователя: Поиск и Основное имя пользователя (User Principal Name, UPN). Если используется Поиск, привязка может быть выполнена либо анонимно, либо с аутентификацией. Метод UPN поддерживается в Active Directory для указания пользователей. Дополнительную информацию о UPN можно найти здесь.
Аутентифицированный поиск
binddn(строка, необязательно) - Имя объекта для привязки при выполнении поиска пользователей и групп. Пример:cn=stronghold,ou=Users,dc=example,dc=com.bindpass(строка, необязательно) - Пароль, используемый вместе сbinddnпри поиске пользователей.userdn(строка, необязательно) - Корневой DN, в котором осуществляется поиск пользователя. Пример:ou=Users,dc=example,dc=com.userattr(строка, необязательно) - Атрибут LDAP-объекта пользователя, который должен совпадать с именем пользователя, переданным при аутентификации. Примеры:sAMAccountName,cn,uid.userfilter(строка, необязательно) - шаблон Go, используемый для построения фильтра поиска пользователей ldap. Шаблон может обращаться к следующим контекстным переменным: [UserAttr,Username]. По умолчанию используется фильтр({{.UserAttr}}={{.Username}})или(userPrincipalName={{.Username}}@UPNDomain), если задан параметрupndomain. Фильтр поиска пользователей можно использовать для ограничения количества пользователей, которые могут попытаться войти в систему. Например, чтобы ограничить вход для пользователей, которые не являются подрядчиками (Contractors), можно написать(&(objectClass=user)({{.UserAttr}}={{.Username}})(!(employeeType=Contractor))).
При указании userfilter в фильтре должно присутствовать либо шаблонизированное значение {{.UserAttr}}, либо литеральное значение, соответствующее userattr, чтобы гарантировать, что поиск возвращает уникальный результат, учитывающий userattr для целей сопоставления псевдонимов сущностей, и избежать возможных коллизий при входе в систему.
Анонимный поиск
discoverdn(bool, необязательно) - Если true, используется анонимное подключение для определения bind DN пользователя.userdn(строка, необязательно) - Корневой DN, в котором осуществляется поиск пользователя. Пример:ou=Users,dc=example,dc=com.userattr(строка, необязательно) - Атрибут LDAP-объекта пользователя, который должен совпадать с именем пользователя, переданным при аутентификации. Примеры:sAMAccountName,cn,uid.userfilter(строка, необязательно) - шаблон Go, используемый для построения фильтра поиска пользователей ldap. Шаблон может обращаться к следующим контекстным переменным: [UserAttr,Username]. По умолчанию используется фильтр({{.UserAttr}}={{.Username}})или(userPrincipalName={{.Username}}@UPNDomain), если задан параметрupndomain. Фильтр поиска пользователей можно использовать для ограничения количества пользователей, которые могут попытаться войти в систему. Например, чтобы ограничить вход для пользователей, которые не являются подрядчиками (Contractors), можно написать(&(objectClass=user)({{.UserAttr}}={{.Username}})(!(employeeType=Contractor))).deny_null_bind(bool, optional) - Опция, предотвращающая обход аутентификации, если указан пустой пароль. По умолчанию установлено значениеtrue.anonymous_group_search(bool, необязательно) - Использовать анонимные подключения при выполнении поиска групп в LDAP. По умолчанию установлено значениеfalse.
При указании userfilter в фильтре должно присутствовать либо шаблонизированное значение {{.UserAttr}}, либо литеральное значение, соответствующее userattr, чтобы гарантировать, что поиск возвращает уникальный результат, учитывающий userattr для целей сопоставления псевдонимов сущностей, и избежать возможных коллизий при входе в систему.
Разрешение алиасов
dereference_aliases(строка, необязательно) - Управляет тем, как алиасы разрешаются при выполнении поиска. Возможные значения:never,finding,searchingиalways. Значениеfindingразрешает алиасы только во время определения имени. Значениеsearchingразрешает алиасы после определения имени.
Использование UPN (AD)
upndomain(строка, необязательно) - userPrincipalDomain, используемый для построения строки UPN (основное имя пользователя) для аутентифицируемого пользователя. UPN будет иметь вид[username]@UPNDomain. Пример:example.com, что приведет к тому, что Stronghold произведет привязку какusername@example.com.
Определение членства в группах
После аутентификации пользователя метод аутентификации LDAP должен определить, к каким группам принадлежит пользователь. Конфигурация может варьироваться в зависимости от вашего LDAP-сервера и схемы каталога. Существует два основных подхода к определению членства в группе — первый заключается в поиске аутентифицированного объекта пользователя и следовании за атрибутом к группам, в которых он состоит. Второй подход подразумевает поиск объектов группы, членом которых является аутентифицированный пользователь. Поддерживаются оба метода.
groupfilter(строка, необязательно) - Шаблон Go, используемый при построении запроса на членство в группе. Шаблон может использовать следующие переменные контекста: [UserDN,Username]. По умолчанию используется(|(memberUid={{.Username}})(member={{.UserDN}})(uniqueMember={{.UserDN}})), что совместимо с несколькими распространенными схемами каталогов. Для поддержки разрешения вложенных групп в Active Directory вместо этого используйте следующий запрос:(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={{.UserDN}})).groupdn(строка, обязательно) - База поиска LDAP для использования при поиске членства в группах. Это может быть корень, содержащий либо группы, либо пользователей. Пример:ou=Groups,dc=example,dc=com.groupattr(строка, необязательно) - Атрибут LDAP, используемый для объектов, возвращаемыхgroupfilter, чтобы перечислить членство в группах пользователя. Примеры: для запросовgroupfilter, возвращающих объекты group, используйте:cn. Для запросов, возвращающих объекты user, используйте:memberOf. Значение по умолчанию —cn.
Примечание: При использовании Аутентифицированного поиска имя, указанное в binddn, также используется для поиска группы. В противном случае для выполнения поиска группы используется аутентифицированный пользователь (пользователь, выполняюший вход).
Другие параметры
username_as_alias(bool, необязательно) - Если установлено в true, метод аутентификации будет использовать имя пользователя, переданное пользователем, в качестве имени алиаса.max_page_size(int, необязательно) - Если установлено значение больше 0, Stronhold будет выполнять постаничный поиск на LDAP-сервере, и запрашивать страницы размером до указанного значения. Этот параметр может понадобиться, если существует ограничение на максимальный размер результата LDAP-сервера. В противном случае постраничный поиск не будет использоваться.
Примеры
Сценацрий 1
- LDAP-сервер доступен по адресу
ldap.example.com, порт 389. - Сервер поддерживает команду
STARTTLSдля инициации шифрования на стандартном порту. - Сертификат УЦ хранится в файле с именем
ldap_ca_cert.pem. - Сервер является Active Directory и поддерживает атрибут userPrincipalName. Пользователи идентифицируются как
username@example.com. - Группы являются вложенными, мы будем использовать
LDAP_MATCHING_RULE_IN_CHAINдля обхода дерева групп. - Поиск групп начнется с
ou=Groups,dc=example,dc=com. Для всех объектов групп по этому пути атрибутmemberбудет проверяться на соответствие аутентифицированному пользователю. - Имена групп определяются на основании их атрибута
cn.
$ d8 stronghold write auth/ldap/config \
url="ldap://ldap.example.com" \
userdn="ou=Users,dc=example,dc=com" \
groupdn="ou=Groups,dc=example,dc=com" \
groupfilter="(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={{.UserDN}}))" \
groupattr="cn" \
upndomain="example.com" \
certificate=@ldap_ca_cert.pem \
insecure_tls=false \
starttls=true
...
Сценарий 2
- LDAP-сервер доступен по адресу
ldap.example.com, порт 389. - Сервер поддерживает команду
STARTTLSдля инициации шифрования на стандартном порту. - Сертификат УЦ хранится в файле с именем
ldap_ca_cert.pem. - Сервер не позволяет анонимные подключения для выполнения поиска пользователей.
- На сервере существует учетная запись для поиска —
cn=stronghold,ou=users,dc=example,dc=comс паролемMy$ecrt3tP4ss. - Объекты пользователей находятся в OU
ou=Users,dc=example,dc=com. - Имя пользователя, переданное в stronghold при аутентификации, отображается на атрибут
sAMAccountName. - Членство в группе будет определяться через атрибут
memberOfобъектов user. Этот поиск начнется вou=Users,dc=example,dc=com.
$ d8 stronghold write auth/ldap/config \
url="ldap://ldap.example.com" \
userattr=sAMAccountName \
userdn="ou=Users,dc=example,dc=com" \
groupdn="ou=Users,dc=example,dc=com" \
groupfilter="(&(objectClass=person)(uid={{.Username}}))" \
groupattr="memberOf" \
binddn="cn=stronghold,ou=users,dc=example,dc=com" \
bindpass='My$ecrt3tP4ss' \
certificate=@ldap_ca_cert.pem \
insecure_tls=false \
starttls=true
...
Сценарий 3
- LDAP-сервер доступен по адресу
ldap.example.com, порт 636 (LDAPS). - Сертификат УЦ хранится в файле с именем
ldap_ca_cert.pem. - Объекты пользователей находятся в OU
ou=Users,dc=example,dc=com. - Имя пользователя, переданное в Stronghold при аутентификации, соответствует атрибуту
uid. - User bind DN будет автоматически определен с использованием анонимного подключения.
- Членство в группе будет определяться через один из атрибутов:
memberUid,memberилиuniqueMember. Этот поиск начнется вou=Groups,dc=example,dc=com. - Имена групп идентифицируются с использованием атрибута
cn.
$ d8 stronghold write auth/ldap/config \
url="ldaps://ldap.example.com" \
userattr="uid" \
userdn="ou=Users,dc=example,dc=com" \
discoverdn=true \
groupdn="ou=Groups,dc=example,dc=com" \
certificate=@ldap_ca_cert.pem \
insecure_tls=false \
starttls=true
...
Сопоставление групп LDAP и политик
Далее мы хотим создать сопоставление группы LDAP с политикой Stronghold:
d8 stronghold write auth/ldap/groups/scientists policies=foo,bar
Это сопоставляет группу LDAP «scientists» с политиками Stronghold «foo» и «bar». Мы также можем добавить определенных пользователей LDAP в дополнительные (потенциально не-LDAP) группы. Обратите внимание, что политики могут быть указаны и для пользователей LDAP.
d8 stronghold write auth/ldap/groups/engineers policies=foobar
d8 stronghold write auth/ldap/users/tesla groups=engineers policies=zoobar
Это добавляет пользователя LDAP «tesla» в группу «engineers», которая соответствует политике Stronghold «foobar». Сам пользователь «tesla» связан с политикой «zoobar».
Наконец, мы можем проверить это, пройдя аутентификацию:
$ d8 stronghold login -method=ldap username=tesla
Password (will be hidden):
Successfully authenticated! The policies that are associated
with this token are listed below:
default, foobar, zoobar
Примечание о сопоставлении политик
Следует отметить, что сопоставление пользователь -> политика происходит во время создания токена. Изменения в членстве группы на LDAP-сервере ниак не повлияют на токены, которые уже были предоставлены. Чтобы эти изменения стали актуальными, необходимо отозвать старые токены и попросить пользователя пройти повторную аутентификацию.
Блокировка пользователя
Если пользователь несколько раз подряд предоставит неверные учетные данные, Stronghold на некоторое время прекратит попытки проверить его учетные данные, а вместо этого сразу же вернет ошибку с отказом доступе. Мы называем такое поведение «блокировкой пользователя» (user_lockout). Время, на которое пользователь будет заблокирован, называется «длительностью блокировки» (lockout_duration). Пользователь сможет войти в систему после истечения срока блокировки. Количество неудачных попыток входа, после которых пользователь будет заблокирован, называется «порог блокировки» (lockout_threshold). Счетчик порога блокировки обнуляется через несколько минут без попыток входа или при успешной попытке входа. Время, в течение которого счетчик будет обнулен после отсутствия попыток входа, называется «сброс счетчика блокировки» (lockout_counter_reset). Это позволяет предотвратить атаки с целью подбора пароля.
Функция блокировки пользователя включена по умолчанию. Значения по умолчанию:
lockout_threshold- 5 попытокlockout_duration- 15 минутlockout_counter_reset- 15 минут.
Функцию блокировки пользователя можно отключить с помощью команды «auth tune», передав значение disable_lockout true
Этот функционал поддерживается только методами userpass, ldap и approle auth.
Экранирование DN
Важно выполнить правильное экранирования DN (Distinguished Names - Уникальные имена), а именно DN пользователя, DN для поиска и так далее. Единственное экранирование DN, выполняемое этим методом, касается имен пользователей, указанных при входе в систему, когда они вставляются в окончательный bind DN, и оно использует правила экранирования, определенные в RFC 4514. Кроме того, в Active Directory существуют правила экранирования, которые немного отличаются от RFC; в частности, требуется экранирование символа ‘#’, независимо от его положения в DN (RFC требует его экранирования только в случае, если он является первым символом), и ‘=’, который согласно RFC может быть экранирован с помощью обратного слэша, но не включен в набор обязательных символов для экранирования. Если вы используете Active Directory и эти символы присутствуют в ваших именах пользователей, убедитесь, что они экранированы, а также корректно экранированы в ваших настроенных DN. Для справки см. RFC 4514 и эту статью TechNet о символах для экранирования в Active Directory.