RBAC с использованием API Gateway и Open Policy Agent (OPA)

Bobur Umurzokov

Bobur Umurzokov

May 15, 2023

Technology

С различными моделями контроля доступа и методами реализации, построение системы авторизации для API серверных служб может быть сложной задачей. Однако конечная цель заключается в том, чтобы обеспечить правильному лицу соответствующий доступ к нужному ресурсу. В этой статье мы обсудим как включить модель авторизации на основе ролей (RBAC) для вашего API с использованием открытого API Gateway Apache APISIX и Open Policy Agent (OPA).

Цели обучения

В этой статье вы узнаете следующее:

  • Что такое RBAC и как это работает?
  • Что такое OPA и как это работает?
  • Как реализовать RBAC с OPA и Apache APISIX?
  • Как определить и зарегистрировать политику в OPA.
  • Как создать апстрим, маршрут и включить плагин OPA.
  • Как извлекаются роль и разрешения пользователя из полезной нагрузки JWT токена или данных потребителя.

Что такое RBAC?

Контроль доступа на основе ролей (RBAC) и Контроль доступа на основе атрибутов (ABAC) — это две распространенные модели контроля доступа, используемые для управления разрешениями и контроля доступа к ресурсам в компьютерных системах. RBAC назначает разрешения пользователям на основе их роли в организации. В RBAC роли определяются на основе функций или обязанностей пользователей, а разрешения назначаются этим ролям. Пользователи затем назначаются на одну или несколько ролей и наследуют разрешения, связанные с этими ролями. В контексте API, например, роль разработчика может иметь разрешение на создание и обновление ресурсов API, в то время как роль конечного пользователя может иметь только разрешение на чтение или выполнение ресурсов API.

По сути, RBAC назначает разрешения на основе ролей пользователей, в то время как ABAC назначает разрешения на основе атрибутов, связанных с пользователями и ресурсами.

В RBAC политика определяется комбинацией назначенной роли пользователя, действий, которые он имеет право выполнять, и ресурсов, на которых он может выполнять эти действия.

Что такое OPA?

OPA (Open Policy Agent) — это механизм политик и набор инструментов, которые предоставляют единый подход к применению политик во всей распределенной системе. Он позволяет вам определять, управлять и применять политики централизованно из одной точки. Определяя политики как код, OPA упрощает их просмотр, редактирование и откат, что способствует эффективному управлению политиками.

Пример Open Policy Agent

OPA предоставляет декларативный язык под названием Rego, который позволяет вам создавать и применять политики по всему вашему стеку. Когда вы запрашиваете решение по политике у OPA, он использует правила и данные, которые вы предоставили в файле .rego, чтобы оценить запрос и выдать ответ. Результат запроса затем отправляется вам как решение по политике. OPA хранит все политики и данные, которые ему нужны, в своей оперативной памяти. В результате OPA быстро возвращает результаты. Вот пример простого файла OPA Rego:

package example default allow = false allow { input.method == "GET" input.path =="/api/resource" input.user.role == "admin" }

В этом примере у нас есть пакет под названием "example", который определяет правило под названием "allow". Правило "allow" указывает, что запрос разрешен, если метод запроса — "GET", запрашиваемый путь — /api/resource, а роль пользователя — "admin". Если эти условия выполнены, то правило "allow" будет оценено как "true", что позволит запросу продолжиться.

Зачем использовать OPA и API Gateway для RBAC?

API Gateway предоставляет централизованное место для настройки и управления API и потребителями API. Он может использоваться как централизованный шлюз аутентификации, избегая необходимости реализации логики аутентификации в каждой отдельной службе. С другой стороны, OPA добавляет уровень авторизации и отделяет политику от кода, создавая отдельное преимущество для авторизации. С этой комбинацией вы можете добавить разрешения для ресурса API к роли. Пользователи могут быть связаны с одной или несколькими ролями. Каждая роль пользователя определяет набор разрешений (GET, PUT, DELETE) на ресурсы RBAC (определенные путями URI). В следующем разделе давайте узнаем, как достичь RBAC с использованием этих двух.

Open Policy Agent с Apache APISIX API Gateway

Как реализовать RBAC с OPA и Apache APISIX

В Apache APISIX вы можете настроить маршруты и плагины для определения поведения вашего API. Вы можете использовать плагин APISIX opa plugin для применения политик RBAC, перенаправляя запросы в OPA для принятия решений. Затем OPA принимает решение об авторизации на основе ролей и разрешений пользователей в реальном времени.

Предположим, что у нас есть Conference API, где вы можете получать/редактировать сессии мероприятий, темы и информацию о спикерах. Спикер может только читать свои собственные сессии и темы, в то время как администратор может добавлять/редактировать больше сессий и тем. Или участники могут оставлять свои отзывы о сессии спикера через POST-запрос на /speaker/speakerId/session/feedback, а спикер может видеть их, запрашивая GET-метод того же URI. Ниже приведена диаграмма, иллюстрирующая весь сценарий:

