Шлюз Salt.Box
Шлюз Salt.Box (Salt.Box Gateway) — это компонент платформы Salt.Box, реализующий API Gateway для микросервисной архитектуры.
Он обеспечивает маршрутизацию запросов, балансировку нагрузки, health-check сервисов, кэширование, а также централизованное управление доступом на основе политик OPA (Open Policy Agent) и системы разрешений приложений («пермишенов»).
Шлюз Salt.Box работает поверх фреймворка FastAPI, интегрируется с Redis для хранения состояния и кэша, а также с OPA для проверки разрешений.
Пермишен (от англ. permission — разрешение, дозволение) — механизм безопасности, предназначенный для защиты конфиденциальности пользователей.
Он ограничивает доступ приложений к различным функциям и данным на устройстве.
Архитектура
Компоненты шлюза Salt.Box:
- ServiceDAO — слой доступа к данным о сервисах (Redis)
- ProxyService — основной класс для проксирования запросов, балансировки, проверки доступа
- BalancingStrategy — фабрика стратегий балансировки
- AsyncOpaClient — клиент для проверки политик OPA
- CustomRedisCache — кэширование ответов
Основные возможности
- Динамическое обнаружение и управление сервисами (Service Discovery)
- Балансировка нагрузки (Round Robin, Weighted RR, Random)
- Health-check экземпляров сервисов
- Кэширование ответов
- Проксирование статических файлов
- Управление доступом через OPA и пермишены
- API для управления сервисами и экземплярами сервисов
- Swagger/OpenAPI документация для сервисов
Динамическое обнаружение и управление сервисами
Функции управления сервисами, реализуемые шлюзом Salt.Box:
- Регистрация/отключение/удаление сервисов и их экземпляров через API
- Автоматическое обновление состояния (health-check)
- Поддержка нескольких экземпляров одного сервиса
Регистрация сервиса в Discovery
Для регистрации нового сервиса (например, core) используется механизм Service Discovery.
Сервис при запуске отправляет информацию о себе (имя, точки подключения («эндпоинты»), тип, стратегия балансировки, разработчик и пр.) шлюзу Salt.Box через API или напрямую в Redis.
Эндпоинт (от англ. endpoint — точка подключения) — конкретный сетевой адрес, URL, который определяет точку доступа к ресурсу или услуге на сервере.
Клиентское приложение обращается к конечной точке для выполнения определённых операций или получения данных.
Регистрация сервиса выполняется по следующему алгоритму:
- Если сервис с таким именем ещё не зарегистрирован, добавляется один экземпляр сервиса.
- Если сервис уже существует, то добавляется новый экземпляр этого сервиса, при совпадении
idсервиса обновляется текущий экземпляр. - В SDK реализован клиент, который отправляет POST-запрос на
/api/discovery/registerс описанием сервиса и его экземпляра. - При регистрации сервис передаёт шлюзу полный список своих эндпоинтов с их настройками: политикой доступа (OPA policy), параметрами кэширования (
cache_ttl), partial-query, action и др. - После регистрации сервис появляется в списке доступных сервисов шлюза и становится доступен для проксирования.
- На основе зарегистрированных эндпоинтов шлюз осуществляет проверку доступа (через OPA) и кэширование ответов согласно настройкам эндпоинта.
Балансировка нагрузки
Шлюз Salt.Box поддерживает следующие стратегии балансировки нагрузки:
rr— Round Robin (Циклический перебор)wrr— Weighted Round Robin (Взвешенный циклический перебор)rand— Random (Случайная)
Стратегия задаётся для каждого сервиса, её можно менять через API.
Кэширование
- Кэшируется только успешные ответы (
200 OK), если эндпоинт поддерживает TTL. - Кэш хранится в Redis,
namespace:gate_cache. - Кэш отключается для Swagger/OpenAPI и приватных эндпоинтов.
Проксирование статических файлов
Для сервисов с настроенным static_host запросы к статическим файлам проксируются напрямую.
Авторизация и управление доступом
Шлюз Salt.Box реализует централизованную систему управления доступом на основе OPA (Open Policy Agent) и пермишенов, поддерживающую модель ABAC (Attribute-Based Access Control).
Преимущества решения
- ABAC: доступ определяется на основе атрибутов пользователя, ресурса, действия и сервиса.
- Гибкость: политики сгруппированы по сервисам, например: core (Ядро), scheduler (Планировщик), ресурсам, например: задачи (tasks), команды (jobs), коллекции (collections) и действиям, например: read (чтение), create (создание).
- Масштабируемость: легко добавлять новые сервисы, ресурсы, роли и условия.
- Partial Query: OPA может возвращать фильтр для ограничения данных на уровне запроса.
Интеграция с OPA (Open Policy Agent)
Для каждого эндпоинта сервисов задаётся OPA-конфигурация: policy, action, partial-query, unknowns.
Шлюз Salt.Box формирует структуру input для OPA: subject (user), action, resource (service, path, query, body).
OPA возвращает разрешение (allow) и, при partial, query для фильтрации данных.
Пример структуры input для OPA:
{
"subject": {
"sub": "user_id",
"email": "user@example.com",
"roles": ["tasks_admin"]
},
"action": {
"method": "GET",
"name": "read"
},
"resource": {
"service_name": "core",
"path": ["tasks", "123"],
"query_params": {},
"body": null
}
}
Пример политики (Rego):
package core.tasks.read
import data.utils
default allow := false
allow if utils.base.is_admin
allow if utils.base.is_tasks_admin
allow if utils.conditions.check_user_permissions(
data.permissions,
input.resource.service_name,
"tasks",
"read",
input.subject,
object_from_api
)
Формат объекта пользователя
"subject": {
"sub": "26b9a3e6-2e80-40c7-8f84-a993a1282169",
"email": "master@example.com",
"email_verified": false,
"name": "Petr Petrov",
"roles": [
"test_common"
]
}
Пермишены
Пример пермишена
{
"is_active": true,
"service": "core",
"resource": "collections",
"action": "read",
"object_conditions": {
"slug": { "$in": ["linux", "alt"] }
},
"subject_type": "user",
"subject_conditions": {
"roles": { "$in": ["test_common"] }
},
"created": "2024-07-28T12:00:00Z",
"modified": "2024-07-28T12:00:00Z"
}
Структура пермишена:
| Ключ | Описание | Пример |
|---|---|---|
is_active | флаг активности пермишена | false | true |
service | имя сервиса | core |
resource | тип ресурса | collections |
action | действие | read, create |
object_conditions | условия на объект | slug должен входить в список |
subject_type | тип субъекта | user |
subject_conditions | условия на пользователя | роль пользователя |
created | дата создания | |
modified | дата изменения |
Формат условий (conditions):
- Условия задаются в виде объектов с операторами (
$in,$eq,$ltи др.). - Можно комбинировать условия по разным полям, использовать вложенные операторы
$and/$or.Пример 1:
"roles": { "$in": ["test_common"] }— пользователь должен иметь одну из указанных ролей.Пример 2:
"slug": { "$in": ["linux", "alt"] }— объект должен иметь slug из списка.
Преимущества использования пермишенов:
- Гибкость: можно описывать сложные правила доступа без изменения кода.
- Масштабируемость: легко добавлять новые условия и операторы.
- Поддержка ABAC: условия могут учитывать любые атрибуты пользователя и объекта.
- Централизованное управление: все права описываются в едином формате и месте.
Partial Query
Для некоторых эндпоинтов OPA возвращает partial query для фильтрации данных (например, списка задач).
Шлюз Salt.Box добавляет фильтр в query-параметры запроса к сервису.
Обновление политик OPA
Политики OPA обновляются вручную: необходимо изменить rego-файлы и перезапустить контейнер OPA для применения изменений.