Spec-Zone.ru › Elasticsearch 8
›Elasticsearch Руководство [8.17] ›Обработка контента с помощью подключений Elasticsearch ›Безопасность на уровне документов

Используйте безопасность на уровне документов из подключений в приложениях поиска

Это руководство объясняет, как обеспечить безопасность на уровне документа (DLS) для документов, импортированных подключеними Elastic, при создании поискового приложения.

В этом примере мы будем:

  • Настроить соединение с SharePoint Online для импорта данных из SharePoint Online
  • Настроить поисковое приложение с использованием индекса Elasticsearch, созданного соединением SharePoint Online
  • Создать ключи API Elasticsearch с ограничениями DLS и рабочего процесса для запроса вашего поискового приложения
  • Создать поисковый интерфейс, где аутентифицированные пользователи могут искать данные, импортированные подключёнными элементами

Настройка подключения для синхронизации данных с управлением доступом

Вы можете запустить соединение SharePoint Online в Elastic Cloud (встроенное) или в развертывании с самостоятельным управлением (подключение с самостоятельным управлением). Обратитесь к справочнику по подключению SharePoint Online, чтобы узнать, как настроить подключение SharePoint Online и включить DLS.

Чтобы запустить подключение с самостоятельным управлением, вам нужно будет запустить сервис подключения дополнительно к вашему развертыванию Elastic. Обратитесь к подключениям с самостоятельным управлением для получения подробной информации о настройке подключения с самостоятельным управлением и запуске службы подключений.

В этом руководстве предполагается, что у вас уже есть развертывание Elastic, которое удовлетворяет требованиям для запуска службы подключения. Если у вас нет развертывания Elastic, зарегистрируйтесь на бесплатную пробную версию Elastic Cloud.

В этом конкретном примере мы используем подключение SharePoint Online. Обратитесь к документальной безопасности (DLS), чтобы узнать список подключений, которые поддерживают DLS.

Обзор индексов Elasticsearch

После настройки подключения SharePoint Online и начала синхронизации содержимого, подключение создаст два отдельных индекса Elasticsearch:

  • Индекс содержимого, который содержит данные для поиска в SharePoint Online. Мы будем использовать этот индекс для создания нашего поискового приложения.
  • Индекс управления доступом, который включает данные о доступе каждого пользователя, имеющего доступ к SharePoint Online. Он будет называться .search-acl-filter-<your index name>, где <your index name> - это имя индекса, которое вы выбрали. Например, индекс под названием search-sharepoint будет иметь индекс фильтра ACL .search-acl-filter-search-sharepoint. Мы будем использовать этот индекс для создания ключей API Elasticsearch, которые контролируют доступ к индексу содержимого.

Создание поискового приложения

Для создания поискового интерфейса для наших данных SharePoint Online нам нужно создать поисковое приложение.

Выполните следующие действия, чтобы создать поисковое приложение в пользовательском интерфейсе Kibana:

  1. Перейдите к Поиск > Поисковые приложения из основного меню или используйте поле глобального поиска.
  2. Выберите Создать.
  3. Имя поисковое приложение.
  4. Выберите используемый индекс подключением SharePoint Online.
  5. Выберите Создать.

Кроме того, вы можете использовать API для добавления поискового приложения.

Создание ключей API Elasticsearch

Далее нам нужно создать ключи API Elasticsearch, чтобы ограничить запросы поисковым приложением. Эти ограничения гарантируют, что пользователи могут запросить только документы, к которым они имеют доступ. Для создания этого ключа мы будем использовать информацию в индексе управления доступом, созданном подключением.

Индекс управления доступом будет содержать документы, аналогичные этому примеру:

{
  "_index": ".search-acl-filter-search-sharepoint",
  "_id": "john@example.co",
  "_version": 1,
  "_seq_no": 0,
  "_primary_term": 1,
  "found": true,
  "_source": {
    "identity": {
      "email": "john@example.co",
      "access_control": [
        "john@example.co",
        "Engineering Members"
      ]
    },
    "query": {
      "template": {
        "params": {
          "access_control": [
            "john@example.co",
            "Engineering Members"
            ]
        },
        "source": """
        {
          "bool": {
            "should": [
              {
                "bool": {
                  "must_not": {
                    "exists": {
                      "field": "_allow_access_control"
                    }
                  }
                }
              },
              {
                "terms": {
                  "_allow_access_control.enum": {{#toJson}}access_control{{/toJson}}
                }
              }
            ]
          }
        }
        """
      }
    }
  }
}

Этот документ содержит запрос Elasticsearch, описывающий, к каким документам имеет доступ пользователь john@example.com. Информация об управлении доступом хранится в поле access_control. В этом случае пользователь имеет доступ только к документам, которые содержат "john@example.co" или "Engineering Members" в поле _allow_access_control.

