В IT-инфраструктуре HOSTKEY для хранения учетных данных и контроля доступа традиционно использовался FreeIPA. Когда появилась необходимость управлять офисными компьютерами с Windows и оборудованием Cisco Systems, пришлось задуматься об интеграции с Active Directory. Рассказываем, как она была реализована в нашей локальной сети.

Для решения задачи можно интегрировать клиентов Linux непосредственно в домен Active Directory и управлять ими с контроллера домена. Второй вариант — интеграция, основанная на синхронизации данных или доверии домена (AD trust). В этом случае учетные записи пользователей с ранее определенными атрибутами реплицируются в другой службе каталогов и становятся доступными для клиентов на Linux. 

Недостатки AD trust

Хотя на AD trust тратятся значительные ресурсы разработчиков, это решение имеет существенные минусы и подходит компаниям, инфраструктура которых изначально основана на Active Directory. Мы же работали с FreeIPA, поэтому внедрение требовало значительных трудозатрат: фактически всю систему управления учетными записями пользователей пришлось бы создавать заново. 

Второй минус — необходимость постоянной поддержки серверов с AD и FreeIPA,так как при падении связи между ними сервер с FreeIPA становится бесполезен и нарушается работа всей компании. Авторизация — чувствительный участок, который должен быть максимально отказоустойчивым. AD trust в подобной ситуации — дополнительная точка отказа. 

Плюсы и минусы Windows sync

Вариант с механизмом Windows sync из FreeIPA предполагает полную синхронизацию всех учетных данных по протоколу LDAP. При этом FreeIPA и Active Directory остаются автономными решениями, и в случае повреждения любого сервера откажут только подключенные к нему сервисы, а не вся инфраструктура. Пользователь работает через одно окно с FreeIPA: например, в нем можно изменить пароль учетной записи одновременно для основанной на Windows и на Linux инфраструктуре. 

Мы остановились на этом варианте, но решили его доработать, поскольку Windows sync не предназначен для управления группами.

К сожалению, механизм синхронизации Windows sync во FreeIPA не считается приоритетным и не развивается, особенно в вопросах управления группами. Нам же группы были необходимы, чтобы организовать структуру персонала по отделам или в ином произвольном порядке. Такой подход позволяет прописывать правила и политики на группу, а не на каждого пользователя в отдельности, что значительно упрощает управление учетными записями и доступом к данным, а также доставку ПО. Другое преимущество групп — они могут быть вложенными.

Например, структура отдела DEVOPS у нас состоит из следующих подгрупп, для каждой из которых определены наборы прав и политик, а также необходимых для работы сервисов:

Созданную учетную запись сотрудника мы добавляем в определенную подгруппу, например в младших инженеров. В итоге новый пользователь оказывается в целом наборе групп: пользователи Rocket.Chat, Jira и т. д. Он автоматически получает доступ ко всем прописанным для подгруппы сервисам. Такую схему нетрудно построить и путем создания полностью аналогичных групп во FreeIPA и AD, но администрировать их придется вручную. Минусы очевидны: будет тратиться время на выполнение рутинных задач, а также (и это главное) возникнут потенциальные угрозы безопасности инфраструктуры. Например, простая смена прав доступа может привести к сбоям в производственном процессе из-за ошибок ручной настройки. 

Решение

Нам была необходима автоматическая синхронизация, которую пришлось реализовать самостоятельно на основе module manage-freeipa. В итоге был написан скрипт, который получает информацию о группах во FreeIPA, включая вложенные подгруппы, и переносит ее в AD. Приводим пошаговое описание алгоритма:

1. Импорт модуля module manage-freeipa.

2. После импорта модуля мы подключаемся к серверу с помощью заранее добавленных учетных данных:

$IPAURL = "freeipa_URL"
$IPAUSER = "USER"
$IPAPASS = "PASSWORD"
$ADOUUSERS = "*OU=users,OU=ipa,DC=win,DC=EXAMPLE,DC=COM"
$ADOUGROUPS = "*OU=groups,OU=ipa,DC=win,DC=EXAMPLE,DC=COM"

