9. Kerberos KDC с использованием OpenLDAP в качестве бэкэнда и аутентификацией SASL GSSAPI

В этом разделе мы научимся использовать OpenLDAP 2.4 в качестве хранилища принципалов (principals) Kerberos и разберем, как настраивать клиентские рабочие станции. Kerberos — это сетевой протокол, который работает на основе билетов (tickets) и позволяет передавать данные через незащищённые сети для безопасной идентификации и аутентификации. Его дизайн преимущественно опирается на клиент-серверную модель и позволяет произвести взаимную аутентификацию субъекта и объекта доступа. Сообщения протокола устойчивы к прослушиванию и атакам повтора. Kerberos работает на основе криптографии с симметричным ключом и требует наличия доверенной третьей стороны, а так же может применяться с использованием криптографии с открытым ключом на некоторых этапах процесса аутентификации.

В этом руководстве в роли сервера Kerberos будем использовать ldap-srv. Но ничто не мешает Вам использовать для этого отдельную машину.

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

Где работаем: ldap-srv

Включите NTP и убедитесь, что сервер и клиенты синхронизированы! Мы не будем описывать, как настраивать NTP. Вы можете найти множество примеров в сети, если потребуется.

Теперь, когда наш сервер OpenLDAP настроен, мы можем приступить к конфигурированию сервера Kerberos. В этом разделе мы опишем, как развернуть центр распределения ключей Kerberos (KDC, Key Distribution Center) для области (realm) EXAMPLE.COM. Начнём с установки необходимых пакетов. В процессе будет так же установлено несколько пакетов-зависимостей. Пакет wamerican создаст файл /usr/share/dict/words, используемый kadmind. Вместо него можно использовать любой другой словарь или несколько словарей. Чтобы посмотреть их список, посмотрите содержимое метапакета wordlist.

#  apt-get install krb5-kdc krb5-pkinit krb5-admin-server wamerican libsasl2-modules-gssapi-mit

В разделе 2.5 мы уже установили схему Kerberos для OpenLDAP сервера, но давайте лишний раз убедимся, что она на месте:

#  ldapsearch -QLLLY EXTERNAL -H ldapi:/// -b cn=schema,cn=config dn | grep -i kerberos
dn: cn={12}kerberos,cn=schema,cn=config

Схема на месте. В ней содержится достаточно много объектов. Чтобы посмотреть их все, используйте следующий запрос:

#  ldapsearch -QLLLY EXTERNAL -H ldapi:/// -b cn={12}kerberos,cn=schema,cn=config | grep NAME | cut -d' ' -f5 | sort

Эта команда должна вернуть список объектов. Это важно, потому что если новых атрибутов Kerberos LDAP нет, то kdb5_ldap_util(8) выдаст следующую ошибку:

kdb5_ldap_util: Kerberos Container create FAILED: No such object while creating realm 'EXAMPLE.COM'

Итак, у нас есть набор схемы данных и объекты. Но есть ли у нас контейнер для принципалов Kerberos?

#  ldapsearch -QLLLY EXTERNAL -H ldapi:/// -b ou=services,dc=example,dc=com dn | grep -i kerberos

Нет, нету. Создадим его, а заодно — пользователя и группу, которые будут использоваться Kerberos для взаимодействия с сервером OpenLDAP. Используем для этой цели вот такой LDIF-файл 9.1-kerberos.ldif:

# Создадим контейнер для Kerberos
dn: cn=kerberos,ou=services,dc=example,dc=com
cn: kerberos
objectClass: top
objectClass: krbContainer

# Добавим группу krbadmin
dn: cn=krbadmin,ou=groups,dc=example,dc=com
objectClass: top
objectClass: posixGroup
cn: krbadmin
gidNumber: 800
description: Kerberos administrator's group.

# Добавим пользователя krbadmin
dn: cn=krbadmin,ou=users,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: posixAccount
objectClass: top
cn: krbadmin
givenName: Kerberos Administrator
mail: kerberos.admin@example.com
sn: krbadmin
uid: krbadmin
uidNumber: 800
gidNumber: 800
homeDirectory: /home/krbadmin
loginShell: /bin/false
displayname: Kerberos Administrator

Загрузим этот файл в базу данных нашего сервера каталогов:

$  ldapadd -xZZWD cn=admin,dc=example,dc=com -f ~/ldap/9.1-kerberos.ldif
Enter LDAP Password:
adding new entry "cn=kerberos,ou=services,dc=example,dc=com"
adding new entry "cn=krbadmin,ou=groups,dc=example,dc=com"
adding new entry "cn=krbadmin,ou=users,dc=example,dc=com"

Зададим пароль для пользователя krbadmin. Сохраните пароль в надежном месте (например, используя keepass или gpg).

$  ldappasswd -xZZWSD "cn=admin,dc=example,dc=com" "cn=krbadmin,ou=users,dc=example,dc=com"

Создадим конфигурационный файл Kerberos /etc/krb5.conf:

[logging]
 default = SYSLOG:INFO:LOCAL1
 kdc = SYSLOG:NOTICE:LOCAL1
 admin_server = SYSLOG:WARNING:LOCAL1

[libdefaults]
 default_realm = EXAMPLE.COM
 dns_lookup_realm = false
 dns_lookup_kdc = false
 ticket_lifetime = 24h
 renew_lifetime = 7d
 forwardable = true

[realms]
 EXAMPLE.COM = {
  kdc = ldap-srv.example.com
  admin_server = ldap-srv.example.com
  default_domain = example.com
  database_module = openldap_ldapconf
 }

[domain_realm]
 .example.com = EXAMPLE.COM
 example.com = EXAMPLE.COM

[appdefaults]
 pam = {
  debug = false
  ticket_lifetime = 36000
  renew_lifetime = 36000
  forwardable = true
  krb4_convert = false
 }