Поле query содержит запрос DLS, который мы будем использовать для создания ключа API Elasticsearch. Этот ключ гарантирует, что запросы ограничены документами, к которым john@example.com имеет доступ.

Для создания ключа мы будем использовать API для создания ключа. Вызов API будет выглядеть так:

resp = client.security.create_api_key(
    name="john-api-key",
    expiration="1d",
    role_descriptors={
        "sharepoint-online-role": {
            "index": [
                {
                    "names": [
                        "sharepoint-search-application"
                    ],
                    "privileges": [
                        "read"
                    ],
                    "query": {
                        "template": {
                            "params": {
                                "access_control": [
                                    "john@example.co",
                                    "Engineering Members"
                                ]
                            },
                            "source": "\n              {\n                \"bool\": {\n                  \"should\": [\n                    {\n                      \"bool\": {\n                        \"must_not\": {\n                          \"exists\": {\n                            \"field\": \"_allow_access_control\"\n                          }\n                        }\n                      }\n                    },\n                    {\n                      \"terms\": {\n                        \"_allow_access_control.enum\": {{#toJson}}access_control{{/toJson}}\n                      }\n                    }\n                  ]\n                }\n              }\n              "
                        }
                    }
                }
            ],
            "restriction": {
                "workflows": [
                    "search_application_query"
                ]
            }
        }
    },
)
print(resp)
const response = await client.security.createApiKey({
  name: "john-api-key",
  expiration: "1d",
  role_descriptors: {
    "sharepoint-online-role": {
      index: [
        {
          names: ["sharepoint-search-application"],
          privileges: ["read"],
          query: {
            template: {
              params: {
                access_control: ["john@example.co", "Engineering Members"],
              },
              source:
                '\n              {\n                "bool": {\n                  "should": [\n                    {\n                      "bool": {\n                        "must_not": {\n                          "exists": {\n                            "field": "_allow_access_control"\n                          }\n                        }\n                      }\n                    },\n                    {\n                      "terms": {\n                        "_allow_access_control.enum": {{#toJson}}access_control{{/toJson}}\n                      }\n                    }\n                  ]\n                }\n              }\n              ',
            },
          },
        },
      ],
      restriction: {
        workflows: ["search_application_query"],
      },
    },
  },
});
console.log(response);
POST /_security/api_key
{
  "name": "john-api-key",
  "expiration": "1d",
  "role_descriptors": {
    "sharepoint-online-role": {
      "index": [
        {
          "names": [
            "sharepoint-search-application"
          ],
          "privileges": [
            "read"
          ],
          "query": {
            "template": {
              "params": {
                "access_control": [
                  "john@example.co",
                  "Engineering Members"
                  ]
              },
              "source": """
              {
                "bool": {
                  "should": [
                    {
                      "bool": {
                        "must_not": {
                          "exists": {
                            "field": "_allow_access_control"
                          }
                        }
                      }
                    },
                    {
                      "terms": {
                        "_allow_access_control.enum": {{#toJson}}access_control{{/toJson}}
                      }
                    }
                  ]
                }
              }
              """
            }
          }
        }
      ],
      "restriction": {
        "workflows": [
          "search_application_query"
        ]
      }
    }
  }
}

Ответ будет выглядеть так:

{
  "id": "0rCD3i-MjKsw4g9BpRIBa",
  "name": "john-api-key",
  "expiration": 1687881715555,
  "api_key": "zTxre9L6TcmRIgd2NgLCRg",
  "encoded": "Qk05dy1JZ0JhRDNyNGpLQ3MwUmk6elRzdGU5QjZUY21SSWdkMldnQ1RMZw=="
}

Поле api_key содержит ключ API, который можно использовать для запроса поискового приложения с соответствующими ограничениями DLS.

Запрос нескольких индексов

В этом разделе описано, как сгенерировать ключ API для запроса поискового приложения, содержащего несколько индексов с документами, импортированными подключением с DLS.

У пользователя может быть несколько идентификаторов, определяющих, какие документы он может читать. В этом случае мы хотим создать один ключ API Elasticsearch, который можно использовать для запроса только тех документов, к которым у этого пользователя есть доступ.

Предположим, мы хотим создать ключ API, который объединяет следующие идентификаторы пользователей:

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

.search-acl-filter-source1 и .search-acl-filter-source2 определяют идентификаторы управления доступом для source1 и source2.

Следующий скрипт иллюстрирует, как сгенерировать ключ API Elasticsearch, объединяющий несколько идентификаторов пользователей:

require("dotenv").config();
const axios = require("axios");

// Elasticsearch URL and creds retrieved from environment variables
const ELASTICSEARCH_URL = process.env.ELASTICSEARCH_URL;
const ELASTICSEARCH_USER = process.env.ELASTICSEARCH_USER;
const ELASTICSEARCH_PASSWORD = process.env.ELASTICSEARCH_PASSWORD;

