这是一个始于 2016 年的项目,旨在统一不同技术和系统的策略执行。今天,OPA 被科技行业内的巨头们所使用。例如,Netflix 使用 OPA 来控制对其内部 API 资源的访问。Chef 用它来为他们的终端用户产品提供 IAM 功能。此外,许多其他公司,如 Cloudflare、Pinterest 等,都使用 OPA 在他们的平台上执行策略(如 Kubernetes 集群)。目前,OPA 已从 CNCF 中毕业。
你可能想知道 OPA 是怎样诞生的?它试图解决什么问题?事实上,API 和微服务的策略执行就如同微服务本身一样古老。没有一个生产级别的应用程序不执行访问控制、授权和策略。为了理解 OPA 的作用,考虑以下用例:你的公司通过一个在线门户销售笔记本电脑。像所有其他类似的应用程序一样,该门户由一个首页组成,客户在这里看到最新的产品,也许还有一些限时促销活动。如果客户想买东西,他们需要登录或创建一个账户。接下来,使用信用卡或其他方法付款。为了确保客户会反复访问,需要支持客户订阅,其中可能包含特别折扣信息。另外,他们可以选择在新产品公布后立即接收浏览器通知。一个非常典型的网上购物应用程序,对吗?现在,让我们用一张图来描述一下这个工作流程是什么样子的,以使这个过程可视化。
上图显示了我们系统内部可能的样子。我们有一些微服务,它们相互沟通,为我们的客户提供服务。现在,显然,Bob 不应该看到系统的任何内部运作。例如,他不能查看(或甚至不知道)归档付款的 S3 Bucket,或通知 API 可以与哪些服务联络。但是,John 呢?他是应用开发者,他需要访问所有的微服务,以便在问题发生时能够进行故障排除和调试。要是他不小心(或故意)对数据库服务进行了一个 API 调用,把客户的送货地址改到了别的地方,怎么办?更糟糕的是,如果他对客户的信用卡号码有读取权限怎么办?为了解决这些风险,我们在每个微服务的之前放置了一个授权控制。该控件检查认证用户是否有必要的权限来执行请求的操作。这样的授权系统可以是内部的、自制的程序,也可以是 AWS IAM 提供的外部程序。这就是一个典型的微服务应用程序的构建和安全。但是,看看使用几种不同的授权系统的缺点,特别是随着应用程序的增长而带来的麻烦。
让我们以 Kubernetes 为例来看看。如果所有用户都被授权访问整个集群,很多讨厌的事情就会发生,比如:
这就是开放策略代理(OPA)发挥作用的地方。引入 OPA 是为了创建一个统一的方法来执行堆栈中的安全策略。
上文中,我们探讨了策略执行和 OPA 试图解决的问题,现在,让我们来看看它是如何工作的。
假设你正在实现我们示例应用程序的支付服务。这个服务负责处理客户的付款。它暴露了一个 API,接受客户的付款。它还允许用户查询特定客户的付款情况。因此,为了获得一个包含 Jane 所做购买的数组,她是公司的一个客户,你向 API 发送一个 GET 请求,路径为 /payment/jane
。你在授权头中提供你的证书信息并发送请求。响应将是一个 JSON 数组,包含你所要求的数据。然而,由于你不希望所有有网络访问权限的人都能够访问支付 API,看到这样的敏感数据,你需要执行一个授权策略。OPA 以如下方式解决这个问题:
这里需要注意的是,OPA 将我们的策略决策与执行解耦。OPA 的工作流程可以用下面的图来描述。
OPA 是一个通用的、与领域无关的策略执行工具。它可以与 API、Linux SSH 守护程序、像 CEPH 这样的对象存储等集成。OPA 的设计者有意避免将其建立在任何其他项目的基础上。因此,策略查询和决定不遵循特定的格式。也就是说,你可以使用任何有效的 JSON 数据作为请求属性,只要它提供所需的数据。同样地,来自 OPA 的策略决策也可以是任何有效的 JSON 数据。你选择什么被输入,什么被输出。例如,你可以选择让 OPA 返回一个 TRUE 或 FALSE 的 JSON 对象,一个数字,一个字符串,甚至是一个复杂的数据对象。
为了充分理解 OPA 并开始在自己的项目中实施它,你必须熟悉它的功能和组件。让我们从如何定义你的策略开始。
Rego 是一种高级的声明性语言,是专门为 OPA 建立的。它使定义策略和解决以下问题变得非常容易:Bob 是否被允许对 /api/v1/products
执行 GET 请求?他实际上被允许查看哪些记录?
当涉及到部署 OPA 时,你有多个选择,这取决于你的具体场景。
为了进一步减少延迟,设计者决定 OPA 应该把所有的策略数据保存在内存中。这确保了 OPA 不会去查询另一个服务来请求数据。为了处理 OPA,你有一组 API,用于不同的目的。
到现在为止,你应该对 OPA 诞生的原因,它试图解决的问题,以及它的设计和管理方式有了相当清晰的认识。现在是试水的时候了,看看用 Rego 语言创建一个策略是什么样子。第一步是用简单的英语定义你的策略。比如说:“客户应该能够查看自己的付款。财务部门的工作人员应该能够查看任何客户的付款。”
下一步是将策略转换为 Rego 代码。我们可以使用 Rego playground 来做这件事。因此,在主面板中,清除那里已经添加的代码,并添加以下内容。
package play
# Customers should be able to view their own payments
allow = true {
input.method = "GET"
input.path = ["payments", customer_id]
input.user = customer_id
}
让我们逐行回顾这个片段。
/payments/customer_id
。注意,customer_id 没有加引号,这意味着它是一个变量,需要在调用时被替换。如果我们把这段代码翻译成普通英语,它看起来就像这样。
“如果请求使用的方法是 GET,路径是 /payments/customer_id
,并且用户是同一个 customer_id,则允许该请求。这实际上允许客户查看自己的支付数据。”
Rego playground 还允许你评估你的代码,并确保该策略将按预期工作。在 INPUT 面板中,我们可以通过添加以下代码来伪造一个合法请求。
{
"method": "GET",
"path": ["payments","bob"],
"user": "bob"
}
注意,INPUT 使用的是任意的 JSON。在提供请求时,没有特定的规则可以遵循。现在,让我们看看 OPA 将如何通过按下 Evaluate 按钮来响应这个决策请求。OUTPUT 面板应该显示如下内容。
{
"allow": true
}
下面是执行上述步骤后的 playground 截图。
现在,让我们试着把请求中的用户改为 alice,这意味着一个客户正试图查看另一个客户的付款。如果我们按 Evaluate 键,你会发现输出显示一个空的 JSON 对象 {}。原因是,OPA 不知道当策略不匹配时应该发送什么。要改变这种行为,在策略的主体前添加以下语句。
default allow = false
因此,整个策略应该是这样的。
package play
# Customers should be able to view their own payments
default allow = false
allow = true {
input.method = "GET"
input.path = ["payments", customer_id]
input.user = customer_id
}
现在,如果你按下 Evaluate,你会看到预期的输出。
{
"allow": false
}
请注意,这个 playground 非常强大,你可以选择策略的一部分,并独立于策略的其他部分进行评估。当你有一个复杂的策略,当它不应该被评估为假时,这可能是超级有用的。在这种情况下,你可以选择策略的部分内容,看看到底哪里出现了缺陷。
好了,现在我们已经执行了策略的第一部分,让我们继续第二部分:财务部门的工作人员应该能够查看任何客户的付款。
在我们之前定义的策略后面添加以下几行。
财务部门的工作人员可以查看任何客户的付款。
allow = true {
input.method = "GET"
input.path = ["payments", customer_id]
finance[input.user]
}
finance = {"john","mary","peter","vivian"}
这个策略的大部分内容与之前的相似,除了第 4 行。我们不是评估用户 ID 是否与客户 ID 相同,而是评估用户是否是财务 JSON 对象的一部分。Rego 有很多内置结构,允许你做很多有用的事情,包括查找。最后,我们定义财务对象并添加在该组中工作的员工的用户名。在现实世界中,这个 JSON 对象将作为 INPUT 请求的一部分或作为一个标记传递。现在,让我们通过将用户和客户设置为相同的名字(例如,Bob)来测试该策略。该策略应该返回 true。将用户改为 john(他是财务部门的一部分),并测试该策略。同样,它应该返回真。最后,将用户改为不在财务部门工作的任何名字(比方说,jane),该策略应该返回错误。
你可以参考官方文档,阅读更多关于 Rego 语言和你能用它做什么。
如前所述,OPA 可以与当今的许多平台集成。让我们来看看 OPA 可以为你做什么的几个例子。
Kubernetes
API 授权
你可以将 OPA 与 Envoy、Istio 和其他平台一起使用,强制执行 IAM 控制。例如,你可以轻松控制安全人员对敏感数据的访问。
Linux PAM
可插拔认证模块(PAM)长期以来一直被用于 Linux,为包括 SSH 和 sudo 在内的多种服务提供细粒度的控制。OPA 有一个 PAM 插件,使其能够与 PAM 集成并执行策略。例如,你可以限制 SSH 对你的生产机器的访问,除非在非工作时间,或者除非用户有一个支持工单。
还有许多其他产品可以与 OPA 集成,提供无穷的可能性。例如,Kafka、ElasticSearch、SQLite 和 CEPH,仅举几例。
最后更新于 2024/12/03