LDAP Linux Auth

Материал из noname.com.ua
Перейти к навигацииПерейти к поиску


Введение

Соглашения и умолчания

Везде в документе приняты следующие соглашения:

  • пароль, если не указан - r00tme
  • все пароли заведомо простые так как использовались для отладки. В реальной инсталляции рекомендую использовать более сложные пароли.
  • изначально настройка не безопасна (используется "админская" учетная запись, и перенастройка на более безопасную конфигурацию описываетсяв отдельной секции.
  • использование шифрования описывается в отдельной секции, изначальная настройка не использует шифрование.
  • OS: Ubuntu 14.04
  • Вся настройка делается для конкретной цели и ОС установлена Fuel-ом (Base OS) для OpenStack и конфигурация может отличаться (незначительно) от обычной установки Ubuntu.

Для простоты и скорости работы я создаю алиасы для утилит, что бы не вписывать логин и пароль каждый раз.
По этой причине команды указаны БЕЗ пароля.

alias ldappasswd='ldappasswd -D "cn=admin,dc=fuel_domain" -w r00tme'
alias ldapsearch='ldapsearch -D "cn=admin,dc=fuel_domain" -w r00tme'
alias ldapmodify='ldapmodify -D "cn=admin,dc=fuel_domain" -w r00tme'
alias ldapadd='ldapadd -D "cn=admin,dc=fuel_domain" -w r00tme'


Если требуется ввести другой пароль то команда обычно предваряется символом \ (unalias), например

\ldapsearch -Y EXTERNAL -H ldapi:///  -b "cn=config"

Репликация

В моей инсталляции фигурируют 2 сервера, сначала настраивается 1 потом дополняется репликацией.
Для простоты я использую алиасы через /etc/hosts

10.20.0.6       ldap2
10.20.0.3       ldap1



Запись сессии

В статье встечаются ссылки на утилиту sudosh - это утилита для записи сессии пользователя. Отмечу что в моей конфигурации она установлена и используется, потому на нее иногда будут ссылки

 dpkg -i  <path>/sudosh2_2.0.1-1_amd64.deb
mkdir /var/log/sudosh; 
chmod a+w /var/log/sudosh
chmod +r /etc/sudosh.conf

LDAP Server Installation

"Тихая" установка (на ldap 1)

DEBIAN_FRONTEND=noninteractive apt-get install slapd ldap-utils

Современные дистрибутивы OpenLDAP используют сам LDAP как хранилище конфигурации. cn=config. По-умолчанию настроен доступ без пароля для локального рута.


Посмотреть содержимое можно так:

ldapsearch -Y EXTERNAL -H ldapi:///  -b "cn=config"

Create database

Создать отдельную базу данных для своих объектов.
Внимательно проверить права на директорию - она должна существовать и быть доступна серверу на запись (/var/lib/ldap_fuel_domain/)

0002_createDatabase.ldif
dn: olcDatabase={2}hdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcHdbConfig
olcDatabase: {2}hdb
olcDbDirectory: /var/lib/ldap_fuel_domain/
olcSuffix: dc=fuel_domain
olcAccess: {0}to  *  by *  write
olcLastMod: TRUE
olcRootDN: cn=admin,dc=fuel_domain
olcRootPW: {SSHA}bxQpFzYmIkILSbDEL3cVl+nf03mdra/t
olcDbCheckpoint: 512 30
olcDbConfig: {0}set_cachesize 0 2097152 0
olcDbConfig: {1}set_lk_max_objects 1500
olcDbConfig: {2}set_lk_max_locks 1500
olcDbConfig: {3}set_lk_max_lockers 1500
olcDbIndex: objectClass eq

Обратить внимание на

olcAccess: {0}to  *  by *  write

Изначально я даю полный доступ всем на все, изменю его позже.

В строке цифра 2 в строке dn: olcDatabase={2}hdb,cn=config обозначает что это 2-я база, ту что существует можно как удалить так и оставить "на потом"

Создание: (подключение через -H ldapi:/// в установке по умолчанию доступно руту без пароля.

mkdir -p /var/lib/ldap_fuel_domain/
chown openldap:openldap /var/lib/ldap_fuel_domain/
ldapadd  -Y EXTERNAL -H ldapi:/// <  0002_createDatabase.ldif
adding new entry "olcDatabase={2}hdb,cn=config"

Если права на директорию неправильные ИЛИ не настроен apparmor возникает ошибка:

adding new entry "olcDatabase={2}hdb,cn=config"
ldap_add: Other (e.g., implementation specific) error (80)
	additional info: olcDbDirectory: value #0: invalid path: Permission denied

В логах:

apparmor="DENIED" operation="mknod" profile="/usr/sbin/slapd" name="/var/lib/ldap_fuel_domain/DUMMY" pid=26365 comm="slapd" requested_mask="c" denied_mask="c" fsuid=107 ouid=107

Исправить:

/etc/apparmor.d/usr.sbin.slapd
##
  /var/lib/ldap*/ rwk,
  /var/lib/ldap** rwk,

и перезапустить apparmor

 /etc/init.d/apparmor  restart

Some info:

Populate Database

Для работы создаем свой домен куда будем помещать все объекты.

  • domain
 0010_create_comain.ldiff
dn: dc=fuel_domain
objectClass: top
objectClass: dcObject
objectClass: organization
o: fuel_users
  • domain_admin
0011_fuel_domain_admin.ldiff
dn: cn=admin,dc=fuel_domain
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
userPassword: {SSHA}bxQpFzYmIkILSbDEL3cVl+nf03mdra/t

Пароль пользователя генерируется утилитой ldappasswd, в моем примере это 'r00tme'

Загрузить объекты:

ldapadd  -Y EXTERNAL -H ldapi:/// <  0010_create_comain.ldiff
<PRE>
<PRE>
adding new entry "dc=fuel_domain"
ldapadd  -Y EXTERNAL -H ldapi:/// <  0011_fuel_domain_admin.ldiff
adding new entry "cn=admin,dc=fuel_domain"

Check connection

Проверить, подключившись с ново-созданным пользователем

ldapsearch  -LL -D "cn=admin,dc=fuel_domain" -w 'r00tme' -b 'dc=fuel_domain' '(objectclass=*)'
  • -D - "логин"
  • -w - пароль
  • -b - base, ветка дерева в которой искать
  • '(objectclass=*)' - "что искать", в примере - "все"

Результат поиска:

dn: dc=fuel_domain
objectClass: top
objectClass: dcObject
objectClass: organization
o: fuel_users
dc: fuel_domain

dn: cn=admin,dc=fuel_domain
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
userPassword:: e1NTSEF9YnhRcEZ6WW1Ja0lMU2JERUwzY1ZsK25mMDNtZHJhL3Q=

Fix permmissions

Исправить права на базу.

0022_fix_database_permissions.ldif
dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break
olcAccess: {1}to attrs=userPassword,shadowLastChange by self write by anonymous auth by dn="cn=admin,dc=fuel_domain" write by * none
olcAccess: {2}to dn.base="" by * read
olcAccess: {3}to * by dn="cn=admin,dc=fuel_domain" write by * read
ldapmodify  -Y EXTERNAL  -H ldapi:/// < 0021_fix_database_permissions.ldif
modifying entry "olcDatabase={2}hdb,cn=config"

Download configuration and check it

Проверить права можно например скачав весь конфиг:

ldapsearch -Y EXTERNAL -H ldapi:///  -b "cn=config" >  all_config

Результат

На этом шаге - рабочий LDAP сервер с минимальными настройками и без шифрования.

Шифрование

Настройка шифрования вынесена на отдельную страницу

PHP LDAP Addmin

Опционально можно поставить phpldapadmin

apt-get  install phpldapadmin

Настройки минимальны и ограничиваются указанием домена пользователя

 diff /etc/phpldapadmin/config.php /etc/phpldapadmin/config.php.original
300c300
< $servers->setValue('server','base',array('dc=fuel_domain'));
---
> $servers->setValue('server','base',array('dc=example,dc=com'));
326c326
< $servers->setValue('login','bind_id','cn=admin,dc=fuel_domain');
---
> $servers->setValue('login','bind_id','cn=admin,dc=example,dc=com');

Если нужно шифрование то

 apt-get install php5-sasl

И конфигурация будет выглядеть так:

$servers->setValue('server','host','ldaps://127.0.0.1:636');
$servers->setValue('server','port',0);

В файле /etc/ldap/ldap.conf должны быть правильные настройки

TLS_CACERT      /etc/ssl/certs/rootca.crt
TLS_REQCERT     allow
TIMELIMIT       15
TIMEOUT         20

LDAP Configuration

Organization

Добавить организацию Обратить внимание - dn: dc=customer_organization,dc=fuel_domain - порядок важен. dc В КОТОРЫЙ добавляется должен быть последним.

# 04_customer_organization
dn: dc=customer_organization,dc=fuel_domain
dc: customer_organization
o: Example Organization
objectClass: dcObject
objectClass: organization

Добавить организацию:

ldapadd  < 04_customer_organization

Результат:

ldapadd  < 04_customer_organization
adding new entry "dc=customer_organization,dc=fue_domain"
ldap_add: Server is unwilling to perform (53)
	additional info: no global superior knowledge

root@node-3:~/ldap# ldapadd  < 04_customer_organization
adding new entry "dc=customer_organization,dc=fuel_domain"


Manager Role

#  05_manager
dn: cn=Manager,dc=customer_organization,dc=fuel_domain
cn: Manager
description: LDAP administrator
objectClass: organizationalRole
objectClass: top
roleOccupant: dc=customer_organization,dc=fuel_domain
ldapadd < 05_manager
adding new entry "cn=Manager,dc=customer_organization,dc=fuel_domain"

Organization Units People and Groups

# 06_people
dn: ou=People,dc=customer_organization,dc=fuel_domain
ou: People
objectClass: top
objectClass: organizationalUnit
# 07_groups
dn: ou=Group,dc=customer_organization,dc=fuel_domain
ou: Group
objectClass: top
objectClass: organizationalUnit
ldapadd  < 06_people
adding new entry "ou=People,dc=customer_organization,dc=fuel_domain"

root@node-3:~/ldap# ldapadd  < 07_groups
adding new entry "ou=Group,dc=customer_organization,dc=fuel_domain"

"Живые Люди"

Добавить пользователя. Обратить внимание - пароль такой же как в /etc/shadow
(Как его генерировать я не знаю пока)

dn: uid=sirmax,ou=People,dc=customer_organization,dc=fuel_domain
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: sirmax
cn: Max Mazur
sn: Mazur
givenName: Mazur
title: Max Mazur
telephoneNumber: +38 067 341 80 70
mobile: +38 067 341 80 70
postalAddress: AddressLine1$AddressLine2$AddressLine3
userPassword: {CRYPT}$6$DS/mzad5$EB.cNCLE7KB7OCPK1nU6aEA8HnQDLY1FPd3KaWPVqaNBtWhmh/4cOUgD1I8tQSFu41yy7jMXDrg9TDqlAbuLX.
labeledURI: http://wiki.sirmax.noname.com.ua/
loginShell: /usr/bin/sudosh
uidNumber: 9999
gidNumber: 9999
homeDirectory: /home/sirmax/
description: This is an example user
ldapadd < 08_user1
adding new entry "uid=sirmax,ou=People,dc=customer_organization,dc=fuel_domain"


Обратить внимание на loginShell: /usr/bin/sudosh - если не используется запись сессий то шелл будет другим.
Остальные пользователи создаются полностью аналогично.


Groups

2 группы

  • группа пользователя (для каждого пользователя)
  • группа fuel_users которой будет разрешено делвть sudo
dn: cn=sirmax,ou=Group,dc=example_organization,dc=fuel
changetype: add
cn: fuel users
objectClass: posixGroup
gidNumber: 9999
description: Fuel Users
memberUid: sirmax
dn: cn=fuel_users,ou=Group,dc=example_organization,dc=fuel
changetype: add
cn: fuel_users
objectClass: posixGroup
gidNumber: 109999
description: Fuel Users
memberUid: sirmax

Добавить:

ldapadd < 09_group_for_user1
adding new entry "cn=sirmax,ou=Group,dc=customer_organization,dc=fuel_domain"

ldapadd  < 10_group_fuel_users
adding new entry "cn=fuel_users,ou=Group,dc=customer_organization,dc=fuel_domain"

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

Вынесено в отдельный документ:

http://wiki.sirmax.noname.com.ua/index.php/LDAP_Linux_Auth_Client

Securing LDAP

В этой секции описывается создание служебных пользователей и групп и ограничение их привелегий.
Эти пользователи будут использоваться на node-1 .. node-4 в файлах

  • /etc/ldap.conf (node-3)
uri ldap://10.20.0.3/
base dc=fuel_domain
ldap_version 3
rootbinddn uid=nssproxy-node3,ou=service_users,dc=customer_organization,dc=fuel_domain
pam_password md5
  • /etc/ldap.secret (пароль для node-1 - "node1", аналогично для остальных нод)
node3
  • /etc/sudo-ldap.conf
BASE              dc=customer_organization,dc=fuel_domain
URI               ldap://10.20.0.3
BINDDN            uid=nssproxy-node3,ou=service_users,dc=customer_organization,dc=fuel_domain
BINDPW            node3
TIMELIMIT         15
TIMEOUT           20
SUDOERS_BASE      ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain

Служебные пользователи

Для того что бы не делать анонимных запросов я создаю для каждого из своих серверов своего пользователя nssproxy-node{X}, например nssproxy-node1. Все пользователи помещаются в отдельный OU.
Отдельный юнит для этих пользователей

dn: ou=service_users,dc=customer_organization,dc=fuel_domain
ou: service_users
objectClass: top
objectClass: organizationalUnit

Пользователь:

dn: uid=nssproxy-node1,ou=service_users,dc=customer_organization,dc=fuel_domain
uid: nssproxy-node1
gecos: Network Service Switch Proxy User
objectClass: top
#objectClass: account
objectClass: posixAccount
objectClass: shadowAccount
objectClass: organizationalPerson
objectClass: inetOrgPerson
userPassword: {SSHA}RsAMqOI3647qg1gAZF3x2BKBnp0sEVfa
cn: node1
sn: node1
shadowLastChange: 15140
shadowMin: 0
shadowMax: 99999
shadowWarning: 7
loginShell: /bin/false
uidNumber: 801
gidNumber: 801
homeDirectory: /home/nssproxy


и т. д. до node4
Обратить внимаение - нужно менять не только имя но и UID

Установка паролей

Меняем пароли для всех пользователей, задавая соответвенно node1, node2, node3, node4.

ldappasswd -S  uid=nssproxy-node1,ou=service_users,dc=customer_organization,dc=fuel_domain
ldappasswd -S  uid=nssproxy-node2,ou=service_users,dc=customer_organization,dc=fuel_domain
ldappasswd -S  uid=nssproxy-node3,ou=service_users,dc=customer_organization,dc=fuel_domain
ldappasswd -S  uid=nssproxy-node4,ou=service_users,dc=customer_organization,dc=fuel_domain

Служебные Группы

Для служебных пользователей создаем отдельную группу, на которую будем назначать привелегии.
Важно отметить, что эта группа имеет тип groupOfNames а не posixGroup, и содержит не список ID а список dn=
Для posixGroup не работает конструкция by group.exact="cn= ... " read в списках контроля доступа.

dn: cn=nssproxy,ou=Group,dc=customer_organization,dc=fuel_domain
cn: nssproxy1
objectClass: groupOfNames
objectClass: top
member: uid=nssproxy-node1,ou=service_users,dc=customer_organization,dc=fuel_domain
member: uid=nssproxy-node2,ou=service_users,dc=customer_organization,dc=fuel_domain
member: uid=nssproxy-node3,ou=service_users,dc=customer_organization,dc=fuel_domain
member: uid=nssproxy-node4,ou=service_users,dc=customer_organization,dc=fuel_domain

Добавлять пользователей в группу отдельно не надо - группа изначально создается содержащей всех необходимых пользователей.


Назначение прав

Пока у пользователя нет прав то он не может получить криптованый пароль так как настройка ACL по умолчанию это запрещает:

olcAccess: {0}to attrs=userPassword,shadowLastChange
  by self write
  by anonymous auth
  by dn="cn=admin,dc=fuel_domain" write
  by * none

Тут можно видеть, что просмотр паролей (хешей) разрешен только администратору "cn=admin,dc=fuel_domain"
Соответвенно утилита getent не может получить доступа к паролю так-как использует пользователя nssproxy-node{N}

getent  shadow sirmax
sirmax:*:::::::

Вообще-то для того что бы работал логин пароль знать не обязательно - с ним можно авторизоваться через PAM (pam_ldap).
но для того что бы работал nss без pam_ldap а только с pam_unix нужно что бы можно было получить хеш пароля.

Проверим текущие разрешения:
Обратить внимание - у меня 2 базы данных потому {2}

\ldapsearch -Y EXTERNAL -H ldapi:///  -b "olcDatabase={2}hdb,cn=config"

Вывод поформатирован:

# {2}hdb, config
dn: olcDatabase={2}hdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcHdbConfig

olcDatabase: {2}hdb
olcDbDirectory: /var/lib/ldap_fuel_domain/
olcSuffix: dc=fuel_domain

olcAccess: {0}to attrs=userPassword,shadowLastChange by self write by anonymous auth by dn="cn=admin,dc=fuel_domain" write by * none
olcAccess: {1}to dn.base="" by * read
olcAccess: {2}to * by dn="cn=admin,dc=fuel_domain" write by * read

olcLastMod: TRUE

olcRootDN: cn=admin,dc=fuel_domain
olcRootPW: {SSHA}bxQpFzYmIkILSbDEL3cVl+nf03mdra/t

olcDbCheckpoint: 512 30
olcDbConfig: {0}set_cachesize 0 2097152 0
olcDbConfig: {1}set_lk_max_objects 1500
olcDbConfig: {2}set_lk_max_locks 1500
olcDbConfig: {3}set_lk_max_lockers 1500
olcDbIndex: objectClass eq

Нас интересует секция

olcAccess: {0}to attrs=userPassword,shadowLastChange by self write by anonymous auth by dn="cn=admin,dc=fuel_domain" write by * none
olcAccess: {1}to dn.base="" by * read
olcAccess: {2}to * by dn="cn=admin,dc=fuel_domain" write by * read

Тут видно что права на чтения и запись пароля есть только у dn="cn=admin,dc=fuel_domain


Требуется добавить разрешение для группы nsswitch

# 21_acl
dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to attrs=userPassword,shadowLastChange
  by self write
  by anonymous auth
  by dn="cn=admin,dc=fuel_domain" write
  by group.exact="cn=nssproxy,ou=Group,dc=customer_organization,dc=fuel_domain" read
  by * none
olcAccess: {1}to dn.base=""
  by * read
olcAccess: {2}to *
  by dn="cn=admin,dc=fuel_domain" write
  by * read
 \ldapmodify  -Y EXTERNAL  -H ldapi:/// < 21_acl

После назначение прав можно увидеть что getent может получить хеш пароля:

getent shadow sirmax
sirmax:$6$DS/mzad5$EB.cNCLE7KB7OCPK1nU6aEA8HnQDLY1FPd3KaWPVqaNBtWhmh/4cOUgD1I8tQSFu41yy7jMXDrg9TDqlAbuLX.

Следующим шагом следует разрешить чтение всего что касается sudo всем кроме группы nssproxy

dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to attrs=userPassword,shadowLastChange
  by self write
  by anonymous auth
  by dn="cn=admin,dc=fuel_domain" write
  by group.exact="cn=nssproxy,ou=Group,dc=customer_organization,dc=fuel_domain" read
  by * none
olcAccess: {1}to dn.subtree="ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain"
  by dn="cn=admin,dc=fuel_domain" write.
  by group.exact="cn=nssproxy,ou=Group,dc=customer_organization,dc=fuel_domain" read
  by anonymous auth
  by * none
olcAccess: {2}to dn.base=""
  by * read
olcAccess: {3}to *
  by dn="cn=admin,dc=fuel_domain" write
  by * read

dn.subtree="ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain" - указать что все поддерево доступно только группе cn=nssproxy,ou=Group,dc=customer_organization,dc=fuel_domain


Проверить то, что доступ к поддереву ограничен можно следующим образом:

  • Создать алиас для простоты использования, который использует "обычного" пользователя.
alias ldapsearch_sirmax='\ldapsearch -D "uid=sirmax,ou=People,dc=customer_organization,dc=fuel_domain" -w r00tme'
ldapsearch   -x -b 'dc=fuel_domain' '(objectclass=*)' | grep sudo

Вывод (часть строк удалена так как вывод длиный)

loginShell: /usr/bin/sudosh
dn: cn=defaults,ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain
objectClass: sudoRole
description: Default sudoOption's go here
sudoOption: env_reset
sudoOption: mail_badpass
sudoOption: secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sb
sudoOrder: 1
...
dn: cn=root,ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain
objectClass: sudoRole
sudoUser: root
sudoHost: ALL
sudoRunAsUser: ALL
sudoRunAsGroup: ALL
sudoCommand: ALL
sudoOrder: 2
# %admin, sudo, services, customer_organization.fuel_domain
dn: cn=%admin,ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain
objectClass: sudoRole
sudoUser: %admin
sudoHost: ALL
sudoRunAsUser: ALL
sudoCommand: ALL
sudoOrder: 3

Для сравнения тот же запрос с использованием "обычного" пользователя не показывает информации о sudo

ldapsearch_sirmax  -x -b 'dc=fuel_domain' '(objectclass=*)' | grep sudo
loginShell: /usr/bin/sudosh
loginShell: /usr/bin/sudosh
loginShell: /usr/bin/sudosh

SUDO

http://wiki.sirmax.noname.com.ua/index.php/LDAP_Linux_LDAP_SUDO

Шифрование

http://wiki.sirmax.noname.com.ua/index.php/LDAP_Linux_LDAP_TLS

Репликация

http://wiki.sirmax.noname.com.ua/index.php/LDAP_Linux_Replication

Ссылки


PAM

PAM vs NSS

http://serverfault.com/questions/538383/understand-pam-and-nss

http://skeletor.org.ua/?p=464

http://pro-ldap.ru/tr/zytrax/ch6/slapd-config.html

https://wiki.archlinux.org/index.php/LDAP_authentication


RUS http://www.bog.pp.ru/work/LDAP.html http://pro-ldap.ru/tr/zytrax/ch6/slapd-config.html http://xgu.ru/wiki/man:ldapmodify https://rtfm.co.ua/openldap-migraciya-s-slapd-conf-na-cnconfig-olc/

http://www.slashroot.in/how-are-passwords-stored-linux-understanding-hashing-shadow-utils