Военная архитектура SSH. Узел-бастион и принцип нулевого доверия
В инфраструктуре организации есть такое понятие, как узел-бастион — специальный компьютер в сети, обычно на внешней стороне демилитаризованной зоны (ДМЗ) организации. Узел назван по военной терминологии. Если кто видел средневековые крепости, там есть специфические выступы — бастионы, как на КДПВ.
То же самое в компьютерных сетях. Например, перед защищённой компьютерной сетью ставится специальный сервер, через который пробрасывается SSH-туннель в свою частную сеть. Данный «бастион» организуется в соответствии с концепцией нулевого доверия, которая предполагает абсолютное недоверие ко всем объектам и пользователям как снаружи организации, так и внутри неё.
Есть несколько вариантов, как технически организовать такую схему. Можно всё сделать самому, а можно использовать готовые сервисы SaaS, которые решают эту задачу.
Узлы-бастионы используются для разных целей, в том числе:
- как веб-сервер,
- DNS-сервер,
- почтовый сервер (например, SMTP),
- FTP-сервер,
- прокси,
- NNTP-сервер,
- ловушка (honeypot),
- VPN-сервер,
- и др.
Если узел используется для доступа к частной сети, его также называют джамп-сервером.
▍ Что такое джамп-сервер
Джамп-сервер (jump server) предоставляет доступ к сервисам внутренней инфраструктуры. Соответственно, для всех внешних (а то и внутренних) пользователей доступ к этим внутренним сервисам осуществляется только через бастион. В принципе, тут нет ничего сложного, а типичные решения для организации SSH-туннелей хорошо описаны на Хабре. Более конкретную инструкцию см. в статье «Помощь друзьям с использованием OSS для удалённого администрирования при наличии публичного IP-адреса».
Проблемы начинаются при масштабировании. Если мы организуем постоянный доступ для множества пользователей (например, для сотрудников организации), то такой сервер требует обслуживания и специальной настройки. Нам необходимы:
- особая конфигурация для доступа к конкретной среде (например, RDP и Windows);
- обязательное обновление последними патчами безопасности;
- ротация SSH-ключей и обновление, когда приходят/уходят сотрудники (ротация ключей SSH в любом случае необходима даже без изменения штатного списка — часто для этого применяют специальные модули или службы, то есть это ещё одна отдельная задача);
- управление ролями через
sudo
, проверка правильности настроек разрешений файловой системы и принадлежности пользователей к соответствующим группам. Нужно строго ограничивать возможности пользователей, чтобы они не навредили себе и другим, а именно: - специальный инструментарий;
- список актуальных сервисов, доступных для взаимодействия (это может быть статический файл, известное имя DNS или документация, как взаимодействовать с этими серверами).
Для управления подобными серверами используют инструменты автоматизации, такие как Terraform, Packer и Ansible.
Поддержка этой инфраструктуры становится дополнительной нагрузкой, которая ложится на плечи штатных инженеров и сисадминов. Никто не будет нанимать отдельный персонал для такой роли, хотя сама задача становится всё более сложной: растёт и нагрузка на сервер, и количество пользователей, и количество инструментов.
Взаимодействие с джамп-сервером осуществляется с помощью SSH-клиента. Это тоже представляет определённую проблему, потому что не всегда легко через SSH-клиент получить все нужные данные из службы внутри VPN. Необходимо сначала установить SSH-соединение с джамп-сервером, потом с другим сервером, затем скопировать искомое содержимое в файл (например, при помощи scp
). Вот нативный подход такого взаимодействия:
$ ssh -A bob@jump-server
$ ssh bob@internal-server '/usr/local/bin/myscript.sh > output.csv'
$ scp bob@internal-server:output.csv . && exit
$ scp bob@jump-server:output.csv .
Локальный проброс портов:
$ ssh -N bob@jump-server -L 8080:internal-web-server:3000
Работу с джамп-сервером облегчает ssh-agent
. Это специфический клиент SSH, который хранит данные аутентификации за пределами одной сессии, способен хранить в памяти расшифрованные ключи и устанавливать соединение с SSH-клиентами через IPC-сокет (сокет межпроцессного взаимодействия. Подробнее об SSH-агентах см. здесь.
▍ Менеджмент джамп-сервера
Для управления инфраструктурой джамп-серверов созданы даже специальные (коммерческие) сервисы, такие как Hoop. В данном случае вместо управления джамп-сервером и всеми инструментами на нём мы управляем агентами, где изначально заложены необходимые инструменты и примитивы. Это замена одной плоскости менеджмента на другую (теоретически, более удобную).
Здесь реализована собственная платформа идентификации, автоматическая ротация ключей SSH, назначение ролей пользователей. Все настройки для sudoers, серверов DNS и прочего делаются автоматически через SSH-агента (hoop).
Некоторые примеры из официальной документации.
Подключение к инстансу postgres
на локальном порту:
$ hoop connect postgres-prod
Проброс порта внутреннего API:
$ hoop connect my-internal-api -p 8000
Создать интерактивную консоль Rails или сессию Django:
$ hoop connect rails-console-homolog
$ hoop connect django-prod
Выполнить скрипт непосредственно в приложении Rails:
$ hoop exec rails-exec-prod <
В общем, неплохой инструмент для джамп-сервера в дополнение к стандартным клиентам SSH, RDP и VPN.
▍ Zrok: P2P-туннели на OpenZiti
Ещё одна новая опенсорсная разработка — система Zrok на базе OpenZiti, создающая безопасный туннель между разными средами, сетями, VPN и т. д.
Вот как выглядит туннель Shares — Public между приватной сетью и открытым интернетом для публичной раздачи (шаринга) ресурсов:
При этом на «публичной» стороне туннеля не требуется установка какого-то специализированного программного обеспечения, клиента zrok
и др. То есть система ориентирована на максимально быстрое и простое использование, в том числе неподготовленными людьми.
Другой вариант — пиринговый туннель Shares — Private между двумя приватными сетями (или персональными компьютерами):
В данном случае безопасный зашифрованный туннель устанавливается между клиентами zrok
(доступны в виде бинарников).
Типичные варианты использования публичного гейта:
- предоставление доступа к своему серверу разработки для друзей и коллег;
- быстрый хук на свой сервер в облаке (например, AWS) для доступа извне;
- публикация в открытом доступе файлов или других ресурсов со своего сервера (например, порт);
- децентрализованный хостинг файлов, репозиториев, видео (в будущем).
Все генерируемые URL по умолчанию эфемерны, то есть прекращают существование сразу после того, как останавливается раздача ресурсов с сервера (в отличие от опции Shares — Reserved, которая генерирует долговременные, постоянные URL).
Примеры команд из документации.
Установка нового контроллера zrok.mydomain.com
вместо адреса по умолчанию api.zrok.io
:
$ zrok config set apiEndpoint https://zrok.mydomain.com
Теперь установка соединения между серверами и клиентами будет происходить через новый контроллер.
Раздача файлов с сервера:
$ zrok share public . --backend-mode web
После этой команды файлы на сервере становятся доступны по публичным URL такого типа:
Платформа Zrok доступна как облачный сервис SaaS или в варианте self-hosted для установки на своём сервере бесплатно (репозиторий Github). В обоих случаях Zrok работает как отдельный узел (контроллер), связывающий серверы и клиентов. Такой же «бастион» перед частной сетью, как в военной архитектуре. Несмотря на интеллектуальный статус информационной безопасности, в ней на удивление часто используется военная терминология.
Примечание. OpenZiti (и Zork) — одна из технологий для удобного шаринга ресурсов между компьютерами, устройствами и приложениями (приватный VPN или zero trust network). В качестве альтернативных инструментов можно использовать Tailscale, ZeroTier, Cloudflare Tunnels, Yggdrasil и др.