Как создать лучшую политику с помощью Open Policy Agent и плагина Apache APISIX OPA

Одно общее дело в каждой организации – это политика. Политики определяют, как работает организация.

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

Программное обеспечение следует той же модели, соблюдая правила, регулирующие его поведение. Эти правила (или политики) могут определять среды программы, разрешенные сетевые маршруты, разрешенные версии зависимостей и когда микросервисы получают запросы API. Обычно разработчики создают их вручную, используя такие документы как электронные таблицы.

Проблема этого метода состоит в том, что он постепенно становится громоздким. Если каждая часть программы имеет свою политику, такими вещами, как авторизация, будет трудно управлять по всей программе. Также может потребоваться повторение политик в разных частях программы.

Кроме того, обновление любой политики потребует перераспределения всей программы. к счастью Откройте агент политики(OPA) нашли способ решить эти проблемы.

В этой статье объясняется, что такое OPA, как он работает, что предполагает плагин OPA и как его использовать.

Давайте начнем!

Что такое OPA?

OPA – это механизм политики общего назначения с открытым кодом. Он может заменить встроенные функциональные политические модули в программном обеспечении и помочь пользователям отделить службы от механизма политики.

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

Метод обработки политики OPA уменьшает сложность и дает больше контроля владельцу программы. OPA позволяет пользователям интегрировать его с другими службами, такими как библиотеки приложений и HTTP API.

Как работает OPA

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

s_EFDBAAA4A6A8765E2C2CBACA1FE670A8A1A3C4F3B2852B5E7907B18C06560424_1662070285391_opa-service

Вот разбивка изображения выше:

  1. Служба (скажем, это микрослужба проверки подлинности) получает запрос (например, запрос на вход). Чтобы служба решила, как обработать запрос, она должна получить политику аутентификации. Это ведет нас к следующему шагу.
  2. Служба посылает запрос (это может быть в любом формате JSON) в OPA с запросом на соблюдение политики при обработке полученного запроса.
  3. Теперь OPA сравнивает данные и политики, к которым доступ, и принимает правильное решение.
  4. Наконец, OPA возвращает решение о политике (это может быть в любом формате JSON), принятое в службу.

Это краткое изложение того, как работает OPA. Вы можете представить множество служб, подключенных к OPA, и OPA помогает им решать, как обрабатывать запросы или события, вместо того, чтобы каждая служба управляла своими политиками. Это обеспечивает более надежную систему, которую легко обслуживать.

Apache APISIX решил интегрироваться с OPA, предоставив плагин OPA. Вот о чем мы сейчас и поговорим.

Плагин Apache APISIX OPA

Плагин позволяет пользователям Apache APISIX удобно вводить возможности политики, предоставленные OPA при использовании Apache APISIX. Он обеспечивает гибкие функции аутентификации и контроля доступа.

Как это работает

Для выполнения своей задачи плагин Apache APISIX OPA выполняет два основных шага:

Во-первых, APISIX переконструирует любые данные, которые он получает, в приемлемые данные JSON и делает с ними запрос политики к OPA. Запрос обычно называют an APISIX для OPA запрос. Посмотрите следующий пример:


{
    "type": "http",
    "request": {
        "scheme": "http",
        "path": "\/get",
        "headers": {
            "user-agent": "curl\/7.68.0",
            "accept": "*\/*",
            "host": "127.0.0.1:9080"
        },
        "query": {},
        "port": 9080,
        "method": "GET",
        "host": "127.0.0.1"
    },
    "var": {
        "timestamp": 1701234567,
        "server_addr": "127.0.0.1",
        "server_port": "9080",
        "remote_port": "port",
        "remote_addr": "ip address"
    },
    "route": {},
    "service": {},
    "consumer": {}
}

Приведенные выше данные JSON сообщают OPA, что пользователь сделал HTTP-запрос с помощью метода GET через 127.0.0.1:9080/get в 1701234567 отметка времени (среда, 29 ноября 2023 г. 05:09:27).

Теперь OPA должна помочь Apache APISIX решить, как обработать запрос.

Далее OPA проверяет доступные политики и данные, сравнивает их и принимает решения в формате JSON:

{
    "result": {
        "allow": true,
        "reason": "test",
        "headers": {
            "an": "header"
        },
        "status_code": 401
    }
}

Вышеприведенное политическое решение есть Сервис OPA для APISIX ответ. Он сообщает APISIX принять запрос по указанной причине (тесту). Если разрешение имеет значение false, Apache APISIX отклоняет его.

Ниже приведено описание некоторых ключей в запросе и ответе выше:

  • type указывает тип запроса (HTTP или stream).
  • request используется, когда type есть HTTP и содержит основную информацию о запросе, таких как URL-адрес и заголовки.
  • var содержит основную информацию о запрошенном подключении (IP, порт, детали сервера и отметку времени запроса).
  • route, serviceи consumer содержат те же данные, что хранятся в APISIX. Они нуждаются в конфигурации, чтобы пользователь видел их после транзакции.
  • allow является обязательным и указывает, разрешено ли запрос проходить через APISIX.
  • reason, headersи status_code являются необязательными и возвращаются, когда вы настраиваете специальный ответ.

Как использовать плагин

Этот раздел познакомит вас с некоторыми функциями плагина. Вы увидите, как использовать Docker для создания служб OPA, создания политики, создания данных пользователей, создания специального маршрута, тестирования запросов, а также включения и выключения плагина.

Как использовать докер для создания служб OPA

Чтобы запустить среду OPA на порту, используйте команду ниже. 8181

docker run -d --name opa -p 8181:8181 openpolicyagent/opa:0.35.0 run -s

К концу этой статьи мы будем использовать CURL. Если вы новичок в нем или используете другие языки программирования, скопируйте запросы или коды ответа и вставьте код сюда, чтобы преобразовать его в нужный язык.

Мы также будем придерживаться -H и -d флаги вместо --header и --data-raw в соответствии.

Как создать политику

Создание политики происходит по следующему формату.

curl -X PUT '127.0.0.1:8181/v1/policies/example1' \
    -H 'Content-Type: text/plain' \
    -d 'package example

import input.request

default allow = false

allow {
    # HTTP method must GET
    request.method == "GET"
}'

Приведенный выше код создан с помощью следующих шагов:

  • Укажите маршрут: 127.0.0.1:8181/v1/policies/example1.
  • Запрос на импорт: import input.request.
  • Укажите, что запросы не разрешены: по умолчанию разрешен = false.
  • Укажите, что допустимо:

allow {
    # HTTP method must GET
    request.method == "GET"
}

Вышеприведенный код указывает, что единственным приемлемым методом HTTP является GET. Каждая строка в объекте разрешения реализуется как политики, кроме строк, начинающихся с #, поскольку они являются комментариями.

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

# Create policy
curl -X PUT '127.0.0.1:8181/v1/policies/example1' \
    -H 'Content-Type: text/plain' \
    -d 'package example

import input.request
import data.users

default allow = false

allow {
    # has the name test-header with the value only-for-test request header
    request.headers["test-header"] == "only-for-test"

    # The request method is GET
    request.method == "GET"

    # The request path starts with /get
    startswith(request.path, "/get")

    # GET parameter test exists and is not equal to abcd
    request.query["test"] != "abcd"

    # GET parameter user exists
    request.query["user"]
}'

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

Специальный ответ предоставляет дополнительные сведения (тело, заголовок и код статуса) о результате транзакции. Теперь наш запрос выглядит так:


# Create policy
curl -X PUT '127.0.0.1:8181/v1/policies/example1' \
    -H 'Content-Type: text/plain' \
    -d 'package example

import input.request
import data.users

default allow = false

allow {
    # has the name test-header with the value only-for-test request header
    request.headers["test-header"] == "only-for-test"
    # The request method is GET
    request.method == "GET"
    # The request path starts with /get
    startswith(request.path, "/get")
    # GET parameter test exists and is not equal to abcd
    request.query["test"] != "abcd"
    # GET parameter user exists
    request.query["user"]
}

# custom response body (Accepts a string or an object, the object will respond as JSON format)
reason = users[request.query["user"]].reason {
    not allow
    request.query["user"]
}

# custom response header (The data of the object can be written in this way)
headers = users[request.query["user"]].headers {
    not allow
    request.query["user"]
}

# custom response status code
status_code = users[request.query["user"]].status_code {
    not allow
    request.query["user"]
}'

Когда пользователь получает сообщение об ошибке, его становится легче отладить, поскольку ошибка приходит с a reason, headers детали, и status_code.

Как создать данные пользователей

Данные юзеров являются объектом объектов. Каждые пользовательские данные являются объектом специальных деталей (тело, заголовок и код статуса), которые помогают авторизовать пользователя.

Нижеследующий код является примером данных пользователей, содержащих четыре (4) пользователей с различными деталями:

# Create test user data
curl -X PUT '127.0.0.1:8181/v1/data/users' \
    -H 'Content-Type: text/plain' \
    -d '{

    "alice": {
        "headers": {
            "Location": "
        },
        "status_code": 302
    },

    "bob": {
        "headers": {
            "test": "abcd",
            "abce": "test"
        }
    },

    "carla": {
        "reason": "Give you a string reason"
    },

    "dylon": {
        "headers": {
            "Content-Type": "application/json"
        },
        "reason": {
            "code": 40001,
            "desc": "Give you a object reason"
        }
    }
}'

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

Как создать специальный маршрут и включить плагин

Гибкость плагина APISIX OPA позволяет пользователям настраивать свой маршрут, как показано в коде ниже:

curl -X PUT ' \
    -H 'X-API-KEY: <api-key>' \
    -H 'Content-Type: application/json' \
    -d '{
    "uri": "/*",
    "methods": [
        "GET",
        "POST",
        "PUT",
        "DELETE"
    ],
    "plugins": {},
    "upstream": {
        "nodes": {
            "httpbin.org:80": 1
        },
        "type": "roundrobin"
    }
}'

Чтобы это работало, плагин должен быть включен. Введите необходимую конфигурацию в plugins объект, чтобы включить его. Итак, имеем:


curl -X PUT ' \
    -H 'X-API-KEY: <api-key>' \
    -H 'Content-Type: application/json' \
    -d '{
    "uri": "/*",
    "methods": [
        "GET",
        "POST",
        "PUT",
        "DELETE"
    ],
    "plugins": {
        "opa": {
            "host": "
            "policy": "example1"
        }
    },
    "upstream": {
        "nodes": {
            "httpbin.org:80": 1
        },
        "type": "roundrobin"
    }
}'

Теперь, когда плагин включен, вы можете использовать свой маршрут, как считаете нужным.

Как проверить запросы

Мы смогли создать политики, данные пользователей и собственные маршруты, а также включили плагин Apache APISIX OPA. Давайте теперь проверим эти настройки и посмотрим, какой ответ мы получим для разных сценариев:

Вот тест, когда запрос разрешен:

запрос:


curl -XGET '127.0.0.1:9080/get?test=none&user=dylon' \
    --header 'test-header: only-for-test'

Ответ:

{
    "args": {
        "test": "abcd1",
        "user": "dylon"
    },
    "headers": {
        "Test-Header": "only-for-test",
        "with": "more"
    },
    "origin": "127.0.0.1",
    "url": "
}

Вот тест, когда запрос отклоняется, а код статуса и заголовки ответа переписываются:

запрос:


curl -XGET '127.0.0.1:9080/get?test=abcd&user=alice' \
    --header 'test-header: only-for-test'

Ответ:


HTTP/1.1 302 Moved Temporarily
Date: Mon, 20 Dec 2021 09:37:35 GMT
Content-Type: text/html
Content-Length: 142
Connection: keep-alive
Location: 
Server: APISIX/2.11.0

Вот тест, когда запрос отклоняется и возвращается специальное название ответа:

запрос:


curl -XGET '127.0.0.1:9080/get?test=abcd&user=bob' \
    --header 'test-header: only-for-test'

Ответ:


HTTP/1.1 403 Forbidden
Date: Mon, 20 Dec 2021 09:38:27 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 150
Connection: keep-alive
abce: test
test: abcd
Server: APISIX/2.11.0

Вот тест, когда запрос отклоняется и возвращается специальный ответ (строка):

запрос:


curl -XGET '127.0.0.1:9080/get?test=abcd&user=carla' \
    --header 'test-header: only-for-test'

Ответ:


HTTP/1.1 403 Forbidden
Date: Mon, 20 Dec 2021 09:38:58 GMT
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX/2.11.0

Give you a string of reason

И вот проверка, когда запрос отклоняется и возвращается специальный ответ (JSON):

запрос:


curl -XGET '127.0.0.1:9080/get?test=abcd&user=dylon' \
    --header 'test-header: only-for-test'

Ответ:


HTTP/1.1 403 Forbidden
Date: Mon, 20 Dec 2021 09:42:12 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX/2.11.0

{"code":40001,"desc":"Give you a object reason"}

Как отключить плагин

Чтобы отключить плагин APISIX OPA, удалите все конфигурации, добавленные при настройке специального маршрута и включении плагина. Теперь мы имеем:


curl -X PUT ' \
    -H 'X-API-KEY: <api-key>' \
    -H 'Content-Type: application/json' \
    -d '{
    "uri": "/*",
    "methods": [
        "GET",
        "POST",
        "PUT",
        "DELETE"
    ],
    "plugins": {},
    "upstream": {
        "nodes": {
            "httpbin.org:80": 1
        },
        "type": "roundrobin"
    }
}'

The plugins пустой объект означает, что плагин не может работать. Это так просто из-за динамического характера Apache APISIX.

Вывод

Целью этой статьи было познакомить вас с плагином Apache APISIX OPA и ознакомить вас с некоторыми его функциями.

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

Apache APISIX имеет более десяти плагинов, связанных с аутентификацией и авторизацией, которые поддерживают взаимодействие с основными службами аутентификации/авторизации в отрасли.

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

Надеюсь, эта статья поможет вам понять, как использовать OPA в Apache APISIX, чтобы вы могли начать применять его самостоятельно. Я также призываю вас найти время, чтобы посетить документацию плагина Apache APISIX OPA, чтобы увидеть другие случаи использования плагина. Чем больше вы практикуетесь с ним, тем лучше вы умеете им пользоваться.

Счастливого формирования политики!

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *