文档级安全
文档级安全允许您将角色限制为索引中的文档子集。开始使用文档级和字段级安全的最简单方法是打开 OpenSearch Dashboards 并选择 Security。然后选择 Roles,创建新角色,并查看 Index Permissions 部分,如下图所示。
文档级安全配置的最大大小为 1024 KB(1,048,404 个字符)。
简单角色
文档级安全使用 OpenSearch 查询领域特定语言(DSL)来定义角色有权访问哪些文档。在 OpenSearch Dashboards 中,选择一个索引模式并在 Document-level security 部分提供一个查询
{
"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
,后者执行精确匹配搜索。有关后一种选项,请参阅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> 是 internal 、jwt 、proxy 或 ldap |
基于属性的安全
您可以使用角色和参数替换以及 terms_set
查询来启用基于属性的安全。
请注意,索引的
security_attributes
需要是keyword
类型。
用户定义
PUT _plugins/_security/api/internalusers/user1
{
"password": "asdf",
"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"
]
}]
}
将术语级查找查询(TLQs)与 DLS 结合使用
您可以使用文档级安全(DLS)执行术语级查找查询(TLQs),有两种模式:自适应模式或过滤级模式。默认模式是自适应模式,其中 OpenSearch 会根据是否存在 TLQ 自动在 Lucene 级或过滤级模式之间切换。不带 TLQ 的 DLS 查询在 Lucene 级模式下执行,而带 TLQ 的 DLS 查询在过滤级模式下执行。
默认情况下,安全插件会检测 DLS 查询是否包含 TLQ,并在运行时自动选择适当的模式。
要了解有关 OpenSearch 查询的更多信息,请参阅术语级查询。
如何在 opensearch.yml
中设置 DLS 评估模式
默认情况下,DLS 评估模式设置为 adaptive
。您也可以在 opensearch.yml
中使用 plugins.security.dls.mode
设置显式设置模式。在 opensearch.yml
中添加一行,其中包含所需的评估模式。例如,要将其设置为过滤级别,请添加此行:
plugins.security.dls.mode: filter-level
DLS 评估模式
评估模式 | 参数 | 描述 | 用法 |
---|---|---|---|
Lucene 级 DLS | lucene-level | 此设置使所有 DLS 查询都应用于 Lucene 级别。 | Lucene 级 DLS 直接修改 Lucene 查询和数据结构。这是最有效的模式,但不允许 DLS 查询中的某些高级构造,包括 TLQs。 |
过滤级 DLS | filter-level | 此设置使所有 DLS 查询都应用于过滤级别。 | 在此模式下,OpenSearch 通过修改其接收到的查询来应用 DLS。这允许在 DLS 查询中使用术语级查找查询,但您只能使用 get 、search 、mget 和 msearch 操作从受保护的索引中检索数据。此外,此模式下跨集群搜索受到限制。 |
自适应 | adaptive-level | 默认设置,允许 OpenSearch 自动选择模式。 | 不带 TLQ 的 DLS 查询在 Lucene 级模式下执行,而包含 TLQ 的 DLS 查询在过滤级模式下执行。 |
DLS 和多个角色
OpenSearch 将所有 DLS 查询与逻辑 OR
运算符结合使用。然而,当一个使用 DLS 的角色与另一个不使用 DLS 的安全角色结合时,查询结果将被过滤,仅显示与第一个角色的 DLS 匹配的文档。此过滤规则也适用于不授予读取文档权限的角色。
DLS 和写入权限
确保具有 DLS 配置角色的用户没有写入权限。如果添加写入权限,用户将能够索引文档,但由于 DLS 过滤,他们将无法检索这些文档。
何时启用 plugins.security.dfm_empty_overrides_all
何时启用 plugins.security.dfm_empty_overrides_all
设置取决于您是否要限制用户对没有 DLS 的文档的访问。
为确保访问不受限制,您可以在 opensearch.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的权限时,查询结果会根据角色A的DLS进行过滤,即使角色B不使用DLS。DLS设置会保留,返回的访问权限会受到适当限制。
当用户同时被分配角色A和角色B,并且启用了plugins.security.dfm_empty_overrides_all
设置时,角色B的权限将覆盖角色A的限制,允许该用户访问所有文档。这确保了没有DLS的角色在搜索查询响应中具有优先权。