设置字段和文档级安全性

编辑

您可以通过向角色添加字段和文档级安全权限来控制对数据流或索引中数据的访问。字段级安全权限限制对文档中特定字段的访问。文档级安全权限限制对特定文档的访问。

文档和字段级安全性目前旨在与只读特权帐户一起使用。为数据流或索引启用了文档和字段级安全性的用户不应执行写操作。

角色可以在每个索引的基础上定义字段和文档级权限。未指定字段级权限的角色授予对所有字段的访问权限。类似地,未指定文档级权限的角色授予对索引中所有文档的访问权限。

在为用户分配多个角色时,请注意不要意外授予超出预期的访问权限。每个用户每个数据流或索引都有一组字段级和文档级权限。请参阅具有文档和字段级安全性的多个角色

具有文档和字段级安全性的多个角色

编辑

一个用户可以拥有多个角色,并且每个角色可以在同一数据流或索引上定义不同的权限。了解在这种情况下文档和字段级安全性的行为非常重要。

文档级安全性会考虑用户拥有的每个角色,并将给定数据流或索引的每个文档级安全查询与“OR”组合。这意味着只需要一个角色查询匹配,就可以返回一个文档。例如,如果一个角色授予对没有文档级安全性的索引的访问权限,而另一个角色授予具有文档级安全性的访问权限,则不应用文档级安全性;同时拥有这两个角色的用户可以访问索引中的所有文档。

字段级安全性会考虑用户拥有的每个角色,并将列出的所有字段组合成每个数据流或索引的单个集合。例如,如果一个角色授予对没有字段级安全性的索引的访问权限,而另一个角色授予具有字段级安全性的访问权限,则不会对该索引应用字段级安全性;同时拥有这两个角色的用户可以访问索引中的所有字段。

例如,假设 role_a 仅授予对 index1 中文档的 address 字段的访问权限;它没有指定任何文档限制。相反,role_b 限制对 index1 中文档子集的访问权限;它没有指定任何字段限制。如果您为用户分配这两个角色,则 role_a 会授予用户对所有文档的访问权限,而 role_b 会授予用户对所有字段的访问权限。

如果您需要同时限制对文档和字段的访问权限,请考虑按索引拆分文档。

模板化角色查询

编辑

创建角色时,可以指定一个查询,该查询定义文档级安全权限。您可以选择在角色查询中使用 Mustache 模板,以将当前经过身份验证的用户的用户名插入到角色中。与 Elasticsearch 中支持模板或脚本的其他位置一样,您可以指定内联、存储或基于文件的模板,并定义自定义参数。您可以通过 _user 参数访问当前经过身份验证的用户的详细信息。

例如,以下角色查询使用模板插入当前经过身份验证的用户的用户名

resp = client.security.put_role(
    name="example1",
    indices=[
        {
            "names": [
                "my-index-000001"
            ],
            "privileges": [
                "read"
            ],
            "query": {
                "template": {
                    "source": {
                        "term": {
                            "acl.username": "{{_user.username}}"
                        }
                    }
                }
            }
        }
    ],
)
print(resp)
const response = await client.security.putRole({
  name: "example1",
  indices: [
    {
      names: ["my-index-000001"],
      privileges: ["read"],
      query: {
        template: {
          source: {
            term: {
              "acl.username": "{{_user.username}}",
            },
          },
        },
      },
    },
  ],
});
console.log(response);
POST /_security/role/example1
{
  "indices" : [
    {
      "names" : [ "my-index-000001" ],
      "privileges" : [ "read" ],
      "query" : {
        "template" : {
          "source" : {
            "term" : { "acl.username" : "{{_user.username}}" }
          }
        }
      }
    }
  ]
}

您可以通过 _user 变量访问以下信息

属性 描述

_user.username

当前经过身份验证的用户的用户名。

_user.full_name

如果指定,则为当前经过身份验证的用户的全名。

_user.email

如果指定,则为当前经过身份验证的用户的电子邮件。

_user.roles

如果关联,则为当前经过身份验证的用户的角色名称列表。

_user.metadata

如果指定,则为保存当前经过身份验证的用户的自定义元数据的哈希。