3. Затем в AD запрашиваем список групп из OU:

$OU = Get-ADOrganizationalUnit -SearchBase "OU=groups,OU=ipa,DC=win,DC=EXAMPLE,DC=COM" -Filter *

4. Фильтруем группу trust admins, которая не участвует в синхронизации данных между FreeIPA и AD:

$groupsAD = $OU | ForEach-Object {Get-ADGroup -SearchBase $_.DistinguishedName -Filter *} | Where {$_.name -notlike "trust admins"}

5. Получаем список всех групп в FreeIPA, за исключением trust admins и групп, которые используются исключительно в управляемой FreeIPA инфраструктуре. Выбор осуществляется только по полю cn:

$groupsIPA = Find-IPAGroup | Where {$_.dn -notlike "cn=invapi*" -and $_.dn -notlike "cn=jira*" -and $_.dn -notlike "cn=trust admins*"} | Select-Object -Property cn

6.Существует ряд групп, которые есть только в AD, мы ищем их и убираем из общего списка:

$groupsOnlyAD = $groupsAD.name | ?{$groupsIPA.cn -notcontains $_}
$listGroupsAD = $groupsAD.Name | ?{$groupsOnlyAD -notcontains $_}

7. Берем список из FreeIPA и отсекаем все группы, которые есть в AD. В итоге остается только список новых групп, которые есть в FreeIPA, но отсутствуют в AD:

$listAddGroups = $groupsIPA.cn | ?{$groupsAD.Name -notcontains $_}

8. Далее идет команда на добавление этих групп в AD:

$listAddGroups | ForEach-Object {New-ADGroup $_ -path 'OU=groups,OU=ipa,DC=win,DC=EXAMPLE,DC=COM' -GroupScope Global -PassThru -Verbose}

9. Затем идет цикл операций для каждой группы AD, которая есть в списке $ListGroupsAD.

9.1. Получаем список пользователей — участников группы в AD:

$listGroupsAD | 
ForEach { $Groupname = $_
$listGroupMembersUsersAD = Get-ADGroupMember $Groupname | Where {$_.distinguishedName -like $ADOUUSERS} | select SamAccountName

9.2. Получаем список подгрупп участников группы в AD:

$listGroupMembersGroupsAD = Get-ADGroupMember $Groupname | Where {$_.distinguishedName -like $ADOUGROUPS} | select SamAccountName 

9.3. Получаем список пользователей этой группы во FreeIPA:

$listGroupMemberUserIPA = Invoke-FreeIPAAPIgroup_show -group_name $Groupname | Select-Object -Property member_user

9.4. Получаем список подгрупп этой группы во FreeIPA:

$listGroupMemberGroupIPA = Invoke-FreeIPAAPIgroup_show -group_name $Groupname | Select-Object -Property member_group

9.5. Списки подгрупп и пользователей в FreeIPA и AD сравниваются (список пользователей FreeIPA вычитается из списка пользователей из AD и наоборот). Формируются списки пользователей и подгрупп на добавление и удаление:

$delListMembers = $listGroupMembersUsersAD.SamAccountName | ?{$listGroupMemberUserIPA.member_user -notcontains $_}
$delListGroups = $listGroupMembersGroupsAD.SamAccountName | ?{$listGroupMemberGroupIPA.member_group -notcontains $_}
$addListMembers = $listGroupMemberUserIPA.member_user| ?{$listGroupMembersUsersAD.SamAccountName -notcontains $_}
$addListGroups = $listGroupMemberGroupIPA.member_group | ?{$listGroupMembersGroupsAD.SamAccountName -notcontains $_}

9.6. Далее идет проверка, есть ли кто-то в списке на удаление пользователей и подгрупп: если никого нет, следующий шаг пропускается:

if (! ([string]::isnullorempty($delListMembers)))
{
$delListMembers | ForEach-Object {Remove-ADGroupMember $Groupname $_ -Confirm:$false}
}
if (! ([string]::isnullorempty($delListGroups)))
{
$delListGroups | ForEach-Object {Remove-ADGroupMember $Groupname $_ -Confirm:$false}
}

9.7. Такая же проверка выполняется на добавление пользователей и подгрупп:

if (! ([string]::isnullorempty($addListGroups))){
$addListGroups | ForEach-Object { Add-AdGroupMember -Identity $Groupname -members $_ }
}
if (! ([string]::isnullorempty($addListMembers)))

9.8. Перед добавлением пользователя в группу в AD необходимо проверить, есть ли он в AD. Весь цикл операций пункта 9 выполняется для каждой группы списка $listGroupsAD, полученного в пункте 6. После завершения происходит отключение сессии от сервера FreeIPA:

$addListMembers |
ForEach-Object { try
{
Get-ADUser -Identity $_
Add-AdGroupMember -Identity $Groupname -members $_
}
catch {}
}
}
}
Disconnect-IPA

