OpenLDAP
Настройка OpenLDAP и его клиентов
Черновик
Рассматривается вопрос использования OpenLDAP для хранения информации о системе, как то:
- список пользователей и паролей
- список хостов, групп
- список пользователей Samba
- список пользователей Postfix (not implemented)
Авторы
- davinchi (davinchi@zu.org.ru или boldin.pavel@gmail.com)
- Anton Gorlov (gorlov@pnz.ru)
- Andrey Chesnokov (aacchhee@gmail.com)
Преамбула
Хотелось бы, чтобы перед прочтением этого руководства, Вы прочитали документацию по LDAP.
Этот документ будет находится в состоянии: «Непонятно для кого», пока не будет причесано кем-либо :)
По историческим причинам и личным пристрастиям мой домашний хост называется nirvana.home.
PAM_LDAP и NSS_LDAP
Аутентификация и информация о пользователях через openldap. Данные пакеты позволяют хранить информацию о пользователях (идентификатор, пароль, путь к домашней директории, любимый shell) в LDAP системе.
Преимуществом такого подхода является отсутствие необходимости синхронизировать кучу /etc/passwd и /etc/shadow файлов на различных машинах (которые, кстати, могут быть выключены в данный момент), минусы же известны — над этим необходимо работать, чему и посвящена эта часть статьи про openldap.
Установка пакетов
Начнем с приятного: все эти пакеты есть в ALM2.4 и Sisyphus.
Поэтому для их установки достаточно просто набрать:
client1 # apt-get install pam_ldap nss_ldap
и для сервера ldap
ldapserver # apt-get install openldap-servers
Настройка в openldap-server
Для начала вам надо настроить Ваш ldap-сервер, для этого:
- найдите файл /etc/openldap/slapd.conf и найдите в нём описание database
- поменяйте значение suffix на нечто более похожее на Ваше доменное имя, к примеру
suffix "dc=<youhostname>,dc=<youdomainname>"
или (у меня)
suffix "dc=nirvana,dc=home"
- Теперь поменяйте rootdn — это «отличительное имя» супер пользователя для этой базы. Супер пользователь может входить под своим dn, даже если каталога на порядок выше не существует. Поменяйте rootpw, это ваш секретный пароль (позже мы настроим sasl + krb5), если затрудняетесь с выбором пароля, используйте pwgen.
- Поменяйте также directory для данного «дерева» ldap:
directory /var/lib/ldap/bases/<Что Либо>
или у меня
directory /var/lib/ldap/bases/nirvana.home
Запустите slapd (# service slapd start). Указанные в конфигурационнном файле директории будут автоматически созданы с нужными правами доступа.
Если вы будете администрировать и обращаться к LDAP c другой машины, то проверьте, что LDAP слушает public interface:
[root@huygens sysconfig]# netstat -al | grep LISTEN tcp 0 0 *:ldap *:* LISTEN
По умолчанию в branch4.0 LDAP слушает только на loopback-интерфейсе без SSL. Нужно выбрать подходящую строку и её раскомментировать в файле /etc/sysconfig/ldap:
######################################## # SLAPD Proccess options ######################################## # SLAPD URL list #SLAPDURLLIST="ldap://localhost/" SLAPDURLLIST="'ldap://localhost/ ldaps:///'" #SLAPDURLLIST="'ldap:/// ldaps:///'" SLAPD_OPTIONS=""
После настройки шифрования стоит вернуться к этому файлу и убрать порты без SSL.
В branch4.0 после установки пакетов все логи ldap выводятся только на tty12. Если вы хотите иметь отдельный логфайл, то добавьте в /etc/syslog.conf следующее:
[root@huygens ~]# cat /etc/syslog.conf | grep ldap local4.* -/var/log/ldap/slapd.log
и перезапустите syslogd.
Теперь необходимо инициализировать наше дерево: Вот примерный файл newentry.ldif:
dn: dc=nirvana,dc=home objectClass: organization objectClass: dcObject dc: nirvana o: home dn: ou=People,dc=nirvana,dc=home objectClass: organizationalUnit ou: People
Вы должны заменить dc=nirvana, dc=home на ваш suffix (смотрите выше).
objectClass определяет класс добавляемого в дерево объекта, в данном случае это тип «организация» с параметром «o:» равным «home».
Второй кусок файла создает ветку, в которой будут хранится логины пользователей (не важно как Вы его назовете, но обычно это ou=People или ou=accounts).
теперь его необходимо «загнать» в ldap.
# ldapadd -x -f newentry.ldif -h 'хост на котором находится slapd' -D <ваш rootdn> -w <ваш rootpw>
вместо опции -w Вы можете использовать опцию -W и пароль будет запрошен на stdin (Для того чтобы выполнить эту команду должен быть установлен пакет openldap-clients, в состав которого входит ldapadd).
пример команды:
# ldapadd -x -f newentry.ldif -h localhost -D cn=admin,dc=nirvana,dc=home -w secret
вывод должен быть похожим на:
adding new entry "dc=nirvana, dc=home" adding new entry "ou=People,dc=nirvana,dc=home"
Теперь Вы можете создавать пользователей в этой ветке, используя gq, или мигрировать существующих из shadow/tcb используя migration-tools или их немного изменённую мною версию для чтения tcb (которая появится здесь немного позже
).
К примеру Вы выбрали второй путь. Если используется tcb, то необходимо сначала конвертировать из tcb в shadow с помощью утилиты tcb_unconvert из пакета tcb-utils. (не забывайте делать резервные копии)
# cd /usr/share/openldap/migration # edit migration_common.ph .... set $DEFAULT_BASE to you rootdn... # ./migrate_passwd.pl /etc/passwd > ~/accounts.ldif
при правильном завершении программы в accounts.ldif Вы получите LDIF для миграции пользователей в OpenLDAP.
Примечание Пароли пользователей хранятся в accounts.ldif в виде хэшей, однако этот файл нужно беречь от глаз посторонних людей.
Запустим его:
# ldapadd -f ~/accounts.ldif -h 'хост с slapd' -p 389 -x -D <ваш rootdn> -w <ваш rootpw>
или, если необходимо быстрее и безопаснее:
ldapserver# service slapd stop ldapserver# slapadd -b <ваш suffix> -l ~/accounts.ldif
Если все прошло успешно, все Ваши пользователи «перехали» в ldap.
Настройка Клиентов
Теперь время настроить клиенты nss_ldap и pam_ldap. В ALM2.4 эти пакеты используют один и тот же конфигурационный файл: /etc/ldap.conf (не путать с /etc/openldap/ldap.conf). В sisyphus — два различных файла: /etc/nss_ldap.conf и /etc/pam_ldap.conf
Разберем его построчно:
# Различительное имя Вашего дерева с пользователями # (или любой другой, в зависимости от того, где расположена используемая # ветка) base <suffix> # Universal Resource Identifier - место расположения Вашего ldap сервера # начинается с имени протокола, имеет форму <protocol>://<hostname>/ # где протокол либо ldap (для незашифрованного соединения), либо # ldaps (для соединения через SSL/TLS). (позже мы настроим второе) uri <uri to ldapserver> # Различительное имя, под которым происходит "анонимное" подключение (bind) # к ldap серверу, советую закомментировать эту строку - будет использовано # анонимное подключение binddn <DN to bind with> # Это очень небезопасная настройка - DN для подключения как root. # Практически не используется, может (и должно) быть отменено. # (используется только при вызове passwd <username> из-под root rootbinddn <dn to bind as root> # порт для подключения к ldap серверу, по умолчанию 389 для ldap, # или 636 для ldaps (может быть другим, если его использует Ваш ldap server) port <port number> # Область для поиска, одно из трех значений: # sub - включая дочерние сущности # base - только в данной сущности # one - только одну сущность ? scope <scope for search> #..... #некоторые параметры, которые могут быть оставлены без изменений #..... # некоторый фильтр для всех запрашиваемых логинов, этот фильтр будет совмещен # с uid=%s # при помощи этого, можно например использовать разрешение на логин к машине # (требует некоторого изменения схем в openldap) # например: # pam_filter allow_server_login=1 pam_filter <filter> # атрибут, содержащий логин пользователя, как правило uid # оставьте значение по умолчанию (в большинстве случаев) pam_login_attribute <login attribute> # для логина пользователь должен быть в группе groupname # пока мне не удалось заставить это работать. #pam_groupdn cn=<groupname>,ou=Groups,dc=nirvana,dc=home # аттрибут для pam_groupdn #pam_member_attribute # максимальный и минимальный uid # пользователя, который может логиниться через pam_ldap pam_min_uid <number> pam_max_uid <number> # это очень важный параметр, отвечающая за передачу пароля # от pam_ldap к openldap серверу. # может быть одной из следующих: clear crypt nds ad exop # по умолчанию _clear_, то есть пересылка пароля ведётся в чистом виде, # без шифрования или хэширования # ЕСЛИ ВЫ РАБОТАЕТЕ с OpenLDAP и использовали migration-tools # для миграции пользователей из tcb -- значит Вы можете использовать # crypt, что я Вам рекомендую, пока не настроен tls/ssl. pam_password <тип передачи пароля> # сообщение, которое выдается пользователю при попытке смена пароля # как правило содержит url, где его можно поменять или команду # (в случае с ldapv3 - kpasswd) pam_password_prohibit_message #............ # много настроек, которые мы сейчас не трогаем #............ # Эти три базовые настройки определяют сущность в директории, # в детях которой будут хранится соответствующие данные # nss_base_passwd - для аналога файла passwd # nss_base_shadow - для аналога файла shadow # nss_base_group - для аналогоа файла group nss_base_passwd ou=People,<suffix> nss_base_shadow ou=People,<suffix> nss_base_group ou=Group,<suffix> # Опции TLS/SSL # Смотрите в секции TLS/SSL #.....
или, Вы можете посмотреть мой конфигурационный файл: (комментарии удалены)
base dc=nirvana,dc=home uri ldaps://nirvana.home/ rootbinddn cn=admin,dc=nirvana,dc=home pam_filter objectclass=posixAccount pam_login_attribute uid pam_member_attribute memberUid pam_password crypt nss_base_passwd ou=People,dc=nirvana,dc=home nss_base_shadow ou=People,dc=nirvana,dc=home nss_base_group ou=Group,dc=nirvana,dc=home #ssl on #tls_checkpeer yes #tls_cacertfile /etc/openldap/ssl/cacert.pem
Настройка PAM для работы с pam_ldap
Настройка pam для pam_ldap очень проста — Вам надо лишь добавить строки, начинающиеся с '>' в файл /etc/pam.d/system-auth
#%PAM-1.0 > auth sufficient /lib/security/pam_ldap.so auth required pam_tcb.so shadow fork prefix=$2a$ count=8 nullok use_first_pass > account sufficient /lib/security/pam_ldap.so account required pam_tcb.so shadow fork use_first_pass password required pam_passwdqc.so min=disabled,24,12,8,7 max=40 passphrase=3 match=4 similar=deny random=42 enforce=users retry=3 > password sufficient /lib/security/pam_ldap.so use_authtok password required pam_tcb.so use_authtok shadow fork prefix=$2a$ count=8 write_to=tcb use_first_pass > session optional /lib/security/pam_ldap.so session required pam_tcb.so session required /lib/security/pam_mkhomedir.so skel=/etc/skel.ru_RU.KOI8-R/ umask=0077 session required pam_limits.so
, что создание домашних каталогов не работает с sshd из ALT Linux Master 2.4.
Возможно это будет работать (в Сизифе точно работает), если pam_mkhomedir вызывать на стадии account: > account required /lib/security/pam_mkhomedir.so skel=/etc/skel.ru_RU.KOI8-R/ umask=0077 Эта строка должна быть первой (!), если account-строк несколько .
Смотрите здесь.
Теперь Вам необходимо отдельно настроить sshd (из-за того что он использует pam_userpass) и xscreensaver (из-за того что он использует <PAMROOT>/system-auth-user_first_pass)
Файл /etc/pam.d/sshd
#%PAM-1.0 auth required pam_userpass.so > auth sufficient pam_ldap.so use_first_pass auth required pam_tcb.so shadow fork prefix=$2a$ count=8 nullok nodelay blank_nolog use_first_pass auth required pam_nologin.so account include system-auth password include system-auth session include system-auth
Файл /etc/pam.d/system-auth-use_first_pass
#%PAM-1.0 > auth sufficient /lib/security/pam_ldap.so use_first_pass auth required pam_tcb.so shadow fork prefix=$2a$ count=8 nullok use_first_pass > password sufficient /lib/security/pam_ldap.so use_first_pass password required pam_tcb.so use_authtok shadow fork prefix=$2a$ count=8 write_to=tcb
Смена паролей в ldap
Теперь сделаем то, из-за чего было столько страданий — изменение паролей в ldap. (Лично я делал все это ради одной только смены паролей.)
Замените Ваш /etc/pam.d/passwd на следующий файл.
#%PAM-1.0 auth sufficient /lib/security/pam_ldap.so account sufficient /lib/security/pam_ldap.so password required pam_passwdqc.so min=disabled,24,12,8,7 max=40 passphrase=3 match=4 similar=deny random=42 enforce=users retry=3 password sufficient /lib/security/pam_ldap.so
, что если Вы не указали rootbinddn в файле /etc/ldap.conf или не создали файл /etc/ldap.secret (в Sisyphus он называется pam_ldap.secret), содержащий пароль rootbinddn, то Вы не сможете менять пароли от пользователя root (вам придётся ввести пароль пользователя для этого). Однако, это не так страшно, если Вы используете ldapadd или gq для управления директорией с пользователями.
: если /etc/pam.d/passwd имеет следующий вид:
#%PAM-1.0 auth include system-auth account include system-auth password include system-auth session required pam_deny.so
то менять ничего не требуется — для изменения пароля будут использованы настройки, сделанные в /etc/pam.d/system-auth.
Использование nss_ldap
NSS — диспетчер имен, расширение для glibc, позволяющее резолвить имена из разных источников (files, dns, nis, nisplus, ldap).
Для того, чтобы заставить его работать с nss_ldap, необходимо изменить /etc/nsswitch.conf следующим образом. Замените обычные строки с passwd, shadow и group на эти.
#LDAP passwd: files ldap nisplus nis shadow: tcb ldap files nisplus nis group: files ldap nisplus nis
: Учтите, что если вы установите ldap в первым в списке, то некоторые статически слинкованные (rpm, sh, vi) программы будут выпадать с segfault.
Подробнее смотрите файл file:///usr/share/doc/nss_ldap-220/README.ALT
Проверка
Настало время проверить нашу систему.
Создайте тестового пользователя в ldap (у меня это был vasya pupkin :-)). (например, используя gq или ldapadd).
Теперь наберите: (# — от root, $ — от обычного пользователя)
0. $ ldapsearch -x -H 'ldap://<hostname>/' -d -1 1. # id vasya 2. # su - vasya 3. # ssh vasya@localhost 4. vasya$ id vasya 5. vasya$ stat . 6. vasya$ exit 7. # su - <user not in ldap> 8. user$ id vasya 9. user$ su - vasya 10. user$ ssh vasya@localhost
Теперь разберем:
если не работает 0: проверьте ваш '''acl''' лист и uri сервера если не работает 1: проверьте /etc/nsswitch.conf и строки, начинающиеся с nss_ в файле /etc/ldap.conf если не работает 2: проверьте наличие домашней директории vasya (если вы '''не''' добавили pam_mkhomedir), проверьте секцию сессии из pam.d/system-auth если не работает 3: проверьте наличие домашней директории vasya ('''даже''' если вы добавили pam_mkhomedir), иногда требуется перезапуск sshd, чтобы изменения вступили в силу (странно, да?) если не работает 4: проверьте может ли пользователь читать файлы /etc/ldap.conf и /etc/openldap/ldap.conf (а еще и сертификаты, если вы используете tls/ssl) если не работает 5: (чего быть не может) - проверьте что выдает он в полях owner и group. если не работает 6: :-). если не работает 7: :-). если не работает 8: смотрите 4. если не работает 9: проверьте /etc/nsswitch.conf и /etc/ldap.conf. если не работает 10: проверьте наличие домашней директории.
Если не работает что-то: проверьте, правильно ли указан uri сервера в /etc/ldap.conf, проверьте также acl лист для ldap сервера.
PAM_LDAP -> PAM_TCB
Однако, вот ваш ldap сервер «упал», а репликацию мы пока не настроили — в этом случае можно использовать pam_tcb (что и случится при выше указанных конфигах pam)
В этом вам поможет perl скрипт, показанный ниже (он, к несчастью, требует perl-ldap, что тянет за собой 15 Mb зависимостей — если для вас это не страшно (все равно perl кем-то еще используется — у нас — студентами)).
Используйте этот скрипт с осторожностью!
#!/usr/bin/perl # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA use Net::LDAP; use strict; my $TCB_ROOT = $ENV{TCB_ROOT}; my $PASSWD = $ENV{PASSWD}; my $BASEDN = $ENV{BASEDN}; my $FILTER = $ENV{FILTER}; my $BINDDN = $ENV{BINDDN}; my $PASSWORD = $ENV{PASSWORD}; my $URI = $ENV{URI}; my $VERIFY = $ENV{VERIFY}; my $CAFILE = $ENV{CAFILE}; my $MIN_UID_NUMBER = $ENV{MIN_UID_NUMBER}; my $MAX_UID_NUMBER = $ENV{MAX_UID_NUMBER}; $TCB_ROOT = "$ENV{HOME}/etc/tcb" if $TCB_ROOT eq ""; $PASSWD = "$ENV{HOME}/etc/passwd" if $PASSWD eq ""; $BASEDN = "dc=nirvana,dc=home" if $BASEDN eq ""; $BINDDN = "cn=tcb,$BASEDN" if $BINDDN eq ""; $URI = "ldap://ldap.server/" if $URI eq ""; $VERIFY = "never" if $VERIFY eq ""; $CAFILE = "/etc/openldap/ssl/cacert.pem" if $CAFILE eq ""; $MIN_UID_NUMBER = 500 if $MIN_UID_NUMBER eq ""; $MAX_UID_NUMBER = 65535 if $MAX_UID_NUMBER eq ""; my @passwd; my %shadow; sub getuid { my $name = $_[0]; my (undef, undef, $uid) = getpwnam($name); return $uid; } sub getgid { my $name = $_[0]; my (undef, undef, $gid) = getgrnam($name); return $gid; } sub add_passwd { my $e = $_[0]; my $pe; #password entry $pe = join(':', $e->get_value('uid'), 'x', $e->get_value('uidNumber'), $e->get_value('gidNumber'), $e->get_value('gecos'), $e->get_value('homeDirectory'), $e->get_value('loginshell')); # ???? $passwd[$#passwd + 1] = $pe; } sub add_shadow { my $e = $_[0]; my $se; my ($uid, $passwd); $uid = $e->get_value('uid'); $passwd = $e->get_value('userPassword'); return if($passwd !~ /{crypt}(.*)/i); $passwd = $1; $se = join(':', $uid, $passwd, $e->get_value('shadowLastChange')."", $e->get_value('shadowMin')."", $e->get_value('shadowMax')."", $e->get_value('shadowWarning')."", $e->get_value('shadowInactive')."", $e->get_value('shadowExpire')."", $e->get_value('shadowFlag').""); $shadow{$uid} = $se; } sub write_passwd { # PASSWD_FILE - is file for /etc/passwd entries open(PASSWD_TEMPLATE,"<$PASSWD") or die "Cannot open system users file"; my @ldappasswd = @passwd; @passwd = (); while(<PASSWD_TEMPLATE>) { my @entry; chomp; @entry = split /:/; next if $entry[2] == undef; if( $entry[2] < $MIN_UID_NUMBER or $entry[2] > $MAX_UID_NUMBER ) { @passwd = (@passwd, $_); } } close(PASSWD_TEMPLATE); # copy it @passwd = (@passwd, "", @ldappasswd); system("cp $PASSWD $PASSWD-"); open(PASSWD_FILE,">$PASSWD"); # print PASSWD_FILE "# LDAP users\n"; for my $var (@passwd) { print PASSWD_FILE "$var\n"; } close(PASSWD_FILE); if ( $< == 0 ) { chown getuid("root"), getgid("root"), $PASSWD; chmod 0644, $PASSWD; } } sub write_shadow { mkdir "$TCB_ROOT" if ( ! -d "$TCB_ROOT" ); if ( $< == 0 ) { chown getuid("root"), getgid("shadow"), $TCB_ROOT; chmod 0710, $TCB_ROOT; } foreach my $key (keys %shadow) { mkdir "$TCB_ROOT/$key" if ( ! -d "$TCB_ROOT/$key" ); open(TCB_FILE, ">$TCB_ROOT/$key/shadow"); print TCB_FILE $shadow{$key}."\n"; close(TCB_FILE); if ( $< == 0 ) { chown getuid($key), getgid("auth"), "$TCB_ROOT/$key"; chown getuid($key), getgid("auth"), "$TCB_ROOT/$key/shadow"; chmod 02710, "$TCB_ROOT/$key"; chmod 0640, "$TCB_ROOT/$key/shadow"; } } } my $ldap = Net::LDAP->new( $URI, verify => $VERIFY, cafile => $CAFILE ) or die "$@"; my $mesg = $ldap->bind( $BINDDN, password => $PASSWORD ) ; $mesg = $ldap->search( # perform a search base => "$BASEDN", filter => "(&(objectClass=posixAccount)$FILTER)", scope => 'sub' ); $mesg->code && die $mesg->error; #foreach $entry ($mesg->all_entries) { $entry->dump; } foreach my $entry ( $mesg->entries) { my $uid = $entry->get_value('uidNumber' ); if( $uid >= $MIN_UID_NUMBER && $uid <= $MAX_UID_NUMBER) { add_passwd($entry); add_shadow($entry); } } $mesg = $ldap->unbind; # take down session write_passwd(); write_shadow();
Безопасность
Корректный ACL
В нашем ACL должно быть: 1. разрешение на запись для админов 2. разрешение на чтения для публичных полей (loginShell, gecos, cn, uid) 3. запрет на чтение userPassword для остальных 4. разрешение на запись в userPassword, loginShell, gecos для пользователя 5. разрешение на чтение всех полей для пользователя TCB (смотрите скрипт выше)
Вот Вам примерный ACL: замените <YOUR ADMIN DN> на Ваш DN в директории (у меня это uid=davinchi, ou=People, dc=vnet1)
access to attr=cn,givenName,sn,gecos by dn="^<YOUR ADMIN DN>$" write by self write by users read access to attr=loginShell,gecos by dn="^<YOUR ADMIN DN>$" write by self write by * read access to attr=userPassword by dn="^<YOUR ADMIN DN>$" write by anonymous auth by self write by * none # The admin dn has full write access access to * by dn="^<YOUR ADMIN DN>$" write by * read
Настройка шифрования (TLS)
Если вам захотелось хоть немного безопасности, и клиенты LDAP’а живут не на одной машинке с самим сервером (что очень вероятно) -то вам придётся открывать доступ к LDAP’у «снаружи», то есть из локальной сети или (мало ли что) даже из всемирной паутины (это может понадобится для хранения профилей почтовиков в LDAP) и вы боитесь что ваш трафик к ldap (хеши паролей, логины или ещё что-то.) засниферят (или более просто говоря -позаимствуют без вашего ведома) — то вам несколько поможет использование шифрования.
Вот об этом мне и хотелось бы с вами поделиться. Итак — приступим. Все действия я проводил на базе ALT LINUX MASTER 2.4.
Что там понадобится из пакетов:
[stalker@ring stalker]$ rpm -qa | grep ssl openssl-0.9.7d-alt1 libssl-0.9.7d-alt1
Сначала нам предстоит сгенерировать сертификаты и ключи. Я для этих целей воспользовался скриптом CA.pl из пакета openssl-0.9.7d-alt1.
В /var/lib/ssl/misc лежит перловый скрипт CA.pl для генерации сертификатов, последовательность команд следующая
cd /etc/openldap/ /var/lib/ssl/misc/CA.pl -newca
Как всё это выглядит
Для начала проверим что тот сервер, на котором крутится ldap готов к работе.
[stalker@fs stalker]$ nslookup ring.local Note: nslookup is deprecated and may be removed from future releases. Consider using the `dig' or `host' programs instead. Run nslookup with the `-sil[ent]' option to prevent this message from appearing. Server: 192.168.1.1 Address: 192.168.1.1#53 Name: ring.local Address: 192.168.1.111
Такую же картину мы должны наблюдать на всех клиентах ldap-сервера. И при создании сертификатов в качестве Common Name надо будет указывать «ring.local» и такое же имя на всех клиентах ldap-сервера для обращения к серверу. То есть никаких IP 192.168.1.111 в настройках остаться не должно. Вместо него должно присутствовать ring.local. Иначе вы получите «CN сертификата не совпадает с именем хоста», это также пожет проявится при подключении через SASL/KRB5.
Generating a 1024 bit RSA private key ...........++++++ .....++++++ writing new private key to './demoCA/private/cakey.pem' Enter PEM pass phrase:<sobakazlaya:)> Verifying - Enter PEM pass phrase:<sobakazlaya> ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:ru State or Province Name (full name) [Some-State]:Privolzhskiy Region Locality Name (eg, city) []:Penza Organization Name (eg, company) [Internet Widgits Pty Ltd]:MyveryCOOLwork Organizational Unit Name (eg, section) []:SysAdmin Common Name (eg, your name or your server's hostname) []:ring.local Email Address []:root@ring.local
Выше мы делали nslookup ring.local, так вот: в Common Name у вас должно стоять тоже самое и LDAP должен висеть на том ip-адресе, который вам вернул nslookup.
Результат: Получаем директорию demoCA в нем нам нужен будет файл cacert.pem
openssl req -new -nodes -keyout newreq.pem -out newreq.pem
Как это выглядит
[root@ring.local openldap]# openssl req -new -nodes -keyout newreq.pem -out newreq.pem Generating a 1024 bit RSA private key .................++++++ .....++++++ writing new private key to 'newreq.pem' ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:ru State or Province Name (full name) [Some-State]:Privolzhskiy Region Locality Name (eg, city) []:Penza Organization Name (eg, company) [Internet Widgits Pty Ltd]:MyveryCOOLwork Organizational Unit Name (eg, section) []:SysAdmin Common Name (eg, your name or your server's hostname) []:ring.local Email Address []:root@ring.local Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []:<здесь нужно просто нажать enter> An optional company name []:MyveryCOOLwork
Результат: Получаем newreq.pem
/var/lib/ssl/misc/CA.pl -sign
Как это выглядит
[root@ring.local openldap]# /var/lib/ssl/misc/CA.pl -sign Using configuration from /var/lib/ssl/openssl.cnf 26354:error:0E06D06C:configuration file routines:NCONF_get_string:no value:conf_lib.c:329:group=CA_default name=unique_subject Enter pass phrase for ./demoCA/private/cakey.pem:<вводим наш первый пароль, самый длинный и секретный> Check that the request matches the signature Signature ok Certificate Details: Serial Number: 1 (0x1) Validity Not Before: Mar 15 12:33:44 2005 GMT Not After : Mar 15 12:33:44 2006 GMT Subject: countryName = ru stateOrProvinceName = Privolzhskiy Region localityName = Penza organizationName = MyveryCOOLwork organizationalUnitName = SysAdmin commonName = ring.local emailAddress = root@ring.local X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: <набор цифорок и буковок> X509v3 Authority Key Identifier: <и опять цифорки и буковки> DirName:/C=ru/ST=Privolzhskiy Region/L=Penza/O=MyveryCOOLwork/OU=root/CN=ring.local/emailAddress=root@ring.local serial:00 Certificate is to be certified until Mar 15 12:33:44 2006 GMT (365 days) Sign the certificate? [y/n]:y 1 out of 1 certificate requests certified, commit? [y/n]y Write out database with 1 new entries Data Base Updated Signed certificate is in newcert.pem
Результат: Подписываем newreq.pem, используя demoCA, и получаем newcert.pem
cd /etc/openldap mkdir ssl cp demoCA/cacert.pem ssl cp newreq.pem ssl/key.pem cp newcert.pem ssl/crt.pem
Можно еще и с правами помутить. Ну это на ваше усмотрение, но коли упрут сертификаты, будет плохо.
На сервере.
Примечания для пользователей Sisyphus
В Пакете openldap из Sisyphus (версий до 2.2.26, кажется) есть баг с неполным chroot: не копируются библиотеки libgssapi и другие, используемые sasl.
Быстрое решение: скопировать эти библиотеки вручную в каталог /var/lib/ldap/lib
Правильное решение: обновить пакет.
Изменения в slapd.conf
Надо добавить следующие строки
TLSCipherSuite HIGH:MEDIUM:+SSLv2 TLSCertificateFile /etc/openldap/ssl/crt.pem TLSCertificateKeyFile /etc/openldap/ssl/key.pem TLSCACertificateFile /etc/openldap/ssl/cacert.pem TLSVerifyClient never
Будьте внимательны и не перепутайте, где чего надо прописать, а то при service slapd start, slapd просто не будет запускаться.
Изменения в ldap.conf из пакета openldap
Надо внести следующую строчку в /etc/openldap/ldap.conf
TLS_CACERT /etc/openldap/ssl/cacert.pem
И изменить ldap на ldaps в URI.
Далее необходимо заставить ldap слушать секурный порт на внешнем адресе, ну и несекурный оставим только для ответов на 127.0.0.1 Для этого идём в /etc/sysconfig и правим там файл «ldap»
было:
######################################## # SLAPD Proccess options ######################################## # SLAPD URL list SLAPDURLLIST="ldap://localhost/" #SLAPDURLLIST="ldap://localhost/ ldaps:///" #SLAPDURLLIST="ldap:/// ldaps:///" SLAPD_OPTIONS="" ######################################## # SLURPD Proccess options ######################################## SLURPD_OPTIONS='-t /var/lib/ldap'
А надо:
######################################## # SLAPD Proccess options ######################################## # SLAPD URL list #SLAPDURLLIST="ldap://localhost/" SLAPDURLLIST='"ldap://localhost/ ldaps:///"' #SLAPDURLLIST='"ldap://localhost/ ldap:///"' #SLAPDURLLIST="ldap:/// ldaps:///" SLAPD_OPTIONS="" ######################################## # SLURPD Proccess options ######################################## SLURPD_OPTIONS='-t /var/lib/ldap'
Дополнение:
SLAPDURLLIST='"ldap://localhost/ ldaps:///"' -- это ' (апостроф кажется) +" (кавычки)ldap://localhost/ ldaps:///" (кавычки)+' (апостроф кажется)
Проверка работостособности Выполняем.
[root@ring sysconfig]# netstat -nap | grep slapd
Результат должен быть приблизительно следующим
[root@ring sysconfig]# netstat -nap | grep slapd tcp 0 0 127.0.0.1:389 0.0.0.0:* LISTEN 8395/slapd tcp 0 0 0.0.0.0:636 0.0.0.0:* LISTEN
Так же
[root@ring.local openldap]# openssl s_client -connect ring.local:636 -showcerts -state -CAfile /etc/openldap/ssl/cacert.pem
Результат должен быть приблизительно следующим
openssl s_client -connect ring.local:636 -showcerts -state -CAfile /etc/openldap/ssl/cacert.pem CONNECTED(00000003) SSL_connect:before/connect initialization SSL_connect:SSLv2/v3 write client hello A SSL_connect:SSLv3 read server hello A depth=1 /C=ru/ST=Privolzhskiy Region/L=Penza/O=RCC/OU=root/CN=ring.local/emailAddress=root@ring.local verify return:1 depth=0 /C=ru/ST=Privolzhskiy Region/L=Penza/O=RCC/OU=root/CN=ring.local/emailAddress=root@ring.local verify return:1 SSL_connect:SSLv3 read server certificate A SSL_connect:SSLv3 read server done A SSL_connect:SSLv3 write client key exchange A SSL_connect:SSLv3 write change cipher spec A SSL_connect:SSLv3 write finished A SSL_connect:SSLv3 flush data SSL_connect:SSLv3 read finished A --- Certificate chain 0 s:/C=ru/ST=Privolzhskiy Region/L=Penza/O=RCC/OU=root/CN=ring.local/emailAddress=root@ring.local i:/C=ru/ST=Privolzhskiy Region/L=Penza/O=RCC/OU=root/CN=ring.local/emailAddress=root@ring.local <кусь> -----BEGIN CERTIFICATE----- <кусь> -----END CERTIFICATE----- --- Server certificate subject=/C=ru/ST=Privolzhskiy Region/L=Penza/O=RCC/OU=root/CN=ring.local/emailAddress=root@ring.local issuer=/C=ru/ST=Privolzhskiy Region/L=Penza/O=RCC/OU=root/CN=ring.local/emailAddress=root@ring.local <и тута типа кусь> --- No client certificate CA names sent --- SSL handshake has read 971 bytes and written 346 bytes --- New, TLSv1/SSLv3, Cipher is AES256-SHA Server public key is 1024 bit SSL-Session: Protocol : TLSv1 Cipher : AES256-SHA Session-ID: 8CB1768A5F90E71FDA7D0CBF47003E36AE9E12643BC35378132DDB111EC1C852 Session-ID-ctx: Master-Key: 996B7555686CDA1142B83CA67BE43C46F6EDCC6567713C00E42F4ECAAD1BAC7EABDE4BB0E7D04C5C72165AB253658498 Key-Arg : None Start Time: 1110890913 Timeout : 300 (sec) Verify return code: 21 (unable to verify the first certificate) ---
Изменения в ldap.conf из пакета nss_ldap В ldap.conf из nss_ldap лежащем в /etc
base dc=ring,dc=local uri ldaps://ring.local/ ssl on tls_cacertfile /etc/openldap/certs/cacert.pem
Лучше всего добавить
tls_checkpeer yes
после
ssl on
это приведет к жесткой проверке сертификата сервера (и исключит man-in-middle атаку).
Изменения в ldap.conf тот что в /etc/openldap Учтите -что если у вас на клиентах не стоит openldap-server то вам придётся руками создать в /etc папку openldap. Создать там файл ldap.conf.
(БП: Странно, rpm -qf /etc/openldap/ldap.conf => openldap-clients)
-rw-r--r-- 1 root root 333 Apr 25 10:59 ldap.conf
Вот что в этом файле на клиентских машинах:
URI ldaps://ring.local TLS_CACERT /etc/openldap/ssl/cacert.pem
Насчёт прав не забывайте — простой пользователь должен иметь возможность читать cacert, иначе при любом вызове nss_ldap вы получите «нет такого пользователя».
[root@ring.local openldap]# ls -la ./ssl total 12 drwxr-xr-x 2 ldap ldap 51 Apr 21 11:32 . drwxr-xr-x 6 root root 140 Apr 21 12:43 .. -rw-r--r-- 2 ldap ldap 1265 Apr 21 11:31 cacert.pem -rw-r----- 2 ldap ldap 3628 Apr 21 11:32 crt.pem -rw-r----- 2 ldap ldap 1587 Apr 21 11:32 key.pem
SAMBA PDC+LDAP+TLS
Здесь мне хотелось бы рассказать как заставить самбу брать данные из LDAP+использовать при этом шифрование.
Для начала хотелось бы напомнить: самба 3 требует, что бы пользователи резолвились в системе. Для этого в данном случае должен быть настроен NSS_LDAP (см выше). Так же не забывайте про /etc/openldap/ldap.conf на клиентских машинах. Напомню, что если его нет (а его и не будет, если LDAP сервер не стоит на этой машине) — то вам нужно будет создать соответствующий каталог+файл, и пользователь (любой) должен иметь возможность прочитать содержимое файла /etc/openldap/ldap.conf и CA-сертефикат.
Предположим что nss_ldap у вас работает, пользователь может залогиниться в систему (например). Итак приступим к танцам. Вот вырезка из работающего конфига:
encrypt passwords = yes unix password sync = no # Настройки для LDAP # #(куда стучаться. Не забывайте указывать именно имя хоста, а не его IP-адрес -иначе не пройдёт проверка сертификатов и LDAP не пустит #самбу к себе) passdb backend = ldapsam:ldaps://ring.local ldap ssl = off ldap admin dn = "cn=admin,dc=MyveryCOOLwork" # суффикс ldap suffix = dc=MyveryCOOLwork #Задаём юзера, который имеет право на подключение клиентских машин к домену. admin users = zombie # Здесь задаётся от чьего имени SAMBA будет коннектиться к лдапу. ldap admin dn = "cn=admin,dc=MyveryCOOLwork" # ветка, где будет храниться информацию о пользователях ldap user suffix = ou=Users # ветка, где будет храниться информацию о группах ldap group suffix = ou=Groups # ветка, где будет храниться информацию о компьютерах, подключенных к домену ldap machine suffix = ou=Computers ldap delete dn = no # фильтр, что бы авторизоваться могли только имеющие uid. А не всякий мусор. ldap filter = (uid=%u) # При смене пароля юзером через smbpasswd меняем его и в LDAP ;-) ldap passwd sync = yes # set local master to no if you don't want Samba to become a master # browser on your network. Otherwise the normal election rules apply local master = yes # Preferred Master causes Samba to force a local browser election on startup # and gives it a slightly higher chance of winning the election preferred master = yes # 6. Domain Control Options: # Enable this if you want Samba to be a domain logon server for # Windows95 workstations or Primary Domain Controller for WinNT and Win2k domain logons = yes # The add user script is used by a domain member to add local user accounts # that have been authenticated by the domain controller, or by the domain # controller to add local machine accounts when adding machines to the domain. # The script must work from the command line when replacing the macros, # or the operation will fail. Check that groups exist if forcing a group. # Script for domain controller for adding machines: add machine script = /usr/sbin/smbldap-useradd -w %u # Script for domain member for adding local accounts for authenticated users: add user script = /usr/local/sbin/smbldap-useradd -m %u [homes] comment = Home Directory for '%u' browseable = no writable = yes # Un-comment the following and create the netlogon directory for Domain Logons [netlogon] comment = Network Logon Service browseable = no path = /var/lib/samba/netlogon guest ok = yes writable = yes # Un-comment the following to provide a specific roving profile share # the default is to use the user's home directory [Profiles] path= /profiles # path = /var/lib/samba/profiles # path = /home/%U # browseable = yes guest ok = no writable = yes
После этого делаем smbpasswd -w админский пароль для доступа в LDAP.
В принципе всё работает. С помощью smbpasswd пользователь теперь может изменить свой пароль….
Для работы SAMBA использует следующие атрибуты в lDAP’е:
homeDirectory loginShell sambaAcctFlags sambaHomeDrive sambaHomePath sambaKickoffTime sambaLMPassword sambaLogoffTime sambaLogonTime sambaNTPassword sambaPasswordHistory sambaPrimaryGroupSID sambaProfilePath sambaPwdCanChange sambaPwdLastSet sambaSID uid uidNumber userPassword
Не забывайте — это должен быть POSIX ACCOUNT!
И ещё о значении нескольких параметров на примере.
homeDirectory : /home/anton sambaHomeDrive : R: sambaHomePath : \\ring.local\anton sambaProfilePath : \\ring.local\profiles\anton
В результате профили пользователя будут лежать в /profiles/username В качестве диска R: (сетевой) будет монтироваться домашний каталог пользователя /home/anton (не забывайте что sambaHomePat — это UNC путь.) Здесь нужно задавать NETBIOS NAME компьютера, где всё это планируется располагать. В данном случае я всё расположил на локальной машинке с LDAP.
Squid+LDAP+TLS
настройка прокси-сервере squid для работы с openldap-сервером достаточно простая. Приведу пример настройки..думаю там будет всё более-менее понятно
cat /etc/squid/squid.conf |grep ldap
auth_param basic program /usr/lib/squid/squid_ldap_auth -P -b dc=nirvana,dc=home -f (uid=%s) -H "ldaps://ring.local" -v 3 -p 636 external_acl_type ldap_group %LOGIN /usr/lib/squid/squid_ldap_group -P -b dc=nirvana,dc=home -f (&(memberUid=%v)(cn=%a)) -H "ldaps://ring.local" -v 3 -p 636 acl users external ldap_group squiduser .... #myACL acl users external ldap_group squiduser http_access allow users
При этом юзер должен входить в группу squiduser в LDAP:
dn:cn=squiduser,ou=Groups,dc=nirvana,dc=home objectClass: posixGroup cn: squiduser gidNumber: 10007 memberUid: proxyuser memberUid: proxyuser2 ...
Если что-то не работает при настройке врукопашную
Краткий чеклист (для ALT Server 9.2 (FalcoRusticolus)), если что-то не работает, а в журнал systemd льётся всякая ерунда типа такой:
sshd[9798]: pam_tcb(sshd:auth): crypt_ra: Invalid argument
Или такой:
янв 13 22:49:04 sekibanki audit[10042]: USER_ACCT pid=10042 uid=0 auid=0 ses=4 msg='op=PAM:accounting grantors=? acct="user" exe="/bin/su" hostname=localhost addr=127.0.0.1 terminal=/dev/pts/1 res=failed' янв 13 22:49:04 sekibanki kernel: audit: type=1101 audit(1642103344.059:491): pid=10042 uid=0 auid=0 ses=4 msg='op=PAM:accounting grantors=? acct="user" exe="/bin/su" hostname=localhost addr=127.0.0.1 terminal=/dev/pts/1 res=failed'
Или такой:
янв 13 22:50:43 sekibanki sshd[10057]: pam_tcb(sshd:auth): Credentials for user user unknown янв 13 22:50:43 sekibanki sshd[10054]: pam_tcb(sshd:auth): Authentication failed for UNKNOWN USER from (uid=0) янв 13 22:50:43 sekibanki audit[10054]: USER_AUTH pid=10054 uid=0 auid=4294967295 ses=4294967295 msg='op=PAM:authentication grantors=? acct="user" exe="/usr/sbin/sshd" hostname=127.0.0.1 addr=127.0.0.1 terminal=ssh res=failed' янв 13 22:50:43 sekibanki kernel: audit: type=1100 audit(1642103443.012:498): pid=10054 uid=0 auid=4294967295 ses=4294967295 msg='op=PAM:authentication grantors=? acct="user" exe="/usr/sbin/sshd" hostname=127.0.0.1 addr=127.0.0.1 terminal=ssh res=failed' янв 13 22:50:45 sekibanki sshd[10054]: Failed password for user from 127.0.0.1 port 36872 ssh2 янв 13 22:50:45 sekibanki audit[10054]: USER_LOGIN pid=10054 uid=0 auid=4294967295 ses=4294967295 msg='op=login acct="user" exe="/usr/sbin/sshd" hostname=? addr=127.0.0.1 terminal=sshd res=failed' янв 13 22:50:45 sekibanki kernel: audit: type=1112 audit(1642103445.431:499): pid=10054 uid=0 auid=4294967295 ses=4294967295 msg='op=login acct="user" exe="/usr/sbin/sshd" hostname=? addr=127.0.0.1 terminal=sshd res=failed'
Следует проверить следующее:
1. Сделаны ли симлинки на соответствующие PAM-сценарии? Например:
cd /etc/pam ln -fs system-auth-ldap system-auth ln -fs system-auth-use_first_pass-ldap system-auth-use_first_pass
2. Если используется TCB, то упомянуто ли это в nsswitch.conf? То есть:
shadow: tcb files ldap
Ссылки
- Инструкции по настройке аутентификации с помощью LDAP
Централизованная схема управления сетью с использованием OpenLDAP- Общие сведения об LDAP на *NIXP.ru
- Рассылка по OpenLDAP
- OpenLDAP backends