LDAP Linux Auth
LDAP Server Installation
"Тихая" установка
DEBIAN_FRONTEND=noninteractive apt-get install slapd ldap-utils
Современные дистрибутивы OpenLDAP используют сам LDAP как хранилище конфигурации.
Посмотреть содержимое можно так:
ldapsearch -Y EXTERNAL -H ldapi:/// -b "cn=config"
Создать отдельную базу данных для своих объектов.
Внимательно проверить права на директорию - она должна существовать и быть доступна серверу на запись (/var/lib/ldap_fuel_domain/)
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
Изначально я даю полный доступ всем на все, изменю его позже.
Создание: (подключение через -H ldapi:/// в установке по умолчанию доступно руту без пароля.
ldapadd -Y EXTERNAL -H ldapi:/// < database SASL/EXTERNAL authentication started SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth SASL SSF: 0 adding new entry "olcDatabase={2}hdb,cn=config"
Если права на директорию неправильные ИЛИ не настроен apparmor возникает ошибка:
root@node-3:~/ldap# ldapadd -Y EXTERNAL -H ldapi:/// < database SASL/EXTERNAL authentication started SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth SASL SSF: 0 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
Исправить:
/etc/apparmor.d/usr.sbin.slapd ## /var/lib/ldap** rwk,
Для работы создаем свой домен куда будем помещать все объекты.
- domain
# fuel_domain dn: dc=fuel_domain objectClass: top objectClass: dcObject objectClass: organization o: fuel_users
- domain_admin
# admin 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:/// < domain ldapadd -Y EXTERNAL -H ldapi:/// < domain_admin
Проверить, подключившись с ново-созданным пользователем
ldapsearch -D "cn=admin,dc=fuel_domain" -w 'r00tme' -b 'dc=fuel_domain' '(objectclass=*)'
- -D - "логин"
- -w - пароль
- -b - base, ветка дерева в которой искать
- '(objectclass=*)' - "что искать", в примере - "все"
Результат поиска:
# extended LDIF # # LDAPv3 # base <dc=fuel_domain> with scope subtree # filter: (objectclass=*) # requesting: ALL # # fuel_domain dn: dc=fuel_domain objectClass: top objectClass: dcObject objectClass: organization o: fuel_users dc: fuel_domain # admin, fuel_domain dn: cn=admin,dc=fuel_domain objectClass: simpleSecurityObject objectClass: organizationalRole cn: admin description: LDAP administrator userPassword:: e1NTSEF9YnhRcEZ6WW1Ja0lMU2JERUwzY1ZsK25mMDNtZHJhL3Q= # search result search: 2 result: 0 Success # numResponses: 3 # numEntries: 2
Исправить права на базу:
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 * 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:/// < 03_fix_permissions SASL/EXTERNAL authentication started SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth SASL SSF: 0 modifying entry "olcDatabase={2}hdb,cn=config"
Проверить права можно например скачав весь конфиг:
ldapsearch -Y EXTERNAL -H ldapi:/// -b "cn=config" > all_config
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');
LDAP Configuration
Aliases
Для простоты я создаю алиасы что бы не вводить пароль каждый раз
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'
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"
Users
Добавить пользователя. Обратить внимание - пароль такой же как в /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: /bin/bash 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"
Groups
2 группы
- группа пользователя
- группа fuel_users
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
Запись сессии
Для записи сессии используем утилиту sudosh2
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
SUDO
Добавить разрешения в файл sudoers
/etc/sudoers
%fuel_users ALL=(ALL:ALL) ALL
Подробно про sudo: https://wiki.archlinux.org/index.php/Sudo_%28%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9%29
SUDO LDAP
Файл sudoers на самом деле может храниться в LDAP
apt-get install sudo-ldap cp /etc/sudoers zcat /usr/share/doc/sudo-ldap/sudoers2ldif.gz > /root/sudoers2ldif chmod +x sudoers2ldif
Co стороны LDAP-сервера требуется более детальная настройка
- Добавить схему для sudo
- Добавить объекты
Добавление схемы
Операция не совсем тривиальная - в пакете ldap-sudo поставляется старая схема и просто так ее залить на сервер не получиться. Требуется конвертация.
- Создать временный файл "конфигурации slapd". В моем примере это /root/slapd.conf с одной строкой:
# cat /root/slapd.conf include ./sudo.OpenLDAP
sudo.OpenLDAP - это файл скопированный из пакета ldap-sudo, /usr/share/doc/sudo-ldap/schema.OpenLDAP
Запустить конвертацию: создать директорию для будущих конфигов и сгенерировать их
# создаём директорию mkdir testdir <PRE>
- запускаем slaptest
slaptest -f slapd.conf -F testdir
В результате в testdir будет создано дерева конфигурации.
Интересующая нас схема расположена в файле testdir/cn=config/cn=schema
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify. # CRC32 75e9d97b dn: cn={0}sudo objectClass: olcSchemaConfig cn: {0}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 caseExactIA5SubstringsMa tch 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 caseExactIA5SubstringsMat ch 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 'Comma nd(s) to be executed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1 466.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 'Option s(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 'Use r(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 'Gr oup(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.14 66.115.121.1.26 ) olcAttributeTypes: {7}( 1.3.6.1.4.1.15953.9.1.8 NAME 'sudoNotBefore' DESC 'Sta rt of time interval for which the entry is valid' EQUALITY generalizedTimeMat ch 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 int eger to order the sudoRole entries' EQUALITY integerMatch ORDERING integerOrd eringMatch 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 En tries' SUP top STRUCTURAL MUST cn MAY ( sudoUser $ sudoHost $ sudoCommand $ s udoRunAs $ sudoRunAsUser $ sudoRunAsGroup $ sudoOption $ sudoOrder $ sudoNotB efore $ sudoNotAfter $ description ) ) structuralObjectClass: olcSchemaConfig entryUUID: aaaded3e-af4b-1035-8f99-f94b551aa988 creatorsName: cn=config createTimestamp: 20160516004836Z entryCSN: 20160516004836.159008Z#000000#000#000000 modifiersName: cn=config modifyTimestamp: 20160516004836Z
Тут dn: cn={0}sudo - взято из имени файла. Если файл со схемой назывался по-другому, то и имя будет другое.
Файл требуется привести к следующему виду:
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 caseExactIA5SubstringsMa tch 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 caseExactIA5SubstringsMat ch 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 'Comma nd(s) to be executed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1 466.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 'Option s(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 'Use r(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 'Gr oup(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.14 66.115.121.1.26 ) olcAttributeTypes: {7}( 1.3.6.1.4.1.15953.9.1.8 NAME 'sudoNotBefore' DESC 'Sta rt of time interval for which the entry is valid' EQUALITY generalizedTimeMat ch 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 int eger to order the sudoRole entries' EQUALITY integerMatch ORDERING integerOrd eringMatch 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 En tries' SUP top STRUCTURAL MUST cn MAY ( sudoUser $ sudoHost $ sudoCommand $ s udoRunAs $ sudoRunAsUser $ sudoRunAsGroup $ sudoOption $ sudoOrder $ sudoNotB efore $ sudoNotAfter $ description ) )
diff:
< # AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify. < # CRC32 75e9d97b < dn: cn={0}sudo --- > dn: cn=sudo,cn=schema,cn=config 5c3 < cn: {0}sudo --- > cn: sudo 41,47d38 < structuralObjectClass: olcSchemaConfig < entryUUID: aaaded3e-af4b-1035-8f99-f94b551aa988 < creatorsName: cn=config < createTimestamp: 20160516004836Z < entryCSN: 20160516004836.159008Z#000000#000#000000 < modifiersName: cn=config
А именно: указать правильный dn и удалить{0}. Удаление {0} означает что LDAP сам назначит номер в последовательности, а не перепишет существующую запись.
Тут подробно:
Ссылки
- ВВедение в 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