【问题标题】:How to implement ACL on an ElasticSearch-based system?如何在基于 ElasticSearch 的系统上实现 ACL?
【发布时间】:2018-05-27 10:45:36
【问题描述】:

我有一个使用 NodeJS 和 Elasticsearch 实现 RBAC 授权策略的系统(RESTful)。 RBAC 授权与其他 API 前面的授权服务器一起使用,根据授权给用户角色的路由测试每个请求(使用不记名令牌对用户进行身份验证)。

我喜欢这种设计,因为其他 API 不需要了解授权/身份验证服务。而且它非常、非常、非常快,因为它使用内存缓存策略,而不是在每次收到新请求以测试身份验证时向 Elasticsearch 发出请求。

但现在我需要实施 ACL 以提供更精细的授权控制。从 REST 的角度来看,该策略将应用于资源级别。示例:“POST:/user/123”仅授权给 A 用户。

我对客户进行了一项调查,85% 的客户只会使用 ACL 的 allow 策略,默认情况下 ACL 控件将拒绝一切。好吧,现在我有了开发这个控件的所有信息。但我没有看到实现这一点的最佳方法。

我的第一个想法是:

  1. 系统最重要的品质是可扩展性;

  2. 好吧,在内存缓存中是不可能的,我用10万用户和100万资源做了一些模拟(可以是真实场景),内存量很大,这个功能会有缓存成本高;

  3. 在这种情况下,身份验证服务无法处理 ACL,因为它无法过滤搜索。 auth 服务不拦截结果,仅针对角色验证标头和路由;

  4. 1234563最终会是这样的:

"acl_allow_method_user":["POST:123434"]

我还必须创建一个通用包,供所有 API 使用,以在每次与 Elasticsearch 交互时验证此策略,但我认为这没有任何问题。

  1. 任何有 ACL 经验的人,这是一个好的设计吗?

  2. Elasticsearch 对数组字段的大小有限制吗?

  3. 性能如何?这种方法会产生影响吗?

【问题讨论】:

  • 你真的需要per document访问控制吗?
  • 很遗憾,是的,这是相关客户的请求。
  • 您考虑过 XACML 吗?

标签: node.js elasticsearch authorization acl


【解决方案1】:

我建议为 ACL 设置一个单独的 Elasticsearch 索引,该索引应该比您的主文档索引小得多。这将允许您适当地调整 ACL 索引设置,例如(1) 分片数量低于主文档索引,(2) auto_expand_replicas 设置为 0-all,以防您想使用术语查询(例如:加载用户拥有的所有文档),以及 (3)执行不同的保留/GDPR 政策。

ACL 索引可以包含每个 ACL 规则的文档,例如userId=1,docId=123,opType=POST。请注意,此方法将允许您在将来为其他类型的主体和资源定义 ACL 规则。此外,这可以支持可以动态匹配新文档的 ACL,例如userId=1,opType=POST,pattern="*" 将允许 userId=1 的用户发布任何文档,实际上是系统管理员。将 ACL 与文档/用户分离将允许您更新 ACL 而无需更新相应的文档,这在 Elasticsearch 中会表现得更好,它不会进行就地更新,而是删除并重新创建文档。此外,您可以替换 (PUT) 整个文档,而不必担心保留关联的 ACL。但是,您可能希望在删除文档或用户时清理 ACL,这可以在删除期间完成,也可以作为单独的计划清理过程来完成。

现在 ACL 与文档本身是分开的,它们可以缓存在 memcached 或 Redis 集群中,而不需要太多内存。在典型的 OLTP 系统中,在任何时间点只有一小部分用户处于活动状态,因此您可以适当地配置 LRU 缓存以提高命中率。如果不知道您的系统具有什么样的访问模式,就很难提供进一步的建议。

要考虑的最后一点是什么 生成 ACL。如果某些 ACL 是自动生成的,例如基于某种模式,那么也许您可以在系统中使用这种模式来避免每个用户每个文档都有一个 ACL 规则。例如,如果某些 ACL 是从目录服务生成的,那么您可能能够在 ACL 管理系统中缓存(并定期刷新)LDAP 规则。

【讨论】:

  • 感谢您的回答!这真的很有意义,我可以使用 auth 服务通过使用已经为 RBAC 实现的缓存来管理它。我们正在使用进程缓存来缓存 RBAC 策略,并且效果很好。但是还有一个问题,一个大问题。调查呢?必须使用 ACL 过滤搜索。这样一来,我看不出来怎么办。
  • 然后你需要执行搜索,然后根据内存中的ACL过滤结果。
  • @xeye 抱歉,但您必须先了解我的问题... 搜索后过滤结果?这是完全错误的。考虑一个简单的“计数”操作。您无法检索 100 万个文档并根据 ACL 策略过滤这些文档。
  • @VictorFrança 每个文档的 ACL 是非常有限制性的事情,你在那里没有太多选择。此外,当您将 ACL 存储在单独的索引中时,您将无法在 ES 中轻松加入它来过滤查询。 ES 的整个概念是关于搜索的,不要像 ACL 那样把业务逻辑推到那里。
  • @VictorFrança,为了避免在客户端的内存中过滤,您可以使用terms query,这将允许您根据 ACL 限制正在搜索的文档集。但是,您必须适当地构建基于 ACL 提供术语的索引,例如用户 ID:{opType:docIds}。然后,当您搜索时,您可以使用带有“path”:“user1/READ”的术语查询,其中 user1 是需要对文档具有 READ 权限的用户 ID。不过,您可能需要增加 index.max_terms_count。
【解决方案2】:

对于遇到相同问题的任何人,我们在此案例中得出的结论是:在微服务 REST 中将 ACL 细化到资源点代表类似于多租户系统的挑战。

它们是业务逻辑,每个服务都知道某人“如何”拥有资源(以及可能的特权是什么)。将这些规则上的数据如何存储标准化,这恰恰违背了对每个服务逻辑的了解。

我们可以标准化的一点是每个微服务的 ACL 的端点(假定相同合同和签名的路由)。而如果你真的想在API(服务)的私有环境中隔离ACL,由于我们有一个负责用户控制和权限的微服务,整个架构可以转向事件溯源。

没有 ACL 的私有 API 隔离的示例:

  1. 我们有 3 个服务:“S (A)”,负责控制用户和权限,“S (B)”和“S (C)”,执行任何普通任务。

  2. 前端应用程序必须了解 S (A)、S (B) 和 S (C) 的端点,并发出单独的请求来控制每个服务的 ACL 策略。

私有 API 隔离和事件溯源示例:

  1. 存在相同的微服务。

  2. 前端应用程序向 S (A) 发出请求,将某些 ACL 策略应用于 S (B) 和 S (C)。

  3. S (A) 记录策略更改请求并在代理中触发通知策略更改的事件。

  4. S (B) 和 S (C) 捕获事件并在其逻辑中应用策略。

  5. S (B) 和 S (C) 发布策略实施结果(授予或撤销)。

  6. S(A) 捕获应用策略的结果事件并记录该结果。

我会选择@alecswan 的答案作为正确答案,因为这是得出该结论的“起点”。

也感谢@xeye,它提醒我们注意业务逻辑部分。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-20
    • 1970-01-01
    • 2014-08-02
    • 1970-01-01
    • 2016-11-09
    • 1970-01-01
    相关资源
    最近更新 更多