您还可以访问自定义用户元数据。例如,如果在用户元数据中维护 group_id,则可以基于文档中的 group.id 字段应用文档级安全性

resp = client.security.put_role(
    name="example2",
    indices=[
        {
            "names": [
                "my-index-000001"
            ],
            "privileges": [
                "read"
            ],
            "query": {
                "template": {
                    "source": {
                        "term": {
                            "group.id": "{{_user.metadata.group_id}}"
                        }
                    }
                }
            }
        }
    ],
)
print(resp)
const response = await client.security.putRole({
  name: "example2",
  indices: [
    {
      names: ["my-index-000001"],
      privileges: ["read"],
      query: {
        template: {
          source: {
            term: {
              "group.id": "{{_user.metadata.group_id}}",
            },
          },
        },
      },
    },
  ],
});
console.log(response);
POST /_security/role/example2
{
  "indices" : [
    {
      "names" : [ "my-index-000001" ],
      "privileges" : [ "read" ],
      "query" : {
        "template" : {
          "source" : {
            "term" : { "group.id" : "{{_user.metadata.group_id}}" }
          }
        }
      }
    }
  ]
}

如果您的元数据字段包含对象或数组,则可以使用 {{#toJson}}parameter{{/toJson}} 函数访问它。

resp = client.security.put_role(
    name="example3",
    indices=[
        {
            "names": [
                "my-index-000001"
            ],
            "privileges": [
                "read"
            ],
            "query": {
                "template": {
                    "source": "{ \"terms\": { \"group.statuses\": {{#toJson}}_user.metadata.statuses{{/toJson}} }}"
                }
            }
        }
    ],
)
print(resp)
const response = await client.security.putRole({
  name: "example3",
  indices: [
    {
      names: ["my-index-000001"],
      privileges: ["read"],
      query: {
        template: {
          source:
            '{ "terms": { "group.statuses": {{#toJson}}_user.metadata.statuses{{/toJson}} }}',
        },
      },
    },
  ],
});
console.log(response);
POST /_security/role/example3
{
  "indices" : [
    {
      "names" : [ "my-index-000001" ],
      "privileges" : [ "read" ],
      "query" : {
        "template" : {
          "source" : "{ \"terms\": { \"group.statuses\": {{#toJson}}_user.metadata.statuses{{/toJson}} }}"
        }
      }
    }
  ]
}

预处理文档以添加安全详细信息

编辑

为了保证用户只读取他们自己的文档,设置文档级安全性是合理的。在这种情况下,每个文档都必须具有与之关联的用户名或角色名称,以便角色查询可以使用此信息进行文档级安全性。这是设置安全用户处理器摄取处理器可以提供帮助的情况。

文档级安全性不适用于写 API。您必须为使用相同数据流或索引的每个用户使用唯一 ID,否则他们可能会覆盖其他用户的文档。摄取处理器只是将当前经过身份验证的用户属性添加到正在索引的文档中。

设置安全用户处理器通过预处理摄取,将来自当前经过身份验证的用户的用户相关详细信息(例如 usernamerolesemailfull_namemetadata)附加到当前文档。当您使用摄取管道索引数据时,用户详细信息会自动附加到文档。如果身份验证凭据是 API 密钥,则 API 密钥 idnamemetadata(如果存在且非空)也会附加到文档。

有关更多信息,请参阅摄取管道设置安全用户

跨集群 API 密钥的字段和文档级安全性

编辑

跨集群 API 密钥 可用于对远程集群的请求进行身份验证。search 参数定义跨集群搜索的权限。replication 参数定义跨集群复制的权限。

replication 不支持任何字段或文档级安全性。search 支持字段和文档级安全性。

由于与具有文档和字段级安全性的多个角色中描述的原因类似,如果 search 参数定义了文档或字段级安全性,则不能创建具有 searchreplication 参数的单个跨集群 API 密钥。

如果您需要使用这两个参数,并且需要为 search 参数定义文档或字段级安全性,请创建两个单独的跨集群 API 密钥,一个使用 search 参数,另一个使用 replication 参数。您还需要建立两个不同的到同一集群的远程连接,每个命名的连接都使用相应的跨集群 API 密钥。