
Если в компании налажен контроль доступа к внутренним ИТ-ресурсам, хорошо не только спецам по ИБ, но и многим другим. Например, лидам, которые отвечают за доступы к базам данных в своих командах. И новым сотрудникам, избавленным от необходимости вручную собирать логины-пароли, а затем где-то их самостоятельно хранить.
В Сравни больше 300 технических спецов, и в силу тематики наших продуктов зачастую они работают с чувствительными данными. Нам требовалось решение, которое поможет не просто централизованно управлять политиками доступов, но и проводить полноценный аудит всех действий в системе (предыдущий процесс логирования явно нуждался в модернизации).
Под обе эти задачи заточены так называемые PAM-инструменты (Privileged Access Management). Под катом рассказываем, как мы обеспечили контроль доступов и аудит инфраструктуры с помощью одного из них. В том числе об особенностях его внедрения, возможностях и некоторых ограничениях, выявленных на практике.
Привет, Хабр! Меня зовут Евгений, я Head of Systems Engineering в Сравни. Выбирая PAM-решение, мы составили список основных задач, в которых он был бы полезен нашей команде ИБ. Вот что нам требовалось в плане функциональности:
1. Ограничить прямой доступ к базам данных — сотрудники не должны подключаться напрямую, только через авторизованный шлюз.
2. Логировать каждое действие — включая команды SQL, открытие сессий и даже временные файлы.
3. Централизовать доступы — управление должно быть удобным, с разграничением прав по ролям и группам.
4. Интегрироваться с текущей инфраструктурой (LDAP) — без лишних костылей и с учётом существующих процессов.
5. Автоматизировать создание сущностей на PAM в соответствии с текущей инфраструктурой — PAM должен отражать актуальное состояние текущей инфраструктуры и автоматически поддерживать актуальное состояние.
Из других пожеланий к инструменту: хотелось, чтобы его можно было быстро и удобно развернуть, а в дальнейшем поддерживать без особых трудозатрат — в общем, искали классический вариант «дёшево и сердито».
После общения с вендорами и изучения функциональности решений, остановились на конкретном варианте: JumpServer. Это PAM-система, ориентированная на контроль и мониторинг привилегированных доступов к ресурсам (SSH, RDP, базы данных, web-интерфейсы). Есть как бесплатная (open-source), так и enterprise-версия.
Помимо очевидных возможностей (гибкое централизованное управление доступами, запись сессий), подкупили дополнительные фичи. Например, возможность интегрировать решение с внутренними инструментами компании посредством API, поддержка работы с облачными БД (в нашем случае это Яндекс Облако), интеграция с AD из коробки и наличие SSO.
Забегая вперед: решение полностью покрыло наши потребности в плане контроля доступов и аудита инфраструктуры; спустя полгода использования JumpServer об этом можно говорить смело. Мы обеспечили изоляцию подключения к базам, централизованное управление доступами, полную запись действий и автоматизацию через API.
Но чтобы всё заработало как надо, самого инструмента было недостаточно — требовалось логичным образом интегрировать его в нашу имеющуюся ИБ-систему. Об этом и поговорим ниже.
Реализация: от изоляции к полному контролю
Для начала обозначу, как инструмент в целом вписан в нашу архитектуру:
-
JumpServer PAM установлен в изолированной подсети.
-
Подключение к базам данных осуществляется только через JumpServer.
-
Интеграция с RDS-сервером — реализована поддержка подключения через опубликованные приложения (например, DBeaver через веб-интерфейс JumpServer).
-
Интеграция с Active Directory — реализована аутентификация, авторизация и построение RBAC-модели на базе групп и пользователей нашей AD.
-
Интеграция с Terraform — автоматическое создание ассетов (серверов, баз данных) в PAM при развёртывании ресурсов в облаке
-
Репозиторий в GitLab с workflow для управления составом AD групп — эта опция позволяет лидам (они отвечают за БД своих команд) оперировать доступами к ресурсам PAM, минуя при этом прямой доступ к AD.
-
HMAC-аутентификация — для автоматических сервисов и скриптов.
А теперь пройдемся подробнее по специфике каждого пункта.
JumpServer PAM в изолированной подсети
Инструмент был развёрнут в отдельной подсети внутри on-prem инфраструктуры с ограниченным доступом из внешнего мира. Это позволило нам контролировать трафик к JumpServer с помощью ACL и Security Group, плюс создать уровень изоляции между пользовательским трафиком, инфраструктурой и базами данных.
Подход обеспечил «бастионную» модель, где все подключения к ресурсам проходят через один проверяемый и логируемый шлюз.
Интеграция с RDS (Remote Desktop Services) и опубликованными приложениями
Для предоставления пользователям доступа к графическим инструментам (например, DBeaver\MongoDB Compas и т.д.) без установки на локальный компьютер, мы использовали RDS:
-
В разделе RemoteApp на JumpServer загрузили приложение из App Market (DBeaver, MongoDB Compass, Redis Desktop Manager и т.д.).
-
Эти приложения — преднастроенные шаблоны .app (по сути, конфиги), которые:
-
определяют команду запуска (например: C:\Program Files\DBeaver\dbeaver.exe);
-
включают иконку, описание и категорию (Database, Web и т.д.);
-
могут быть установлены автоматически на RDS-хост.
-
JumpServer сам устанавливает эти приложения, через PAM-компонент Tink.
Как это работает:
-
Tink, подключаясь по WinRM, проверяет, установлено ли приложение на RDS-хосте.
-
Если нет — автоматически его загружает и устанавливает, при наличии соответствующего дистрибутива.
-
Приложения устанавливаются на сервере с настроенным Remote Desktop Services (RDS) под Windows.
-
RDS добавлен в JumpServer как remote app machine и используется в режиме «Published Application».
-
Через JumpServer пользователю становится доступно опубликованное приложение (например, DBeaver) — оно запускается удалённо на RDS-сервере, но отображается в веб-интерфейсе пользователя.
-
Всё подключение происходит через RDP, проксируемое и логируемое PAM.
К подобному решению я пришел, когда при работе с JumpServer столкнулся с ограничениями для пользователей MongoDB (об этом расскажу в далее в статье) — подход позволил не обделять их функциональностью.
В целом решение позволяет:
-
запускать GUI-инструменты из браузера без установки на рабочую станцию;
-
строго контролировать, какие приложения доступны пользователю;
-
вести запись и аудит действий, включая запуск приложений и взаимодействие с интерфейсом;
-
при необходимости — ограничивать файловый доступ и буфер обмена.
Подключение к базам данных только через JumpServer
Модель доступа к ресурсам выглядит следующим образом:
1. Пользователь проходит аутентификацию на PAM-сервере.
2. Во время аутентификации JumpServer получает список групп пользователя из AD.
3. На основе полученных групп, пользователю назначаются права доступа к ассетам и разрешенные действия.
В рамках политики безопасности было запрещено прямое подключение к базам и использование учетных данных непосредственно от БД.
JumpServer стал единой точкой входа. Пользователь сначала аутентифицируется в PAM, после чего может подключиться к назначенной базе.
Режимы подключения:
-
Web-интерфейс (CLI, GUI, Applet — позволяет в веб-интерфейсе JumpServer открыть опубликованное на RDS приложение).
-
DBguide — генерация временных кредов для подключения базе через JumpServer, с их помощью можно подключиться к базам из стандартных профильных приложений для работы с БД, при этом PAM будет проксировать это подключение.
-
JumpServer client — локальный клиент, который может запустить профильное ПО для работы с базой, например SSMS, DBeaver и прокинуть в них коннекшен-стринги для автоматического подключения к БД.
Таким образом вся активность фиксируется, и реальные учётные данные баз остаются скрыты от конечных пользователей.
Интеграция с Active Directory (LDAP)
Аутентификация и авторизация пользователей реализована через LDAP-интеграцию с существующим Active Directory. Это дало следующие преимущества:
-
единый вход;
-
автоматическая синхронизация пользователей и групп;
-
построение RBAC на базе AD-групп;
-
прозрачное управление доступами на уровне PAM через привязку групп к ресурсам.
Доступ к инфраструктурным ресурсам регулируется через механизм Asset Authorization Rules и Command Filter внутри JumpServer.
Основные компоненты, которые позволяют управлять доступом к ресурсам:
-
PAM-аутентификация. Пользователь проходит аутентификацию через JumpServer, как правило, с использованием LDAP или другого внешнего провайдера.
-
Asset Authorization Rules. Это центральный механизм контроля доступа. В нём задаются:
-
группы пользователей из AD (AD user group);
-
целевые ресурсы (Target Asset);
-
разрешённые аккаунты на ресурсах (Target account);
-
разрешённые протоколы подключения (например, SSH, RDP);
-
разрешённые действия (доступ, передача файлов, буфер обмена и т.д.).
-
-
Command Filter (Фильтр команд). Для повышения уровня безопасности доступ может ограничиваться только разрешёнными командами. Используются:
-
регулярные выражения для определения допустимых команд;
-
назначение групп команд (Command group) пользователям и активам.
-
-
Asset (Ресурсы). Конечные целевые системы (БД, серверы и т.д.), к которым осуществляется подключение. Связь происходит по:
-
строке подключения (Connection string);
-
указанным аккаунтам (DB accounts).
-
При этом поддерживаются действия (Permissions): Connect, Transfer, Upload, Download, Delete, Clipboard, Copy, Paste, Share.
Вот пример работы схемы:
-
Пользователь проходит аутентификацию.
-
На основании его группы в AD проверяется наличие правил доступа (authorization rules).
-
Если доступ разрешён, проверяется соответствие командам (если активен фильтр команд).
-
Предоставляется доступ к целевому ресурсу с ограничениями по действиям и командам.

