Автор Тема: Аутентифкация по ssh с публичным ключом из LDAP  (Прочитано 6704 раз)

marawu

  • Пользователь
  • **
  • Сообщений: 76
  • !
    • Просмотр профиля
Доброго дня. Есть задача, настроить аутентификацию SSH по ключам из LDAP. Я нашел несколько статей как это сделать, но у всех разные механизмы. Хотя все они сходятся в том, что нужно добавить 2 новых атрибута на сервер. Вот тут у меня возникает первый вопрос, эти 2 атрибута лучше добавить отдельной схемой или добавить в какую-нибудь существующую? Так у меня вопрос к более опытным специалистам, если они настраивали такой механизм, как это сделать лучше?

egor

  • Администратор
  • Старожил
  • *****
  • Сообщений: 400
    • Просмотр профиля
Re: Аутентифкация по ssh с публичным ключом из LDAP
« Ответ #1 : 07 Октябрь 2016, 14:36:40 »
Здравствуйте!
На самом деле это одна из моих излюбленнейших "фишек" LDAP-каталогов, наглядно демонстрирующая всю простоту и элегантность централизованного подхода хранения данных =) . До конца года я собирался написать статью по этому поводу, но раз уж у Вас созрел вопрос прямо сейчас, будем считать что это превью будущей статьи =) .

Нужно начать с того, что речь идёт об openssh и аутентификации по паре ключей. То есть сервер openssh знает некий набор "авторизованных" для данного пользователя открытых ключей, и если пользователь при попытке входа сумеет доказать, что он обладает одним из этих ключей и парным к нему закрытым ключом, то сервер будет считать аутентификацию пройденной и пустит пользователя без пароля.

Список "авторизованных" ключей пользователя лежит в его домашнем каталоге на сервере в файле ~/.ssh/authorized_keys. Если пользователь заходит по ssh с авторизацией по ключам на несколько серверов, то на каждом из них в файле authorized_keys должен присутствовать его открытый ключ. Со временем разработчики openssh поняли, что практически в каждой организации имеется централизованное хранилище данных пользователей в том или ином виде и что логичнее хранить общий открытый ключ для многих серверов именно в нём. И в openssh версии 6.2 появились директивы настройки, позволяющие черпать информацию об "авторизованных" ключах пользователя не только из файла authorized_keys, но и путём запуска сторонней программы, получающей на вход имя пользователя и выдающей на выход ключи этого пользователя. Как именно программа будет получать ключи этого пользователя оставляется на усмотрение разработчика этой программы.

Вот такой простейший подход, но одновременно и гениальный: храни ключи где хочешь в любой точке сети, отдай их по запросу серверу ssh и пользователь сможет на основании этого ключа пройти аутентификацию.

В данном случае LDAP-каталог -- однин из вариантов такого централизованного хранилища, причём вполне себе неплохой, с учётом того, что каталог есть практически в любой организации (тот же AD, к примеру). Поместил открытый ключ в один из свободных атрибутов, написал простейший скрипт поискового запроса LDAP, получающего содержимое этого атрибута из записи пользователя, имя которого передано на вход, и вывел извлечённый ключ на стандартный вывод, где его заберёт и оценит сервер openssh.

Повторюсь, атрибут для хранения ключа может быть любым текстовым (например, description или favoriteDrink), но общепринятой практикой является использование атрибута sshPublicKey из схемы данных проекта openssh-ldappubkey (решавшего задачу получения открытого ключа из каталога до появления openssh 6.2). Эту схему (во вложении) нужно добавить на сервер OpenLDAP, модифицировать запись пользователя, добавив ему вспомогательный объектный класс ldapPublicKey и его обязательный атрибут sshPublicKey, куда поместить открытый ключ пользователя из его пары ключей (обычно, содержимое файла ~/.ssh/id_rsa.pub). Примерный LDIF:

dn: uid=ivanov,ou=People,dc=mycompany,dc=ru
changetype: modify
add: objectClass
objectClass: ldapPublicKey
-
add: sshPublicKey
sshPublicKey:< file:///home/ivanov/.ssh/id_rsa.pub


Затем на сервере openssh в файле /etc/ssh/sshd_config раскомментировать или добавить строки:

AuthorizedKeysCommand /usr/bin/get_ldap_ssh_key.sh
AuthorizedKeysCommandUser nobody

В первой из них указывается имя скрипта извлечения ключа, во второй -- имя пользователя, с правами которого этот скрипт будет выполняться (в данном случае бесправный nobody).

