所有文章 > API开发 > 利用 API 网关和开放策略代理 (OPA) 实现 RBAC 管理
利用 API 网关和开放策略代理 (OPA) 实现 RBAC 管理

利用 API 网关和开放策略代理 (OPA) 实现 RBAC 管理

由于存在多种访问控制模型和实现方法,为后端服务 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 的凭证生成一个新的令牌,并在有效负载中分配 rolepermission

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-rewritejwt-authopa 插件。

使用以下 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)

#你可能也喜欢这些API文章!