Привет! Меня зовут Амир Уразалин, я DevOps-инженер в KTS.

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

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

Оглавление

Где начали проявляться ограничения старой схемы

Изначально модель была классической: Ansible-плейбук на каждом проекте создавал пользователей и доставлял их публичные SSH-ключи на 100+ виртуальных машин. Это работало, но со временем стали заметны минусы такой схемы:

  • Нет связи с корпоративной учетной записью. Доступ к серверам определяется SSH-ключом, а не ролью пользователя или его актуальным статусом в компании.

  • Доступ приходится обновлять вручную на каждом проекте. При добавлении нового инженера нужно отдельно прогонять плейбуки на инфраструктуре каждого проекта.

  • Отзыв доступа занимает время. Чтобы убрать доступ, нужно прогнать playbook и убедиться, что он применился на всех хостах. Если какая-то машина была недоступна, то доступ может остаться, появляется угроза безопасности.

  • Сложно понять, кто подключался к серверу. При инциденте приходится искать информацию в логах на отдельных машинах.

Ansible отлично справляется с конфигурацией серверов, но доступ к инфраструктуре — это не только конфигурация, это политика и контроль. В какой-то момент стало очевидно: мы управляем ключами, но не управляем доступом.

А доступ к инфраструктуре все-таки должен определяться не наличием SSH-ключа на сервере, а ролью пользователя в корпоративной системе и актуальным статусом в компании. Стало понятно, что нужна другая модель доступа.

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

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

При этом единая точка входа не должна становиться single point of failure. Поэтому хотелось иметь возможность развернуть решение в Kubernetes и запустить несколько реплик для отказоустойчивости.

Разбираем, как мы внедрили клиентам Warpgate bastion с SSO, RBAC и IaC вместо набора jump-host и Ansible-плейбуков.

Что такое Warpgate

Warpgate — это опенсорсный сервис, который работает как прозрачный бастион-хост для доступа к внутренним и публичным ресурсам: SSH, HTTPS, базам данных (MySQL, PostgreSQL) и Kubernetes.

Warpgate принимает подключение пользователя, проверяет его аутентификацию и роли, после чего проксирует соединение напрямую к целевому ресурсу. 

Важный момент: Warpgate работает без установки агентов на целевые серверы. Для внедрения не нужно разворачивать отдельные компоненты на каждой виртуальной машине.

Сервис поддерживает SSO и двухфакторную аутентификацию, записывает сессии и позволяет посмотреть историю подключений через встроенный веб-интерфейс. Фактически Warpgate становится единой точкой доступа к инфраструктуре, через которую проходят все подключения.

Чем Warpgate отличается от jump-хостов, VPN и Teleport

Обычно такие решения приходится дополнительно сравнивать и отдельно обосновывать выбор. В случае с Warpgate это оказалось проще: в README проекта на GitHub уже есть сравнительная таблица с отличиями от других подходов.

Warpgate

SSH jump host

VPN

Teleport

✅ Точная привязка пользователей к конкретным сервисам

Обычно: полный доступ к сети за jump-хостом

Обычно: полный доступ к сети

✅ Точная привязка пользователей к конкретным сервисам

✅ Не нужен отдельный клиент

Требуется настройка jump-хоста

✅ Не нужен отдельный клиент

Требуется отдельный клиент

✅ 2FA из коробки

🟡 2FA возможно через дополнительные PAM-плагины

🟡 Зависит от провайдера

✅ 2FA из коробки

✅ SSO из коробки

🟡 SSO возможно через дополнительные PAM-плагины

🟡 Зависит от провайдера

Платно

✅ Аудит на уровне команд

🟡 Аудит только на уровне соединения на jump-хосте, без безопасного аудита на целевом хосте при наличии root-доступа

Безопасный аудит на целевом хосте невозможен при наличии root-доступа

✅ Аудит на уровне команд

✅ Полная запись сессий

Безопасная запись на целевом хосте невозможна при наличии root-доступа

Безопасная запись на целевом хосте невозможна при наличии root-доступа

✅ Полная запись сессий

✅ Неинтерактивные подключения

🟡 Возможны, если клиент нативно поддерживает jump-хост

✅ Неинтерактивные подключения

Для неинтерактивных подключений нужен SSH-wrapper или запуск туннеля

✅ Self-hosted, данные хранятся у вас

✅ Self-hosted, данные хранятся у вас

🟡 Зависит от провайдера

SaaS

Источник: официальное сравнение в README проекта Warpgate на GitHub, перевод мой.

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

Архитектура решения

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

SSO через Keycloak

Аутентификацию в Warpgate мы настроили через Keycloak по OIDC. В Keycloak у нас заведены группы, которые соответствуют ролям или проектам. Например, группа /teams/devops/project-A означает, что пользователь должен получить доступ к инфраструктуре проекта project-A.

Дальше схема простая: человека добавляют в нужную группу в Keycloak, после чего он заходит в Warpgate через SSO. Warpgate получает группы пользователя из OIDC-токена, автоматически создает ему аккаунт и назначает роль по настроенному маппингу.

За счет этого доступ к проектам управляется через группы в Keycloak. Чтобы выдать доступ, достаточно добавить человека в нужную группу. Чтобы отозвать — убрать из нее.

Ниже показана часть конфигурации warpgate.yaml:

sso_providers:
  - name: keycloak
    label: "Login with Keycloak"
    auto_create_users: true
    provider:
      type: custom
      client_id: warpgate
      client_secret: $OIDC_CLIENT_SECRET
      issuer_url: $ISSUER_URL
      scopes: ["openid", "email"]
      role_mappings:
        '/teams/devops/warpgate-admin': 'warpgate:admin'
        '/teams/devops/project-A': 'project-A'
        '/teams/devops/project-B': 'project-B'

В этом примере группа /teams/devops/warpgate-admin маппится на админскую роль в Warpgate, а группа /teams/devops/project-A — на роль, которая дает доступ к ресурсам проекта project-A.

Доступ к инфраструктуре as-a-code

У Warpgate есть свой Terraform Provider, и мы активно его используем. Через него мы описываем не просто список серверов, а всю схему доступа: какие есть роли, к каким ресурсам они привязаны и через какой шлюз идет подключение.

Для нас это особенно важно, потому что проектов много. Если управлять ресурсами, ролями и доступами вручную через UI, то при росте числа проектов такая схема просто перестает масштабироваться. Особенно это заметно при подключении нового клиента: если в его инфраструктуре 100+ серверов, заводить их руками в интерфейсе долго, неудобно и просто рискованно — слишком легко ошибиться в адресах, ролях или привязках доступа.

Сама Terraform-структура у нас отражает простую идею. В корне описан центральный Warpgate. Дальше каждый клиентский проект вынесен в отдельную папку, чтобы все его ресурсы, роли и правила доступа лежали отдельно и не смешивались с другими.

Если инфраструктура проекта находится во внутреннем контуре и недоступна напрямую, внутри его папки появляется inner. В нем описан отдельный Warpgate, который играет роль шлюза и дает доступ к внутренним ресурсам клиента.

В итоге структура остается понятной: в корне находится центральная точка входа, а внутри проектов отдельно описан доступ до внутренних ресурсов клиента, например до виртуальных машин с внутренними IP.

Что Warpgate не делает

Важно понимать, что Warpgate не отменяет Ansible полностью. На целевых ВМ все равно нужен технический пользователь, под которым Warpgate будет подключаться к хостам.

Но разница в том, что этот пользователь один, и его не нужно создавать заново для каждого инженера. Вместо раскатки множества пользователей и SSH-ключей на все машины мы поддерживаем один технический доступ со стороны Warpgate, а права инженеров уже управляются централизованно через SSO и роли.

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

Что изменилось на практике

Главный эффект от такого подхода — доступ инженеров к клиентской инфраструктуре больше не управляется через персональные SSH-ключи и локальных пользователей на серверах.

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

В итоге схема доступа становится проще в сопровождении и лучше масштабируется на несколько клиентских проектов.

Если вы тоже используете Warpgate или похожие решения, делитесь опытом в комментариях, будет интересно сравнить подходы!

А если интересно почитать еще о том, как мы работаем с инфраструктурой, рекомендую статьи моих коллег: