DLS 的工作原理

编辑

文档级安全性 (DLS) 使您能够控制对文档级别内容的访问。可以根据允许查看的身份(例如用户名、电子邮件、组等)独立管理索引中每个文档的访问权限。

此功能借助特殊访问控制文档来实现,这些文档由连接器索引到与标准内容索引关联的隐藏 Elasticsearch 索引中。如果您的内容文档具有与访问控制文档中定义的条件匹配的访问控制字段,则 Elasticsearch 会将 DLS 应用于连接器同步的文档。

核心概念

编辑

从非常高的层面来看,有两个基本组件可以实现连接器的文档级安全性

  • 访问控制文档:这些文档定义了来自第三方源的文档的访问控制策略。它们存在于一个隐藏索引中,该索引的名称模式如下: .search-acl-filter-<索引名称>。有关更多详细信息和示例,请参阅访问控制文档
  • 带有访问控制字段的内容文档:来自第三方源的同步内容必须具有与访问控制文档中定义的条件匹配的访问控制字段。这些文档存在于一个索引中,该索引的名称模式如下:search-<索引名称>

    • 如果内容文档没有访问控制字段,则不会限制谁可以查看它。
    • 如果存在访问控制字段但为空,则任何身份都无法访问,并且该文档实际上不可见。

      有关更多详细信息,请参阅内容文档

启用 DLS

编辑

要启用 DLS,您需要执行以下步骤

  1. 首先,在连接器配置中为您的连接器启用 DLS
  2. 运行访问控制同步。
  3. 这会创建一个以 .search-acl-filter- 为前缀的隐藏访问控制索引。例如,如果您将连接器索引命名为 search-sharepoint,则访问控制索引将命名为 .search-acl-filter-search-sharepoint
  4. 隐藏索引上的访问控制文档定义了哪些身份可以查看带有访问控制字段的文档。
  5. 访问控制文档使用搜索模板来定义如何根据身份筛选搜索结果。
  6. 计划定期执行访问控制同步,以更新隐藏索引中的访问控制文档。

请注意以下有关内容文档和同步的详细信息

  1. 请记住,要使 DLS 工作,您的内容文档必须具有与访问控制文档中定义的条件匹配的访问控制字段。内容文档包含用户将搜索的实际内容。如果内容文档没有访问控制字段,则不会限制谁可以查看它。
  2. 当用户搜索内容时,访问控制文档会确定允许用户查看哪些内容。
  3. 搜索时,将返回没有 _allow_access_control 字段或在 _allow_access_control.enum 中具有允许值的文档。确定文档是否已启用访问控制的逻辑基于 _allow_access_control* 字段是否存在或值。
  4. 运行内容同步以将您的第三方数据源同步到 Elasticsearch。这些文档中的特定字段(或多个字段)与访问控制文档中的查询参数相关联,从而启用文档级安全性 (DLS)。

您必须在运行第一个内容同步之前为您的连接器启用 DLS。如果您已经运行了内容同步,则需要删除索引上的所有文档,启用 DLS,然后运行新的内容同步。

索引时的 DLS

编辑
访问控制文档
编辑

这些文档定义了索引到 Elasticsearch 中的数据的访问控制策略。访问控制文档的示例如下所示

{
  "_id": "[email protected]",
  "identity": {
      "username": "example username",
      "email": "[email protected]"
   },
   "query": {
        "template": {
            "params": {
                "access_control": [
                    "[email protected]",
                    "example group",
                    "example username"]
            }
        },
        "source": "..."
    }
}

在此示例中,identity 对象指定此文档所属用户的身份。然后,query 对象使用模板列出构成此身份的访问控制策略的参数。它还包含查询 source,它将指定一个查询来获取该身份可以访问的所有内容文档。_id 可以是用户的电子邮件地址或用户名等。 identity 的确切内容和结构取决于相应的实现。

内容文档
编辑

内容文档包含来自第三方源的实际数据。这些文档中的特定字段(或多个字段)与访问控制文档中的查询参数相关联,从而启用文档级安全性 (DLS)。请注意,用于实现 DLS 的字段名称可能因不同的连接器而异。在以下示例中,我们将使用字段 _allow_access_control 来指定用户身份的访问控制。

{
  "_id": "some-unique-id",
  "key-1": "value-1",
  "key-2": "value-2",
  "key-3": "value-3",
  "_allow_access_control": [
    "[email protected]",
    "example group",
    "example username"
  ]
}
访问控制同步与内容同步比较
编辑

将文档摄取到 Elasticsearch 索引中称为同步。DLS 使用两种类型的同步进行管理

  • 内容同步:将内容摄取到以 search- 开头的索引中。
  • 访问控制同步:单独的附加同步,将访问控制文档摄取到以 .search-acl-filter- 开头的索引中。

在同步期间,连接器会根据文档的类型(内容或访问控制)将文档摄取到相关索引中。访问控制文档确定内容文档的访问控制策略。

通过利用 DLS,您可以根据访问控制文档中定义的权限,确保只有正确的用户或组才能安全地访问您的 Elasticsearch 数据。

搜索时的 DLS

编辑
身份何时可以查看内容文档
编辑

如果用户访问控制文档中的至少一个访问控制元素与文档的 _allow_access_control 字段中的一个项匹配,则用户可以查看该文档。

