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

IDM стал таким местом — и почти сразу мы уперлись в проблему. Очередь на подключение к IDM начала превышать количество уже подключённых систем, а фич‑реквесты от команд копились быстрее, чем мы успевали их разобрать. Инструмент против хаоса сам стал источником хаоса.

Привет, Хабр! Я Николай Соколов, руководитель службы разработки IDM в Yandex Infrastructure. В статье расскажу, как с этим справились — и с какими новыми сюрпризами столкнулись, когда в IDM оказалось 1500 систем.

Эта статья написана по мотивам доклада на infra.conf 2026

Вот запись доклада, если вам удобнее смотреть видео.

IDM — единая точка для всех доступов

IDM (identity manager) — система, которая управляет учётными записями пользователей, их ролями и доступами. 

В компании обычно есть много различных информационных систем: базы данных, серверы, HR‑ и финансовые платформы и так далее. В каждой нужно разграничивать доступ: например, нельзя, чтобы любой сотрудник видел зарплаты или мог изменять их. IDM — это единая точка, где доступ можно запросить, согласовать и автоматически выдать в целевой системе. Также потом его можно пересмотреть и отозвать, увидеть историю: когда доступ появился, кто его подтвердил и на каком основании. 

Пока систем в компании мало, единая точка управления доступами не особо нужна. Каждая команда сама решает проблему доступов, пишет свою админку, создаёт процессы согласования и настраивает свои интеграции. Заявки на доступ подаются по‑разному: через чаты, почту, тикеты или прямо через UI‑системы. 

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

Очевидное решение: сделать систему, через которую проходят все доступы и которая хранит всю историю. Так работала наша первая версия IDM. Пользователь приходит в IDM, выбирает систему и роль, описывает, зачем ему доступ, и отправляет запрос. IDM проверяет, кто должен согласовать этот запрос, собирает подтверждения и затем автоматически выдает его в целевой системе, а у себя сохраняет всю историю. Системам об этом беспокоиться не нужно. Казалось бы, с IDM теперь всё просто и прозрачно. Мы действительно сделали всех счастливее и сняли проблему хаоса — но хаос переехал в команду IDM. 

Часть систем приходили сами: подключиться к готовой системе дешевле, чем разрабатывать свою. Кто не приходил, того приводила служба безопасности, потому что IDM стал стандартом управления доступами для всех. В какой‑то момент очередь на подключение превысила количество уже подключенных систем.

Одновременно рос список запросов на доработки, и у каждой системы они были свои. Одним нужны дополнительные поля в форме запроса роли, вторым — более сложная модель системных ролей, третьим — подтягивать данные из собственной базы, четвертым — писать свои процессы автоматизации поверх IDM. 

Было очевидно, что если мы продолжим все это делать сами, то наши планы и возможности опять перестанут сходиться. Поэтому следующий шаг — перестать быть сервисной командой, которая по заявкам подключает системы, и стать платформой, предоставляющей self‑service интеграцию. 

Self‑service‑интеграция

Self‑service‑интеграция означает, что теперь мы разделяем зоны ответственности. Мы, как платформа определяем правила игры, обеспечиваем хорошую базовую функциональность и реализуем важные требования службы безопасности и аудита. Подключение систем передаем командам. Это означает, что нам нужно обеспечить контракты, валидацию, ограничения и достаточную гибкость конфигурации под разнообразные сценарии. 

Первый шаг здесь — создать контракт для подключения систем. У нас получилось 4 основных метода. 

  1. Add‑role позволяет выдать роль пользователю в целевой системе. 

  2. Remove‑role — отозвать роль. 

  3. Info выдает справочник ролей из системы для того, чтобы IDM мог обновить его у себя. 

  4. Get‑roles выдает все активные роли пользователей для сверки с IDM. 

Если в системе предусмотрена выдача ролей на группы и требуется управление списками групп через IDM, опционально можно добавить ещё три метода. 

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

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

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

Вот так это может выглядеть: 

POST https://<base_url>/add-role/

