由于存在多种访问控制模型和实现方法,为后端服务 API 构建授权系统仍然具有挑战性。最终目标是确保合适的个人能够适当地访问相关资源。本文将探讨如何利用开源 API 网关 Apache APISIX 和开放策略代理(OPA)为 API 实现基于角色的访问控制(RBAC)授权模型。
什么是 RBAC?
基于角色的访问控制(RBAC)和基于属性的访问控制(ABAC)是两种常用的访问控制模型,用于管理权限和控制对计算机系统资源的访问。RBAC 根据用户在组织中的角色来分配权限。角色是根据用户的职能或职责定义的,权限则分配给这些角色。用户被分配到一个或多个角色,从而继承与这些角色关联的权限。例如,在 API 上下文中,开发人员角色可能具备创建和更新 API 资源的权限,而最终用户角色可能仅具有读取或执行 API 资源的权限。
简而言之,RBAC 根据用户的角色分配权限,而 ABAC 则根据与用户和资源关联的属性分配权限。
在 RBAC 中,策略是由用户分配的角色、他们可以执行的操作以及这些操作可执行的资源的组合来定义的。
什么是 OPA?
OPA(Open Policy Agent)是一个策略引擎和工具集,提供了统一的策略实施方法,适用于整个分布式系统。它允许从一个集中点定义、管理和执行策略。通过将策略定义为代码,OPA 使策略管理更加高效,支持轻松查看、编辑和回滚策略。
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 和其使用者的位置,避免了每个服务内部实现独立的身份验证逻辑,从而简化了身份验证管理。OPA 则在此基础上增加了授权层,将策略与代码分离,提供了更灵活的策略定义和管理方式。通过结合 API Gateway 和 OPA,可以有效地为 API 资源分配角色权限。用户可以与一个或多个角色关联,每个角色定义了一组对 RBAC 资源(由 URI 路径定义)的权限(如 GET、PUT、DELETE)。接下来,将详细讲解如何使用这两个工具实现 RBAC。
如何使用 OPA 和 Apache APISIX 实现 RBAC
在 Apache APISIX 中,通过配置路由和插件可以定义 API 的行为。利用 APISIX 的 OPA 插件,可以将请求转发给 OPA 以执行 RBAC 策略,从而根据用户的角色和权限实时做出授权决策。
例如,假设有一个 Conference API,用于检索和编辑活动会话、主题和演讲者信息。演讲者只能查看自己的会话和主题,而管理员则可以添加或编辑更多会话和主题。同时,与会者可以通过 POST 请求提交对演讲者会话的反馈,而演讲者只能通过 GET 请求查看这些反馈。以下图示展示了这一场景:/speaker/speakerId/session/feedback
API 使用者通过 API Gateway 提供凭证(如授权标头中的 JWT 令牌)来请求路由。 API Gateway 将带有 JWT 标头的使用者数据发送到 OPA 引擎。 OPA 根据 .rego 文件中定义的策略(角色和权限)评估使用者是否有权访问资源。 如果 OPA 决定允许访问,请求将被转发到上游的 Conference 服务。 接下来,需要在 OPA 中安装和配置 APISIX,并定义相应的策略。
先决条件
- Docker:用于安装容器化的 etcd 和 APISIX。
- curl:用于向 APISIX Admin API 发送请求。也可以使用 Postman 等工具与 API 进行交互。
curl -sL https://run.api7.ai/apisix/quickstart | sh
第 1 步:安装 Apache APISIX
可以通过以下 quickstart 脚本轻松安装和启动 APISIX:
curl -sL https://run.api7.ai/apisix/quickstart | sh
第 2 步:配置后端服务(上游)
要将请求路由到会议 API 的后端服务,需要通过 Admin API 在 Apache APISIX 中添加上游服务器。可以使用以下命令进行配置:
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 使用者
接下来,在 Apache APISIX 中创建一个新的 API 使用者(例如用户名为 jack
)。为该使用者配置 jwt-auth
插件,以便使用 JSON Web 令牌(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
插件生成和签署 JWT 令牌。在这种情况下,API Gateway 充当身份提供商服务器,使用配置的密钥来创建和验证令牌。身份提供商也可以是其他第三方服务,如 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:为 API 使用者生成新的 JWT 令牌
现在,可以通过创建的公共终端节点,从 API Gateway 获取扬声器 Jack 的新 JWT 令牌。以下 curl
命令使用 Jack 的凭证生成一个新的令牌,并在有效负载中分配 role
和 permission
。
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 步:创建新的插件配置
这一步涉及在 Apache APISIX 中配置三个插件:proxy-rewrite
、jwt-auth
和 opa
插件。
使用以下 curl
命令配置插件:
curl "http://127.0.0.1:9180/apisix/admin/plugin_configs/1" -X PUT -d '
{
"plugins": {
"jwt-auth": {},
"proxy-rewrite": {
"host": "conferenceapi.azurewebsites.net"
}
}
}'
上述插件配置将请求代理到主机 conferenceapi.azurewebsites.net
。
OPA 插件的配置将使用运行在 http://localhost:8181/v1/data/rbacExample
上的 OPA 策略引擎进行身份验证。此外,APISIX 会将所有与消费者相关的信息发送给 OPA。接下来,我们将添加这个策略文件 .rego
。
步骤 7:为会议会话创建路由
最后一步是为 Conferences 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。在此配置中,路由处理两个不同 URI 的 GET 和 POST 请求。upstream_id
字段指定处理此路由的上游服务的 ID,而 plugin_config_id
字段指定用于该路由的插件配置 ID。
第 8 步:在没有 OPA 的情况下测试设置
到目前为止,已为 APISIX 配置了所有必要设置,以将传入请求路由到会议 API 端点,并仅允许授权的 API 消费者访问。此时,每次 API 使用者访问终端节点时,必须提供 JWT 令牌才能从 Conference 后端服务检索数据。可以通过以下方式验证设置是否正常工作,即请求自定义 API 网关而非实际的会议服务:
curl -i http://127.0.0.1:9080/speaker/1/topics -H 'Authorization: {API_CONSUMER_TOKEN}'
第 9 步:运行 OPA 服务
接下来的步骤是使用 Docker 运行 OPA 服务,并通过其 API 上传策略定义,这些定义将用于评估传入请求的授权策略。
docker run -d --network=apisix-quickstart-net --name opa -p 8181:8181 openpolicyagent/opa:latest run -s
该 Docker 命令会启动 OPA 的最新版本容器。容器将创建一个名为 opa
的新实例,并将其暴露在端口 8181 上,使 APISIX 能够通过 http://opa:8181
地址直接向 OPA 发送策略检查请求。请确保 OPA 和 APISIX 运行在同一 Docker 网络中。
步骤 10:定义并注册策略
您需要在 OPA 中定义策略,以控制对 API 资源的访问。这些策略应包括角色分配和角色权限分配,并通过读取 JWT 有效负载来验证用户权限。以下是将策略上传到 OPA 的命令和 Rego 文件示例:
curl -X PUT '127.0.0.1:8181/v1/policies/rbacExample'
-H 'Content-Type: text/plain'
-d 'package rbacExample
# Assigning user roles
user_roles := {
"jack": ["speaker"],
"bobur": ["admin"]
}
# Role permission assignments
role_permissions := {
"speaker": [{"permission": "read"}],
"admin": [{"permission": "read"}, {"permission": "write"}]
}
# Helper JWT Functions
bearer_token := t {
t := input.request.headers.authorization
}
# Decode the authorization token to get a role and permission
token = {"payload": payload} {
[_, payload, _] := io.jwt.decode(bearer_token)
}
# Logic that implements RBAC
default allow = false
allow {
# Lookup the list of roles for the user
roles := user_roles[input.consumer.username]
# For each role in that list
r := roles[_]
# Lookup the permissions list for role r
permissions := role_permissions[r]
# For each permission
p := permissions[_]
# Check if the permission granted to r matches the user's request
p == {"permission": token.payload.permission}
}'
这个策略文件定义了用户角色和角色权限分配。bearer_token
是从请求头中提取的 JWT 令牌,token
用于解码并获取权限。策略逻辑确保用户的角色权限与请求中的权限匹配。如果匹配,则允许访问。
第 11 步:使用 OPA 插件更新现有插件配置
在定义了 OPA 策略之后,您需要更新 APISIX 的插件配置以使用 OPA 插件。这涉及到指定 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
}
}
}'
在这个命令中:
host
指定了 OPA 服务的地址。policy
指定了之前在 OPA 中定义的策略名称。with_consumer
设置为true
以确保将消费者信息传递给 OPA 进行授权决策。
执行此命令后,APISIX 将使用配置的 OPA 插件来评估请求的授权策略。
第 12 步:使用 OPA 测试设置
现在,您可以测试所有配置的设置,以确保 OPA 策略正常工作。使用以下 curl
命令来验证 API Gateway 端点是否按照定义的 OPA 策略进行授权:
curl -i http://127.0.0.1:9080/speaker/1/topics -H 'Authorization: {API_CONSUMER_TOKEN}'
在此命令中:
{API_CONSUMER_TOKEN}
应替换为之前生成的 JWT 令牌。
此请求将发送到 APISIX API Gateway,APISIX 将首先检查 JWT 令牌的有效性,然后将请求数据和令牌信息传递给 OPA 以进行策略评估。如果 OPA 确定请求符合授权规则,则请求将被转发到会议 API 服务;否则,将收到拒绝响应。
结论
在本文中,我们学习了如何结合 OPA 和 Apache APISIX 实现基于角色的访问控制(RBAC)。我们通过定义自定义的策略逻辑,确保只有具有适当角色和权限的 API 使用者才能访问特定的 API 资源。教程演示了如何从 APISIX 发送的 JWT 令牌或消费者对象中提取相关信息,并通过 OPA 策略文件进行授权决策。这种方法使得策略管理更加集中和灵活,从而提升了 API 的安全性和管理效率。
原文链接:RBAC With API Gateway and Open Policy Agent (OPA)
Keyword: 地图api