LDAP Linux Auth
Введение
Везде в документе приняты следующие соглашения:
- пароль, если не указан - r00tme
- все пароли заведомо простые так как использовались для отладки. В реальной инсталляции рекомендую использовать более сложные пароли.
- изначально настройка не безопасна (используется "админская" учетная запись, и перенастройка на более безопасную конфигурацию описываетсяв отдельной секции.
- использование шифрования описывается в отдельной секции, изначальная настройка не использует шифрование.
- OS: Ubuntu 14.04
Для простоты и скорости работы я создаю алиасы для утилит, что бы не вписывать логин и пароль каждый раз.
По этой причине команды указаны БЕЗ пароля.
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"
LDAP Server Installation
"Тихая" установка
DEBIAN_FRONTEND=noninteractive apt-get install slapd ldap-utils
Современные дистрибутивы OpenLDAP используют сам LDAP как хранилище конфигурации. cn=config. По-умолчанию настроен доступ без пароля для локального рута.
Посмотреть содержимое можно так:
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
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"
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
Запись сессии
Для записи сессии используем утилиту 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
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
# запускаем slaptest slaptest -f slapd.conf -F testdir
В результате в testdir будет создано дерева конфигурации.
Интересующая нас схема расположена в файле testdir/cn=config/cn=sudo
# 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 сам назначит номер в последовательности, а не перепишет существующую запись.
Тут подробно:
Добавление объектов
Установить sudo с поддержкой ldap и необходимые утилиты и схемы
apt-get install sudo-ldap
Бекап настроек sudo
cp /etc/sudoers /root/sudoers
Распаковать утилиту для конвертации файла sudoers а объекты LDAP
zcat /usr/share/doc/sudo-ldap/sudoers2ldif.gz > /root/sudoers2ldif chmod +x sudoers2ldif
Конвертация
SUDOERS_BASE=ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain ./sudoers2ldif sudoers > sudoers.ldif
Переменная SUDOERS_BASE=ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain определяет в каком OU/DOMAIN помещать объекты
Загрузить конфигурацию в LDAP
ldapadd < sudoers.ldif adding new entry "cn=defaults,ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain" adding new entry "cn=root,ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain" adding new entry "cn=%admin,ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain" adding new entry "cn=%sudo,ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain" adding new entry "cn=%fuel_users,ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain"
Ссылки
- ВВедение в 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