示例
编辑

本节说明用户何时可以根据访问控制访问某些文档。

一个访问控制文档

{
  "_id": "[email protected]",
  "identity": {
      "username": "example username",
      "email": "[email protected]"
   },
   "query": {
        "template": {
            "params": {
                "access_control": [
                    "[email protected]",
                    "example group",
                    "example username"]
            }
        },
        "source": "..."
    }
}

让我们看看这些权限可以访问以下示例文档中的哪些文档,以及原因。

{
  "_id": "some-unique-id-1",
  "_allow_access_control": [
    "[email protected]",
    "example group",
    "example username"
  ]
}

用户 example username 将可以访问此文档,因为他是相应组的成员,并且他的用户名和电子邮件地址也明确属于 _allow_access_control

{
  "_id": "some-unique-id-2",
  "_allow_access_control": [
    "example group"
  ]
}

用户 example username 也可以访问此文档,因为他们是 example group 的成员。

{
  "_id": "some-unique-id-3",
  "_allow_access_control": [
    "[email protected]"
  ]
}

用户 example username 将无法访问此文档,因为他们的电子邮件与 [email protected] 不匹配。

{
  "_id": "some-unique-id-4",
  "_allow_access_control": []
}

任何人无法访问此文档,因为 _allow_access_control 字段为空。

查询多个索引
编辑

本节说明如何定义一个 Elasticsearch API 密钥,该密钥具有对启用了 DLS 的多个索引的受限读取访问权限。

用户可能具有多个身份,这些身份定义了他们可以读取哪些文档。我们可以为用户有权访问的每个索引定义具有角色描述符的 Elasticsearch API 密钥。

示例
编辑

假设我们要创建一个 API 密钥,该密钥组合以下用户身份

GET .search-acl-filter-source1
{
  "_id": "[email protected]",
  "identity": {
      "username": "example username",
      "email": "[email protected]"
   },
   "query": {
        "template": {
            "params": {
                "access_control": [
                    "[email protected]",
                    "source1-user-group"]
            }
        },
        "source": "..."
    }
}
GET .search-acl-filter-source2
{
  "_id": "[email protected]",
  "identity": {
      "username": "example username",
      "email": "[email protected]"
   },
   "query": {
        "template": {
            "params": {
                "access_control": [
                    "[email protected]",
                    "source2-user-group"]
            }
        },
        "source": "..."
    }
}

.search-acl-filter-source1.search-acl-filter-source2 定义了 source1source2 的访问控制身份。

您可以使用如下的 API 调用来创建 Elasticsearch API 密钥

resp = client.security.create_api_key(
    name="my-api-key",
    role_descriptors={
        "role-source1": {
            "indices": [
                {
                    "names": [
                        "source1"
                    ],
                    "privileges": [
                        "read"
                    ],
                    "query": {
                        "template": {
                            "params": {
                                "access_control": [
                                    "[email protected]",
                                    "source1-user-group"
                                ]
                            }
                        },
                        "source": "..."
                    }
                }
            ]
        },
        "role-source2": {
            "indices": [
                {
                    "names": [
                        "source2"
                    ],
                    "privileges": [
                        "read"
                    ],
                    "query": {
                        "template": {
                            "params": {
                                "access_control": [
                                    "[email protected]",
                                    "source2-user-group"
                                ]
                            }
                        },
                        "source": "..."
                    }
                }
            ]
        }
    },
)
print(resp)
const response = await client.security.createApiKey({
  name: "my-api-key",
  role_descriptors: {
    "role-source1": {
      indices: [
        {
          names: ["source1"],
          privileges: ["read"],
          query: {
            template: {
              params: {
                access_control: [
                  "[email protected]",
                  "source1-user-group",
                ],
              },
            },
            source: "...",
          },
        },
      ],
    },
    "role-source2": {
      indices: [
        {
          names: ["source2"],
          privileges: ["read"],
          query: {
            template: {
              params: {
                access_control: [
                  "[email protected]",
                  "source2-user-group",
                ],
              },
            },
            source: "...",
          },
        },
      ],
    },
  },
});
console.log(response);
POST /_security/api_key
{
  "name": "my-api-key",
  "role_descriptors": {
    "role-source1": {
      "indices": [
        {
          "names": ["source1"],
          "privileges": ["read"],
          "query": {
            "template": {
                "params": {
                    "access_control": [
                        "[email protected]",
                        "source1-user-group"]
                }
            },
            "source": "..."
          }
        }
      ]
    },
    "role-source2": {
      "indices": [
        {
          "names": ["source2"],
          "privileges": ["read"],
          "query": {
            "template": {
                "params": {
                    "access_control": [
                        "[email protected]",
                        "source2-user-group"]
                }
            },
            "source": "..."
          }
        }
      ]
    }
  }
}
工作流指南
编辑

我们建议依赖连接器访问控制同步来自动化并使文档与原始内容源的用户权限更改保持同步。

考虑在创建 Elasticsearch API 密钥时设置 expiration 时间。如果未设置 expiration,则 Elasticsearch API 密钥将永不过期。

可以使用使 API 密钥 API 失效来使 API 密钥失效。此外,如果用户的权限发生更改,您需要更新或重新创建 Elasticsearch API 密钥。

了解更多
编辑