IDM Midpoint от Evolveum, с одной стороны, является многофункциональным продуктом с хорошими возможностями настройки под потребности любой компании. С другой, сложность настройки растет по мере того, как вы отходите от стандартных описанных решений. А описано в документации, увы, мало.

По мере погружения в настройку Midpoint, вы можете в полной мере прочувствовать этот  забытый и не совсем научный Эффект Даннинга - Крюгера. Когда вам будет казаться, что вы, наконец, поняли Midpoint, вы будете снова оказываться в ситуации, когда все сломалось после небольшого, казалось бы, изменения.

Ниже описаны проблемы, с которыми вы можете столкнуться во время внедрения Midpoint, а также решения и рекомендации по улучшению качества жизни с этим продуктом. Актуально для версий 4.8.x (возможно и более ранних), в 4.9 есть нововведения и там может быть своя специфика.

До Midpoint был опыт разработки минималистичной собственной IDM-подобной системы. После реализации минимума от идеи отказались, т.к. слишком много ресурсов надо вложить и Midpoint с его возможностями показался более логичным решением. Забегая вперед, скажу, что неоднократно были сомнения в правильности этого выбора :)

1. Проблемы и решения

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

1.1 PolyString и кириллица

В целом, Midpoint из коробки умеет работать с кириллицей в Resource-ах, но в некоторых аспектах это будет приносить боль в дефолтной инсталляции. Например, вы не сможете выполнять поиск в UI на кириллице или не все будет находить.

Проблема связана с тем, что внутри Midpoint строки хранятся как в оригинальной, так и нормализованной форме (еще есть т.н. ProtectedString). Как раз с нормализованной формой происходит большинство действий. Для нормализации есть несколько алгоритмов, дефолтный AlphanumericPolyStringNormalizer работает только с latin-алфавитом.

Решение простое - в SystemConfiguration прописать другой normalizer:

<systemConfiguration oid="00000000-0000-0000-0000-000000000001">
    ...
    <internals>
        <polyStringNormalizer>
            <className>PassThroughPolyStringNormalizer</className>
            <nfkd>false</nfkd>
        </polyStringNormalizer>
    </internals>
    ...
</systemConfiguration>

1.2 Reconcilation в одном Resource затрагивает соседние

Вы можете для каждого ресурса прописать Task-и, которые будут заниматься Reconciliation объектов Resource-а. Если ресурсов у вас будет несколько, то в какой-то момент вы можете заметить, что запуск Task на Resource 1 вносит изменения на Resource 2. Я заметил на том, что inbound associations стали работать иначе. В моей конфигурации был двусторонний синк групп между Active Directory ⇔ Midpoint. И в этом случае Midpoint стал удалять группы у пользователей, хотя не должен был. Кстати, не рекомендую делать двусторонний синк - будет о-о-о-очень много проблем.

Причина в том, что по-умолчанию синхронизация работает без ограничения на propagation. Для устранения стоит всего лишь прописать limitPropagation (в реакцию на linked) в Resource:

<resource>
	...
    <schemaHandling>
		...
        <objectType>
			...
            <synchronization>
				...
                <reaction>
					...
                    <situation>linked</situation>
                    <actions>
                        <synchronize>
                            <limitPropagation>true</limitPropagation>
                        </synchronize>
                    </actions>
					...
                </reaction>
				...
            </synchronization>
			...
        </objectType>
		...
    </schemaHandling>
	...
</resource>

1.3 Тормозит UI и периодически происходит OOM-kill

Начнем с простого - UI всегда будет в том или ином виде тормозить. В зависимости от ваших действий, задержка может занимать от 0.5 до нескольких секунд. Для дефолтного UI Midpoint это, увы, норма и с этим, кажется, ничего нельзя сделать. Слышал, что некоторые компании переписывали UI под себя.

Немного сложнее - при запуске в LXC или Docker приложение иногда падает, независимо от активности в нем. В логах OS вы можете заметить сообщения, что пришел OOM Killer и убил приложение.

Опытным путем удалось установить, что выделение 12-15 Гб под приложение + примерно столько же сверху для ОС устраняет проблему с OOM Killer. Это расчеты под сервис примерно на 2000 пользователей с несколькими разными ресурсами. Вы можете подобрать свои значения, но рекомендую придерживаться формулы распределения памяти на контейнер: 50-60% на приложение + 40-50% на остальное.

1.4 Слишком большая Resource Schema

В обновлении Midpoint 4.8.4 была поднята версия Spring Boot до 3.3.2. Неожиданно, во время обновления Midpoint на тестовом стенде, некоторые Resource (связанные с Active Directory) перестали открываться с ошибкой 

Couldn’t parse JSON\YAML object: String value length (20051112) exceeds the maximum allowed (20000000 from …

Проверка БД показала, что схема весит 31 Мб, но раньше все работало отлично. Оказалось, что в новой версии Spring Boot была обновлена библиотека Jackson на 2.17, а в версии 2.15 завезли новое поведение - лимит в 20 Мб на чтение потока (Jackson release notes). Лимит можно поменять, но в 4.8.5 команда Midpoint не обратила на это внимания.

Избавиться от проблемы можно несколькими путями:

  • Собрать свою сборку Midpoint, в которой лимиты будут повышены (не все пойдут на этой)

  • Уменьшить размер Resource-schema (не всегда это возможно)

  • Отключить чтение схемы (может работать не везде). 

Я использовал вариант с отключением чтения схемы. Для Active Directory ресурсов в настройках подключения коннектора указываем

<resource>
    ...
    <connectorConfiguration>
		...
        <icfc:configurationProperties>
			...
            <readSchema>false</readSchema>
			...
        </icfc:configurationProperties>
		...
    </connectorConfiguration>
	...
</resource>

У этой опции есть side-effect - по-другому начинает работать процессинг атрибутов ресурса. В некоторых случаях вы можете получать ошибки, что атрибут, который вы пытаетесь установить (например, в роли) не указан в схеме, хотя он указан. Попробуйте в этом случае указать значение атрибута так

<expression>
    <script>
        <code>
            return "NEW_VALUE"
        </code>
    </script>
</expression>

1.5 Association + inbound mapping

Association это указание связи между разными типами объектов внутри Resource, которая описывается в соответствующем блоке Resource Schema Handling. Фактически, это виртуальная связь (например, между пользователем и группой в Active Directory), которая явно не находит отображение в Shadow, но ее можно увидеть при просмотре Shadow объекта в UI.

При описании association важно помнить о том, что она состоит из Subject (принимающая сторона, обычно account) и Object (что принимается, обычно это group/entitlement). Связь описывается направлением subjectToObject (Subject содержит атрибут, по которому определяется связь с другим объектом, например, пользователь содержит список групп) или objectToSubject (Object содержит атрибут, указывающий на другие объекты, например, группа содержит список пользователей).

Блок association (сама связь) принадлежит тому объекту, в котором он описан. Обычно блок указывается в account/user, чтобы association был связан с пользователем, а не группой. Если сделать иначе, то при создании inbound mapping (будет дальше), ваш маппинг будет работать с группой и навешивать ей роль, а не пользователю. Возможно это можно обойти, но я не смог найти быстрое решение.

Если вы хотите, чтобы эта связь стала более осязаемой, то вы можете превратить ее в роль (связанную с группой) для пользователя. В этом вам поможет inbound mapping внутри association. В этот момент, технически, вы включаете двусторонний синк - например, связь пользователь <=> группа в Active Direсtory превратится в роль для пользователя в Midpoint.

Двусторонний синк довольно сложная тема, требующая более глубокого погружения. Я бы рекомендовал ее избегать, т.к. там будет много проблем. Если вы все же решили его включить, то помните о следующем:

  • Роль, которая будет создаваться на основе inbound mapping, должна описывать assignment (чтобы создавался entitlement на основе роли, если его нет) + inducement (чтоб роль давала проекцию entitlement на пользователя, в котором она указана)

  • Скорее всего, потребуется написать код, проверяющий, что роль уже не указана у пользователя (иначе будет несколько одинаковых ролей у пользователя)

  • inbound mapping будет превращаться в роль для пользователя. Это породит циклическое навешивание роли, когда вы удаляет роль, а она снова появляется, т.к. ее добавляет inbound mapping. Вам потребуется написать дополнительный код, чтобы убедиться, что роль не удаляется в текущем цикле операций (вы можете собрать эту информацию через анализ изменений, см. midpoint.getFocusContext().getExecutedDeltas())

  • Если вы будете навешивать пользователям роли, ограниченные по времени, то помните, что вам нужно выключать tolerant для association. Иначе роль вернется в виде постоянной через inbound mapping.

  • Выключение tolerant может привести к тому, что у ваших пользователей в конечной системе начнут пропадать entitlement (например, группы), которые Midpoint обнаружит при discovery, но которые не будут почему-то указаны в качестве ролей в Midpoint

В версии 4.9 меняется формат описания association - она выносится в отдельный блок внутри schemaHandling, но вне objectType.

2. Советы и рекомендации

Эти советы и рекомендации помогут вам несколько снизить уровень дискомфорта при изучении Midpoint и ускорят погружение в продукт.

2.1 Документация и открытая информация

Не буду отрицать, полноценной документации по Midpoint очень не хватает. Тем не менее есть ряд ресурсов, где вы можете почерпнуть для себя полезное и ответы на вопросы:

  • Midpoint Book - обязательно прочитайте, хотя бы, по диагонали, поможет понять концепцию Midpoint и как он работает

  • Evolveum Docs - официальная документация, не полная, но некоторые аспекты там хорошо описаны

  • Описания XML-схем - вы можете их найти в каждом дистрибутиве в папке doc\schema. Но рекомендую их читать через midpoint studio, сильно удобнее и можно переходить к описанию прямо из кода

  • Midpoint Samples - примеры настроек, часть немного устарело, но все еще полезно. Рекомендую выкачать локально и искать по всем файлам примеры использования тех или иных настроек

  • Bug Tracker - если нет платной подписки, то вряд ли вам помогут, но можете найти решение некоторых своих проблем

  • Mailing lists - рассылка по проблемам с ответами, часто находил там ответы на вопросы. Лучше искать через google примерно таким запросом: site:lists.evolveum.com <ключевые слова> (пример)

2.2 Midpoint Studio

Есть несколько вариантов, как вы можете настраивать Midpoint:

  • Через UI - там доступно далеко не все и, в большинстве случаев, лучше там смотреть, но не настраивать

  • Через XML в UI - вариант с бОльшими возможностями, но все еще не очень удобно

  • Midpoint Studio - плагин для IntelliJ IDEA (в том числе CE), позволяет подключаться к Midpoint для чтения и загрузки конфигов, есть поиск по коду и описаниям тегов в xml-схемах

Я рекомендую сразу использовать Midpoint Studio + хранить ключевые аспекты конфигурации в git. К слову, нормального IaC из коробки нет, наверное, можно прикрутить извне, но я не пробовал.

2.3 Чтение исходного кода и активный debug

Лучше всего понять тонкости работы Midpoint можно через чтение его исходников. Задача не самая простая (большая кодовая база), но реальная. Нужно уметь читать Java-код и базово разбираться как происходит сборка Maven. Если пошли по этому пути, то рекомендую такие шаги:

  • Берем любимую IDE, например, IntelliJ IDEA CE

  • Скачиваем исходники: https://github.com/Evolveum/midpoint 

  • Переключаемся на свою ветку (tag по названию своей версии)

  • Выполняем Maven Package (нужно чтобы кодогенерация XML-схем отработала), скорее всего упадет под конец (не страшно)

  • Читаем код и разбираемся :)

Хорошим подспорьем будет посмотреть в режиме активного debug как работает Midpoint:

  • Берем любимую IDE, например, IntelliJ IDEA CE

  • Прописываем в строку запуска Midpoint ключи для удаленного debug-a

    -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005

  • Подключаемся из IDE к Midpoint инстансу, ставим breakpoint. Входную точку вам придется найти самостоятельно, например, вы можете встать на одну из строк в stacktrace ошибки, с которой вы разбираетесь.

  • ждем попадания в него и смотрим на Midpoint изнутри

Также могу предложить вариант активного debug-а для скриптов (тоже много раз выручал)

  • Берем любимую IDE, например, IntelliJ IDEA CE

  • Создаем примерно такой класс

package mp_debugger;

public class Debugger {
    
    public static void enter(String entryPointName, Object object){
        System.out.print(entryPointName);
    }
}
  • Упаковываем класс в JAR

  • Помещаем полученный JAR в папку libs внутри рабочей директории Midpoint (например, /var/midpoint/lib) 

  • Прописываем в строку запуска Midpoint ключи для удаленного debug-a

    -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005

  • Перезапускаем приложение

  • Подключаемся из IDE к Midpoint инстансу, ставим breakpoint на System.out.print(entryPointName);

  • Вставляем код вызова этой библиотеки в скрипт

<expression>
    <script>
        <code>
            mp_debugger.Debugger.enter(“myPoint”, this)
        </code>
    </script>
</expression>
  • Ждем вызова этого кода и в IDE, смотрим с чем работает скрипт на самом деле и можем даже кусочками проверять будущий код.

2.4 Методы пассивного debug скриптов

Пассивность подразумевает, что мы не видим с чем работает скрипт в момент выполнения, но можем вывести информацию об этом в логи. В этом нам может помочь:

  • Включение трассировки выполнения скриптов. В логах вы сможете увидеть объекты, которые подаются на вход скрипта (базовая информация), результаты работы скрипта

<expression>
	<trace>true</trace>
	...
	<script>
		<trace>true</trace>
		...
		<condition>
			<trace>true</trace>
			...
		</condition>
	</script>
	...
</expression>
  • Дополнительное логирование из скриптов (error-логи пробрасываются без дополнительных настроек)

<expression>
    <script>
        <code>
	        …
            log.error("Step 1 success")
            log.error("resource = {}", basic.debugDump(resource))
	        …
        </code>
    </script>
</expression>

Также не забывайте про официальные инструкции по отладке:

2.5 Не забывайте про библиотеки

В Midpoint есть несколько готовых библиотек с полезными функциями - ищите ссылки на JavaDoc на странице Script Expression Functions

Также вы можете разрабатывать свои собственные библиотеки в виде JAR-файлов (как мы делали выше).

Еще можно в виде FunctionLibrary - здесь вы пишите библиотеку в виде xml и потом загружаете в Midpoint. Будьте осторожны с указанием типов входных и выходных данных. У меня были случаи, когда из-за этого происходила конверсия типов: boolean на выходе функции превращался в String, из-за этого if-ы работали неправильно.

Вызов FunctionLibrary

<expression>
	<script>
		<code>
			...
			myLib.execute("testFunc", Map.of("resource", resource))
			...
		</code>
	</script>
</expression>

2.6 ActiveDirectory и фильтрация

На первых этапах внедрения вы, наверняка, заходите ограничить список объектов, которыми будет управлять Midpoint.

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

Также вы можете воспользоваться возможностями Midpoint по фильтрации объектов, указанию protected-объектов, еще можно положиться на какое-то значение атрибута в объекте. Помните, что protected-фильтр работает только с атрибутами, которые сохранены в БД midpoint для этого объекта (можете увидеть их в xml-представлении для shadow этого объекта)

<resource>
	...
    <schemaHandling>
        <objectType>
			...
            <kind>account</kind>
            <delineation>
                <objectClass>ri:user</objectClass>
                <baseContext>
                    <objectClass>ri:user</objectClass>
                    <filter>
                        <q:text>attributes/dn='OU=SomeOU,DC=TestDC,DC=local'</q:text>
                    </filter>
                </baseContext>
                <filter>
                    <q:text>attributes/name!='SomeOU' and attributes/adminDescription='MP_ENABLED'</q:text>
                </filter>
            </delineation>
            <protected>
                <filter>
                    <q:text>
                        (attributes/dn endsWith[stringIgnoreCase] "OU=Computers,DC=TestDC,DC=local")
                        or (attributes/dn endsWith[stringIgnoreCase] "OU=Users,DC=TestDC,DC=local")
                    </q:text>
                </filter>
            </protected>
			...
			<attribute>
                <ref>ri:adminDescription</ref>
                <volatilityTrigger>true</volatilityTrigger>
            </attribute>
			...
        </objectType>
		...
    </schemaHandling>
    ...
</resource>

В версии 4.9 улучшили механизм разметки объектов (protected и не только). В перспективе это должно упростить работу с такими объектами.

2.7 Внедрение, обновление, отладка и эксплуатация

Независимо от уровня вашего владения настройкой Midpoint, было бы полезно следовать этим рекомендациям:

  • У вас всегда есть несколько окружений:

    • Update-окружение - опциональное окружение для отладки процесса обновления, на нем нужно понять, что новая версия в принципе заводится

    • Dev-окружение - максимально production-like, тут вы проверяете любые изменения перед внедрением в Production, в т.ч. обновление версий

    • Prod-окружение - очевидно, ваш production-инстанс, управляющий всем и вся :) 

  • Любые изменения проходят Dev-окружение, даже если они кажутся незначительными. Поверьте на слово, были крайне простые изменения, которые давали интересные side-effects

  • Аккаунт, от имени которого Midpoint работает в конечной системе, должен иметь минимум необходимых прав. Если не нужны права супер-администратора - не давайте. Midpoint достаточно сложен внутри и лишние права только увеличат площадь возможных проблем при некорректной настройке

  • У вас всегда должны быть резервные копии - как самого Midpoint, так и интегрируемых с ним систем. Они должны быть рабочими - т.е. вы знаете как с их помощью восстановить систему и делали это уже хотя бы раз.

  • Настройте выгрузку Audit Logs из БД, например, в ELK и повесьте на значимые события alert-ы. Это позволит быстро замечать, что что-то пошло не так

  • В какой-то момент вам может прийти мысль, что было бы неплохо иметь двусторонний синк. Например, когда некоторые изменения в Active Directory реплицируются в Midpoint. Очень хорошо подумайте перед принятием такого решения. Точка правды должна быть одна - Midpoint, так проще всего. Midpoint может менять свое “понимание правды”, например, когда увольнение сотрудника в 1С влечет отключение аккаунта в Midpoint и связанных аккаунтов в Resource-ах. Старайтесь максимально избегать ситуации двустороннего синка - отладка может добавить вам седых волос, но, с другой стороны, углубит ваши знания в Midpoint :) 

  • Перед запуском в Production: 

    • убедитесь, что ваши технические команды готовы к запуску, что команда сопровождения Midpoint (ваша или outsource) готова быстро реагировать на инциденты 

    • Пропишите сценарии быстрого обнаружения проблем и отключения Midpoint в этом случае

  • Будьте готовы к тому, что внедрение Midpoint - долгий и кропотливый процесс, который нельзя решить “с наскока”. Если у вас нет опыта, то я бы предложил ориентироваться на полгода-год на запуск какого-то нормального пилота с ним. За это время вы поймете как его настраивать, подготовитесь к проблемам, подготовите регламенты и решения.

  • В РФ есть интеграторы, которые могут помочь, но это не дешево и не быстро. Рекламировать не буду - контакты интеграторов можете запросить через форму обратной связи в Evolveum

Вместо заключения

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

Но я справился и вы справитесь. Мне кажется, что в IT (возможно, и в мире) нет нерешаемых проблем, скорее, нас чаще не устраивает та цена, которую мы платим за решение.

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

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