[dbmodules]
 openldap_ldapconf = {
  db_library = kldap
  ldap_kerberos_container_dn = cn=kerberos,ou=services,dc=example,dc=com
  ldap_kdc_dn = cn=krbadmin,ou=users,dc=example,dc=com
   # этот объект должен иметь права на чтение контейнера области,
   # контейнера принципала и поддеревьев области
  ldap_kadmind_dn = cn=krbadmin,ou=users,dc=example,dc=com
   # этот объект должен иметь права на чтение контейнера области,
   # контейнера принципала и поддеревьев области
  ldap_service_password_file = /etc/krb5.d/stash.keyfile
  ldap_servers = ldapi:///
  ldap_conns_per_server = 5
 }

Теперь создадим список контроля доступа (ACL) администратора Kerberos. Не путайте этот ACL с ACL OpenLDAP. Это не одно и то же. Чуть ниже мы поработаем с ACL для OpenLDAP. Создадим файл /etc/krb5kdc/kadm5.acl с таким содержимым:

*/admin@EXAMPLE.COM *

Отредактируем /etc/krb5kdc/kdc.conf, конфигурационный файл службы аутентификации (AS, Authentication Service) и центра распределения ключей (KDC):

[kdcdefaults]
 kdc_ports = 88
 kdc_tcp_ports = 88

[realms]
 EXAMPLE.COM = {
  #master_key_type = aes256-cts
  acl_file = /etc/krb5kdc/kadm5.acl
  dict_file = /usr/share/dict/words
  admin_keytab = /etc/krb5kdc/kadm5.keytab
  supported_enctypes = aes256-cts:normal aes128-cts:normal des3-hmac-sha1:normal arcfour-hmac:normal des-hmac-sha1:normal des-cbc-md5:normal des-cbc-crc:normal
 }

В отдельном терминале включите просмотр журнала сервера OpenLDAP. Так мы сможем увидеть сообщения, генерируемые командой kdb5_ldap_util(8):

#  tail -F /var/log/slapd.log

Создайте каталог-тайник для пароля. В файле /etc/krb5.conf он указан в переменной ldap_service_password_file:

#  mkdir /etc/krb5.d
#  chmod u=rwx,g=,o= /etc/krb5.d

Извлеките пароль пользователя cn=krbadmin,ou=users,dc=example,dc=com, используя kdb5_ldap_util(8):

#  kdb5_ldap_util -D "cn=admin,dc=example,dc=com" stashsrvpw -f /etc/krb5.d/stash.keyfile cn=krbadmin,ou=users,dc=example,dc=com

Вам будет предложено ввести мастер-пароль базы данных. Очень важно, чтобы Вы НЕ ЗАБЫЛИ этот пароль!

В основном терминале выполните следующую команду для добавления записей Kerberos в базу данных OpenLDAP:

#  kdb5_ldap_util -D "cn=admin,dc=example,dc=com" create -subtrees "cn=kerberos,ou=services,dc=example,dc=com" -r EXAMPLE.COM -s

Вышеуказанная команда создаст несколько записей в cn=kerberos,ou=services,dc=example,dc=com. Чтобы увидеть их, выполните запрос:

#  ldapsearch -QLLLY EXTERNAL -H ldapi:/// -b cn=kerberos,ou=services,dc=example,dc=com dn

Но может ли кто-нибудь кроме пользователя cn=admin увидеть нашу информацию Kerberos? Это было-бы не очень мудро. Поэтому давайте взглянём на ACL нашего сервера OpenLDAP:

#  ldapsearch -QLLLY EXTERNAL -H ldapi:/// -b olcDatabase={1}mdb,cn=config olcAccess

Что нам надо сделать, так это дать права доступа на чтение/запись администратору Kerberos (cn=krbadmin,ou=users,dc=example,dc=com) к поддереву cn=kerberos,ou=services,dc=example,dc=com. Никакой другой пользователь не должен иметь доступа к этой информации (за исключением администратора каталога).

Для этого сформируем LDIF-файл 9.1-kerberos.acl.ldif:

dn: olcDatabase={1}mdb,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to *
  by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage
  by * break
olcAccess: {1}to attrs=userPassword,userPKCS12
  by self write
  by anonymous auth
olcAccess: {2}to attrs=shadowLastChange
  by self write
olcAccess: {3}to dn.subtree="cn=kerberos,ou=services,dc=example,dc=com"
  by dn.exact="cn=krbadmin,ou=users,dc=example,dc=com" manage
olcAccess: {4}to *
  by dn.base="cn=nssproxy,ou=users,dc=example,dc=com" read
  by self read

Загрузим данные в сервер каталогов:

#  ldapmodify -QY EXTERNAL -H ldapi:/// -f 9.1-kerberos.acl.ldif

Убедитесь, что новые ACL работают. Суперпользователь и пользователь cn=admin,dc=example,dc=com должны иметь доступ к поддереву cn=kerberos,ou=services,dc=example,dc=com. Пользователь cn=nssproxy,ou=users,dc=example,dc=com не сможет обнаружить само существование контейнера Kerberos, а cn=krbadmin,ou=users,dc=example,dc=com должен не только видеть контейнер, но и иметь для него права на чтение/запись. Мы так же должны убедиться, что обычные пользователи всё ещё могут использовать сервер OpenLDAP для аутентификации и что они могут менять себе пароли.

Этот запрос возвращает поддерево cn=kerberos,ou=services,dc=example,dc=com:

$  ldapsearch -xZZLLLWD cn=krbadmin,ou=users,dc=example,dc=com -b cn=kerberos,ou=services,dc=example,dc=com dn

Следующий запрос должен завершиться с ошибкой No such object (32):

$  ldapsearch -xZZLLLWD cn=nssproxy,ou=users,dc=example,dc=com -b cn=kerberos,ou=services,dc=example,dc=com dn

