Привет! Меня зовут Даниил Донецков, я DevOps-инженер в KTS.

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

Мы решили проблему с помощью сервиса Firezone, и в этой статье я хочу поделиться нашим опытом. Сегодня я расскажу о том, как DevOps-юнит KTS:

  • внедрил виртуальную сеть в существующую инфраструктуру, состоящую из двух k8s-кластеров и нескольких ВМ в разных облаках;

  • обеспечил бесперебойный доступ для более чем 150 сотрудников к веб-сервисам.

Оглавление

Почему Firezone

Наш выбор пал на Firezone по нескольким причинам.

  • Сервис имеет открытый исходный код. Он активно поддерживается, регулярно обновляется и улучшается.

  • Изначально Firezone спроектирован для горизонтального масштабирования. Следовательно, при работе с ним можно просто поднять новый сервер и запустить на нем дополнительный компонент частной сети.

  • Основан на протоколе WireGuard, что гарантирует скорость и безопасность.

  • Управляется и настраивается из веб-интерфейса, поэтому для настройки не приходится вручную менять конфиги на серверах.

  • Можно закрыть сеть от сторонних пользователей через интеграцию с сервисом Keycloak.

  • Можно включать по доменам. Если домен переедет, Firezone сам позаботится о том, что вы получите доступ к ресурсу.

Примечание: в документации Yandex Cloud есть инструкция по установке Firezone, но относится она к версиям Firezone 0.7.*. Мы же поговорим о том, как развернуть версии 1.*.*, у которых есть заметные преимущества (о них ниже).

Сборка

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

По сути, мы допиливали только «голову» — API, Domain и Web. В Web мы исправляли скрипты для деплоя сетевых компонентов (Relay и Gateway, о них поговорим отдельно), фиксировали версию и игрались с параметрами.

Для самих сетевых компонентов мы решили не переделывать Docker-образы, поскольку для наших целей хватает и общедоступных.

Подготовка Helm Chart

В своем репозитории разработчики для тестирования запустили голову через Docker-Compose. Так же они форкнули репозиторий с чартом, но не поддерживают и не актуализируют его.

Мы же форкнули оригинальный репозиторий и добавили в него:

  • CronJob для вытягивания пользователей из Kecyloak: голова Firezone не умеет самостоятельно синхронизировать пользователей с сервисами аутентификации, и для решения этой проблемы мы добавили в наш Helm chart кронджобу, которая каждый час синхронизирует пользователей, добавляя их в основную группу;

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

Запуск в Kubernetes

Мы запускаем Firezone в k8s через Terraform. Весь процесс инициализации занимает меньше часа, после чего Firezone уже готов к работе.

Вся прелесть версий 1.*.* в том, что голова (в документации называемая «Portal») не обязана быть развернута на сервере, через который будет выполняться подключение к сервисам. Таким образом, обслуживать голову становится заметно легче.

Инициализация организации

Для инициализации организации нужно выполнить следующие действия:

  1. Подключиться к поду firezone-web:
    kubectl exec -n firezone -it deployment/firezone-web -- bash

  1. Запустить окружения Elixir:
    bin/web remote

  1. Создать аккаунт:
    {:ok, account} = Domain.Accounts.create_account(%{name: "<ACCOUNT_NAME>", slug: "<ACCOUNT_SLUG>"})

  1. Создать провайдера Keycloak:
    {:ok, openid_connect} = Domain.Auth.create_provider(account, %{name: "<PROVIDER_NAME>", adapter: :openid_connect, adapter_config: %{"auto_create_users" => true, "client_id" => "firezone", "client_secret" => "<CLIENT_SECRET>,"response_type" => "code","scope" => "openid email profile offline_access","discovery_document_uri" => "<KEYCLOAK_DOCUMENT_URI>","redirect_uri" => "https://<FIREZONE_HOST>/auth/oidc/<PROVIDER_NAME>/callback/"}})

  2. Создать первого админ-пользователя:
    {:ok, actor} = Domain.Actors.create_actor(account, %{type: :account_admin_user, name: "<ADMIN NAME>"})

  3. Создать идентификатор для первого админ-пользователя:
    {:ok, identity} = Domain.Auth.upsert_identity(actor, openid_connect, %{provider_identifier: "<ADMIN_EMAIL>", provider_identifier_confirmation: "<ADMIN_EMAIL>"})

  4. Разблокировать расширенную функциональность:
    account |> Ecto.Changeset.change(features: %{flow_activities: true,policy_conditions: true,multi_site_resources: true,traffic_filters: true,self_hosted_relays: true,idp_sync: true,rest_api: true})|> Domain.Repo.update!()

После этого вы сможете войти в ваш аккаунт:

Авторизация через Keycloak будет выглядеть следующим образом:

Добавление ресурсов

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

После создания сайта в интерфейсе откроется его вкладка. В нем можно добавить новые шлюзы и ресурсы (ip-адреса, подсети и домены).

Деплой Gateway-сервисов

Gateway-сервисы, или шлюзы — это двоичные файлы Linux, которые работают в вашей инфраструктуре. Их можно развернуть и в виде контейнеров Docker, и в виде служб systemd через дефолтный скрипт, или же взять минимально рекомендуемые настройки системы для запуска шлюза и сделать свой вариант запуска.

Шлюзы были разработаны как переносимые, чрезвычайно легкие и не требующие внешних зависимостей. Это упрощает их развертывание и управление ими в больших масштабах.

Работают шлюзы без необходимости в постоянном хранилище; вместо этого для их правильного функционирования требуется настроить лишь несколько переменных среды. Дополнительную информацию об их деплое см. в руководстве по развертыванию шлюзов.

Firezone предоставляет 4 готовых варианта развертывания шлюзов — через systemd, Docker, Terraform и кастомный. По сути это вкладки с готовым кодом, который можно просто скопировать и выполнить на нужной машине. Этот готовый код пришлось немного допилить, чтобы команды работали сразу, и любой сотрудник с необходимым доступом смог бы создать или масштабировать систему. В результате получилось довольно удобно.

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

При этом помимо перечисленных способов есть еще один, неочевидный — деплой через Helm chart. В стандартных вариантах деплоя его нет, но Helm chart для Gateway можно найти на GitHub. Gateway-сервис, развернутый в k8s-кластере, позволяет обращаться к сервисам внутри Kubernetes по DNS кластера (к примеру, postgres.database.svc.cluster.local).

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

  • пользователям группы DataScience доступны ресурсы  **.database.svc.cluster.local (все сервисы в неймспейсе Database);

  • пользователям группы KubernetesAdmins доступны ресурсы  **.svc.cluster.local (все сервисы в Kubernetes).

Деплой Relay-сервисов (отдельные STUN-серверы)

Relay (ретрансляторы) помогают клиентам устанавливать прямые соединения со шлюзами, используя метод обхода NAT, стандартизированный как STUN. Это хорошо работает в подавляющем большинстве случаев.

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

  • клиент или шлюз находятся за особенно строгим брандмауэром, который иногда называют симметричным NAT. Такие брандмауэры чаще встречаются в корпоративных средах, но в последние годы их использование сокращается;

  • сетевая среда клиента или шлюза блокирует трафик WireGuard. Это случается редко, но может произойти в некоторых общедоступных сетях Wi-Fi и даже в некоторых странах.

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

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

Однако коммьюнити не дремлет: к примеру, тут можно найти инструкцию для поднятия Relay через systemd. Сразу оговорюсь: запуск двух ретрансляторов на одном сервере — подход сомнительный и нестабильный, они валятся с ошибкой занятого адреса. Лучший вариант — запускать по одному Relay-сервису на одной машине, и машин должно быть как минимум две.

Мы же запустили ретрансляторы в YC с помощью Terraform.

Закрытие ресурсов от Ethernet

Посмотрим на примерах, как закрыть ресурсы наших сервисов от общего доступа.

  • В k8s — отдельный ingress для админской консоли поднимается со следующей анотацией:
    nginx.ingress.kubernetes.io/whitelist-source-range: "{gateway_ip}"

  • Для сервисов на ВМ с доступом через nginx:
    Location /admin {
    allow {gateway_ip};
    deny all;
    }

Заключение

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

Кстати, у коммьюнити Firezone есть активный Discord-канал. Сам я неоднократно писал туда при возникновении проблем с деплоем, поддержкой и обслуживанием сервиса. В канале можно задать любой вопрос. Особенно приятно, что быстро отвечают не только активные пользователи, но и разработчики сервиса.

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

Также рекомендую почитать статьи моих коллег для DevOps-инженеров:

И, наконец, напоминаю о том, что мы регулярно проводим DevOps-челленджи и награждаем победителей крутым мерчом. Доступ к архивным челленджам всегда открыт, так что вы можете начать готовиться к будущим испытаниям уже сейчас. Переходите в бота по ссылке, и он расскажет вам подробности.

Удачи!

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


  1. chemtech
    25.12.2024 15:12

    Рассматривали ли NetBird?