LDAP Linux Auth
Введение
Соглашения и умолчания
Везде в документе приняты следующие соглашения:
- пароль, если не указан - 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
Прокси для Active-Backup конфигурации - на виртуальном IP который (не реализовано) будет перемещаться между нодами. (В примере - перенос осуществляется в ручном режиме)
10.20.0.100 ldap
Запись сессии
В статье встечаются ссылки на утилиту 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 сервер с минимальными настройками и без шифрования.
Шифрование
Настройка шифрования вынесена на отдельную страницу
На данный момент настроено шифрование.
Репликация
Перед началом настройки репликации - настроить на обоих серверах шифрования. Конфигурация аналогичная за исключением сертификата и хостнейма
http://wiki.sirmax.noname.com.ua/index.php/LDAP_Linux_Replication
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
Populate LDAP
Customers_Organization
Контейнер для всех остальных объектов
0000_Customers_Organization
dn: dc=customer_organization,dc=fuel_domain dc: customer_organization o: Example Organization objectClass: dcObject objectClass: organization
Groups
Контейнер для групп и для пользователей.
0001_Groups
dn: ou=Group,dc=customer_organization,dc=fuel_domain ou: Group objectClass: top objectClass: organizationalUnit dn: ou=People,dc=customer_organization,dc=fuel_domain ou: People objectClass: top objectClass: organizationalUnit
User sirmax (мой пользователь)
Первый пользователь и его группа, который сможет логиниться на ноды.
0002_User_sirmax
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 me :) dn: cn=sirmax,ou=Group,dc=customer_organization,dc=fuel_domain changetype: add cn: sirmax objectClass: posixGroup gidNumber: 9999 description: Fuel Users memberUid: sirmax
Group Fuel_Users
Группа пользователей которая используется для sudo
0004_GroupFuelUsers
dn: cn=fuel_users,ou=Group,dc=customer_organization,dc=fuel_domain changetype: add cn: fuel_users objectClass: posixGroup gidNumber: 109999 description: Fuel Users memberUid: sirmax
ServiceOU and Sudoers
Создать контейнеры для сервисных объектов и поместить в него контейнер для sudo.
0005_ServiceOU_and_Sudoers
dn: ou=services,dc=customer_organization,dc=fuel_domain ou: Services objectClass: top objectClass: organizationalUnit description: Group all services under this OU dn: ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain objectClass: organizationalUnit description: sudo objectClass: top
ServieUsersOU
Контейнер для служебных пользователей
0006_ServieUsersOU
dn: ou=service_users,dc=customer_organization,dc=fuel_domain ou: service_users objectClass: top objectClass: organizationalUnit
nssproxy_group
Группа для служебных пользователей, пользователям этой группы будет разрешено читать хеши пароля и пользователи этой группы используются для nss, pam и ldap-sudo
0007_nssproxy_group
dn: cn=nssproxy,ou=Group,dc=customer_organization,dc=fuel_domain cn: nssproxy 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
0008_nssProxyUsers
Служебные пользователи (4 по числу серверов)
0008_nssProxyUsers
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 dn: uid=nssproxy-node2,ou=service_users,dc=customer_organization,dc=fuel_domain uid: nssproxy-node2 gecos: Network Service Switch Proxy User objectClass: top #objectClass: account objectClass: posixAccount objectClass: shadowAccount objectClass: organizationalPerson objectClass: inetOrgPerson userPassword: {SSHA}RsAMqOI3647qg1gAZF3x2BKBnp0sEVfa cn: node2 sn: node2 shadowLastChange: 15140 shadowMin: 0 shadowMax: 99999 shadowWarning: 7 loginShell: /bin/false uidNumber: 802 gidNumber: 801 homeDirectory: /home/nssproxy dn: uid=nssproxy-node3,ou=service_users,dc=customer_organization,dc=fuel_domain uid: nssproxy-node3 gecos: Network Service Switch Proxy User objectClass: top #objectClass: account objectClass: posixAccount objectClass: shadowAccount objectClass: organizationalPerson objectClass: inetOrgPerson userPassword: {SSHA}RsAMqOI3647qg1gAZF3x2BKBnp0sEVfa cn: node3 sn: node3 shadowLastChange: 15140 shadowMin: 0 shadowMax: 99999 shadowWarning: 7 loginShell: /bin/false uidNumber: 803 gidNumber: 801 homeDirectory: /home/nssproxy dn: uid=nssproxy-node4,ou=service_users,dc=customer_organization,dc=fuel_domain uid: nssproxy-node4 gecos: Network Service Switch Proxy User objectClass: top #objectClass: account objectClass: posixAccount objectClass: shadowAccount objectClass: organizationalPerson objectClass: inetOrgPerson userPassword: {SSHA}RsAMqOI3647qg1gAZF3x2BKBnp0sEVfa cn: node4 sn: node4 shadowLastChange: 15140 shadowMin: 0 shadowMax: 99999 shadowWarning: 7 loginShell: /bin/false uidNumber: 804 gidNumber: 801 homeDirectory: /home/nssproxy
Fix Permissions: Alow NSS Read Passwords
Добавляем группе nss права на чтение паролей/хешей паролей
0009_FixPermissionsAlowNSSReadPAsswords.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 group.exact="cn=nssproxy,ou=Group,dc=customer_organization,dc=fuel_domain" read by * none olcAccess: {2}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: {3}to dn.base="" by * read olcAccess: {4}to * by dn="cn=admin,dc=fuel_domain" write by * read
Вносить исправление через ldapi:///
ldapmodify -Y EXTERNAL -H ldapi:/// < 0009_FixPermissionsAlowNSSReadPAsswords.ldif
Sudo Scheme
Cхема для sudo (как ее генерировать описано в отдельном разделе)
0010_SudoScheme.ldif
dn: cn=sudo,cn=schema,cn=config objectClass: olcSchemaConfig cn: sudo olcAttributeTypes: {0}( 1.3.6.1.4.1.15953.9.1.1 NAME 'sudoUser' DESC 'User(s) who may run sudo' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) olcAttributeTypes: {1}( 1.3.6.1.4.1.15953.9.1.2 NAME 'sudoHost' DESC 'Host(s) who may run sudo' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) olcAttributeTypes: {2}( 1.3.6.1.4.1.15953.9.1.3 NAME 'sudoCommand' DESC 'Command(s) to be executed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) olcAttributeTypes: {3}( 1.3.6.1.4.1.15953.9.1.4 NAME 'sudoRunAs' DESC 'User(s)impersonated by sudo (deprecated)' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) olcAttributeTypes: {4}( 1.3.6.1.4.1.15953.9.1.5 NAME 'sudoOption' DESC 'Options(s) followed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) olcAttributeTypes: {5}( 1.3.6.1.4.1.15953.9.1.6 NAME 'sudoRunAsUser' DESC 'User(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) olcAttributeTypes: {6}( 1.3.6.1.4.1.15953.9.1.7 NAME 'sudoRunAsGroup' DESC 'Group(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) olcAttributeTypes: {7}( 1.3.6.1.4.1.15953.9.1.8 NAME 'sudoNotBefore' DESC 'Start of time interval for which the entry is valid' EQUALITY generalizedTimeMatch ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 ) olcAttributeTypes: {8}( 1.3.6.1.4.1.15953.9.1.9 NAME 'sudoNotAfter' DESC 'End of time interval for which the entry is valid' EQUALITY generalizedTimeMatch ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 ) olcAttributeTypes: {9}( 1.3.6.1.4.1.15953.9.1.10 NAME 'sudoOrder' DESC 'an integer to order the sudoRole entries' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 ) olcObjectClasses: {0}( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' DESC 'Sudoer Entries' SUP top STRUCTURAL MUST cn MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $ sudoRunAsGroup $ sudoOption $ sudoOrder $ sudoNotBefore $ sudoNotAfter $ description ) )
Sudoers
Файл sudoers (как его генерировать описано в отдельном разделе)
0010_sudoers.ldif
dn: cn=defaults,ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain objectClass: top objectClass: sudoRole cn: defaults 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:/sbin:/bin" sudoOrder: 1 dn: cn=root,ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain objectClass: top objectClass: sudoRole cn: root sudoUser: root sudoHost: ALL sudoRunAsUser: ALL sudoRunAsGroup: ALL sudoCommand: ALL sudoOrder: 2 dn: cn=%admin,ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain objectClass: top objectClass: sudoRole cn: %admin sudoUser: %admin sudoHost: ALL sudoRunAsUser: ALL sudoCommand: ALL sudoOrder: 3 dn: cn=%sudo,ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain objectClass: top objectClass: sudoRole cn: %sudo sudoUser: %sudo sudoHost: ALL sudoRunAsUser: ALL sudoRunAsGroup: ALL sudoCommand: ALL sudoOrder: 4 dn: cn=%fuel_users,ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain objectClass: top objectClass: sudoRole cn: %fuel_users sudoUser: %fuel_users sudoHost: ALL sudoRunAsUser: ALL sudoRunAsGroup: ALL sudoCommand: ALL sudoOrder: 5
Сброс паролей для служебных пользователей
Пароли всем пользователям ставлю (для теста) - по номеру ноды, например для node-1 пользователь будет nssproxy-node1 с паролем '1111'
0011_setPaswordsAndCheck.sh
for N in `seq 1 4` do echo user=nssproxy-node${N} ldappasswd -H ldaps://ldap -s ${N}${N}${N}${N} uid=nssproxy-node${N},ou=service_users,dc=customer_organization,dc=fuel_domain -D "cn=admin,dc=fuel_domain" -w 'r00tme' ldapsearch -D "uid=nssproxy-node${N},ou=service_users,dc=customer_organization,dc=fuel_domain" -w ${N}${N}${N}${N} -b 'dc=fuel_domain' -H ldaps://ldap '(objectclass=*)' done
Test user
Пользователь который добавляется для демонстрации - изначально не имеет прав sudo.
9902_User_test_user
dn: uid=test1,ou=People,dc=customer_organization,dc=fuel_domain objectClass: top objectClass: person objectClass: organizationalPerson objectClass: inetOrgPerson objectClass: posixAccount objectClass: shadowAccount uid: test1 cn: test1 test1 sn: test1 givenName: test1 title: test user for demo 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.test1.noname.com.ua/ loginShell: /usr/bin/sudosh uidNumber: 9998 gidNumber: 9998 homeDirectory: /home/test1 description: This is me :) dn: cn=test1,ou=Group,dc=customer_organization,dc=fuel_domain changetype: add cn: test1 objectClass: posixGroup gidNumber: 9998 description: Fuel Users memberUid: test1
Настройка клиента
Вынесено в отдельный документ:
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
Ссылки
- ВВедение в PAM https://www.ibm.com/developerworks/ru/library/l-pam/
PAM
PAM vs NSS
http://serverfault.com/questions/538383/understand-pam-and-nss
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