{

"login": "alice-the-girl",

"subject_type": "user",

”role_path": "/hranalyst/",

"fields": {

”department": ”marketing",

”region": ”moscow"

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

Правила согласования 

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

Например, если доступ запрошен к продакшн, то это одни правила — «Используй руководителя». Если нужен доступ к клиентским данным — «Используй службу безопасности». Если доступ к ресурсу какого‑то бизнес‑юнита, добавляем подтверждающего руководителя этого бизнес‑юнита. А если требуется временный доступ только на чтение к ресурсам команды дежурному от этой команды, то согласовываем этот запрос автоматически. 

В итоге мы пришли к тому, что правила согласования нужно задавать кодом — принцип Policy as Code. Мы дали системам возможность программировать правила самим на Python. 

# Одна секция: достаточно kharlamov или ovechkin

approvers = [any_from([‘kharlamov', ‘ovechkin'])]

# Секция с командой сервиса в качестве группы:

approvers = [group(‘group_code')]

# Две секции:

# 1) djokovic или alcaraz

# 2) обязательно rublev

approvers = [any_from(['djokovic', 'alcaraz']), ‘rublev']

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

Дать условия не так сложно, важно и сложнее сделать так, чтобы этот питоновский код был безопасным и управляемым. Здесь ключевая инженерная часть — исполнение чужого кода. Мы не можем просто выполнять код в основном процессе IDM. Нельзя допустить, чтобы плохой код положил всю платформу, потому что он может уйти в бесконечный цикл, съесть память или читать лишние данные и так далее 

Здесь нужен Sandbox — изолированная среда, которая позволит наложить ограничения по времени на доступ и предоставить ограниченный API. У нас получилась вот такая схема. 

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

Такой же сценарий происходит при ошибке выполнения. Доступ из этого контейнера есть только ко внутреннему модулю сервера, который предоставляет тот самый ограниченный API. Командам дается возможность использовать dry‑run как в UI IDM, так и через API. 

Есть возможность делать локальные автотесты. Для этого поднимается локальный контейнер с IDM, в него загружается код правил согласования, и команда может проводить свои тесты на своих тестовых данных. 

Кроме того большие системы, которые к нам подключены, получили возможность делегировать часть скоупа в отдельные модули, владение которым можно передавать кому‑то еще. 

API и кастомные процессы

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

Есть соблазн взять и самим запилить эти замечательные фичи. Однако очень быстро они переезжают «в планы на Q5», то есть становятся задачами, которые никогда не будут сделаны, потому что всегда есть более приоритетные

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

# Пример API

POST /api/v1/role-requests

{

"subject": "user:ivan",

"system": "data-platform",

"role": "writer",

"resource": "/bu-a/project-42",

"ttl": "2026-06-05",

"reason": "incident investigation"

}

GET /api/v1/users/ivan/roles

DELETE /api/v1/roles/654321

Чтобы это нормально работало, мы сделали разграничение доступа и защиту от высокой нагрузки. Добавили RPS Limiter на балансировщике и достаточное количество платформенных фич. 

В итоге количество систем, подключенных к IDM, растет ежегодно в геометрической прогрессии. Сейчас их уже более 1500. Более половины из них пользуются IDM API. В месяц, по последним данным, через нас проходит порядка 9 миллионов запросов ролей на 30 тысяч сотрудников компании. 

К счастью, более 98% проходят через автоматику. Команды используют контракт и подключаются к нам самостоятельно: описывают свои ролевые модели, политики согласования, свои данные в виде ресурсов. 

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

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

Сверка ролей

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

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

Старый алгоритм был достаточно простым и работал так:

  1. Мы выгружали все роли из IDM. 

  2. Вызывали эндпоинт get roles у системы.

  3. Клали оба списка во множество. 

  4. Сравнивали.

  5. Получали разницу. 

С ростом числа ролей мы начинаем упираться в память, сериализацию, время ответа эндпоинта и общую стоимость обработки. 

По старому алгоритму мы могли загрузить всё в память и сравнить sets. 

roles_from_idm = load_all_roles(system)

roles_from_system = call_get_roles(system)

diff = set(roles_from_idm) ^ set(roles_from_system)

for role in diff:

report_inconsistency(role)

У этого подхода есть несколько проблем: 

  • не помещается в RAM; 

  • большой payload; 

  • дорогая сериализация; 

  • долгий endpoint.

Только для одной сверки на поде требовалось порядка 2 Гб. С учетом того, что количество систем сильно выросло и существуют другие процессы, которым тоже нужна память, её просто перестало хватать.

В какой‑то момент к нам пришли аудиторы и сказали: «Мы проводим аудит по процессу управления доступами, обходим все наиболее важные системы. У вас, оказывается, в некоторых системах сверки не работают». Нам грозил недостаток в аудиторском отчете.

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

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

Для больших систем сверки тоже заработали. Ошибки на стороне IDM полностью устранили, а покрытие систем сверками заметно выросло. Аудиторы приободрились, и теперь тех же самых 2 Гб памяти хватает не для одной системы, а уже для ста. Правда, на этом проблемы со сверками не закончились.

Некоторые системы стали очень большими и начали часто выдавать и отзывать роли. С помощью API они получили возможность делать это программно. В итоге стала появляться проблема ложных расхождений, так называемый race condition. 

Обычно это происходит, когда во время проведения сверки выдаются или отзываются роли. Можете себе представить негодование пользователя, который запросил роль через IDM; добился её согласования; получил уведомление, что роль наконец‑то выдана, и он может ей воспользоваться. А тут же прилетает следующее уведомление, которое сообщает, что роль уже отозвана.

Хорошим решением здесь могло бы быть использование снапшотов, когда система должна увидеть и дать состояние ролей — слепок на момент времени. Также можно использовать хеш‑дерево, change log или версионированный эндпоинт. 

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

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

Что дальше

Наш ближайший вызов — это AI‑агенты. Согласно аналитике Gartner, к 2028 году средняя компания из списка Fortune 500 будет иметь более 150 тысяч AI‑агентов. Вы могли слышать историю компании Replit, когда их агент снес продакшн‑базу клиентов. Агент работал полностью автономно и запустился ночью. Он считал задачу из таск‑трекера, получил исходные коды, прочитал схему базы данных, и решил, что можно снести текущую схему, а потом создать её с нуля. 

Такие истории заставляют серьезнее относиться к процессу создания агентов и вопросам безопасности. Несмотря на подобные случаи, популярность ИИ‑агентов во всем мире растет, и Яндекс не исключение. Создать хорошего агента — это отдельное искусство и итерационный процесс, в котором важно управлять рисками. 

Агенты уже становятся новым типом identity. Есть прогнозы, что у каждого сотрудника будет несколько личных агентских учеток. Здесь важно понимать, действует ли агент от лица человека или сам сотрудник выполняет операцию. Более того, мы не можем просто взять и выдать агенту все доступы сотрудников, потому что не всегда можем доверять агенту. Важно уметь делегировать только часть доступов на определенные операции и ресурсы. 

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

Ещё один вызов — научиться выдерживать кратно большую нагрузку. Количество систем растет в геометрической прогрессии. Увеличивается количество данных и ролей. Всё больше используется автоматика IDM API. Мы прогнозируем большой рост AI‑агентов. По нашим прогнозам, в течение ближайших 3–5 лет стоит ожидать увеличение нагрузки на IDM на два порядка. Поэтому необходимо подготовиться заранее и улучшить архитектуру IDM. 

Выводы 

Централизация действительно помогает устранить хаос компании в части управления доступами, но при росте количества систем это создает новое бутылочное горлышко. Важно в таком случае не зацикливать всю работу на себе и дать командам self‑service. 

Подход в Policy as Code дает действительно очень высокую гибкость, но очень важно использовать его надежно и безопасно. Его применение без Sandbox, без версионирования, без dry‑run может привести к проблемам. 

Дайте командам удобную платформу и API — они всё сделают сами и быстрее, а вы не станете бутылочным горлышком. 

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

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


  1. QtRoS
    05.09.2026 04:16

    По технологиям расскажете немного? Интересно, что под капотом такой системы.