文档级安全

文档级安全允许您将角色限制为索引中文档的一个子集。开始使用文档级和字段级安全的最简单方法是打开 UDB-SX Dashboards 并选择 安全。然后选择 角色,创建一个新角色,并查看 索引权限 部分,如下图所示。

UDB-SX Dashboards 中的文档级和字段级安全屏幕

文档级安全配置的最大大小为 1024 KB(1,048,404 个字符)。

简单角色

文档级安全使用 UDB-SX 查询领域特定语言 (DSL) 来定义角色授予访问权限的文档。在 UDB-SX Dashboards 中,选择一个索引模式并在 文档级安全 部分提供一个查询:

{
  "bool": {
    "must": {
      "match": {
        "genres": "Comedy"
      }
    }
  }
}

此查询指定,要使角色能够访问文档,其 genres 字段必须包含 Comedy

发送到 _search API 的典型请求在查询周围包含 { "query": { ... } },但在此情况下,只需指定查询本身。

通过访问 REST API 更新角色

在 REST API 中,您需要将查询作为字符串提供,因此必须转义引号。此角色允许用户读取任何索引中 public 字段设置为 true 的任何文档:

PUT _plugins/_security/api/roles/public_data
{
  "cluster_permissions": [
    "*"
  ],
  "index_permissions": [{
    "index_patterns": [
      "pub*"
    ],
    "dls": "{\"term\": { \"public\": true}}",
    "allowed_actions": [
      "read"
    ]
  }]
}

这些查询可以根据需要尽可能复杂,但我们建议保持简单,以最小化文档级安全功能对集群的性能影响。

Unicode 特殊字符的说明

由于与 Unicode 特殊字符相关的单词边界,当包含这些特殊字符之一时,Unicode 标准分析器无法将文本字段类型值作为整体值索引。因此,包含特殊字符的文本字段值会被标准分析器解析为由特殊字符分隔的多个值,有效地将其两侧的不同元素进行词元化。这可能导致文档的无意过滤,并可能损害对其访问的控制。

以下示例说明了包含特殊字符的值,这些值将被标准分析器不正确地解析。在此示例中,值中连字符/减号的存在阻止了分析器区分 user.id 的两个不同用户,并将它们解释为同一个用户:

{
  "bool": {
    "must": {
      "match": {
        "user.id": "User-1"
      }
    }
  }
}
{
  "bool": {
    "must": {
      "match": {
        "user.id": "User-2"
      }
    }
  }
}

在使用 Query DSL 或 REST API 时,为避免这种情况,可以使用自定义分析器或将字段映射为 keyword,后者执行精确匹配搜索。

有关字段类型为 text 时应避免的字符列表,请参阅单词边界

参数替换

存在许多变量,您可以使用它们来根据用户的属性强制执行规则。例如,${user.name} 被替换为当前用户的名称。

此规则允许用户读取任何文档,其中用户名是 readable_by 字段的值:

PUT _plugins/_security/api/roles/user_data
{
  "cluster_permissions": [
    "*"
  ],
  "index_permissions": [{
    "index_patterns": [
      "pub*"
    ],
    "dls": "{\"term\": { \"readable_by\": \"${user.name}\"}}",
    "allowed_actions": [
      "read"
    ]
  }]
}

下表列出了替换项。

术语 替换为
${user.name} 用户名。
${user.roles} 用户后端角色的逗号分隔的引用列表。
${user.securityRoles} 用户安全角色的逗号分隔的引用列表。
${attr.<TYPE>.<NAME>} 为用户定义的属性,名称为 <NAME><TYPE>internaljwtproxyldap

基于属性的安全

您可以使用角色和参数替换与 terms_set 查询一起启用基于属性的安全。

请注意,索引的 security_attributes 需要是 keyword 类型。

用户定义

PUT _plugins/_security/api/internalusers/user1
{
  "password": "Jiuyou@123",
  "backend_roles": ["abac"],
  "attributes": {
    "permissions": "\"att1\", \"att2\", \"att3\""
  }
}

角色定义

PUT _plugins/_security/api/roles/abac
{
  "index_permissions": [{
    "index_patterns": [
      "*"
    ],
    "dls": "{\"terms_set\": {\"security_attributes\": {\"terms\": [${attr.internal.permissions}], \"minimum_should_match_script\": {\"source\": \"doc['security_attributes'].length\"}}}}",
    "allowed_actions": [
      "read"
    ]
  }]
}

将术语级查找查询 (TLQ) 与 DLS 一起使用

可以使用两种模式之一执行术语级查找查询 (TLQ) 和文档级安全 (DLS):自适应模式或过滤器级别。默认模式是自适应的,UDB-SX 根据是否存在 TLQ 自动在 Lucene 级别和过滤器级别模式之间切换。不带 TLQ 的 DLS 查询在 Lucene 级别模式下执行,而带有 TLQ 的 DLS 查询在过滤器级别模式下执行。

默认情况下,Security 插件会检测 DLS 查询是否包含 TLQ,并在运行时自动选择适当的模式。

如何在 udbsx.yml 中设置 DLS 评估模式

默认情况下,DLS 评估模式设置为 adaptive。您还可以在 udbsx.yml 中使用 plugins.security.dls.mode 设置显式设置模式。向 udbsx.yml 添加一行,指定所需的评估模式。 例如,要将其设置为过滤器级别,请添加以下行:

plugins.security.dls.mode: filter-level

DLS 评估模式

评估模式 参数 描述 用法
Lucene 级别 DLS lucene-level 此设置使所有 DLS 查询应用于 Lucene 级别。 Lucene 级别 DLS 直接修改 Lucene 查询和数据结构。这是最高效的模式,但 DLS 查询中不允许某些高级构造,包括 TLQ。
过滤器级别 DLS filter-level 此设置使所有 DLS 查询应用于过滤器级别。 在此模式下,UDB-SX 通过修改接收到的查询来应用 DLS。这允许在 DLS 查询中使用术语级查找查询,但只能使用 getsearchmgetmsearch 操作从受保护的索引检索数据。此外,此模式下跨集群搜索受到限制。
自适应 adaptive-level 允许 UDB-SX 自动选择模式的默认设置。 不带 TLQ 的 DLS 查询在 Lucene 级别模式下执行,而包含 TLQ 的 DLS 查询在过滤器级别模式下执行。

DLS 和多个角色

UDB-SX 使用逻辑 OR 运算符组合所有 DLS 查询。然而,当使用 DLS 的角色与另一个不使用 DLS 的安全角色结合时,查询结果会被过滤,只显示与第一个角色的 DLS 匹配的文档。此过滤规则也适用于不授予读取文档权限的角色。

DLS 和写入权限

确保具有 DLS 配置角色的用户没有写入权限。如果添加了写入权限,用户将能够索引由于 DLS 过滤而无法检索的文档。

何时启用 plugins.security.dfm_empty_overrides_all

何时启用 plugins.security.dfm_empty_overrides_all 设置取决于您是否希望在没有 DLS 的情况下限制用户对文档的访问。

为确保访问不受限制,可以在 udbsx.yml 中设置以下配置:

plugins.security.dfm_empty_overrides_all: true

以下示例显示了启用 DLS 和未启用 DLS 的角色根据交互的访问级别。这些示例可以帮助您决定何时启用 plugins.security.dfm_empty_overrides_all 设置。

示例:文档访问

此示例演示了在需要特定用户对文档具有不受限制的访问权限,尽管他们属于具有受限访问权限的更广泛组的情况下,启用 plugins.security.dfm_empty_overrides_all 是有益的。

具有 DLS 的角色 A:此角色被授予广泛的用户组,并包含 DLS 以限制对特定文档的访问,如下面的权限集所示:

{
  "index_permissions": [
    {
      "index_patterns": ["example-index"],
      "dls": "[.. some DLS here ..]",
      "allowed_actions": ["indices:data/read/search"]
    }
  ]
}

不具有 DLS 的角色 B:此角色专门授予某些用户,例如管理员,不包含 DLS,如下面的权限集所示:

{
  "index_permissions" : [
    {
      "index_patterns" : ["*"],
      "allowed_actions" : ["indices:data/read/search"]
    }
  ]
}

plugins.security.dfm_empty_overrides_all 设置为 true 可确保分配了角色 B 的管理员可以覆盖角色 A 施加的任何 DLS 限制。这允许特定的角色 B 用户访问所有文档,无论角色 A 的 DLS 限制如何。

示例:搜索模板访问

在此示例中,定义了两个角色,一个具有 DLS,另一个不具有 DLS,授予对搜索模板的访问权限:

具有 DLS 的角色 A:

{
  "index_permissions": [
    {
      "index_patterns": [
        "example-index"
      ],
      "dls": "[.. some DLS here ..]",
      "allowed_actions": [
        "indices:data/read/search",
      ]
    }
  ]
}

不具有 DLS 的角色 B,仅授予对搜索模板的访问权限:

{
  "index_permissions" : [
    {
      "index_patterns" : [ "*" ],
      "allowed_actions" : [ "indices:data/read/search/template" ]
    }
  ]
}

当用户同时具有角色 A 和角色 B 权限时,即使角色 B 不使用 DLS,查询结果也会根据角色 A 的 DLS 进行过滤。DLS 设置被保留,并且返回的访问受到适当限制。

当用户被分配了角色 A 和角色 B 并且启用了 plugins.security.dfm_empty_overrides_all 设置时,角色 B 的权限将覆盖角色 A 的限制,允许该用户访问所有文档。这确保在搜索查询响应中,不具有 DLS 的角色优先。