Коллеги, Здарова!
Меня зовут Храмов Максим. И сегодня мне хотелось бы рассказать, как мы управляем приложениями в изолированном контуре. Вообще, прецедентом для написания статьи стал один из наших последних заказов. Мы работали с инфраструктурой заказчика, которая являлась очень гетерогенной, а совместно с этим ожесточалась правилами информационной безопасности.
В разных сетях находились десятки K8S кластеров, в сутки создавались и удалялись десятки виртуальных машин и все из этого нужно было конфигурировать. А одним из требований к нашей работе, стало использование, так называемого нами, контролируемого периметра. То есть всем приложениям работающие в нем, строжайше запрещалось взаимодействовать с публичными сетями любым образом, начиная DNS и NTP запросами и заканчивая использованием публичных Docker Registry, APT, PyPI, npm, Helm, Maven и других репозиториев.
И мне хотелось бы поделиться очевидными и не очень решениями, к которым мы пришли.
Для начала я дам определение контролируемому периметру, в нашем понимании это изолированные сети, обычно в разных VLAN, которые не имеют прямой связи с интернетом. Прямой связи - означает, что мы используем внутренние прокси, шлюзы или бастион хосты для подключения к внешним сетям.
Таким образом, мы создаем одну из самых классических, дешевых и легким способов отделить внутренние сети от внешних, для примера я зарисую ниже.

Что мы видим на этой упрощенной топологии:
Во-первых доступ в приложение осуществляется через отдельный VLAN с веб-балансировщиками.
Во-вторых внутри сети располагаются собственные DNS сервера, NTP сервера и все другие инфраструктуры штучки. Таким образом мы уже немного изолировались от интернета.
В-третьих мы видим, что все межсетевое взаимодействие у нас осуществляется через firewall. Вот тут и начинается движуха. Мы можем себе позволить запретить доступ VLAN 200 и 250 в публичную сеть, способов много, начиная от правил на firewall
VLAN200 -> VLAN103:443 ALLOW
VLAN250 -> VLAN103:443 ALLOW
VLAN200 -> WAN DENY
VLAN250 -> WAN DENY
VLAN103 -> WAN:443 ALLOW
Заканчивая маршрутизацией. Тут уже кто на что горазд.
И вот, казалось бы все хорошо, у нас на виртуальных машинах установлено актуальное время, разные продуктовые VLAN ограничены. Но совсем скоро мы сталкиваемся с проблемой - а как, например, устанавливать APT пакеты, если у нас нет прямого доступа в deb.debian.org, или как мы можем скачать новый образ докера и затеплить его.
Тут нашему взору открывается новая DMZ сеть, в которой располагаются кеширующие и проецирующие репозитории. Тут мы, кстати, решаем сразу несколько проблем, во-первых мы естественно ограничили доступ продуктовых контуров в глобальную сеть, с помощью правил на FW мы можем управлять тем, какой VLAN может сходить в WAN, а какой VLAN не сможет установить соединение с внешней сетью. Но и одной из неочевидных причин это ограничение запросов к публичным репозиториям, например, на docker hub есть ограничение на сто запросов на pull , интервалом на 6 часов. Пару раз мы уже встречали с тем, что несколько разработчиков или девопсов решили спуллить себе образов и нарвались на ограничение, тем самым парализовав работу другие людей.
Для создания кеширующих репозиториев мы выбрали для себя следующие решения.
Для Docker - harbor. Позволяет кешировать любые образы и теги, обладает репликацией и поддержкой скандирования образов на всякую заразу.
Для Java Maven мы используем или Sonatype Nexus, если позволяет лицензия, либо Jfrog. Оба решения полностью удовлетворяют требования кеширования.
Для Helm чартов мы любим использовать или тот же Sonatype Nexus, либо Harbor.
Sonatype Nexus оказался очень крутым инструментом, ведь через него мы проксируем вдобавок и Ansible коллекции, и NPM и много всего остального
Интересная ситуация оказалась с APT репозиториями. Сначала мы использовали старый и популярный APT-Mirror, но быстро от него отказались. С ним было много проблем, отсутствовало нормальное легирование и мониторинг, а еще нам хотелось уметь добавлять репозитория по API чтобы более детально использовать IaC. Потом попробовали Aptly, но он используется для другого, в основном для создания своих кастомных репозиториев, а не зеркал и кеша, и нам не особо подходил. Попробовали еще пару решений, которые нам тоже не подошли по тем или иным причинам и сделали ход конем. Мы изобрели очередной велосипед и разработали собственный сервис для зеркалирования APT репозиториев. А чуть позже даже сделали его публичным APT Relay. И используем его в продуктовых окружениях и поддерживаем его. Постарались добавить весь необходимый нам функционал, начиная от добавлением репозиториев и запуск синхронизаций по API. А заканчивая удобным алертингом и логированием.
Теперь вернемся ненадолго к сегментированию сети. Мы составляем для каждого заказчика определенную матрицу с доступами
Source (Источник) |
Destination (Назначение) |
Protocol |
Port |
Description |
WAN |
Reverse Proxy — VLAN 102 |
TCP |
443 |
Публикация внешних HTTPS-сервисов |
APP-01 — VLAN 200 |
DNS — VLAN 50 |
UDP |
53 |
Разрешение DNS-имен |
APP-01 — VLAN 200 |
Infra DMZ — VLAN 103 |
TCP |
443 |
Docker/Helm/APT/Nexus/Artifactory/Harbor |
Очень рекомендуем взять шаблон себе на вооружение и вести такую же матрицу доступов для себя, только не пренебрегайте комментариями.
Так же мы считаем, что у нас разрешено только то, что не запрещено - поэтому запрещаем любое сетевое взаимодействие между всеми VLAN по умолчанию. Так же не забывайте, что DNS, NTP, LDAP/idM - это критическая инфраструктура и должна работать автономно, без зависимостей от внешних сетей.
Так же мне очень хочется напомнить по IPv6, частенько наблюдал ошибки, когда IPv4 фильтрует, а IPv6 нет :).
И под конец я бы хотел развить еще одну мысль. Полная изоляция сети обычно выглядит самым безопасным вариантом на первый взгляд. На второй взгляд становится ясно, что чем сильнее контура отделены от внешней инфраструктуры, чем гораздо сложней становится их эксплуатация. В полной air-gap среде даже простая операция, вроде, установки новой версии пакета превращается в отдельный адский процесс: пакет нужно получить снаружи, проверить, перенести внутрь изолированного контура, зарегистрировать и самое важное убедится, что вмести с этим пакетом доставлены все его зависимости, расстроиться и повторить эту процедуру еще несколько раз. Здесь вам нужно принять компромисс: чрезмерно строгая изоляция может снизить сетевые риски, но при этом одновременно создавать эксплуатационные затраты. Если процедура обновления слишком сложная, то ваши системы будут обновляться гораздо реже. А если нормальной матрицы доступа нет, то резко повышаются негативные последствия.
Подведу вас к выводу:
Перед созданием изолированных (ait-gap) сетей стоит определить какую именно проблемы мы пытаемся решить.
Если наша проблема звучит как, рабочие сервера должны быть изолированы от интернета , то для этого совсем не обязательно физически разрывать сеть, достаточно сделать контролируемый периметр с VLAN, бастионом, FW и DMZ сетями. В такой архитектуре продуктовое окружение действительно будет изолировано от интернета и неконтролируемых внешних взаимодействий, а так же мы действительно упростим себе жизнь, избавившись от эксплуатационных рисков.
В ином случае, вам необходимо здраво оценить стоимость физического разделения ваших сетей, самое главное вам надо помнить, что каждая "ступень" повышает безопасность определённого класса угроз, но одновременно повышает стоимость эксплуатации. По этому хороший изолированный контур - это не обязательно максимально закрытый. А хороший тот, где каждое сетевое взаимодействие понятно, минимально и обязательно контролируется. Именно поэтому в большинстве корпоративных инфраструктур практичнее строить не абсолютный air-gap, а контролируемый периметр. Внутренние системы остаются изолированными, а взаимодействие с внешним миром происходит через небольшое количество специально предназначенных и хорошо защищённых сервисов.
Храмов Максим