Исторически сложилось, что sudo права регулировались содержимым файлов из /etc/sudoers.d и visudo, а авторизация по ключам велась с использованием ~/.ssh/authorized_keys. Однако с ростом инфраструктуры возникает желание управлять этими правами централизованно. На сегодняшний день вариантов решения может быть несколько:
На мой субъективный взгляд, оптимальным вариантом централизованного управления является все-таки связка Active Directory + sssd. Преимущества данного подхода вот в чем:
Сегодняшняя сюита будет посвящена именно связке Active Directory + sssd для управления правами sudo и хранением ssh ключей в едином репозитории.
Итак, зал застыл в напряженном молчании, дирижер поднял палочку, оркестр приготовился.
Поехали.
Дано:
Оба решения вносят изменения в схему Active Directory, поэтому проверяем все на тестовом окружении и только потом вносим изменения в рабочую инфраструктуру. Хочу заметить — все изменения точечные и, по сути, добавляют лишь необходимые атрибуты и классы.
Для расширения схемы Active Directory необходимо скачать последний релиз sudo — 1.8.27 на сегодняшний день. Распаковываем, копируем файл schema.ActiveDirectory из каталога ./doc на контроллер домена. Из командной строки с правами администратора из директории, куда скопировали файл, запускаем:
(Не забываем подставлять свои значения)
Открываем adsiedit.msc и подключаемся к контексту по умолчанию:
В корне домена создаем подразделение sudoers. (Буржуины упорно утверждают, что именно в этом подразделении демон sssd производит поиск на предмет sudoRole объектов. Однако, после включения детального дебага и изучения логов, было выявлено, что поиск производится по всему дереву каталога.)
Создаем в подразделении первый объект, принадлежащий классу sudoRole. Имя может быть выбрано абсолютно произвольно, так как служит исключительно для удобной идентификации.
Среди возможных доступных атрибутов из расширения схемы основными являются следующие:
рис 1. Объекты sudoRole в подразделении sudoers в корне каталога
рис 2. Членство в группах безопасности, указанных в sudoRole-объектах.
Следующая настройка производится на стороне Linux.
В файле /etc/nsswitch.conf добавляем в конец файла строку:
В файле /etc/sssd/sssd.conf в секции [sssd] в сервисы добавляем sudo
После всех операций нужно очистить кэш sssd демона. Автоматическое обновление производится раз в 6 часов, но зачем нам столько ждать, когда мы хотим уже сейчас.
Частенько случается так, что очистка кэша не помогает. Тогда останавливаем сервис, чистим базу, стартуем сервис.
Подключаемся под первым пользователем и проверяем, что ему доступно из-под sudo:
То же самое проделываем со вторым нашим пользователем:
Подобный подход позволяет централизованно определять роли sudo для различных групп пользователей.
При небольшом расширении схемы есть возможность хранить ключи ssh в атрибутах пользователя Active Directory и использовать их при авторизации на Linux хостах.
Должна быть настроена авторизация через sssd.
Добавляем нужный атрибут при помощи PowerShell скрипта.
После добавления атрибута нужно перезапустить службу Active Directory Domain Services.
Переходим к пользователям Active Directory. Любым удобным для Вас способом генерируем пару ключей для ssh подключения.
Запускаем PuttyGen, нажимаем кнопочку «Generate» и судорожно елозим мышью в пределах пустой области.
По завершению процесса мы можем сохранить публичный и приватные ключи, залить публичный ключ в атрибут пользователя Active Directory и наслаждаться процессом. Однако публичный ключ необходимо использовать из окна "Public key for pasting into OpenSSH authorized_keys file:".
Добавляем ключ в атрибут пользователя.
Вариант 1 — GUI:
Вариант 2 — PowerShell:
Итак, мы имеем на текущий момент: пользователь с заполненным атрибутом sshPublicKey, настроенный клиент Putty для авторизации по ключам. Остается один небольшой момент, как же заставить демон sshd вытягивать нужный нам публичный ключ из атрибутов пользователя. С этим успешно справляется небольшой скрипт, найденный на просторах буржуйского интернета.
Выставляем на него права 0500 для root.
В данном пример для бинда к каталогу используется учетная запись администратора. В боевых условиях должна быть отдельная учетная запись с минимальным набором прав.
Меня лично очень смущал момент пароля в чистом виде в скрипте, несмотря на выставленные права.
Вариант решения:
Финальным аккордом в сегодняшней сюите редактируем sshd_config
Как следствие, получаем следующую последовательность при настроенной авторизации по ключам в ssh клиенте:
Таким образом ключи хранятся в атрибутах пользователя Active Directory, разрешения sudo — аналогично, доступ к хостам Linux по доменным учетным записям осуществляется путем проверки принадлежности к группе Active Directory.
Финальный взмах дирижерской палочки — и зал замирает в благоговейной тишине.
Ресуры, использованные при написании:
- Система управления конфигурацией — Chef, Puppet, Ansible, Salt
- Active Directory + sssd
- Разнообразные извращения в виде скриптов и ручного редактирования файлов
На мой субъективный взгляд, оптимальным вариантом централизованного управления является все-таки связка Active Directory + sssd. Преимущества данного подхода вот в чем:
- Действительно Единый централизованный каталог пользователей.
- Раздача прав sudo сводится к добавлению пользователя в определенную группу безопасности.
- В случае различных Linux-систем возникает необходимость вводить дополнительные проверки на определение ОС при использовании систем конфигурации.
Сегодняшняя сюита будет посвящена именно связке Active Directory + sssd для управления правами sudo и хранением ssh ключей в едином репозитории.
Итак, зал застыл в напряженном молчании, дирижер поднял палочку, оркестр приготовился.
Поехали.
Дано:
- Домен Active Directory testopf.local на Windows Server 2012 R2.
- Linux хост под управлением Centos 7
- Настроенная авторизация с использованием sssd
Оба решения вносят изменения в схему Active Directory, поэтому проверяем все на тестовом окружении и только потом вносим изменения в рабочую инфраструктуру. Хочу заметить — все изменения точечные и, по сути, добавляют лишь необходимые атрибуты и классы.
Действие 1: управление sudo ролями через Active Directory.
Для расширения схемы Active Directory необходимо скачать последний релиз sudo — 1.8.27 на сегодняшний день. Распаковываем, копируем файл schema.ActiveDirectory из каталога ./doc на контроллер домена. Из командной строки с правами администратора из директории, куда скопировали файл, запускаем:
ldifde -i -f schema.ActiveDirectory -c dc=X dc=testopf,dc=local
(Не забываем подставлять свои значения)
Открываем adsiedit.msc и подключаемся к контексту по умолчанию:
В корне домена создаем подразделение sudoers. (Буржуины упорно утверждают, что именно в этом подразделении демон sssd производит поиск на предмет sudoRole объектов. Однако, после включения детального дебага и изучения логов, было выявлено, что поиск производится по всему дереву каталога.)
Создаем в подразделении первый объект, принадлежащий классу sudoRole. Имя может быть выбрано абсолютно произвольно, так как служит исключительно для удобной идентификации.
Среди возможных доступных атрибутов из расширения схемы основными являются следующие:
- sudoCommand — определяет, какие команды разрешены к выполнению на хосте.
- sudoHost — определяет для каких хостов применяется данная роль. Может быть задано как ALL, так и для отдельного хоста по имени. Также возможно использование маски.
- sudoUser — указываем, каким пользователям разрешено выполнение sudo.
В случае указания группы безопасности, в начале имени добавляем знак “%”. Если в имени группы присутствуют пробелы, беспокоиться не о чем. Судя по логам, задачу экранирования пробелов берет на себя механизм sssd.
рис 1. Объекты sudoRole в подразделении sudoers в корне каталога
рис 2. Членство в группах безопасности, указанных в sudoRole-объектах.
Следующая настройка производится на стороне Linux.
В файле /etc/nsswitch.conf добавляем в конец файла строку:
sudoers: files sss
В файле /etc/sssd/sssd.conf в секции [sssd] в сервисы добавляем sudo
cat /etc/sssd/sssd.conf | grep services
services = nss, pam, sudo
После всех операций нужно очистить кэш sssd демона. Автоматическое обновление производится раз в 6 часов, но зачем нам столько ждать, когда мы хотим уже сейчас.
sss_cache -E
Частенько случается так, что очистка кэша не помогает. Тогда останавливаем сервис, чистим базу, стартуем сервис.
service sssd stop
rm -rf /var/lib/sss/db/*
service sssd start
Подключаемся под первым пользователем и проверяем, что ему доступно из-под sudo:
su user1
[user1@testsshad log]$ id
uid=1109801141(user1) gid=1109800513(domain users) groups=1109800513(domain users),1109801132(admins_)
[user1@testsshad log]$ sudo -l
[sudo] password for user1:
Matching Defaults entries for user1 on testsshad:
!visiblepw, always_set_home, match_group_by_gid, always_query_group_plugin,
env_reset, env_keep="COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS",
env_keep+="MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE",
env_keep+="LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES",
env_keep+="LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE",
env_keep+="LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY",
secure_path=/sbin\:/bin\:/usr/sbin\:/usr/bin
User user1 may run the following commands on testsshad:
(root) /usr/bin/ls, /usr/bin/cat
То же самое проделываем со вторым нашим пользователем:
su user2
[user2@testsshad log]$ id
uid=1109801142(user2) gid=1109800513(domain users) groups=1109800513(domain users),1109801138(sudo_root)
[user2@testsshad log]$ sudo -l
Matching Defaults entries for user2 on testsshad:
!visiblepw, always_set_home, match_group_by_gid, always_query_group_plugin,
env_reset, env_keep="COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS",
env_keep+="MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE",
env_keep+="LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES",
env_keep+="LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE",
env_keep+="LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY",
secure_path=/sbin\:/bin\:/usr/sbin\:/usr/bin
User user2 may run the following commands on testsshad:
(root) ALL
Подобный подход позволяет централизованно определять роли sudo для различных групп пользователей.
Хранение и использование ssh ключей в Active Directory
При небольшом расширении схемы есть возможность хранить ключи ssh в атрибутах пользователя Active Directory и использовать их при авторизации на Linux хостах.
Должна быть настроена авторизация через sssd.
Добавляем нужный атрибут при помощи PowerShell скрипта.
AddsshPublicKeyAttribute.ps1
Function New-AttributeID {
$Prefix=«1.2.840.113556.1.8000.2554»
$GUID=[System.Guid]::NewGuid().ToString()
$Parts=@()
$Parts+=[UInt64]::Parse($guid.SubString(0,4),«AllowHexSpecifier»)
$Parts+=[UInt64]::Parse($guid.SubString(4,4),«AllowHexSpecifier»)
$Parts+=[UInt64]::Parse($guid.SubString(9,4),«AllowHexSpecifier»)
$Parts+=[UInt64]::Parse($guid.SubString(14,4),«AllowHexSpecifier»)
$Parts+=[UInt64]::Parse($guid.SubString(19,4),«AllowHexSpecifier»)
$Parts+=[UInt64]::Parse($guid.SubString(24,6),«AllowHexSpecifier»)
$Parts+=[UInt64]::Parse($guid.SubString(30,6),«AllowHexSpecifier»)
$oid=[String]::Format("{0}.{1}.{2}.{3}.{4}.{5}.{6}.{7}",$prefix,$Parts[0],
$Parts[1],$Parts[2],$Parts[3],$Parts[4],$Parts[5],$Parts[6])
$oid
}
$schemaPath = (Get-ADRootDSE).schemaNamingContext
$oid = New-AttributeID
$attributes = @{
lDAPDisplayName = 'sshPublicKey';
attributeId = $oid;
oMSyntax = 22;
attributeSyntax = «2.5.5.5»;
isSingleValued = $true;
adminDescription = 'User Public key for SSH login';
}
New-ADObject -Name sshPublicKey -Type attributeSchema -Path $schemapath -OtherAttributes $attributes
$userSchema = get-adobject -SearchBase $schemapath -Filter 'name -eq «user»'
$userSchema | Set-ADObject -Add @{mayContain = 'sshPublicKey'}
$Prefix=«1.2.840.113556.1.8000.2554»
$GUID=[System.Guid]::NewGuid().ToString()
$Parts=@()
$Parts+=[UInt64]::Parse($guid.SubString(0,4),«AllowHexSpecifier»)
$Parts+=[UInt64]::Parse($guid.SubString(4,4),«AllowHexSpecifier»)
$Parts+=[UInt64]::Parse($guid.SubString(9,4),«AllowHexSpecifier»)
$Parts+=[UInt64]::Parse($guid.SubString(14,4),«AllowHexSpecifier»)
$Parts+=[UInt64]::Parse($guid.SubString(19,4),«AllowHexSpecifier»)
$Parts+=[UInt64]::Parse($guid.SubString(24,6),«AllowHexSpecifier»)
$Parts+=[UInt64]::Parse($guid.SubString(30,6),«AllowHexSpecifier»)
$oid=[String]::Format("{0}.{1}.{2}.{3}.{4}.{5}.{6}.{7}",$prefix,$Parts[0],
$Parts[1],$Parts[2],$Parts[3],$Parts[4],$Parts[5],$Parts[6])
$oid
}
$schemaPath = (Get-ADRootDSE).schemaNamingContext
$oid = New-AttributeID
$attributes = @{
lDAPDisplayName = 'sshPublicKey';
attributeId = $oid;
oMSyntax = 22;
attributeSyntax = «2.5.5.5»;
isSingleValued = $true;
adminDescription = 'User Public key for SSH login';
}
New-ADObject -Name sshPublicKey -Type attributeSchema -Path $schemapath -OtherAttributes $attributes
$userSchema = get-adobject -SearchBase $schemapath -Filter 'name -eq «user»'
$userSchema | Set-ADObject -Add @{mayContain = 'sshPublicKey'}
После добавления атрибута нужно перезапустить службу Active Directory Domain Services.
Переходим к пользователям Active Directory. Любым удобным для Вас способом генерируем пару ключей для ssh подключения.
Запускаем PuttyGen, нажимаем кнопочку «Generate» и судорожно елозим мышью в пределах пустой области.
По завершению процесса мы можем сохранить публичный и приватные ключи, залить публичный ключ в атрибут пользователя Active Directory и наслаждаться процессом. Однако публичный ключ необходимо использовать из окна "Public key for pasting into OpenSSH authorized_keys file:".
Добавляем ключ в атрибут пользователя.
Вариант 1 — GUI:
Вариант 2 — PowerShell:
get-aduser user1 | set-aduser -add @{sshPublicKey = 'AAAAB...XAVnX9ZRJJ0p/Q=='}
Итак, мы имеем на текущий момент: пользователь с заполненным атрибутом sshPublicKey, настроенный клиент Putty для авторизации по ключам. Остается один небольшой момент, как же заставить демон sshd вытягивать нужный нам публичный ключ из атрибутов пользователя. С этим успешно справляется небольшой скрипт, найденный на просторах буржуйского интернета.
cat /usr/local/bin/fetchSSHKeysFromLDAP
#!/bin/sh
ldapsearch -h testmdt.testopf.local -xb "dc=testopf,dc=local" '(sAMAccountName='"${1%@*}"')' -D Administrator@testopf.local -w superSecretPassword 'sshPublicKey' | sed -n '/^ /{H;d};/sshPublicKey:/x;$g;s/\n *//g;s/sshPublicKey: //gp'
Выставляем на него права 0500 для root.
chmod 0500 /usr/local/bin/fetchSSHKeysFromLDAP
В данном пример для бинда к каталогу используется учетная запись администратора. В боевых условиях должна быть отдельная учетная запись с минимальным набором прав.
Меня лично очень смущал момент пароля в чистом виде в скрипте, несмотря на выставленные права.
Вариант решения:
- Сохраняю пароль в отдельный файл:
echo -n Supersecretpassword > /usr/local/etc/secretpass
- Выставляю права на файл 0500 для root
chmod 0500 /usr/local/etc/secretpass
- Меняю параметры запуска ldapsearch: параметр -w superSecretPassword меняю на -y /usr/local/etc/secretpass
Финальным аккордом в сегодняшней сюите редактируем sshd_config
cat /etc/ssh/sshd_config | egrep -v -E "#|^$" | grep -E "AuthorizedKeysCommand|PubkeyAuthe"
PubkeyAuthentication yes
AuthorizedKeysCommand /usr/local/bin/fetchSSHKeysFromLDAP
AuthorizedKeysCommandUser root
Как следствие, получаем следующую последовательность при настроенной авторизации по ключам в ssh клиенте:
- Пользователь подключается к серверу, указывая свой логин.
- Демон sshd через скрипт вытягивает значение публичного ключа из атрибута пользователя в Active Directory и проводит авторизацию по ключам.
- Демон sssd производит дальнейшую аутентификацию пользователя на основании принадлежности к группе. Внимание! Если таковая не сконфигурирована, то любой пользователь домена будет иметь доступ к хосту.
- При попытке sudo происходит поиск демоном sssd в каталоге Active Directory на предмет ролей. При наличии ролей проверяются атрибуты и членство пользователя в группе (если sudoRoles настроены на использовании групп пользователей)
Итог
Таким образом ключи хранятся в атрибутах пользователя Active Directory, разрешения sudo — аналогично, доступ к хостам Linux по доменным учетным записям осуществляется путем проверки принадлежности к группе Active Directory.
Финальный взмах дирижерской палочки — и зал замирает в благоговейной тишине.
Ресуры, использованные при написании: