Open Policy Agent (OPA) is an open source lightweight general policy engine, which can replace the built-in policy function module in the software and help users realize the decoupling of service and policy engine. Thanks to OPA 's complete ecosystem , users can easily integrate OPA and other services, such as libraries, HTTP APIs, and more.
As shown in the figure below, OPA first describes the policy through the policy language Rego; then stores the policy data through JSON, and then users can send query requests. After receiving a query request, OPA will combine the policy, data, and the content of the query request entered by the user to generate a policy decision, and send the decision to the service.
Plugin introduction
Apache APISIX provides a opa
plug-in. Users can use this plug-in to easily introduce the policy capabilities provided by OPA into Apache APISIX to achieve flexible authentication and admission control functions.
After configuring the opa
plugin on the route, Apache APISIX will assemble the request information, connection information, etc. into JSON data when processing the response request, and send it to the policy decision API address. As long as the policies deployed in OPA conform to the data specifications set by Apache APISIX, functions such as passing requests, rejecting requests, custom status codes, custom response headers, and custom response headers can be implemented.
This article takes HTTP API as an example to introduce opa
plug-in, and details how to integrate Apache APISIX with OPA to realize the authentication and authorization decoupling of back-end services.
how to use
Step 1: Build a test environment
- Build the OPA service using Docker.
# 使用 Docker 运行 OPA
docker run -d --name opa -p 8181:8181 openpolicyagent/opa:0.35.0 run -s
- Create
example
policy.
# 创建策略
curl -XPUT 'localhost:8181/v1/policies/example' \
--header 'Content-Type: text/plain' \
--data-raw 'package example
import input.request
import data.users
default allow = false
allow {
# 具有名为 test-header 值为 only-for-test请求头
request.headers["test-header"] == "only-for-test"
# 请求方法为 GET
request.method == "GET"
# 请求路径以 /get 开头
startswith(request.path, "/get")
# GET 参数 test 存在且不等于 abcd
request.query["test"] != "abcd"
# GET 参数 user 存在
request.query["user"]
}
reason = users[request.query["user"]].reason {
not allow
request.query["user"]
}
headers = users[request.query["user"]].headers {
not allow
request.query["user"]
}
status_code = users[request.query["user"]].status_code {
not allow
request.query["user"]
}'
- Create
users
data.
# 创建测试用户数据
curl -XPUT 'localhost:8181/v1/data/users' \
--header 'Content-Type: application/json' \
--data-raw '{
"alice": {
"headers": {
"Location": "http://example.com/auth"
},
"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"
}
}
}'
Step 2: Create a route and enable the opa
plugin
curl -XPUT 'http://127.0.0.1:9080/apisix/admin/routes/r1' \
--header 'X-API-KEY: <api-key>' \
--header 'Content-Type: application/json' \
--data-raw '{
"uri": "/*",
"methods": [
"GET",
"POST",
"PUT",
"DELETE"
],
"plugins": {
"opa": {
"host": "http://127.0.0.1:8181",
"policy": "example"
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'
Step 3: Test the request
# 允许请求
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": "http://127.0.0.1/get?test=abcd1&user=dylon"
}
# 拒绝请求并重写状态码和响应头
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: http://example.com/auth
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 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"}
Added: Turn off plugins
Thanks to the dynamic nature of Apache APISIX, you only need to remove the opa
plugin-related configuration in the routing configuration and save it to close the OPA plugin on the route.
Summarize
This article describes the detailed operation steps for the connection between Apache APISIX and Open Policy Agent. I hope that this article will give you a clearer understanding of the use of Open Policy Agent in Apache APISIX and facilitate subsequent hands-on operations.
Apache APISIX is not only committed to maintaining its own high performance, but also attaches great importance to the construction of the open source ecosystem. At present, Apache APISIX has more than 10 plug-ins related to authentication and authorization, which supports connection with mainstream authentication and authorization services in the industry.
If you need to connect with other authentication and authorization, please visit Apache APISIX's GitHub and leave your suggestions through issue; or subscribe to Apache APISIX's mailing list to express your thoughts by email.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。