Непутёвые заметки *** LDAP/PAM/SAMBA

ВАЖНОЕ ЗАМЕЧНИЕ: ВСЕ ДЕЙСТВИЯ, ОПИСАННЫЕ В ДАННОЙ СТАТЬЕ БЫЛИ БОЛЕЕ-МЕНЕЕ ПРОВЕРЕНЫ НА ПРАКТИКЕ, НО В ЛЮБОМ СЛУЧАЕ - ВСЕ ВРЕМЯ УСТАНОВКИ ЭТИХ НАСТРОЕК Я НАСТОЯТЕЛНО РЕКОМЕНДУЮ ВАМ ИМЕТЬ ДВЕ ЗАПАСНЫХ (Т.Е. ТЕХ, С КОТОРЫХ ВЫ НЕ РАБОТАЕТЕ В ТЕКУЩИЙ МОМЕНТ) КОНСОЛИ С ПРАВАМИ СИСТЕМНОГО АДМИНИСТРАТОРА.

Что такое PAM_LDAP?

PAM_LDAP и NSS_LDAP - это модули для подсистем PAM (Pluggable Authentication Modules) и NSS (Name Service Switch), позволяющие хранить в каталоге LDAP единую базу системной информации - пользователей, групп, компьютеров, сервисов и т.д., которую могут совместно использовать множество Linux-сиситем. Хотя существуют реализации этого модуля не только для Linux, но и для FreeBSD, Solaris и других Unix-систем, в этой краткой инструкции я буду рассматривать ТОЛЬКО Linux, причем на примере своего дистрибутива Fedora 7 (впрочем, эти же инструкции должны естественным образом без особых изменений пойти и на других более-менее современных дистрибутивах).

Необходимые условия

Настройка сервера OpenLDAP

Прежде всего, необходимо выбрать suffix - фактически, это полное имя корневого объекта вашего каталога. Обычно его связывают с доменным именем, например для домена pupkin.com.ru оптимальнее всего использовать следующий суффикс: dc=pupkin,dc=com,dc=ru. Кроме этого, нам потребуется имя для администраторского эккаунта в каталоге. Это имя получается добавлением уникального в текущей ветви дерева идентификатора к суффиксу. Полученное значение называют rootdn, и используя это имя, можно получить полный доступ к каталогу. Пусть в нашем примере rootdn будет cn=sysadm,dc=pupkin,dc=ru. теперь укажем пароль для этой учетной записи, для чего запустим утилиту slappasswd:

slappasswd -h '{SMD5}' -s zarazamelkaya

Слово zarazamelkaya в данном случае и будет являться паролем. В приципе, можно указать пароль и открытым текстом, но этого делать не рекомендуется. Выданную утилитой slappasswd строку стоит записать куда-нибудь :-)

Теперь приступаем к редактированию /etc/openldap/slapd.conf:

include         /etc/openldap/schema/core.schema
include         /etc/openldap/schema/cosine.schema
include         /etc/openldap/schema/inetorgperson.schema
include         /etc/openldap/schema/nis.schema
#
# Следующий файл взят из пакета samba - если вам
# не нужна интеграция ldap с samba - удалите эту строку
#
include         /etc/openldap/schema/samba.schema

pidfile /var/run/slapd.pid

database        ldbm
suffix          "dc=pupukin,dc=com,dc=ru"
rootdn          "cn=sysadm,dc=pupkin,dc=com,dc=ru"
rootpw          {SMD5}hjUUf7pqdVsrpG44/Ql+hlszywY=

directory       /var/lib/ldap

index objectClass                       eq,pres
index ou,cn,mail,surname,givenname      eq,pres,sub
index uidNumber,gidNumber,loginShell    eq,pres
index uid,memberUid                     eq,pres,sub
index nisMapName,nisMapEntry            eq,pres,sub

#
# Контроль доступа на атрибуты из схемы Samba
#
access to attrs=sambaNTPassword by self write by * none
access to attrs=sambaLMPassword by self write by * none
#
# Общие ограничения контроля доступа.
# Не давайте пользователю править какие-либо
# поля кроме своего пароля!
#
access to attrs=userPassword by self write by * auth
access to * by peername=127.0.0.1 read by anonymous auth by users read

В качестве параметра для rootpw мы и указали сгенерированный хэш от пароля первичного администратора сервера каталога. Директивы include служат для подключения файлов схем LDAP, описывающих атрибуты и классы объектов, хранимых в каталоге. Директивы index указывают, по каким атрибутам нужно строить индектсы для ускорения поиска. Параметр database определяет бакэнд для хранения базы. Запускаем сервер:

service ldap start

Создаем корневой объект каталога:

admin$ echo -e "dn: dc=pupkin,dc=com,dc=ru
objectClass: dcObject
objectClass: organization
dc: pupkin
o: Vasya Pupkin and Co. Ltd" | ldapadd -x \
   -D "cn=sysadm,dc=pupkin,dc=com,dc=ru"
   -w zarazamelkaya
   -h localhost -p 389

Проверяем, что сервер работает:

ldapsearch -x -D "cn=sysadm,dc=pupkin,dc=com,dc=ru" \
   -w zarazamelkaya -s sub -b "dc=pupkin,dc=com,dc=ru" \
   "(objectClass=*)"

Если ошибок нигде совершено не было, ldapsearch выдаст на стандартный вывод описание созданого командой ldapadd объекта в формате ldiff. Впоследствии такой ldiff-файл может быть использован для восстановления каталога, или для создания его двойника.

Настройка PAM для использования LDAP

Для достижения нужного эффекта нам необходимо "довести до ума" конфигурационный файл для pam_ldap (называется он /etc/ldap.conf) и произвести настройку собственно PAM. Начинаем со второго пункта, и запускаем authconfig (в RedHat и подобных). Активизируем использование аутентификации в LDAP, НЕ ОТКЛЮЧАЯ ИСПОЛЬЗОВАВШИХСЯ РАНЕЕ ОПЦИЙ, иначе начнутся проблемы. Указываем в качестве адреса сервера LDAP адрес 127.0.0.1 и в качестве basedn значение нашего suffix'а из конфигурации сервера: dc=pupkin,dc=com,dc=ru

На самом деле, authconfig просто исправляет три файла:

при этом после завершения authconfig рекомендуется проверить, чтобы содержимое /etc/ldap.conf выглядело примерно описанным ниже образом. В принципе, в /etc/ldap.conf есть много очень полезных комментариев и параметров, но нам пока что они не интересны. Вот слегка измененная копия /etc/ldap.conf с работающей системы.

host 127.0.0.1
base dc=pupkin,dc=com,dc=ru
rootbinddn cn=sysadm,dc=pupkin,dc=com,dc=ru
port 389
scope sub
pam_filter objectclass=posixAccount
pam_login_attribute uid
nss_base_passwd dc=pupkin,dc=com,dc=ru?sub?objectClass=posixAccount
nss_base_shadow dc=pupkin,dc=com,dc=ru?sub?objectClass=posixAccount
nss_base_group  dc=pupkin,dc=com,dc=ru?sub?objectClass=posixGroup
ssl no
pam_password md5
bind_policy soft

Также неоходимо создать файл /etc/ldap.secret и сохранить в нем пароль администратора каталога. Этот пароль будет использоваться для выполнения административных функций, и не будет доступен обычным пользователям:

# echo "zarazamelkaya" >/etc/ldap.secret
# chmod 600 /etc/ldap.secret
# chown root:root /etc/ldap.secret

В /etc/nsswitch.conf строки, указывающие, из какого источника программам нужно брать данные о пользователях, паролях и группах, должны выглядеть аналогично следующему примеру:

passwd:     files ldap
shadow:     files ldap
group:      files ldap

Настройки PAM для использования LDAP производятся путем корректного вписывания pam_ldap.so в нужные файлы в /etc/pam.d - уточним, что нужный файл в моем любимом дистрибутиве Fedora 7 только один, зовется он /etc/pam.d/system-auth и выглядит следующим образом:

#%PAM-1.0
#%PAM-1.0
# This file is auto-generated.
# User changes will be destroyed the next time authconfig is run.
auth        required      pam_env.so
auth        sufficient    pam_unix.so nullok try_first_pass
auth        sufficient    pam_ldap.so use_first_pass
auth        requisite     pam_succeed_if.so uid >= 500 quiet
auth        required      pam_deny.so

account     sufficient    pam_unix.so
account     sufficient    pam_ldap.so
account     sufficient    pam_localuser.so
account     sufficient    pam_succeed_if.so uid < 500 quiet
account     required      pam_permit.so

password    requisite     pam_cracklib.so try_first_pass retry=3
password    sufficient    pam_unix.so md5 shadow nullok try_first_pass use_authtok
password    sufficient    pam_ldap.so use_authtok
password    required      pam_deny.so

session     optional      pam_keyinit.so revoke
session     required      pam_limits.so
session     [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
session     required      pam_unix.so
session     optional      pam_ldap.so

Необходимо отметить, что если вы попытаетсь настроить все это используя утилиту authconfig, в рискуете получить неработспособную в случае отсутствия LDAP-сервера систему. Приведенный мной пример содержимого файла /etc/pam.d/system-auth свободен от этого недостатка - хотя, возможно, обладает другими ошибками. Тем не менее, поскольку этот файл работает и у меня дома, и на работе, я буду считать его подходящим. Естественно, не следует также забывать о том, что опции, передаваемые в pam_unix.so (md5, shadow & etc) варьируются в зависсимости от настроек вашей системы.

Совершив данные исправления, можно приступать к тестированию, для чего необходимо завести пользователя. Пользователи у нас будут являться сочетанием двух классов - nisMailAlias и posixAccount. Почему так? Да потому, что я ленив - и данное сочетание удовлетворяет минимальным необходимым условиям: класс nisMailAlias является STRUCTURAL (т.е. экземпляр объекта этого класса можно породить), и требует только наличия атрибута cn, а класс posixAccount является AUXILIARY, и требует атрибутов cn, uidNumber, gidNumber и uid:

admin$ echo "dn: cn=vasya,dc=pupkin,dc=com,dc=ru
objectClass: nisMailAlias
objectClass: posixAccount
cn: vasya
uid: vasya
uidNumber: 1000
gidNumber: 1000
gecos: Vasiliy Pupkin
loginShell: /bin/bash
homeDirectory: /home/vasya" | ldapadd -x \
   -D "cn=sysadm,dc=pupkin,dc=com,dc=ru" \
   -w zarazamelkaya \
   -h localhost -p 389

admin$ echo "dn: cn=petya,dc=pupkin,dc=com,dc=ru
objectClass: nisMailAlias
objectClass: posixAccount
cn: petya
uid: petya
uidNumber: 1001
gidNumber: 1000
gecos: Petya Pupkin
loginShell: /bin/bash
homeDirectory: /home/petya" | ldapadd -x \
   -D "cn=sysadm,dc=pupkin,dc=com,dc=ru" \
   -w zarazamelkaya \
   -h localhost -p 389

admin$ echo "dn: cn=katya,dc=pupkin,dc=com,dc=ru
objectClass: nisMailAlias
objectClass: posixAccount
cn: katya
uid: katya
uidNumber: 1001
gidNumber: 1000
gecos: Katya Pupkina
loginShell: /usr/bin/mc
homeDirectory: /export/home/katya" | ldapadd -x \
   -D "cn=sysadm,dc=pupkin,dc=com,dc=ru" \
   -w zarazamelkaya \
   -h localhost -p 389

Значения атрибутов с их привязкой к идентификаторам: uid==getenv("USER"), uidNumber==getuid(), gidNumber==getgid(), остальные поля понятны по названию. Тэк-с, пользователей мы создали - теперь создадим группу:

admin$ echo "dn: cn=pupkingroup,dc=pupkin,dc=com,dc=ru
objectClass: posixGroup
cn: pupkingroup
gidNumber: 1000
description: Primary group of Pupkin-COM-RU domain
memberUid: vasya
memberUid: petya
memberUid: katya" | ldapadd -x \
   -D "cn=sysadm,dc=pupkin,dc=com,dc=ru" \
   -w zarazamelkaya \
   -h localhost -p 389

И напоследок установим пароли для наших пользователей:

admin$ ldappasswd -x \
   -D "cn=sysadm,dc=pupkin,dc=com,dc=ru \"
   -w zarazamelkaya \
   -h localhost -p 389 -s SuperParol cn=vasya,dc=pupkin,dc=com,dc=ru

Вот и все, осталось проверить, что пользователь vasya может логиниться. По крайней мере, у меня он логинился с паролем SuperParol. Есть один немаловажный аспект, в данной статье не рассмотреный - это настройки безопасности и контроля доступа сервера LDAP - но это уже отдельная тема.

Настройка Samba

Прежде всего, выясним путь, по которому пойдет настройка Samba. Мы будем настраивать самбу на использование в режиме standalone-сервера, хранящего свою информацию в каталоге, обслуживаемом сервером OpenLDAP. В процессе настроек нам необходимо определить какие атрибуты будет использовать сервер samba из дерева каталогов, и как именно настроить OpenLDAP для работающей поддержки samba.

Файл схемы: в нем перечисляются необходимые для работы samba атрибуты и типы объектов для сервера OpenLDAP. Копируем файл, описывающий схему, используемую samba, в конфигурационный каталог OpenLDAP:

# cp /usr/share/doc/samba-3.0.28/LDAP/samba.schema /etc/openldap/schema/samba.schema

Скопированный файл указываем в настройках OpenLDAP, в этом же файле ограничиваем доступ к атрибутам, в которых сохраняется пароль пользователя:

# cat /etc/openldap/slapd.conf
include         /etc/openldap/schema/core.schema
include         /etc/openldap/schema/cosine.schema
include         /etc/openldap/schema/inetorgperson.schema
include         /etc/openldap/schema/nis.schema
include         /etc/openldap/schema/misc.schema
include         /etc/openldap/schema/samba.schema
[....]
access to attrs=sambaNTPassword by self write by * none
access to attrs=sambaLMPassword by self write by * none
access to attrs=userPassword by self write by * auth
access to * by peername=127.0.0.1 read by anonymous auth by users read

После внесения изменений делаем перезапуска сервера LDAP(!)

# service ldap restart

Описываем наш сервер LDAP в глобальной секции конфигурации Samba. Я не буду приводить полный файл конфигурации, поскольку он ну очень длинный, особенно если не сбрасывать комментарии:

# cat /etc/samba/smb.conf
[global]
{... пропустим то что не имеет отношения к LDAP ...}
ldap admin dn = "cn=root,dc=pupkin,dc=com,dc=ru"
ldap ssl = off
passdb backend = ldapsam:ldap://localhost
ldap delete dn = no
ldap suffix = dc=pupkin,dc=com,dc=ru
ldap filter = (&(uid=%u)(objectClass=sambaSamAccount))
{... пропустим то что не имеет отношения к LDAP ...}

Чтобы SAMBA могла "ходить" на сервер LDAP за информацией о паролях пользователей, необходимо сохранить пароль администратора сервера LDAP (или другого пользователя с достаточными правами) в файле secret.tdb . Сделать это можно примерно так:

# smbpasswd -w zarazamelkaya

Кроме того, нужно создать еще один объект в каталоге, отвечающий за представление сервера (в принципе, этого можно и не делать, тогда SAMBA сама создаст его аккурат в той ветви, которая обозначена как suffix в smb.conf). Я предпочитаю добавлять эту запись самостоятельно, чтобы она создалась в нужной мне ветви каталога. Добавить эту служебную запись можно воспользовавшись, например, командой ldapadd:

# echo "dn: sambaDomainName=MYSERVERNAME,dc=pupkin,dc=com,dc=ru
objectClass: sambaDomain
sambaDomainName: MYSERVERNAME
sambaSID: S-1-5-21-3905436772-1214432718-1934470886
sambaAlgorithmicRidBase: 1000" | \
	ldapadd -x -w zarazamelkaya \
	-D "cn=root,dc=pupkin,dc=com,dc=ru"

Стартуем сервер samba:

# service smb start

Финальная проверка

Ну вот, пришло время финального теста - заводим пользователя, меняем ему пароль используя smbpasswd и проверяем работоспособность. Пользовательский эккаунт будет образован сочетанием трех классов: AUXILIARY-классов sambaSamAccount (необходимые поля для Windows) и posixAccount - атрибуты, необходимые для сопоставления учетной записи идентификаторов пользователя и группы (uid и gid), а также STRUCTURAL-класса sambaSidEntry

# echo "dn: cn=serega,dc=pupkin,dc=com,dc=ru
objectClass: sambaSamAccount
objectClass: sambaSidEntry
objectClass: posixAccount
cn: serega
uid: serega
uidNumber: 1000
gidNumber: 1001
homeDirectory: /home/serega
sambaSID: S-1-5-21-3905436772-1214432718-19344733
" | \
	ldapadd -x -w zarazamelkaya \
	-D "cn=root,dc=pupkin,dc=com,dc=ru"

# smbpasswd serega SeryoginMegaParol
# smbclient -L MYSERVERNAME -U serega

Когда smbclient спросит у вас пароль пользователя serega, надо вспомнить, что мы его установили на предыдущем шаге в команде smbpasswd. С тем же паролем пользователь serega сможет зайти в систему, например, по SSH - если установить его учетной записи в LDAP атрибут loginShell. Если же вы хотите, чтобы пользователи не могли заходить на сервер, а использовали только ресурсы SAMBA - просто отключите PAM_LDAP в /etc/pam.d/system-auth, а также уберите слово ldap из всех строк в /etc/nsswitch.conf

Реализация домена на базе SAMBA и LDAP

Вкратце говоря, для реализации домена вам необходимо сделать то же самое, что при настройке samba в режиме standalone, за исключением следующих отличий: