利用 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)

Keyword: 地图api

Leave a Reply

Your email address will not be published. Required fields are marked *