Open Policy Agent с Apache APISIX

  1. Потребитель API запрашивает маршрут на API Gateway с его учетными данными, такими как JWT токен в заголовке авторизации.
  2. API Gateway отправляет данные потребителя с заголовком JWT в движок OPA.
  3. OPA оценивает, имеет ли потребитель право доступа к ресурсу, используя политики (роли и разрешения), которые мы указали в файле .rego.
  4. Если решение OPA разрешено, то запрос будет перенаправлен в вышестоящую службу Conference.

Далее мы установим, настроим APISIX и определим политики в OPA.

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

  • Docker используется для установки контейнеризованного etcd и APISIX.
  • curl используется для отправки запросов к Admin API APISIX. Вы также можете использовать такие инструменты, как Postman, для взаимодействия с API.

Шаг 1: Установка Apache APISIX

APISIX можно легко установить и запустить с помощью следующего скрипта быстрого старта:

curl -sL https://run.api7.ai/apisix/quickstart | sh

Шаг 2: Настройка серверной службы (апстрим)

Для маршрутизации запросов к серверной службе для Conference API вам нужно настроить её, добавив апстрим сервер в Apache APISIX через Admin API.

curl http://127.0.0.1:9180/apisix/admin/upstreams/1 -X PUT -d ' { "name":"Conferences API upstream", "desc":"Register Conferences API as the upstream", "type":"roundrobin", "scheme":"https", "nodes":{ "conferenceapi.azurewebsites.net:443":1 } }'

Шаг 3: Создание потребителя API

Далее мы создаем потребителя (нового спикера) с именем пользователя jack в Apache APISIX. Он настраивает плагин jwt-auth для потребителя с указанным ключом и секретом. Это позволит потребителю аутентифицироваться с использованием JSON Web Token (JWT).

curl http://127.0.0.1:9180/apisix/admin/consumers -X PUT -d ' { "username": "jack", "plugins": { "jwt-auth": { "key": "user-key", "secret": "my-secret-key" } } }'

Шаг 4: Создание публичной конечной точки для генерации JWT токена

Вам также нужно настроить новый маршрут, который генерирует и подписывает токен с использованием плагина public-api. В этом сценарии API Gateway действует как сервер поставщика идентификации для создания и проверки токена с ключом нашего потребителя jack. Поставщик идентификации также может быть любым другим сторонним сервисом, таким как Google, Okta, Keycloak, и Ory Hydra.

curl http://127.0.0.1:9180/apisix/admin/routes/jas -X PUT -d ' { "uri": "/apisix/plugin/jwt/sign", "plugins": { "public-api": {} } }'

Шаг 5: Получение нового JWT токена для потребителя API

Теперь мы можем получить новый токен для нашего спикера Jack от API Gateway, используя публичную конечную точку, которую мы создали. Следующая команда curl генерирует новый токен с учетными данными Jack и назначает роль и разрешения в полезной нагрузке.

curl -G --data-urlencode 'payload={"role":"speaker","permission":"read"}' http://127.0.0.1:9080/apisix/plugin/jwt/sign?key=user-key -i

После выполнения этой команды вы получите токен в ответе. Сохраните этот токен где-нибудь, позже мы будем использовать его для доступа к нашей новой конечной точке API Gateway.

Шаг 6: Создание новой конфигурации плагина

Этот шаг включает настройку 3 плагинов APISIX: proxy-rewrite, jwt-auth и opa.

curl "http://127.0.0.1:9180/apisix/admin/plugin_configs/1" -X PUT -d ' { "plugins":{ "jwt-auth":{ }, "proxy-rewrite":{ "host":"conferenceapi.azurewebsites.net" } } }'
  • Плагин proxy-rewrite настроен для проксирования запросов на хост conferenceapi.azurewebsites.net.
  • Плагин аутентификации OPA настроен на использование движка политик OPA, работающего по адресу http://localhost:8181/v1/data/rbacExample. Также APISIX отправляет всю информацию, связанную с потребителем, в OPA. Мы добавим этот файл политики .rego в раздел конфигурации Opa.

Шаг 7: Создание маршрута для сессий Conference

Финальный шаг — создание нового маршрута для сессий спикеров Conference API:

curl "http://127.0.0.1:9180/apisix/admin/routes/1" -X PUT -d ' { "name":"Conferences API speaker sessions route", "desc":"Create a new route in APISIX for the Conferences API speaker sessions", "methods": ["GET", "POST"], "uris": ["/speaker/*/topics","/speaker/*/sessions"], "upstream_id":"1", "plugin_config_id":1 }'