Теперь с клиентской машины убедимся, что пользователь, учётная запись которого хранится на сервере каталогов, может менять свой пароль:

Где работаем: ldap-client

$  su - test.user
$  passwd
(current) LDAP Password:
Новый пароль :
Повторите ввод нового пароля :
passwd: password updated successfully

Где работаем: ldap-srv

Настало время настроить журналирование. Для начала добавим в конфигурацию rsyslog следующие строки (/etc/rsyslog.conf):

...

# Пишем журнал демона krb5-kdc в /var/log/krb5kdc.log:
if $programname == 'krb5kdc' then /var/log/krb5kdc.log
& ~

# Пишем журнал демона krb5-admin-server в /var/log/kadmind.log:
if $programname == 'kadmind' then /var/log/kadmind.log
& ~

Создадим файлы журналов и зададим для них права доступа:

#  touch /var/log/{krb5kdc,kadmind}.log
#  chmod 0640 /var/log/{krb5kdc,kadmind}.log
#  chown syslog:adm /var/log/{krb5kdc,kadmind}.log

Настроим logrotate. Создадим два конфигурационных файла.

Файл /etc/logrotate.d/krb5kdc для демона krb5-kdc:

/var/log/krb5kdc.log {
 daily
 missingok
 rotate 7
 compress
 delaycompress
 notifempty
}

Файл /etc/logrotate.d/kadmind для демона krb5-admin-server:

/var/log/kadmind.log {
 daily
 missingok
 rotate 7
 compress
 delaycompress
 notifempty
}

Перезапустим демон rsyslog, чтобы конфигурация вступила в силу. Добавим демоны krb5-kdc и krb5-admin-server в автоматический запуск, затем запустим их:

#  service rsyslog restart
#  update-rc.d krb5-kdc defaults
#  update-rc.d krb5-admin-server defaults
#  service krb5-kdc start
#  service krb5-admin-server start

Загляните в журнал /var/log/krb5kdc.log. Вы должны увидеть там подобную строку:

...
Dec  1 15:49:54 ldap-srv krb5kdc[1992]: commencing operation

Проверим, что наши демоны слушают необходимые порты. Порт 88 (krb5kdc), порты 464 и 749 (kadmind):

$  ss -tan | egrep ':88|:464|:749'
LISTEN     0      2                         *:749                      *:*
LISTEN     0      5                         *:464                      *:*
LISTEN     0      5                         *:88                       *:*

Поздравляю, теперь у Вас есть рабочий сервер аутентификации (AS) и сервер распределения ключей (KDC) MIT Kerberos 5!

Что дальше? В первую очередь нам необходимо создать принципал для локального сервера. Затем — принципал для пользователя test.user. Сделаем это так (разобъём вывод на части, чтобы добавить комментарии):

#  kadmin.local
Authenticating as principal root/admin@EXAMPLE.COM with password.

Здесь мы создаём принципал машины для текущего сервера (на котором залогинены). Далее жирный шрифт — вводимый нами текст:

kadmin.local:  addprinc -randkey host/ldap-srv.example.com@EXAMPLE.COM
WARNING: no policy specified for host/ldap-srv.example.com@EXAMPLE.COM; defaulting to no policy
Principal "host/ldap-srv.example.com@EXAMPLE.COM" created.

После создания принципала сервера мы можем добавить его в набор ключей Kerberos (/etc/krb5.keytab):

kadmin.local:  ktadd host/ldap-srv.example.com@EXAMPLE.COM
Entry for principal host/ldap-srv.example.com@EXAMPLE.COM with kvno 2, encryption type aes256-cts-hmac-sha1-96 added to keytab FILE:/etc/krb5.keytab.
Entry for principal host/ldap-srv.example.com@EXAMPLE.COM with kvno 2, encryption type aes128-cts-hmac-sha1-96 added to keytab FILE:/etc/krb5.keytab.
Entry for principal host/ldap-srv.example.com@EXAMPLE.COM with kvno 2, encryption type des3-cbc-sha1 added to keytab FILE:/etc/krb5.keytab.
Entry for principal host/ldap-srv.example.com@EXAMPLE.COM with kvno 2, encryption type arcfour-hmac added to keytab FILE:/etc/krb5.keytab.
Entry for principal host/ldap-srv.example.com@EXAMPLE.COM with kvno 2, encryption type des-hmac-sha1 added to keytab FILE:/etc/krb5.keytab.
Entry for principal host/ldap-srv.example.com@EXAMPLE.COM with kvno 2, encryption type des-cbc-md5 added to keytab FILE:/etc/krb5.keytab.

Следующим шагом создадим принципал для моего пользователя pablo и зададим для него пароль:

kadmin.local:  addprinc pablo@EXAMPLE.COM
WARNING: no policy specified for pablo@EXAMPLE.COM; defaulting to no policy
Enter password for principal "pablo@EXAMPLE.COM": 
Re-enter password for principal "pablo@EXAMPLE.COM":                             
Principal "pablo@EXAMPLE.COM" created.

Теперь создадим принципал пользователя с правами администратора. Помните файл /etc/krb5kdc/kadm5.acl? Вот где он вступает в игру. С помощью этого файла пользователи с префиксом /admin имеют права администратора на доступ к области Kerberos. Это значит, что они могут создавать и удалять записи пользователей и политики доступа. Поэтому убедитесь, что Вы знаете этих пользователей и доверяете им!

kadmin.local:  addprinc pablo/admin@EXAMPLE.COM
WARNING: no policy specified for pablo/admin@EXAMPLE.COM; defaulting to no policy
Enter password for principal "pablo/admin@EXAMPLE.COM": 
Re-enter password for principal "pablo/admin@EXAMPLE.COM": 
Principal "pablo/admin@EXAMPLE.COM" created.

Посмотрим список текущих принципалов в области:

kadmin.local:  get_principals
K/M@EXAMPLE.COM
krbtgt/EXAMPLE.COM@EXAMPLE.COM
kadmin/admin@EXAMPLE.COM
kadmin/changepw@EXAMPLE.COM
kadmin/history@EXAMPLE.COM
kadmin/ldap-srv.example.com@EXAMPLE.COM
host/ldap-srv.example.com@EXAMPLE.COM
pablo@EXAMPLE.COM
pablo/admin@EXAMPLE.COM

А эта команда выведет подробную информацию о принципале host/ldap-srv.example.com@EXAMPLE.COM:

kadmin.local:  getprinc host/ldap-srv.example.com@EXAMPLE.COM
Principal: host/ldap-srv.example.com@EXAMPLE.COM
Expiration date: [never]
Last password change: Сб. дек. 06 09:21:17 MSK 2014
Password expiration date: [none]
Maximum ticket life: 1 day 00:00:00
Maximum renewable life: 0 days 00:00:00
Last modified: Сб. дек. 06 09:21:17 MSK 2014 (root/admin@EXAMPLE.COM)
Last successful authentication: [never]
Last failed authentication: [never]
Failed password attempts: 0
Number of keys: 6
Key: vno 2, aes256-cts-hmac-sha1-96, no salt
Key: vno 2, aes128-cts-hmac-sha1-96, no salt
Key: vno 2, des3-cbc-sha1, no salt
Key: vno 2, arcfour-hmac, no salt
Key: vno 2, des-hmac-sha1, no salt
Key: vno 2, des-cbc-md5, no salt
MKey: vno 1
Attributes:
Policy: [none]
kadmin.local:  exit

Обратите внимание, что был создан новый файл /etc/krb5.keytab. Вот почему мы запустили бинарник kadmin.local от имени суперпользователя. Иначе мы получили бы следующую ошибку:

$  kadmin.local
Authenticating as principal pablo/admin@EXAMPLE.COM with password.
kadmin.local: Error reading password from stash: Permission denied while initializing kadmin.local interface

Только суперпользователь имеет доступ на чтение к файлу-тайнику (/etc/krb5.d/stash.keyfile).

Давайте посмотрим, что записано в /etc/krb5.keytab:

#  klist -ek /etc/krb5.keytab
Keytab name: FILE:/etc/krb5.keytab
KVNO Principal
---- ---------------------------------------------------------------
   2 host/ldap-srv.example.com@EXAMPLE.COM (aes256-cts-hmac-sha1-96)
   2 host/ldap-srv.example.com@EXAMPLE.COM (aes128-cts-hmac-sha1-96)
   2 host/ldap-srv.example.com@EXAMPLE.COM (des3-cbc-sha1)
   2 host/ldap-srv.example.com@EXAMPLE.COM (arcfour-hmac)
   2 host/ldap-srv.example.com@EXAMPLE.COM (des-hmac-sha1)
   2 host/ldap-srv.example.com@EXAMPLE.COM (des-cbc-md5)

Как мы можем видеть, это список ключей шифрования машины ldap-srv. Неудивительно, что доступ предоставлен только суперпользователю!

У нас осталась ещё одна вещь на сервере, которую надо поправить. Это ошибка

mdb_equality_candidates: (krbPrincipalName) not indexed
в журнале /var/log/slapd.log. Создадим LDIF-файл 9.1-kerberos.indexes.ldif, который внесёт поправки в индексы:

dn: olcDatabase={1}mdb,cn=config
changetype: modify
add: olcDbIndex
olcDbIndex: krbPrincipalName eq
-
add: olcDbIndex
olcDbIndex: ou eq

Добавим эти индексы в сервер каталогов:

#  ldapadd -QY EXTERNAL -H ldapi:/// -f 9.1-kerberos.indexes.ldif

Отлично! Теперь у нас есть настроенный KDC!

9.2 Настройка клиента

С действующим KDC мы можем заставить клиентские машины и сервисы использовать его. Обозначим основные цели по настройке клиентов, чтобы интегрировать их в инфраструктуру Kerberos:

  1. 1. Аутентификация Kerberos для sshd.
  2. 2. Аутентификация OpenLDAP с помощью SASL GSSAPI.
  3. 3. Применение аутентификации SASL GSSAPI для AutoFS.

9.2.1 Аутентификация Kerberos для sshd

Где работаем: ldap-client

ВНИМАНИЕ! Клиенты Kerberos должны иметь возможность подключения к TCP портам KDC с номерами 88 и 749!

Установим необходимые пакеты:

#  apt-get install krb5-user libpam-krb5 libsasl2-modules-gssapi-mit

Во время установки в качестве области Kerberos можете задать EXAMPLE.COM, а в качестве серверов, обслуживающих область, ldap-srv.example.com.

Отредактируйте конфигурацию клиента в файле /etc/krb5.conf следующим образом:

[logging]
 default = SYSLOG:INFO:LOCAL1
 kdc = SYSLOG:NOTICE:LOCAL1
 admin_server = SYSLOG:WARNING:LOCAL1

[libdefaults]
 default_realm = EXAMPLE.COM
 dns_lookup_realm = false
 dns_lookup_kdc = false
 ticket_lifetime = 24h
 renew_lifetime = 7d
 forwardable = true

[realms]
 EXAMPLE.COM = {
  kdc = ldap-srv.example.com
  admin_server = ldap-srv.example.com
  default_domain = example.com
 }

[domain_realm]
 .example.com = EXAMPLE.COM
 example.com = EXAMPLE.COM

[appdefaults]
 pam = {
  debug = false
  ticket_lifetime = 36000
  renew_lifetime = 36000
  forwardable = true
  krb4_convert = false
 }

Создайте новый принципал машины для этого хоста. Мы запускаем команду kadmin от имени суперпользователя, чтобы можно было записать результирующий файл /etc/krb5.keytab. Иначе мы получим не очень понятную ошибку No such file or directory while adding key to keytab. Мы так же должны использовать модификатор -p, чтобы дать понять команде kadmin, от имени какого принципала мы хотим подключиться. Если мы его не зададим, то получим ошибку Client not found in Kerberos database while initializing kadmin interface, потому что не создавали принципал root/admin@EXAMPLE.COM. Не создавайте этот принципал! Мы хотим знать, кто подключается с правами администратора (пользователи с префиксом /admin). Если создадим — не сможем различать администраторов между собой.

#  kadmin -p pablo/admin@EXAMPLE.COM
Authenticating as principal pablo/admin@EXAMPLE.COM with password.
Password for pablo/admin@EXAMPLE.COM:

kadmin:  addprinc -randkey host/ldap-client.example.com@EXAMPLE.COM
kadmin:  ktadd host/ldap-client.example.com@EXAMPLE.COM
kadmin:  exit

Эта команда создала файл /etc/krb5.keytab.

Теперь мы можем отредактировать /etc/ssh/sshd_config и включить аутентификацию Kerberos. Не забудьте добавить test.group в директиву AllowGroups. Иначе мы не сможем протестировать конфигурацию и увидим ошибку

User test.user from ldap-srv.example.com not allowed because none of user's groups are listed in AllowGroups
в файле /var/log/auth.log.

AddressFamily inet
Port 22
Protocol 2
AllowGroups sysadmin test.group
SyslogFacility AUTHPRIV
LoginGraceTime 30s
PermitRootLogin no
StrictModes yes
IgnoreRhosts yes
PermitEmptyPasswords no
PasswordAuthentication yes
AllowTcpForwarding no
X11Forwarding yes
PrintLastLog yes
ClientAliveInterval 120
ClientAliveCountMax 2
Banner /etc/issue

UsePAM yes
ChallengeResponseAuthentication yes
KerberosAuthentication yes
KerberosOrLocalPasswd yes
KerberosTicketCleanup yes
GSSAPIAuthentication yes
GSSAPICleanupCredentials yes

Перезапустим демон:

#  service ssh restart

Запустите на клиентской рабочей станции отображение файла журнала:

#  tail -F /var/log/auth.log

А пока вернёмся на сервер.

Где работаем: ldap-srv

Создадим принципал пользователя test.user:

$  kadmin -p pablo/admin@EXAMPLE.COM
Authenticating as principal pablo/admin@EXAMPLE.COM with password.
Password for pablo/admin@EXAMPLE.COM: 
kadmin:  addprinc test.user@EXAMPLE.COM
WARNING: no policy specified for test.user@EXAMPLE.COM; defaulting to no policy
Enter password for principal "test.user@EXAMPLE.COM": 
Re-enter password for principal "test.user@EXAMPLE.COM": 
Principal "test.user@EXAMPLE.COM" created.
kadmin:  exit

Возьмём билет Kerberos у test.user и прикинемся этим пользователем. Сначалы мы уничтожим свои собственные билеты (если они есть), используя kdestroy, затем возьмём билет test.user с помощью kinit, а в итоге проверим, что он у нас есть с помощью klist:

$  kdestroy
$  kinit -p test.user@EXAMPLE.COM
Password for test.user@EXAMPLE.COM: 
$  klist 
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: test.user@EXAMPLE.COM
 
Valid starting       Expires              Service principal
06.12.2014 14:58:06  07.12.2014 14:58:06  krbtgt/EXAMPLE.COM@EXAMPLE.COM

Теперь попробуем авторизоваться на клиенте без пароля, используя этот билет:

$  ssh test.user@ldap-client.example.com

Где работаем: ldap-client

В открытом нами журнале на клиенте /var/log/auth.log мы должны увидеть что-то подобное:

Dec  6 15:00:55 ldap-client sshd[2170]: Authorized to test.user, krb5 principal test.user@EXAMPLE.COM (krb5_kuserok)
Dec  6 15:00:55 ldap-client sshd[2170]: Accepted gssapi-with-mic for test.user from 192.168.122.150 port 45995 ssh2
Dec  6 15:00:55 ldap-client sshd[2170]: pam_unix(sshd:session): session opened for user test.user by (uid=0)

Успех! Переходим к следующей цели.

9.2.2 Аутентификация OpenLDAP с помощью SASL GSSAPI

Где работаем: ldap-srv

Для настройки аутентификаци SASL GSSAPI мы должны изменить конфигурацию сервера OpenLDAP таким образом, чтобы он знал о существовании нашей области Kerberos. После этого мы можем настроить клиентов.

Подключимся к KDC и создадим новый принципал. Мы по-прежнему запускаем kadmin от имени суперпользователя, потому что хотим создать новый набор ключей в файле /etc/ldap/krb5.keytab, чтобы наш демон slapd имел свой набор.

#  kadmin -p pablo/admin@EXAMPLE.COM
kadmin:  addprinc -randkey ldap/ldap-srv.example.com@EXAMPLE.COM
kadmin:  ktadd -k /etc/ldap/krb5.keytab ldap/ldap-srv.example.com@EXAMPLE.COM

Поменяем права доступа на этот файл, чтобы демон slapd смог его читать:

#  chown root:openldap /etc/ldap/krb5.keytab
#  chmod 640 /etc/ldap/krb5.keytab

Создадим LDIF-файл 9.2.2-sasl.ldif с директивами SASL:

dn: cn=config
changetype: modify
add: olcSaslSecProps
olcSaslSecProps: noanonymous,noplain
-
add: olcSaslHost
olcSaslHost: ldap-srv.example.com
-
add: olcSaslRealm
olcSaslRealm: EXAMPLE.COM

И загрузим его в базу данных службы каталогов:

#  ldapadd -QY EXTERNAL -H ldapi:/// -f 9.2.2-sasl.ldif