const config = {
  auth: {
    username: ELASTICSEARCH_USER,
    password: ELASTICSEARCH_PASSWORD,
  },
  headers: {
    "Content-Type": "application/json",
  },
};

async function createApiKey({
  searchApplication,
  userId,
  indices = "",
  metadata,
  expiration = "1d"
}) {
  try {
    const indices = indices.split(",");

    let combinedQuery = { bool: { should: [] } };

    for (const index of indices) {
      const aclsIndex = `.search-acl-filter-${index}`;
      const response = await axios.get(
        `${ELASTICSEARCH_URL}/${aclsIndex}/_doc/${userId}`,
        config
      );
      combinedQuery.bool.should.push({
        bool: {
          must: [
            {
              term: {
                "_index": index,
              },
            },
            response.data._source.query.source,
          ],
        },
      });
    }

    if (!metadata || Object.keys(metadata).length === 0) {
      metadata = { created_by: "create-api-key" };
    }

    const apiKeyBody = {
      name: userId,
      expiration,
      role_descriptors: {
        [`${searchApplication}-role`]: {
          index: [
            {
              names: [searchApplication],
              privileges: ["read"],
              query: combinedQuery,
            },
          ],
          restriction: {
            workflows: ["search_application_query"],
          },
        },
      },
      metadata,
    };

    const apiKeyResponse = await axios.post(
      `${ELASTICSEARCH_URL}/_security/api_key`,
      apiKeyBody,
      config
    );

    console.log(apiKeyResponse.data);
    return apiKeyResponse.data.encoded;
  } catch (error) {
    console.log(error)
  }
}

// example usage:
createApiKey({
  searchApplication: "my-search-app",
  userId: "example.user@example.com",
  indices: "source1,source2",
  expiration: "1d",
  metadata: {
    application: "my-search-app",
    namespace: "dev",
    foo: "bar",
  },
}).then((encodedKey) => console.log(encodedKey));

Пример объединяет несколько идентификаторов в один дескриптор роли. Это связано с тем, что ключ API Elasticsearch может использовать ограничения роли только в том случае, если у него есть один дескриптор роли.

Реализация в вашем приложении-клиенте

Если вы создаете приложение-клиент, используйте поле encoded, чтобы передать ключ API в приложение-клиент. Затем ваше приложение может использовать ключ API для запроса поискового приложения. Рабочий процесс будет примерно таким:

  1. Пользователь входит в ваше приложение.
  2. Ваше приложение генерирует ключ API Elasticsearch с помощью API для создания ключа.
  3. Поле encoded возвращается приложению-клиенту.
  4. При поиске документов приложение-клиент передает поле encoded в _search конечную точку вашего поискового приложения. Например, вы можете использовать клиент поискового приложения для выполнения фактических запросов с использованием ключа API:

    const client = SearchApplicationClient(applicationName, endpoint, apiKey, params);

Вот как выглядит этот рабочий процесс на схеме последовательности:

DLS API key and search application client workflow

При создании ключа API Elasticsearch для запроса поисковых приложений, вы должны включить ограничение search_application_query. Это гарантирует, что ключ API может получить доступ только к API поиска поискового приложения.

Рекомендуется всегда устанавливать срок действия expiration при создании ключа API Elasticsearch. Если expiration не задан, ключ API Elasticsearch никогда не истечёт.

Руководство по рабочему процессу

Рекомендуется полагаться на синхронизацию управления доступом подключений, чтобы автоматизировать и поддерживать синхронизацию документов с изменениями разрешений пользователей в исходном источнике контента.

В этом рабочем процессе вам необходимо обработать генерацию ключа API Elasticsearch в бэкенде вашего приложения в ответ на вход в браузер.

После генерации ключа бэкенд также должен вернуть этот ключ клиенту (браузеру) для использования в последующих запросах к вашему поисковому приложению.

Ключ API можно аннулировать, используя API для аннулирования ключа. Кроме того, если права пользователя изменятся, вам нужно будет обновить или пересоздать ключ API Elasticsearch.

Следующие шаги

Узнайте, как использовать клиент поискового приложения для запроса вашего поискового приложения. См. клиент поисковых приложений.

Дополнительная информация

  • Подключения Elastic
  • Безопасность на уровне документа (DLS)
  • Поисковые приложения

© 2023-2025 Elasticsearch
As of September 2024, Elasticsearch is available under a choice of three licenses: the Server Side Public License (SSPL), the Elastic License, or the AGPLv3 (OSI approved).
Elasticsearch and the Elasticsearch logo are trademarks of Elasticsearch B.V., registered in the U.S. and in other countries.
https://www.elastic.co/guide/en/elasticsearch/reference/8.17/es-dls-e2e-guide.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API