随着微服务的发展,经常遇到实施身份验证和授权(A&A)的问题。我们需要一个强大且集中管理的身份验证和授权策略。但是,应用程序的分布式性质使其难以实现。在本文中,我将探讨Open Policy Agent如何帮助简化授权问题。

让我们快速查看“身份验证和授权”的定义。认证是指识别用户(“who”)。而授权是指确定经过身份验证的用户具有的访问级别(“what”)。

我这篇文章的重点是授权部分。为了简单起见,我创建了一个带有一组微服务的示例应用程序。有一个基本的用户界面,我们可以在其中执行各种操作并查看结果。该应用程序的唯一目的是显示Open Policy Agent如何处理各种授权方案。在后续文章中,我们将扩展该应用程序的范围,以涵盖日益复杂的用例和策略管理。

示例应用

首先,关于应用程序的一些上下文。我以销售团队通常使用的CPQ应用程序为客户配置报价为例。

有以下角色:

  1. 销售–具有“销售”角色的用户可以为其客户创建新报价并更新报价。但是,具有“销售”角色的用户不能删除商品。
  2. 销售支持–支持人员,他们可以查看所有报价,但不能编辑任何报价。、
  3. 销售管理员–行政人员可以查看所有报价,但不能编辑/创建任何报价。但是,如果需要确保清理,他们可以删除要约。

由于我们专注于授权部分,因此我假设用户已经过身份验证,并且具有有效的JSON Web令牌(JWT)。每个API请求都在请求标头中包含此JWT。

在此处从github下载示例应用程序。按照自述文件中的安装说明进行操作,您应该可以使用URL http://<MINIKUBE URL>/访问UI。

授权实战

基于我们在上面看到的角色,期望销售团队能够

  • 创建新报价
  • 列出报价
  • 更新现有报价

而销售支持团队只能列出报价,而不能编辑/创建报价。 Sales Admin团队只能列出报价并将其删除。

UI显示了多个按钮,每个按钮代表用户的操作。选择您要使用的角色,然后尝试创建,编辑或删除商品。 UI将提供有关操作是否成功的反馈。

那么,这里发生了什么?

让我们快速了解一下当前的设置。

该应用程序具有两个微服务优惠和客户。 NGINX反向代理将这些API公开给外界。 NGINX截获每个API请求并请求授权服务以验证是否允许用户执行请求的操作。我们使用NGINX的auth_request指令来拦截传入的API调用。每个API调用都有一个Authorization标头,其中包含JWT。包括角色在内的整个用户信息都包含在JWT中。

授权服务有两个容器:

  1. 授权–一种定制服务(Authorization),用于接收请求并为Open Policy Agent创建格式化的输入请求。
  2. 开放策略代理(OPA)–作为辅助工具运行,并公开http端点以与授权容器进行通信。

基本上,NGINX将/authorize请求发送到Authorization容器以授权API调用。然后,授权服务咨询开放策略代理是否授权请求(是/否)。然后,它向NGINX返回成功(200 OK)或错误(403 Forbidden)响应。因此,NGINX允许API调用或向客户端返回403 Forbidden响应。

Open Policy Agent 是什么?

Open Policy Agent(OPA,发音为“ oh-pa”)是一种开放源代码的通用策略引擎,它统一了整个堆栈中的策略执行。 OPA提供了一种高级的声明性语言,可让您将策略指定为代码和简单的API,以减轻软件决策的负担。您可以使用OPA在微服务,Kubernetes,CI / CD管道,API网关等中实施策略。

基本上,OPA将决策与执法脱钩。它接受结构化数据作为输入(JSON),并且可以返回决策(对/错)或任意结构化数据作为输出。

OPA使用rego作为策略语言。您可以在https://www.openpolicyagent.org/docs/latest/上了解有关rego和开放策略代理的更多信息。

授权服务详解

让我们详细查看授权服务,以了解其工作原理。

我们在服务器模式下运行Open Policy Agent,并利用其REST API更新策略并获取策略决策。

  • Open Policy Agent公开REST API来创建或更新策略。
PUT /v1/policies/<id>
Content-Type: text/plain

对于我们的示例,使用带有以下请求的终结点(在GitHub README中也提到了)来更新OPA中的策略。

curl -X PUT --data-binary @policies/httpapi.authz.rego http://<MINIKUBE URL>/authorize/v1/policies/httpapi/authz
  • 要根据此政策做出决定,还有另一个API
POST /v1/data/<path>
Content-Type: application/json

这里的<path>是由软件package标识的策略的路径,例如package httpapi.authz。对于我们的示例,要删除商品ID“ 1000”,授权服务将使用以下请求正文调用端点http://localhost:8181/data/httpapi/authz:

{
    "input" : {
        "method": "DELETE",
        "api": "/offer/1000",
        "jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE1NzQ2NjM3MDAsImV4cCI6NDA5OTE4NTMwMCwiYXVkIjoib3BhLWV4YW1wbGUuY29tIiwic3ViIjoianJvY2tldEBleGFtcGxlLmNvbSIsIkdpdmVuTmFtZSI6IkpvaG5ueSIsIlN1cm5hbWUiOiJSb2NrZXQiLCJFbWFpbCI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJSb2xlIjoiU2FsZXMgQWRtaW4ifQ._UtjZtowF3NNN3IF1t0LBHuzQhdfIfsO8jC-46GvbRM"
    }
}
  • 授权应用程序将接收来自NGINX的请求,并如上所述生成对OPA的输入请求。为了这个示例,我已经在前端代码中对JWT进行了硬编码。每个API请求都在Authorization标头中包含JWT。授权应用程序将提取JWT并将其添加到OPA的输入请求中。
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJMb2NhbEpXVElzc3VlciIsImlhdCI6MTU3MzcyNzM5MSwiZXhwIjo0MDk4MjQ1Mzc4LCJhdWQiOiJvcGEtZXhhbXBsZS5jb20iLCJzdWIiOiJzYWxlc0BleGFtcGxlLmNvbSIsIkdpdmVuTmFtdyI6IkpvaG5ueSIsIlN1cm5hbWUiOiJTYWxlcyIsIkVtYWlsIjoianNhbGVzQGV4YW1wbGUuY29tIiwiUm9sZSI6IlNhbGVzIn0.UbHWQpCMwupzsFp8f0CQ4o_bJSVaBugKijhcURZ_Mko
  • 请注意,授权服务仅从传入请求中检索JWT,而不会对其进行解码。 OPA通过内置函数io.jwt.decode支持JWT的解析。
  • 您可以在这里在rego操场上尝试我们用于本示例的rego策略。尝试不同的输入请求,您将看到OPA为每个输入请求生成的输出。

结论

因此,简而言之,Open Policy Agent提供了一种将授权决策与微服务中的业务逻辑分离的方法。系统管理员可以设置Open Policy Agent,并将生成授权策略(重发策略)的责任委托给各个微服务所有者。微服务所有者和系统管理员都不会处理其边界之外的区域。

PS: 本文属于翻译,原文


iyacontrol
1.4k 声望2.7k 粉丝

专注kubernetes,devops,aiops,service mesh。