Полезная нагрузка содержит информацию о маршруте, такую как его имя, описание, методы, URI, ID апстрима и ID конфигурации плагина. В этом случае маршрут настроен для обработки GET и POST запросов для двух разных URI, /speaker/topics и /speaker/sessions. Поле "upstream_id" указывает ID вышестоящей службы, которая будет обрабатывать входящие запросы для этого маршрута, а поле "plugin_config_id" указывает ID конфигурации плагина, которая будет использоваться для этого маршрута.

Шаг 8: Тестирование настройки без OPA

На данный момент мы настроили все необходимые конфигурации для APISIX, чтобы направлять входящие запросы на конечные точки Conference API, разрешая только авторизованным потребителям API. Теперь каждый раз, когда потребитель API хочет получить доступ к конечной точке, он должен предоставить JWT токен для получения данных из серверной службы Conference. Вы можете проверить это, отправив запрос на конечную точку, и доменный адрес, который мы запрашиваем сейчас, — это наш собственный API Gateway, а не фактическая служба Conference:

curl -i http://127.0.0.1:9080/speaker/1/topics -H 'Authorization: {API_CONSUMER_TOKEN}'

Шаг 9: Запуск службы OPA

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

docker run -d --network=apisix-quickstart-net --name opa -p 8181:8181 openpolicyagent/opa:latest run -s

Эта команда Docker запускает контейнер с образом OPA последней версии. Она создает новый контейнер в существующей сети APISIX apisix-quickstart-net с именем opa и открывает порт 8181. Таким образом, APISIX может отправлять запросы на проверку политик в OPA напрямую, используя адрес [http://opa:8181](http://opa:8181). Обратите внимание, что OPA и APISIX должны работать в одной сети Docker.

Шаг 10: Определение и регистрация политики

Второй шаг на стороне OPA — это определение политик, которые будут использоваться для контроля доступа к ресурсам API. Эти политики должны определять атрибуты, необходимые для доступа (Какие пользователи имеют какие роли) и разрешения (Какие роли имеют какие разрешения), которые разрешены или запрещены на основе этих атрибутов. Например, в приведенной ниже конфигурации мы говорим OPA проверить таблицу user_roles, какую роль имеет jack. Эта информация отправляется APISIX внутри input.consumer.username. Также мы проверяем разрешения потребителя, читая полезную нагрузку JWT и извлекая token.payload.permission оттуда. Комментарии описывают шаги ясно.

curl -X PUT '127.0.0.1:8181/v1/policies/rbacExample' \ -H 'Content-Type: text/plain' \ -d 'package rbacExample # Назначение ролей пользователям user_roles := { "jack": ["speaker"], "bobur":["admin"] } # Назначение разрешений ролям role_permissions := { "speaker": [{"permission": "read"}], "admin": [{"permission": "read"}, {"permission": "write"}] } # Вспомогательные функции JWT bearer_token := t { t := input.request.headers.authorization } # Декодирование токена авторизации для получения роли и разрешения token = {"payload": payload} { [_, payload, _] := io.jwt.decode(bearer_token) } # Логика, реализующая RBAC default allow = false allow { # Поиск списка ролей для пользователя roles := user_roles[input.consumer.username] # Для каждой роли в этом списке r := roles[_] # Поиск списка разрешений для роли r permissions := role_permissions[r] # Для каждого разрешения p := permissions[_] # Проверка, соответствует ли разрешение, предоставленное роли r, запросу пользователя p == {"permission": token.payload.permission} }'

Шаг 11: Обновление существующей конфигурации плагина с плагином OPA

После того как мы определили политики в службе OPA, нам нужно обновить существующую конфигурацию плагина для маршрута, чтобы использовать плагин OPA. Мы указываем это в атрибуте policy плагина OPA.

curl "http://127.0.0.1:9180/apisix/admin/plugin_configs/1" -X PATCH -d ' { "plugins":{ "opa":{ "host":"http://opa:8181", "policy":"rbacExample", "with_consumer":true } } }'

Шаг 12: Тестирование настройки с OPA

Теперь мы можем протестировать все настройки, которые мы сделали с политиками OPA. Если вы попытаетесь выполнить ту же команду curl для доступа к конечной точке API Gateway, она сначала проверит JWT токен как процесс аутентификации и отправит данные потребителя и JWT токена в OPA для проверки роли и разрешения как процесс авторизации. Любой запрос без JWT токена или с неразрешенными ролями будет отклонен.

curl -i http://127.0.0.1:9080/speaker/1/topics -H 'Authorization: {API_CONSUMER_TOKEN}'

Заключение

В этой статье мы узнали, как реализовать RBAC с OPA и Apache APISIX. Мы определили простую пользовательскую логику политики, чтобы разрешать/запрещать доступ к ресурсам API на основе роли и разрешений нашего потребителя API. Также этот учебник продемонстрировал, как мы можем извлекать информацию, связанную с потребителем API, в файле политики из полезной нагрузки JWT токена или объекта потребителя, отправленного APISIX.

Связанные ресурсы

Рекомендуемый контент

Tags: