LDAP Linux LDAP SUDO
Настройка состоит из 2 независимых частей - настройка сервера и клиента.
Настройка сервера
Добавление схемы
Операция не совсем тривиальная - в пакете 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 сам назначит номер в последовательности, а не перепишет существующую запись.
Тут подробно:
Добавление объектов
Следующим шагом следует конвертировать существующий файл sudoers в объекты LDAP
Установить sudo с поддержкой ldap и необходимые утилиты и схемы
apt-get install sudo-ldap
Бекап настроек sudo
cp /etc/sudoers /root/sudoers
В файле предназначенном для конвертации я добавил разрешения для sudo для группу fuel_users
%fuel_users ALL=(ALL:ALL) ALL
Распаковать утилиту для конвертации файла 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"
Настройка клиента
На клиенте следует установить пакет sudo-ldap который заменяет стандартный пакет sudo.
В файле nsswitch прописать использование sudo:
cat /etc/nsswitch.conf | grep sudo
sudoers: ldap files
В случае когда у меня было files ldap - не работало.
Настроить файл /etc/sudo-ldap.conf.
По-умолчанию это символическая ссылка но это не очень удобно, потому проще заменить его на файл
BASE dc=customer_organization,dc=fuel_domain URI ldaps://ldap-srv.example.com 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 SUDOERS_DEBUG 2 TLS_CACERT /etc/ssl/certs/rootca.crt TLS_REQCERT demand
- BASE - "база" ждя поиска
- URI - адрес LDAP сервера, в случае шифрования - ldaps://
- BINDDN , BINDPW - "логин" и прароль для подключения к LDAP
- TIMELIMIT, TIMEOUT - параметры подключения.
- SUDOERS_BASE - "база" поиска объектов sudo. Их вооб-ще то можно положить куда угодно, но лишние права на это поддерево лучше не давать
- SUDOERS_DEBUG - отладка. Я использовал значение 2 для отладки, 0 - для продкашена.
- TLS_CACERT - путь к сертефикату
- TLS_REQCERT - опция, влияющая на то будет ли принят самоподписанный сертификат.
Пример подключения ( с дебагом)
sirmax@node-2:~$ sudo su - sudo: LDAP Config Summary sudo: =================== sudo: uri ldaps://ldap-srv.example.com sudo: ldap_version 3 sudo: sudoers_base ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain sudo: binddn uid=nssproxy-node3,ou=service_users,dc=customer_organization,dc=fuel_domain sudo: bindpw node3 sudo: timelimit 15 sudo: ssl (no) sudo: tls_cacertfile /etc/ssl/certs/rootca.crt sudo: =================== sudo: ldap_set_option: debug -> 0 sudo: ldap_set_option: tls_cacertfile -> /etc/ssl/certs/rootca.crt sudo: ldap_set_option: tls_cacert -> /etc/ssl/certs/rootca.crt sudo: ldap_initialize(ld, ldaps://ldap-srv.example.com) sudo: ldap_set_option: ldap_version -> 3 sudo: ldap_set_option: timelimit -> 15 sudo: ldap_set_option(LDAP_OPT_TIMEOUT, 20) sudo: ldap_sasl_bind_s() ok sudo: Looking for cn=defaults: cn=defaults sudo: found:cn=defaults,ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain sudo: ldap sudoOption: 'env_reset' sudo: ldap sudoOption: 'mail_badpass' sudo: ldap sudoOption: 'secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"' sudo: ldap search '(|(sudoUser=sirmax)(sudoUser=%sirmax)(sudoUser=%#9999)(sudoUser=%fuel_users)(sudoUser=%#109999)(sudoUser=ALL))' sudo: searching from base 'ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain' sudo: adding search result sudo: ldap sudoHost 'ALL' ... MATCH! sudo: order attribute raw: 5 sudo: order attribute: 5.000000 sudo: result now has 1 entries sudo: ldap search '(sudoUser=+*)' sudo: searching from base 'ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain' sudo: adding search result sudo: result now has 1 entries sudo: sorting remaining 1 entries sudo: searching LDAP for sudoers entries sudo: ldap sudoRunAsUser 'ALL' ... MATCH! sudo: ldap sudoCommand 'ALL' ... MATCH! sudo: Command allowed sudo: LDAP entry: 0x7f734b60dc90 sudo: done with LDAP searches sudo: user_matches=1 sudo: host_matches=1 sudo: sudo_ldap_lookup(0)=0x02 [sudo] password for sirmax: sudo: removing reusable search result root@node-2:~#
Cсылки
Подробно про sudo: https://wiki.archlinux.org/index.php/Sudo_%28%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9%29