На самом деле нам не нужно играться с olcSaslSecProps, но я оставил его, потому что пытался добавить ключевое слово noactive. Если при этом попытаться выполнить поиск, то получим следующую ошибку:

#  ldapsearch -LLLY EXTERNAL -H ldapi:/// -b cn=config -s base | grep -i sasl
SASL/EXTERNAL authentication started
ldap_sasl_interactive_bind_s: Authentication method not supported (7)
additional info: SASL(-4): no mechanism available: security flags do not match required

В данный момент такое поведение — не совсем то, что нам нужно. Может быть позже. Сейчас проверим, загрузил ли демон slapd нашу конфигурацию SASL:

#  ldapsearch -QLLLY EXTERNAL -H ldapi:/// -b cn=config -s base | grep -i sasl
olcSaslSecProps: noanonymous,noplain
olcSaslHost: ldap-srv.example.com
olcSaslRealm: EXAMPLE.COM

Хорошо! Теперь нам нужно добавить параметр KRB5_KTNAME в файл /etc/default/slapd:

SLAPD_CONF=
SLAPD_USER="openldap" 
SLAPD_GROUP="openldap"
SLAPD_PIDFILE=
SLAPD_SERVICES="ldap:/// ldapi:///"
SLAPD_SENTINEL_FILE=/etc/ldap/noslapd
SLAPD_OPTIONS="-4"
export KRB5_KTNAME=/etc/ldap/krb5.keytab

Для того, чтобы изменения вступили в силу, нам нужно перезапустить демон slapd:

#  service slapd restart

Демон slapd снова запущен — мы можем переходить к настройке клиента.

Где работаем: ldap-client

Зайдём на клиентскую рабочую станцию по ssh от имени пользователя pablo:

$  ssh pablo/admin@ldap-client.example.com

Или даже так:

$  ssh pablo/admin@EXAMPLE.COM@ldap-client.example.com

Получим билет от KDC:

$  kdestroy
$  kinit -p pablo/admin
$  klist 
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: pablo@EXAMPLE.COM
 
Valid starting       Expires              Service principal
07.12.2014 14:16:24  08.12.2014 14:16:24  krbtgt/EXAMPLE.COM@EXAMPLE.COM

Все настройки для доступа на сервер у нас уже внесены в файл /etc/ldap/ldap.conf. Проверим, можем ли мы сделать запрос к LDAP-серверу:

$  ldapwhoami
ldap_sasl_interactive_bind_s: No such object (32)

Такая ошибка может показаться странной. Нужно указать механизм GSSAPI для доступа с помощью SASL. Такой вариант должен сработать:

$  ldapwhoami -Y GSSAPI
SASL/GSSAPI authentication started
SASL username: pablo@EXAMPLE.COM
SASL SSF: 56
SASL data security layer installed.
dn:uid=pablo,cn=example.com,cn=gssapi,cn=auth

Супер! Добавленный модификатор мы тоже можем внести в /etc/ldap/ldap.conf, чтобы его не приходилось вбивать вручную каждый раз:

BASE  dc=example,dc=com
URI  ldap://ldap-srv.example.com
TLS_CACERT /etc/ssl/certs/rootca.crt
TLS_CRLFILE /etc/ssl/rootca.crl
TLS_REQCERT allow
TIMELIMIT 15
TIMEOUT  20
SASL_MECH GSSAPI

Вы заметили, что OpenLDAP преобразовал имя принципала Kerberos в формат DN (Distinguished Name)? У нас был принципал с таким именем:

pablo@EXAMPLE.COM

… который был преобразован slapd в это:

dn:uid=pablo,cn=example.com,cn=gssapi,cn=auth

Это значит нам нужно вернуться на сервер и задать новые правила доступа (ACL), если мы хотим, чтобы наш Kerberos-принципал AutoFS мог читать информацию для автоматического монтирования.

9.2.3 Применение аутентификации SASL GSSAPI для autoFS

Вздохните поглубже, далее от Вас потребуется внимательность и терпение. ;)

Где работаем: ldap-srv

Вернёмся на наш сервер OpenLDAP и отредактируем правила доступа ACL. Но прежде чем мы продолжим, всегда неплохо проверить текущую конфигурацию. Теперь мы можем формировать запросы с использованием GSSAPI (без модификатора -x):

$  ldapsearch -xZZLLLWD cn=admin,dc=example,dc=com -b cn=config olcAccess

Запрос вернёт нам четыре DN с атрибутами olcAccess:

dn: olcDatabase={-1}frontend,cn=config
dn: olcDatabase={0}config,cn=config
dn: olcDatabase={1}mdb,cn=config
dn: olcDatabase={2}monitor,cn=config

Мы должны изменить ACL для olcDatabase={0}config и olcDatabase={1}mdb. Приготовьтесь, ACL станут немного сложней. Создадим LDIF-файл 9.2.3-gssapi.acl.ldif и запишем в него:

dn: olcDatabase={0}config,cn=config
changetype: modify
delete: olcAccess
-
add: olcAccess
olcAccess: {0}to *
  by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage
  by dn.regex="uid=.*/admin,cn=example.com,cn=gssapi,cn=auth" manage

dn: olcDatabase={1}mdb,cn=config
changetype: modify
delete: olcAccess
-
add: olcAccess
olcAccess: {0}to *
  by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage
  by * break
-
add: olcAccess
# Позволять принципалам Kerberos с префиксом /admin
# менять любые пароли.
olcAccess: {1}to attrs=userPassword,userPKCS12
  by dn.regex="uid=.*/admin,cn=example.com,cn=gssapi,cn=auth" manage
  by self write
  by anonymous auth
-
add: olcAccess
# Позволять принципалам Kerberos с префиксом /admin
# записывать метку времени об изменении пароля.
olcAccess: {2}to attrs=shadowLastChange
  by dn.regex="uid=.*/admin,cn=example.com,cn=gssapi,cn=auth" manage
  by self write
-
add: olcAccess
# Позволять принципалам Kerberos с префиксом /admin просматривать
# контейнер с настройками Kerberos, но не менять его содержимое.
# Это правило заставит пользоваться инструментами Kerberos при администрировании области.
olcAccess: {3}to dn.subtree="cn=kerberos,ou=services,dc=example,dc=com"
  by dn.exact="cn=krbadmin,ou=users,dc=example,dc=com" write
  by dn.regex="uid=.*/admin,cn=example.com,cn=gssapi,cn=auth" read
-
# Позволять принципалам Kerberos с именем autofsclient/*
# видеть содержимое карт автоматического монтирования.
add: olcAccess
olcAccess: {4}to dn.subtree="ou=autofs,ou=services,dc=example,dc=com"
  by dn.regex="uid=.*/admin,cn=example.com,cn=gssapi,cn=auth" manage
  by dn.regex="uid=autofsclient/.*,cn=example.com,cn=gssapi,cn=auth" read
-
add: olcAccess
# Позволять принципалам Kerberos с префиксом /admin доступ на запись к остальному каталогу.
olcAccess: {5}to *
  by dn.regex="uid=.*/admin,cn=example.com,cn=gssapi,cn=auth" manage
  by dn.exact="cn=krbadmin,ou=users,dc=example,dc=com" write
  by self read
  by dn.base="cn=nssproxy,ou=users,dc=example,dc=com" read

Ух! Вы поняли все производимые изменения? Напоминаю, что cn=admin,dc=example,dc=com (RootDN) всегда имеет полный доступ к olcDatabase={1}mdb,cn=config. То же касается и olcDatabase={0}config. Поэтому cn=admin явно не упомянут в ACL. Не волнуйтесь и внимательно прочитайте правила, одно за другим. У Вас всё получится ;)

Изменения масштабные, поэтому сделаем резервную копию на случай, если всё пойдёт наперекосяк:

#  tar zcvf ~/ldap/slapd.d.backup.tar.gz /etc/ldap/slapd.d

Загрузим новые ACL в конфигурацию OpenLDAP:

#  ldapmodify -QY EXTERNAL -H ldapi:/// -f 9.2.3-gssapi.acl.ldif
modifying entry "olcDatabase={-1}frontend,cn=config" 
modifying entry "olcDatabase={0}config,cn=config" 
modifying entry "olcDatabase={1}mdb,cn=config"
modifying entry "olcDatabase={2}monitor,cn=config"

Проверим, что cn=admin,dc=example,dc=com имеет права доступа к базе данных сервера OpenLDAP. Следующий запрос должен вернуть dn: cn=config:

$ ldapsearch -xLLLZWD cn=admin,dc=example,dc=com -b cn=config -s base dn

Суперпользователь с UID и GID равными нулю имеет аналогичный уровень доступа:

#  ldapsearch -LLLQY EXTERNAL -H ldapi:/// -b cn=config -s base dn

Такой же уровень доступа имеют принципалы с префиксом /admin. Получим билет принципала и выполним запрос от его имени с помощью SASL:

$  kdestroy
$  kinit -p pablo/admin@EXAMPLE.COM
$  ldapsearch -ZZLLLQb cn=config -s base dn
dn: cn=config

Проверьте, работают ли права для пользователя cn=nssproxy. Следующая команда должна вернуть все DN из DIT кроме записей, в которых присутствует cn=kerberos:

$  ldapsearch -xZZLLLWD cn=nssproxy,ou=users,dc=example,dc=com -b dc=example,dc=com dn

А могут ли обычные пользователи менять свой пароль? Проверим это с клиентской рабочей станции.

Где работаем: ldap-client

Процесс обновления пароля изменился. Если мы попытаемся запустить команду passwd от имени пользователя, которого нет в локальном файле /etc/passwd, пароль будет изменен с использованием механизмов Kerberos:

$ su - test.user
$ passwd 
Current Kerberos password: 
Новый пароль : 
Повторите ввод нового пароля : 
passwd: password updated successfully

Для спокойствия убедимся, что пароль поменялся в нужном месте. Сверим текущее время и время изменения пароля в принципале test.user@EXAMPLE.COM. Они должны различаться незначительно.

Время изменения пароля записывается в принципалах в атрибуте krbLastPwdChange. Запись содержит время по Гринвичу (GMT). Поэтому для начала посмотрим текущее время GMT на клиентской машине:

$ date -u
Сб. дек. 20 17:19:24 UTC 2014

Теперь получим билет администратора, чтобы заглянуть в атрибуты принципала test.user@EXAMPLE.COM.

$  kdestroy
$  kinit -p pablo/admin@EXAMPLE.COM

И наконец, отправим вот такой длиннющий запрос (ответ сервера — только последняя строчка) к серверу каталогов по атрибуту krbLastPwdChange:

$  ldapsearch -ZZLLLQb krbPrincipalName=test.user@EXAMPLE.COM,cn=EXAMPLE.COM,cn=kerberos,ou=services,dc=example,dc=com -s base krbLastPwdChange

dn: krbPrincipalName=test.user@EXAMPLE.COM,cn=EXAMPLE.COM,cn=kerberos,ou=servi ces,dc=example,dc=com
krbLastPwdChange: 20141220171526Z

Как мы можем видеть, пароль принципала test.user@EXAMPLE.COM был изменён четыре минуты назад (буква Z указывает на время по Гринвичу). Замечательно!

Теперь мы можем настроить клиентскую машину для использования механизма GSSAPI в работе с картами автомонтирования AutoFS. На этом этапе Вы должны быть авторизованы на клиентской машине от имени пользователя, домашний каталог которого не лежит на сервере NFS! Если это не так, авторизуйтесь повторно.

