Как защитить API с помощью edge — Versola Docs
VersolaVersola/docs
До 1.00.7.1versola.kzGitHub

Как защитить API с помощью edge

Поставьте внутренний API за edge. Зарегистрируйте ресурс, выдайте разрешения через роль, добавьте пресет авторизации для входа в браузере, CEL-правило и проверьте через curl, включая ответ 403.

В этом руководстве один upstream API ставится за edge, и браузерное приложение вызывает его с cookie сессии. В конце пользователь читает свои заказы, не может читать чужие, а у вас есть команды curl, которые это доказывают. Нужна работающая установка с тенантом, привязанным к edge, и ваш API, доступный для edge по сети.

В примере используются эти имена. Замените их своими.

ЧтоЗначение
Публичный адрес edge (edge-url)https://edge.example.com
Публичный адрес authhttps://id.example.com
Ваше браузерное приложениеhttps://app.example.com
Upstream APIhttp://orders.internal.example.com:8080
ID ресурсаorders-api
Клиентacme-web
Разрешение, рольorders:read, customer
Пресетweb

Предварительные условия

  • Установка с central, auth и edge (Запуск Versola локально).
  • Тенант с нужным профилем, привязанный к вашему edge в разделе Tenants. См. Профили безопасности.
  • В central настроен бэкенд УЦ для клиентских сертификатов, потому что веб-клиент за edge получает выпущенный сертификат (Клиентские сертификаты edge). Цели CLI настраивают его сами.
  • Upstream API с двумя маршрутами: GET /orders и GET /users/{userId}/orders.

1. Зарегистрируйте ресурс

  1. Откройте Resources и нажмите + Create Resource.

  2. Укажите Resource ID orders-api и Absolute resource URI http://orders.internal.example.com:8080. В URI нет пути, query и фрагмента.

  3. В поле Audience добавьте клиента acme-web, когда создадите его (шаг 3). К этому полю можно вернуться позже.

  4. Выберите тип internal. Тогда edge вызывает ваш API с HTTP Basic-учётными данными и никогда не пересылает токен пользователя.

  5. Нажмите Add endpoint и добавьте GET /orders. Правила оставьте пустыми.

  6. Добавьте второй эндпоинт, GET /users/{userId}/orders. В Allow (CEL) введите:

    request.path.params.userId == token.sub
  7. Нажмите Create Resource и скопируйте секрет, который покажет баннер. Он показывается один раз. Настройте ваш API на Basic-аутентификацию: пользователь orders-api, пароль — этот секрет. Подробности в Как зарегистрировать ресурс.

Правило сравнивает userId из URL с claim sub токена вызывающего. Остальные поля и переменные описаны в разделе Политики эндпоинтов.

Карточка эндпоинта в форме ресурса. Правило из руководства вводится в Allow (CEL)
Endpoint ресурса с Allow, step-up и правилом Inject.

2. Выдайте доступ через разрешение и роль

Пока эндпоинт не покрыт разрешением, он отвечает 403.

  1. Откройте Permissions, создайте orders:read и привяжите оба эндпоинта orders-api (Как зарегистрировать разрешение).
  2. Откройте Roles, создайте customer и добавьте в неё orders:read (Как зарегистрировать роль).
  3. Откройте Users и назначьте тестовому пользователю роль customer.

3. Создайте клиента и пресет авторизации

  1. Откройте Clients и запустите мастер создания. На первом шаге выберите Web app и задайте ID клиента acme-web.

  2. Добавьте redirect URI https://edge.example.com/complete. Это маршрут /complete в edge, который принимает код от auth.

  3. Завершите мастер и вернитесь в поле Audience ресурса, чтобы добавить acme-web, если вы пропустили это раньше (Как зарегистрировать клиента).

  4. В клиенте откройте Authorization Presets и нажмите + Add Preset:

    ПолеЗначение
    Preset IDweb
    Redirect URIhttps://edge.example.com/complete
    Scopesopenid
    Response Typecode
    Post-login redirect URIhttps://app.example.com/
    Post-logout redirect URI (optional)https://app.example.com/logged-out
    Session cookie domain, path (optional)оставьте пустыми: cookie на хосте edge, путь /
  5. Нажмите Save Presets. edge загружает пресеты вместе с остальной конфигурацией, так что подождите до configuration-cache-refresh-interval (по умолчанию генерируется 5 минут, локально 1 минута).

4. Направьте браузерное приложение на edge

  • Вход. Отправьте браузер на https://edge.example.com/login/web. После входа он вернётся на https://app.example.com/ и будет держать cookie EDGE_SESSION, которую JavaScript прочитать не может. Чтобы потребовать свежий или более сильный вход, добавьте в URL acr_values или max_age.
  • Вызов API. Запрашивайте https://edge.example.com/resources/orders-api/orders с credentials: 'include'. Часть после /resources/orders-api сопоставляется с зарегистрированными эндпоинтами.
  • Один сайт, один origin. Cookie имеет SameSite=Strict, поэтому приложение и edge должны быть на одном сайте. edge не отправляет заголовки CORS, поэтому отдавайте приложение и edge с одного origin, например маршрутизируйте /resources/* и /login/* с прокси вашего сайта на edge.
  • Истёкшая сессия. Если cookie нельзя обновить, edge отвечает 401 с заголовком Location: /login/web. Перейдите по нему.
  • Выход. Отправьте браузер на https://edge.example.com/logout/web.

5. Проверьте через curl

Войдите в браузере и скопируйте значение cookie EDGE_SESSION из инструментов разработчика. Оно имеет вид web:<access token>. ID пользователя, то есть claim sub, возьмите из токена или из раздела Users. Токен, привязанный к сертификату edge, работает только из cookie, поэтому отправляйте его как cookie, а не как Authorization: Bearer.

Прочитайте свои заказы:

curl -i -H "Cookie: EDGE_SESSION=web:<access token>" \
  https://edge.example.com/resources/orders-api/users/<your-user-id>/orders
HTTP/1.1 200 OK
...

Тело — то, что вернёт ваш API. Теперь запросите чужие заказы:

curl -i -H "Cookie: EDGE_SESSION=web:<access token>" \
  https://edge.example.com/resources/orders-api/users/<another-user-id>/orders
HTTP/1.1 403 Forbidden

Правило вернуло false. edge пишет в лог access_rule_denied для этого запроса и не отправляет тело. Upstream вызова не видел. Без учётных данных:

curl -i https://edge.example.com/resources/orders-api/orders
HTTP/1.1 401 Unauthorized

Путь, под который не подходит ни один эндпоинт, при действующей сессии даёт 404.

Если не работает

Что вы видитеЧто проверить
404 на /login/webПресет не сохранён или edge ещё не перечитал конфигурацию. Подождите один интервал обновления
403 на каждый вызовУ роли нет разрешения или разрешение не привязано к эндпоинту. Код permission_denied в логе edge это подтверждает. Изменения ролей и разрешений тоже доходят до одного интервала обновления
403 с audience_denied в логеКлиента нет в Audience ресурса
403 на ваши собственные заказыtoken.sub — не тот ID пользователя, что в URL
500Правило не вычисляется. Ищите access_rule_failed в логе
Ваш API отвечает 401Он не принимает Basic-учётные данные orders-api:<secret>

Что дальше