Таким образом добавление пользователя в группу в AD автоматически даёт ему нужный уровень доступа в JumpServer.
Интеграция с Terraform
Для автоматического добавления ресурсов в PAM мы реализовали интеграцию на основе анализа Terraform state-файлов, без прямой связи с Terraform-провайдерами.
Как это работает:
-
Terraform state-файлы хранятся в Object Storage (например, S3-совместимом);
-
PowerShell-скрипт:
-
подключается к бакету с помощью ключей доступа;
-
читает .tfstate;
-
извлекает из него данные об инфраструктуре (имя ресурса, IP-адрес, теги, тип — VM или база).
-
-
После парсинга данных:
-
создаются или обновляются ассеты в JumpServer через API (с HMAC-подписью);
-
происходит автоматическое распределение по группам, согласно тегам или шаблонам.
-
Вследствие такого подхода у нас нет зависимости от Terraform-провайдеров или Git-хуков, а скрипт можно запускать по расписанию (cron/CI/CD). При этом обнаруживаются как новые ресурсы, так и изменения существующих.
Плюс, работая со стейтами Terraform, я могу сам контролировать ситуацию с добавлением ресурсов — без необходимости привлекать DevOps-команду. Сканирую текущую инфру, делаю скан PAM-сервера, вычисляю дельту, смотрю, чего не хватает и добавляю на PAM-сервер в автоматическом режиме недостающие элементы: учётные записи, ассеты и т.д.
HMAC-аутентификация для автоматизации
Вместо базовой авторизации мы внедрили безопасную HMAC-подпись для запросов к API JumpServer.
HMAC-подпись формируется из AccessKey, SecretKey и Timestamp, после чего передаётся в заголовках запроса. Это исключает риски, связанные с хранением паролей в скриптах, MitM-атаками, и позволяет точно определить, какой сервис выполнил какой вызов.
Рабочий пример:
function Generate-Signature { param ( [string]$Key, # Секретный ключ (SecretID) для HMAC [string]$Data # Строка, которую нужно подписать (stringToSign) ) # Преобразуем ключ и данные в байты $KeyBytes = [System.Text.Encoding]::UTF8.GetBytes($Key) $DataBytes = [System.Text.Encoding]::UTF8.GetBytes($Data) # Создаем объект HMAC-SHA256 и задаем ключ $HMAC = New-Object System.Security.Cryptography.HMACSHA256 $HMAC.Key = $KeyBytes # Вычисляем хэш и возвращаем его в формате Base64 return [Convert]::ToBase64String($HMAC.ComputeHash($DataBytes)) } # Функция Get-AuthHeaders # Назначение: формирует заголовки для HMAC-аутентифицированного запроса к JumpServer API. function Get-AuthHeaders { param ( [string]$KeyID, # Идентификатор ключа (используется в поле keyId) [string]$SecretID, # Секретный ключ для подписи [string]$Path, # Путь запроса, например: "/api/assets/" [string]$Method # HTTP-метод запроса (GET, POST и т.д.) ) # Получаем текущее время в формате RFC1123 (обязательный заголовок 'date') $Date = (Get-Date -Format "R") # Формируем строку request-target для подписи $RequestTarget = "(request-target): $Method $Path" # Формируем полную строку, которую нужно подписать $StringToSign = "$RequestTarget`naccept: application/json`ndate: $Date" # Генерируем подпись с помощью функции Generate-Signature $Signature = Generate-Signature -Key $SecretID -Data $StringToSign # Возвращаем словарь (hashtable) с заголовками для запроса return @{ "Accept" = "application/json" "Content-Type" = "application/json" "X-JMS-ORG" = "00000000-0000-0000-0000-000000000002" # ID организации в JumpServer "Authorization" = "Signature keyId=`"$KeyID`",algorithm=`"hmac-sha256`",headers=`"(request-target) accept date`",signature=`"$Signature`"" "Date" = $Date } } Пример использования: # Функция Get-Assets-By-Name # Назначение: выполняет запрос к JumpServer API для поиска ассетов (ресурсов) по имени. # Возвращает массив ассетов, имя которых соответствует строке поиска. # Параметры: # - $JmsUrl — базовый URL JumpServer (например, https://pam.example.local) # - $KeyID — идентификатор HMAC-ключа # - $SecretID — секретный ключ HMAC # - $SearchName — строка для поиска ассетов (имя, полное или частичное) function Get-Assets-By-Name { param ( [string]$JmsUrl, [string]$KeyID, [string]$SecretID, [string]$SearchName ) # Формируем путь запроса с параметром поиска $Path = "/api/v1/assets/assets/?search=$SearchName" # Генерируем заголовки с HMAC-подписью $Headers = Get-AuthHeaders -KeyID $KeyID -SecretID $SecretID -Path $Path -Method "get" try { # Выполняем GET-запрос к JumpServer API $response = Invoke-RestMethod -Uri "$JmsUrl$Path" -Method Get -Headers $Headers -UseBasicParsing # Если ассеты не найдены — возвращаем пустой массив if ($response.Count -eq 0) { # Write-Warning "Ассет не найден на ПАМ | '$SearchName'" return @() } # Фильтруем результаты по имени ассета (точное или частичное совпадение) return $response | Where-Object { $_.Name -like "$SearchName" } } catch { # Обработка ошибок при выполнении запроса Write-Error "Ошибка при запросе списка ассетов: $_" return @() } } $assets = Get-Assets-By-Name -JmsUrl $JmsUrl -KeyID $KeyID -SecretID $SecretID -SearchName $SearchName
Репозиторий в GitLab с workflow
Этот механизм пока не внедрён в наш прод, но уже протестирован.
В теории доступами в PAM можно управлять вручную через GUI JumpServer, используя разделение на воркспейсы и организационные сущности («организации»). Но этот подход не был для нас оптимальным.
Во-первых, смущала невозможность прямой синхронизации OU из AD в раздельные воркспейсы PAM. То есть пользователей, импортированных из AD, пришлось бы вручную перемещать по организациям, либо дополнительно автоматизировать этот процесс через API.
Во-вторых, нам требуется централизованное и автоматизированное управление доступом через AD, в контексте интеграции PAM с внутренними сервисами.
В результате выбрали такое решение: GitLab → AD → PAM.
Общая схема:

Конфигурации AD-групп хранятся в GitLab-репозитории в виде JSON-файлов. Управление доступом реализовано через механизм Merge Request и CI/CD Pipeline. Процесс выглядит следующим образом:
-
Создание изменений. Тимлид создает Merge Request (MR), в котором редактирует JSON-файл: добавляет или помечает на удаление пользователей (например, с флагом ##).
-
Проверка и утверждение. Ответственный инженер по безопасности (или указанный в CODEOWNERS) проверяет и утверждает MR.
-
CI/CD-пайплайн после слияния. После слияния MR запускается GitLab CI/CD Pipeline, который выполняет:
-
Валидацию JSON. Проверка синтаксиса и структуры JSON-файлов.
-
Запуск скрипта управления AD и PAM. Скрипт (на PowerShell или Python) выполняет:
-
проверку, что имена групп и ассетов соответствуют разрешённым шаблонам (исключение управления чужими группами);
-
проверку наличия групп и их состава в AD;
-
создание новых групп в AD, если они отсутствуют;
-
обновление состава существующих групп в AD — добавление и удаление пользователей;
-
проверку, что группы синхронизированы в PAM;
-
создание или обновление правил доступа к ассетам в PAM через API с использованием AD-групп.
-
-
Обновление репозитория (при необходимости). Скрипт вносит изменения в JSON-файл в репозитории только в следующих случаях:
-
если пользователь был помечен на удаление с флагом ## — он удаляется из АД группы, а сам файл актуализируется;
-
если были автоисправления (например, напрямую из АД удалили пользователя);
-
при добавлении пользователей через MR скрипт не изменяет файл — только применяет изменения в AD.
-
-
-
Безопасность исполнения. Все действия выполняются self-hosted GitLab Runner’ом, работающим во внутренней сети с доступом к AD и PAM.
Логика синхронизации Git ↔ AD ↔ PAM выглядит так:
Добавление пользователей:
-
Если пользователь присутствует в AD-группе, но отсутствует в JSON-файле — он автоматически добавляется с постфиксом # (автодобавление).
-
Если пользователь прописан вручную в JSON, но не найден в AD-группе — он автоматически добавляется в группу AD.
Удаление пользователей:
-
Если пользователь помечен как ##:
-
он удаляется из AD-группы;
-
удаляется из JSON-файла;
-
коммит с изменениями формируется автоматически и пушится в GitLab при выполнении скрипта.
-
-
Если пользователь удалён напрямую из AD, но в JSON-файле имел #:
-
он считается автодобавленным и удаляется из файла.
-
-
Если пользователь удалён из AD, но в JSON указан без #:
-
скрипт восстанавливает его членство в AD-группе.
-
И немного о том, как в рамках процесса мы работаем с безопасностью:
-
Все изменения фиксируются в истории GitLab (MR, commit-log).
-
Журнал изменений в AD может быть синхронизирован с SIEM.
-
Доступ к репозиторию ограничен:
-
только тимлиды и секьюрити-инженеры имеют права на запись;
-
используется CODEOWNERS для обязательного ревью.
-
-
Секреты (например, LDAP_USER, LDAP_PASS) хранятся в GitLab CI/CD Variables:
-
помечены как Protected и Masked;
-
доступны только в нужных окружениях (prod, staging).
-
-
Рекомендуется использовать подписанные коммиты, Protected branches, Environments для разграничения prod/dev логики.
Заметки из опыта внедрения
Проблем, с которыми мы столкнулись в ходе внедрения, по факту было больше, чем я указываю в этом разделе. Но поскольку многие из них довольно специфичны, подсвечу наиболее значимые загвоздки. (К слову, с некоторыми вопросами нам быстро помогла разобраться русскоязычная поддержка продукта: в том числе с их помощью можно отправлять запросы разработчикам.)
-
Проблемы с RDS и русифицированной ОС
После успешной интеграции Remote Desktop Services (RDS) с JumpServer возникла проблема: новые пользователи перестали автоматически пробрасываться с PAM-сервера на RDS. Причина оказалась в русифицированной ОС, где системные группы имели локализованные (русские) названия. JumpServer не мог корректно их интерпретировать.
Рекомендация: использовать ОС без локализации. По последним данным, проблема была решена в более поздних релизах JumpServer.
-
Отображение JSON в Web-интерфейсе PostgreSQL
При выполнении SQL-запросов с JSON-ответами данные отображаются некорректно в веб-интерфейсе JumpServer.
Временное решение:
SELECT response_body::text FROM …
Рекомендация: поскольку приведение JSON к тексту позволяет обойти проблему отображения, при работе с JSON-ответами PostgreSQL имеет смысл использовать текстовую интерпретацию — до появления нативной поддержки.
-
Ограничения при работе с кластерными managed-базами
При работе с MongoDB в JumpServer отсутствовала поддержка проксирования — разработчик уже это исправил, но мы с нюансом успели столкнуться.
Также в многоадресной строке подключения MongoDB не поддерживается формат mongodb://host1,host2,host3/… Подключение к каждому хосту кластера выполняется отдельно — каждый в своём ассете.
Есть нюансы и при использовании Redis Sentinel. Так, JumpServer не поддерживает Sentinel-режим при подключении через ассеты. Подключение к Redis происходит напрямую, минуя механизмы отказоустойчивости Sentinel.
Рекомендация: в проектах с MongoDB и Redis предусматривать временные архитектурные обходные пути (например, отдельные ассеты или использование клиентов вне PAM до появления поддержки).
***
В итоге мы не просто получили в распоряжение подходящий инструмент для контроля привилегированных доступов. Но и на практике убедились: JumpServer можно гибко адаптировать под реальные процессы — от интеграции с AD и Terraform до публикации GUI-приложений через RDS. Отдельно радует, что продукт развивается: появляются новые фичи и фиксятся баги, а разработчики оперативно реагируют на обратную связь по проблемам, возникающим в ходе эксплуатации.
Будем рады узнать о вашем опыте использования подобных инструментов — и ответить на вопросы по нашей реализации. Пишите в комменты!
ссылка на оригинал статьи https://habr.com/ru/articles/924308/
Добавить комментарий