Перед тем как продолжить, проверьте, отмонтированы ли все каталоги NFS:

$  df -h

Проверьте общесистемную конфигурацию AutoFS в файле /etc/defaults/autofs:

TIMEOUT=300
BROWSE_MODE="no"
MOUNT_NFS_DEFAULT_PROTOCOL=4
LOGGING="debug"
OPTIONS="-d -v"
LDAP_URI="ldap://ldap-srv.example.com"
SEARCH_BASE="ou=autofs,ou=services,dc=example,dc=com"
MAP_OBJECT_CLASS="automountMap"
ENTRY_OBJECT_CLASS="automount"
MAP_ATTRIBUTE="ou"
ENTRY_ATTRIBUTE="cn"
VALUE_ATTRIBUTE="automountInformation"
USE_MISC_DEVICE="yes"

Заметьте, что атрибут LOGGING установлен в значение debug, а OPTIONS — в -d -v. Это для того, чтобы помочь нам с поиском проблем, если они возникнут. В рабочей конфигурации этот параметр должен быть изменён. Мы вернёмся к этому через пару минут.

Далее нам нужно создать принципал Kerberos для демона autofs. Мы так же должны добавить ключи этого нового принципала в набор ключей нашего клиента.

#  kadmin -p pablo/admin@EXAMPLE.COM
kadmin:  addprinc -randkey autofsclient/ldap-client.example.com@EXAMPLE.COM
kadmin:  ktadd autofsclient/ldap-client.example.com@EXAMPLE.COM

Как мы можем видеть, ключи autofsclient теперь являются частью набора ключей клиента:

#  klist -ek /etc/krb5.keytab
Keytab name: FILE:/etc/krb5.keytab
KVNO Principal
---- --------------------------------------------------------------------------
   2 host/ldap-client.example.com@EXAMPLE.COM (aes256-cts-hmac-sha1-96)
   2 host/ldap-client.example.com@EXAMPLE.COM (aes128-cts-hmac-sha1-96)
   2 host/ldap-client.example.com@EXAMPLE.COM (des3-cbc-sha1)
   2 host/ldap-client.example.com@EXAMPLE.COM (arcfour-hmac)
   2 host/ldap-client.example.com@EXAMPLE.COM (des-hmac-sha1)
   2 host/ldap-client.example.com@EXAMPLE.COM (des-cbc-md5)
   2 autofsclient/ldap-client.example.com@EXAMPLE.COM (aes256-cts-hmac-sha1-96)
   2 autofsclient/ldap-client.example.com@EXAMPLE.COM (aes128-cts-hmac-sha1-96)
   2 autofsclient/ldap-client.example.com@EXAMPLE.COM (des3-cbc-sha1)
   2 autofsclient/ldap-client.example.com@EXAMPLE.COM (arcfour-hmac)
   2 autofsclient/ldap-client.example.com@EXAMPLE.COM (des-hmac-sha1)
   2 autofsclient/ldap-client.example.com@EXAMPLE.COM (des-cbc-md5)

Теперь мы можем изменить порядок аутентификации autofs в файле /etc/autofs_ldap_auth.conf, используя механизм GSSAPI и новый принципал:

<?xml version="1.0" ?>
 <autofs_ldap_sasl_conf
  usetls="yes"
  tlsrequired="yes"
  authrequired="yes"
  authtype="GSSAPI"
  clientprinc="autofsclient/ldap-client.example.com@EXAMPLE.COM"
/>
<!-- EOF -->

Перезапустим демон autofs:

#  service autofs restart

Проверим журнал /var/log/syslog, всё ли работает?

...
Dec 20 22:12:27 ldap-client automount[943]: Starting automounter version 5.0.7, master map auto.master 
Dec 20 22:12:27 ldap-client automount[943]: using kernel protocol version 5.02 
Dec 20 22:12:27 ldap-client automount[943]: lookup_nss_read_master: reading master ldap auto.master 
Dec 20 22:12:28 ldap-client kernel: [    4.116950] e1000: eth0 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: RX 
Dec 20 22:12:28 ldap-client kernel: [    4.118253] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready 
Dec 20 22:12:28 ldap-client nslcd[972]: version 0.8.13 starting 
Dec 20 22:12:28 ldap-client nslcd[972]: accepting connections 
Dec 20 22:12:28 ldap-client automount[943]: master_do_mount: mounting /nfs 
Dec 20 22:12:28 ldap-client automount[943]: automount_path_to_fifo: fifo name /var/run/autofs.fifo-nfs 
Dec 20 22:12:28 ldap-client automount[943]: lookup_nss_read_map: reading map ldap ldap:ou=auto.nfs,ou=autofs,ou=services,dc=example,dc=com 
Dec 20 22:12:28 ldap-client automount[943]: mounted indirect on /nfs with timeout 300, freq 75 seconds 
Dec 20 22:12:28 ldap-client automount[943]: st_ready: st_ready(): state = 0 path /nfs
...

Отлично! Попробуем перейти в каталог /nfs/home:

$  cd /nfs/home
$  pwd
/nfs/home

Супер! Изменим атрибуты LOGGING и OPTIONS в файле /etc/defaults/autofs на повседневные:

...
LOGGING="none" 
# OPTIONS="-d -v"
...

И перезапустим демон autofs:

#  service autofs restart

Вот и всё! На этом фокусы с Kerberos закончились. :)

В следующем разделе мы опишем, как создавать резервную копию сервера OpenLDAP и восстанавливаться из неё. Затем мы настроим репликацию. Принимая во внимание зависимость наших клиентов от сервера OpenLDAP, нам надо обеспечить некоторый уровень отказоустойчивости.

Pro-LDAP.ru 2015 г. Последнее изменение страницы — 3 мая 2015 г. Вопросы и предложения принимаются на форуме проекта.