Сам скрипт у меня простейший:

#!/bin/bash

# Параметры поиска в LDAP-каталоге
LDAP_URI="ldap://127.0.0.1:389"
BASE_DN="ou=People,dc=mycompany,dc=ru"

# Имя пользователя из первого аргумента вызова скрипта
SSH_USER=$1

# Получаем ключ
KEY=$(ldapsearch -x -LLL -o ldif-wrap=no -c -H "${LDAP_URI}" -b "${BASE_DN}" -S sshPublicKey "(&(uid=${SSH_USER})(sshPublicKey=*))" sshPublicKey | grep -v 'dn:' | perl -pe 's/sshPublicKey: //;')

# И выводим его
echo "${KEY}"

Остаётся дать права на исполнение данного скрипта, перезапустить openssh и пробовать зайти по ssh с клиента.

Егор

egor

  • Администратор
  • Старожил
  • *****
  • Сообщений: 400
    • Просмотр профиля
Re: Аутентифкация по ssh с публичным ключом из LDAP
« Ответ #2 : 10 Октябрь 2016, 12:34:31 »
Первоначальная запись:
$ ldapsearch -x -LLL -H ldap://127.1:9000 -b dc=mycompany,dc=ru uid=ivanov
dn: uid=ivanov,ou=People,dc=mycompany,dc=ru
objectClass: inetOrgPerson
objectClass: posixAccount
uid: ivanov
cn: Ivan Ivanov
sn: Ivanov
userPassword:: aXZhbm92UGFzc3dvcmQ=
uidNumber: 1001
gidNumber: 1001
homeDirectory: /home/ivanov
loginShell: /bin/bash

LDIF-файл mod2.ldif:
dn: uid=ivanov,ou=People,dc=mycompany,dc=ru
changetype: modify
add: objectClass
objectClass: ldapPublicKey
-
add: sshPublicKey
sshPublicKey:< file:///home/ivanov/.ssh/id_rsa.pub

Применяем:
$ ldapmodify -x -D 'cn=manager,dc=mycompany,dc=ru' -w xxxxxxxxx -H ldap://127.1:9000 -f ./mod2.ldif
modifying entry "uid=ivanov,ou=People,dc=mycompany,dc=ru"

Что вышло:
$ ldapsearch -x -LLL -H ldap://127.1:9000 -b dc=mycompany,dc=ru uid=ivanov
dn: uid=ivanov,ou=People,dc=mycompany,dc=ru
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: ldapPublicKey
uid: ivanov
cn: Ivan Ivanov
sn: Ivanov
userPassword:: aXZhbm92UGFzc3dvcmQ=
uidNumber: 1001
gidNumber: 1001
homeDirectory: /home/ivanov
loginShell: /bin/bash
sshPublicKey:: c3NoLXJzYSBBQUFBQjNOemFDMXljMkVBQUFBREFRQUJBQUFCQVFDNVJvOVFLbWJ
 IOXlOTExCMVBmbEkxbHN3Y21nSm1zaFFFTVlMWElYbytzdjhCeStqTFRKaFlIVEMydVBrNHZ0RHRw
 R3JhYlgzcFlRK2NjbWRrMWxrRktXRUwxQzljdnlkNzYxcGE0Y3FKREJPUjl1MnQyUG9tSW0zTDJmR
 kwrWWhuNldvZVZ6aW81OHVUc2p1TmFmc3E5bS9Eazc2enB3SjNUT1JKTzlIVmdZQUFYR2tqbENnUU
 tnN1duMk9sOHQwNjdtS1BobEpwYWJiWEJkR0Yya0cvVDNmZXQ0N2V2ejExdGpVeC9VTlVQMjljSll
 yZ3haL2tYZ08yZXViRzRNc2hMelZRUHk2NWpuZkE1TW9EL0JhZmdWQ0o2cjdqSitzcDV4R0IwcEk1
 clpXNXA3Qkc3Uklhc0JOT3Q4K0hma2Rhc0ZpTHBwYkxaVU1seXR0NVB6Q2ggZWdvckBMZW5vdm8tW
 W9nYS0yLTEzCg==

Файл с открытым ключом находится там, где Вы его указываете в URL file:// ? Вместо URL можно попробовать просто вставить текст открытого ключа из файла. Да, ещё, возможно, в записи нет атрибута uid, обязательного для класса ldapPublicKey, тогда его тоже нужно добавить в том же LDIF.

Егор