Скрипт запускается планировщиком заданий каждые 15 минут.

Выводы

Скрипт значительно упростил управление учетными записями пользователей и введение новых сотрудников в рабочий процесс, а также повысил общую безопасность внутренней IT-инфраструктуры компании HOSTKEY. Дальше мы планируем настроить интеграцию FreeIPA с Active Directory напрямую через API без прокладки в виде module manage-freeipa. Это придется сделать по соображениям безопасности, поскольку последний раз модуль обновлялся два года назад. Существует риск, что он будет заброшен разработчиками.


А специальный промокод «Я С ХАБРА» откроет врата щедрости: назовите его консультанту на сайте при размещении заказа — и получите дополнительную скидку. Платить можно как всегда в рублях с НДС российской компании или в евро — компании в Нидерландах.

Комментарии (8)


  1. edo1h
    07.06.2022 06:19

    Мы же работали с FreeIPA, поэтому внедрение требовало значительных трудозатрат: фактически всю систему управления учетными записями пользователей пришлось бы создавать заново.

    не можете пояснить? не пробовал, но как мне представляется, доверие работает в обе стороны, и сразу после его настройки пользователи и группы из freeipa автомагически станут доступными на windows, останется только раздать им права


    1. nikweter
      07.06.2022 10:05

      Когда я занимался этой штукой, там доверие работало только в одну сторону. FreeIPA видела пользователей в АД и можно было с ними работать. А вот виндовс пользователей ИПА не видела. Ну или я не смог правильно настроить (хотя я пытался именно двухстороннее доверие).

      Позже, в списках рассылки вроде мелькало упоминание одним из разработчиков именно таких ограничений, но я уже отошел от этой темы и больше не интересовался.


      1. volkanin
        07.06.2022 10:18

        Наверное, это потому, что в freeipa не реализован глобальный каталог ?


        1. nikweter
          07.06.2022 12:00

          Ну это был 2017 год, с трудом припоминаю что там и как. Со стороны линукса все было удобно, одной командой вводишь компы в домен, роли, сертификаты - круть. А в потрохах - не очень удобные схемы лдап, шаманство с доверием, с SSO.

          За давностью лет меня пытать бессмысленно, слишком устаревшая инфа.


          1. mityann
            07.06.2022 14:34

            Сейчас действительно уже реализованы двусторонние трасты (не тестировал). Но под нашу задачу нужны односторонние. Работают достаточно стабильно, но подводных камней много. Для подключения к AD используется sssd и на самом деле он кеширует весь каталог (судя по логам). Можно указать отдельный dn, который будет использоваться, чтобы не синхронить весь данные. Т.е. в случае разрыва связи с AD, все продолжает работать (со стороны клиентов IPA).


            1. edo1h
              07.06.2022 16:15

              но подводных камней много

              интересно


  1. AlexGluck
    07.06.2022 16:28

    А пароли пользователей при такой схеме синхронизируется?


    1. nikweter
      07.06.2022 16:35

      Это не синхронизация, это доверие.