OpenLDAP

Материал из ALT Linux Wiki
Freesource-logo.png Blue Glass Arrow.svg MediaWiki logo.png
Эта страница была перемещена с freesource.info.
Эта страница наверняка требует чистки и улучшения — смело правьте разметку и ссылки.
Просьба по окончанию убрать этот шаблон со страницы.


Настройка 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-сервер, для этого:

  1. найдите файл /etc/openldap/slapd.conf и найдите в нём описание database
  2. поменяйте значение suffix на нечто более похожее на Ваше доменное имя, к примеру
suffix "dc=<youhostname>,dc=<youdomainname>"

или (у меня)

suffix "dc=nirvana,dc=home"
  1. Теперь поменяйте rootdn — это «отличительное имя» супер пользователя для этой базы. Супер пользователь может входить под своим dn, даже если каталога на порядок выше не существует. Поменяйте rootpw, это ваш секретный пароль (позже мы настроим sasl + krb5), если затрудняетесь с выбором пароля, используйте pwgen.
  2. Поменяйте также 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
Обратите внимание — Common Name == ring.local

Результат: Получаем 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

48px-Mail-mark-junk red.svg.png
Эта статья конкретно протухла.
Статья уже не подходит под современные реалии, под современные версии Альта или сломана совсем. Возможно, её уже не доработать и не поместить в архив.


Здесь мне хотелось бы рассказать как заставить самбу брать данные из 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
...

Если что-то не работает при настройке врукопашную

Примечание: Сперва стоит обратить внимание на control system-auth list и саму утилиту control


Краткий чеклист (для 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

Ссылки