Разрабатывайте индивидуальные решения для графовой платформы

Замечание

Сейчас эта функция доступна в предварительной версии. См. дополнительные условия использования предварительных версий Microsoft Azure.

Пользовательское графовое решение Microsoft Sentinel — это решение на основе записных книжек, которое определяет узлы и рёбра на основе таблиц озера данных Microsoft Sentinel, строит граф и позволяет пользователям выполнять запросы к этому графу с помощью языка запросов к графам (GQL).

Используйте это руководство, чтобы создать, протестировать, подготовить к развертыванию, упаковать и опубликовать настраиваемое графовое решение как предложение SaaS в Microsoft Partner Center, чтобы клиенты могли найти его в Microsoft Security Store.

Необходимые условия

Чтобы создать пользовательские решения Graph, необходимо подключиться к озеру данных. Дополнительные сведения см. в разделе "Подключение к озеру данных Microsoft Sentinel".

Permissions

В следующей таблице перечислены необходимые разрешения для каждой операции или области в этом руководстве.

Операция Требуемая роль
Подключение к озеру данных Sentinel Microsoft Entra ID — администратор безопасности или глобальный администратор
Подключите рабочую область Sentinel к порталу Defender Владелец подписки или администратор доступа пользователей на уровне подписки, а также участник Microsoft Sentinel на уровне подписки или группы ресурсов
Подключить рабочую область Sentinel к озеру данных Владелец подписки или участник Microsoft Sentinel на уровне подписки или группы ресурсов
Моделирование и создание графа записной книжки Пользовательская унифицированная роль RBAC Microsoft Defender XDR с разрешением data (manage) для сбора данных в Microsoft Sentinel
Сохранение (материализация) графа Оператор безопасности, администратор безопасности или глобальный администратор
Запрос сохраняемого графа Настраиваемая унифицированная роль RBAC Microsoft Defender XDR с security data basics (read) управлением сбором данных Microsoft Sentinel
Публикация настраиваемого решения Graph Учетная запись Publisher Marketplace в Microsoft Partner Center

Инструменты

Для создания и публикации пользовательского решения графа требуются следующие средства:

Tip

Используйте повторно существующее озеро данных, если ваш арендатор уже подключён к запросам KQL, записным книжкам или агенту Security Copilot. Существует одно озеро данных для каждого клиента. На портале Defender перейдите в раздел Система>Параметры>Microsoft Sentinel>Озеро данных. Если статус — Provisioned, пропустите шаг 1.

Рабочий процесс сборки

Ниже описан процесс создания и публикации настраиваемого графового решения.

  1. Загрузите образцы данных в таблицы, которые моделирует ваш граф.
  2. Проверьте подключение с помощью простой записной книжки.
  3. Создание настраиваемого графа.
  4. Проверьте графический блокнот.
  5. Запланируйте задание на построение графа, чтобы материализовать граф.
  6. Запрос и визуализация графа из обозревателя Graph.
  7. Упакуйте и опубликуйте настраиваемое решение для графа.

Загрузка образцов данных

Эта задача загружает таблицы ресурсов Microsoft Entra ID, которые используются в примере графа в этом руководстве: EntraUsers, EntraGroups, EntraServicePrincipals и EntraMembers.

  1. На портале Defender перейдите в System>Settings>Microsoft Sentinel>Соединители данных.
  2. Включите коннектор Microsoft Entra ID, чтобы таблицы ресурсов Entra загружались в озеро данных. Для получения дополнительной информации см. раздел «Данные об активах» в data lake Microsoft Sentinel.
  3. Убедитесь, что в обозревателе озера данных отображаются следующие таблицы:
    • EntraUsers
    • EntraGroups
    • EntraServicePrincipals
    • EntraMembers
  4. Эти таблицы попадают в рабочее пространство Системные таблицы.
  5. Необязательно. Добавьте данные из других коннекторов и замените имена таблиц на последующих шагах, если в вашем сценарии используются другие данные.

Замечание

Если таблица не отображается в обозревателе озера данных, ее нельзя использовать для создания графов, и ИИ-помощник не будет ее учитывать.

Проверка подключения с помощью простой записной книжки

Создайте и запустите минимальный блокнот, чтобы проверить подключение к озеру данных перед разработкой графа.

  1. Откройте Visual Studio Code и войдите в расширение Microsoft Sentinel с той же учетной записью, которая имеет доступ к озеру данных.

  2. В Visual Studio Code в разделе Sentinel Extension — Graphs выберите Создать новый блокнот. Снимок экрана: параметр создания записной книжки в VS Code.

  3. Сохраните записную книжку, например hello-world-show-tables.ipynb.

  4. Выберите Выбрать ядро, затем выберите Microsoft Sentinel и доступный пул Spark. Снимок экрана: выбор параметра ядра в VS Code.

  5. Добавьте следующие ячейки в порядок.

Ячейка 1 — Markdown:

# Hello World: Show Tables
A minimal connectivity test for the Microsoft Sentinel data lake.
If every cell below runs without error, your environment is ready
to author custom graphs.
Steps:
1. Connect to the data lake with the Microsoft Sentinel provider
2. Point at your workspace
3. Read a table and show a few rows

Ячейка 2. Код (подключение и настройка рабочей области):

from sentinel_lake.providers import MicrosoftSentinelProvider
# The provider gives the notebook access to data lake tables.
lake_provider = MicrosoftSentinelProvider(spark=spark)
# >>> ADD YOUR WORKSPACE HERE <<<
# Replace with the Log Analytics workspace that holds your tables.
# Entra asset tables (EntraUsers, EntraGroups, ...) live in "System tables".
LOG_ANALYTICS_WORKSPACE = "System tables"
print(f"Using workspace: {LOG_ANALYTICS_WORKSPACE}")

Ячейка 3 — Markdown:

## Read a table and show rows
Reading a known table is the fastest way to confirm the extension
can reach the lake with your permissions. Swap EntraGroups for any
table that exists in your workspace.

Ячейка 4 . Код (чтение таблицы и отображение строк):

# Read a table from the data lake into a Spark DataFrame.
df_groups = lake_provider.read_table("EntraGroups", LOG_ANALYTICS_WORKSPACE)
# Show a sample. .df exposes the underlying Spark DataFrame.
df_groups.df.select("id", "displayName", "mailEnabled").show(20, truncate=False)

Ячейка 5 — код (необязательные проверочные подсчёты):

# Confirm the read returned data and inspect the schema.
print("Row count:", df_groups.df.count())
df_groups.df.printSchema()
  1. Запустите все ячейки сверху вниз.
  2. Убедитесь, что каждая ячейка завершается без красной трассировки, отображаются данные предварительного просмотра таблицы, а число строк не равно нулю.

Замечание

Если чтение завершается с ошибкой или не возвращает ни одной строки, убедитесь, что соединитель из раздела Загрузка образцов данных завершил свой начальный снимок, LOG_ANALYTICS_WORKSPACE указывает на существующую рабочую область и у вашей учетной записи есть права на чтение. Проверьте оглавление с помощью KQL на портале Defender, чтобы подтвердить наличие данных. Дополнительные сведения см. в разделе Запуск запросов KQL в озере данных Microsoft Sentinel.

Создайте пользовательский граф

Создайте одним из следующих способов:

  • Разработка графов с поддержкой искусственного интеллекта.
  • Автор вручную.

Разработка графов с поддержкой искусственного интеллекта

Чтобы создать граф с помощью ИИ, выполните следующие действия.

  1. В Visual Studio Code откройте Copilot Chat GitHub.

  2. Начните запрос со вспомогательного средства для создания графов @sentinel /graph-authoring и опишите свой граф простым языком:

    @sentinel /graph-authoring Create a graph that maps Entra groups to
    their member users, groups, and service principals using EntraGroups,
    EntraUsers, EntraServicePrincipals, and EntraMembers from the
    "System tables" workspace.
    

    Снимок экрана: разработка графов с помощью ИИ в VS Code.

    Copilot создает следующие ячейки для жизненного цикла разработки графа:

    Стадия жизненного цикла Сгенерированные выходные данные
    Настройка среды Проверяет необходимые пакеты и сведения о подключении
    Загрузка данных Считывает именованные таблицы из озера данных Sentinel
    Преобразование данных Подготавливает данные узлов и рёбер
    Схема графа Определяет узлы и края
    Проверка схемы Проверяет определение графа
    Построение графа Материализует граф для сеанса
    Графовый запрос Выполняет пример запроса GQL и визуализирует результат
  3. Продолжайте дорабатывать блокнот с помощью таких запросов:

    Goal Prompt
    Добавьте связь @sentinel Add an edge from User to IPAddress
    Фильтрация данных @sentinel Filter the data to show only failed sign-ins
    Изменение диапазона времени @sentinel Change the time range to the last 7 days
    Исправлена ошибка сборки @sentinel Fix the error in the graph build step
    Понимание кода @sentinel Explain how edge keys are defined
    Найти API без возможности редактирования What parameters does build_graph_with_data() accept? #Sentinel

Tip

Используется @sentinel /graph-authoring для создания или изменения ячеек записной книжки. Если вам нужны пояснения по API или примеры запросов, спросите Copilot и укажите #Sentinel, чтобы получить ответы по Sentinel.

Автор вручную

Чтобы создать граф вручную, выполните следующие действия.

  1. Подключитесь и прочитайте таблицы активов.

    from pyspark.sql import functions as F
    from sentinel_lake.providers import MicrosoftSentinelProvider
    lake_provider = MicrosoftSentinelProvider(spark=spark)
    # Entra asset tables live in the "System tables" workspace.
    # If your data is elsewhere, update this and ensure the tables exist.
    LOG_ANALYTICS_WORKSPACE = "System tables"
    # Use the latest snapshot of EntraUsers as the point-in-time for all tables.
    snapshot_time = (
        lake_provider.read_table("EntraUsers", LOG_ANALYTICS_WORKSPACE)
        .df.agg(F.max("_SnapshotTime").alias("max_snapshot"))
        .collect()[0]["max_snapshot"]
        .strftime("%Y-%m-%dT%H:%M:%SZ")
    )
    print(f"Using snapshot_time: {snapshot_time}")
    snapshot_filter = (F.col("_SnapshotTime") == F.lit(snapshot_time).cast("timestamp"))
    # Edges: group contains user / group / servicePrincipal
    df_members = (
        lake_provider.read_table("EntraMembers", LOG_ANALYTICS_WORKSPACE)
        .filter(
            snapshot_filter
            & (F.col("sourceType") == "group")
            & (F.col("targetType").isin("user", "group", "servicePrincipal"))
        )
    )
    # Nodes
    df_groups = (
        lake_provider.read_table("EntraGroups", LOG_ANALYTICS_WORKSPACE)
        .filter(snapshot_filter)
        .select("id", "displayName", "mailEnabled")
    )
    df_users = (
        lake_provider.read_table("EntraUsers", LOG_ANALYTICS_WORKSPACE)
        .filter(snapshot_filter)
        .select("id", "accountEnabled", "displayName", "department",
                "userPrincipalName", "usageLocation")
    )
    
  2. Подготовьте DataFrame для узлов и рёбер.

    # NODES
    user_nodes = df_users.df.select(
        "id", "displayName", "accountEnabled", "department",
        "userPrincipalName", "usageLocation")
    group_nodes = df_groups.df.select("id", "displayName", "mailEnabled")
    # EDGES
    edge_group_contains_user = (
        df_members.df.filter(F.col("targetType") == "user")
        .select(F.col("sourceId").alias("SourceGroupId"),
                F.col("targetId").alias("TargetUserId"))
        .distinct()
        .withColumn("EdgeKey", F.concat_ws("_", F.col("SourceGroupId"), F.col("TargetUserId")))
    )
    edge_group_contains_group = (
        df_members.df.filter(F.col("targetType") == "group")
        .select(F.col("sourceId").alias("SourceGroupId"),
                F.col("targetId").alias("TargetGroupId"))
        .distinct()
        .withColumn("EdgeKey", F.concat_ws("_", F.col("SourceGroupId"), F.col("TargetGroupId")))
    )
    
  3. Определите схему графа и привяжите объекты DataFrame.

    from sentinel_graph import GraphSpecBuilder, Graph
    entra_group_graph_spec = (
        GraphSpecBuilder.start()
        # === NODES ===
        .add_node("EntraUser").from_dataframe(user_nodes)
        .with_columns("id", "displayName", "accountEnabled", "department",
                      "userPrincipalName", "usageLocation",
                      key="id", display="displayName")
        .add_node("EntraGroup").from_dataframe(group_nodes)
        .with_columns("id", "displayName", "mailEnabled",
                      key="id", display="displayName")
        # === EDGES ===
        .add_edge("ContainsUser").from_dataframe(edge_group_contains_user)
        .source(id_column="SourceGroupId", node_type="EntraGroup")
        .target(id_column="TargetUserId", node_type="EntraUser")
        .with_columns("SourceGroupId", "TargetUserId", "EdgeKey",
                      key="EdgeKey", display="EdgeKey")
        .add_edge("ContainsGroup").from_dataframe(edge_group_contains_group)
        .source(id_column="SourceGroupId", node_type="EntraGroup")
        .target(id_column="TargetGroupId", node_type="EntraGroup")
        .with_columns("SourceGroupId", "TargetGroupId", "EdgeKey",
                      key="EdgeKey", display="EdgeKey")
    ).done()
    # Validate the schema before building.
    entra_group_graph_spec.show_schema()
    
  4. Создайте граф.

    # Build = prepare data + publish for the session.
    entra_group_graph = Graph.build(entra_group_graph_spec)
    print(entra_group_graph.build_status.status)   # "published" or "prepared"
    

    Замечание

    Graph.build() подготавливает данные и публикует их за один вызов. Чтобы проверить подготовленные узлы и рёбра перед публикацией, вызовите Graph.prepare(spec), проверьте graph.nodes и graph.edges, затем вызовите graph.publish().

  5. Запустите GQL-запрос.

    # Find nested group relationships up to 8 levels deep. 
    # Update the Entra Group name that you want to traverse from 
    
    query_nested_groups = """ 
    MATCH p=(g1:EntraGroup)-[cg]->{1,8}(g2) 
    WHERE g1.displayName = 'tmplevel3' 
    RETURN * 
    """ 
    entra_group_graph.query(query_nested_groups).show()
    

Протестируйте блокнот графов

Проверьте блокнот, чтобы убедиться, что он выводит ожидаемый график:

  1. Перезапустите ядро и запустите все ячейки сверху вниз. Снимок экрана: кнопка перезапуска ядра.

  2. Подтвердите успешное завершение каждой ячейки.

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

  4. Убедитесь, что show_schema() возвращает ожидаемые узлы и рёбра.

  5. Запустите пример запроса GQL и проверьте визуализацию и табличные выходные данные.

  6. Проверьте граничные случаи:

    • Пустые входные данные.
    • Изменение схемы.
    • Отсутствует доступ к таблице.

Tip

Добавьте ячейки Markdown над каждым разделом кода с описанием назначения, входных данных, выходных данных, а также создаваемых узлов или рёбер.

Планирование задания графа для материализации графа

Графы, созданные в интерактивном сеансе, являются временными. Запланируйте задачу для сохранения и обновления графа. Дополнительные сведения см. в статье Планирование заданий графа Microsoft Sentinel и управление ими.

  1. В блокноте графа выберите Создать задание по расписанию>Создать задание графа. Снимок экрана: кнопка создания задания графа.

  2. Введите имя и описание графа и проверьте путь к записной книжке.

  3. Выберите расписание:

    • По запросу: выполняет сборку один раз с 30-дневным хранением по умолчанию.
    • Запланировано: выберите повторяемую периодичность и время начала и окончания.
  4. Нажмите кнопку "Отправить".

  5. Откройте граф в расширении Sentinel и отслеживайте сведения о задании.

  6. Используйте Запустить сейчас, чтобы при необходимости выполнить запуск вне расписания.

  7. Подтвердите последовательность изменения статуса от Queued до In Progress до Ready.

Important

Отправленные задания не зависят от вашего локального блокнота. Редактирование локального .ipynb не обновляет запланированную задачу. Чтобы обновить блокнот задания, скачайте его с панели Graphs, внесите изменения, затем выберите Изменить задание>Отправить.

Запрос и визуализация из обозревателя Graph

После того как статус задания графа станет Ready, можно выполнять запросы и визуализировать данные на портале Defender, в записных книжках и через REST API.

  1. На портале Defender в разделе Microsoft Sentinel откройте представление графа и выберите свой материализованный граф.
  2. Выполняйте запросы GQL, просматривайте схему, переключайтесь между визуальным и табличным представлением результатов и переходите к следующему узлу.
  3. Используйте этот краткий справочник по GQL:
Шаблон или предложение Пример
Узел с меткой (g:EntraGroup)
Типизированный, направленный край -[c:ContainsUser]->
Путь переменной длины (от 1 до 8 прыжков) (a)-[e]->{1,8}(b)
Filter WHERE g.displayName = 'Finance Admins'
Проекция, сортировка, ограничение RETURN g.displayName ORDER BY g.displayName LIMIT 10
Выражения для меток (:EntraUser \| EntraServicePrincipal)

Замечание

Каждый запрос GQL начинается с MATCH. Движок работает по времени UTC. Используется ZONED_DATETIME(...) для литералы datetime. INSERT и CREATE не поддерживаются. Графы доступны только для чтения.

  1. Запрос из блокнота.

    from sentinel_graph import Graph
    # Attach to an already-materialized graph by name.
    graph = Graph.get("entra_group_membership")
    graph.query("MATCH (g:EntraGroup)-[c:ContainsUser]->(u:EntraUser) RETURN g, c, u").show()
    # Purpose-built security algorithms are available too:
    graph.blast_radius(source_property_value="Finance Admins", min_hop_count=1).show()
    
  2. Запрос с помощью REST API Graph.

    GET https://api.securityplatform.microsoft.com/graphs/graph-instances?graphTypes=Custom
    Authorization: Bearer <access_token>
    
    POST https://api.securityplatform.microsoft.com/graphs/graph-instances/{graphName}/query
    Authorization: Bearer <access_token>
    Content-Type: application/json
    {
      "query": "MATCH (g:EntraGroup)-[c:ContainsUser]->(u) RETURN g, c, u LIMIT 100",
      "responseFormats": ["Table", "Graph"],
      "queryLanguage": "GQL"
    }
    

responseFormats управляет формой выходных данных. "Table" возвращает строки, "Graph" возвращает узлы и края и ["Table", "Graph"] возвращает оба.

Дополнительные сведения см. в разделе REST API Graph для настраиваемых графов.

Упакуйте и опубликуйте решение графа

После тестирования и материализации графа упаковайте его для развертывания клиентам. Подробные инструкции по упаковке см. в статье Упаковка и публикация решений Microsoft Sentinel с графами и записными книжками.

Troubleshooting

Используйте следующие таблицы для диагностики распространенных проблем по симптомам.

Разработка графов

Симптом Вероятно, причина и исправление
MicrosoftSentinelProvider или sentinel_graph не найдено Снова войдите в расширение и убедитесь, что выбрано ядро Microsoft Sentinel.
Ячейка зависает на этапе «Запуск сессии Spark» Первый запуск может занять от 3 до 5 минут. Если значение превышает 6 минут, проверьте емкость пула и повторите попытку.
show_schema() пуст или Graph.build() дает сбой Убедитесь, что ключевые и отображаемые столбцы существуют и не являются null, а исходные и целевые node_type значения соответствуют псевдонимам узлов.
Запрос GQL не возвращает строк Убедитесь, что значения фильтров присутствуют в выбранном снимке, и проверьте фильтрацию по снимкам.
publish() завершается с ошибкой: доступ запрещён Убедитесь, что у вас есть роль оператора безопасности, администратора безопасности или глобального администратора.

Создание с использованием искусственного интеллекта

Симптом Вероятно, причина и исправление
@sentinel /graph-authoring ничего не делает Убедитесь, что расширения GitHub Copilot и Jupyter установлены и включены, и у вас оформлен тарифный план Copilot Business или Copilot Enterprise.
Созданный код ссылается на недостающую таблицу Подтвердите настройку соединителя и убедитесь, что таблица отображается в обозревателе озера данных.

Планирование заданий

Симптом Вероятно, причина и исправление
Изменения локальной записной книжки не отражаются в задании Скачайте блокнот задания на панели «Graphs», измените его, затем нажмите Изменить задание>Отправить.
Материализованный граф исчез Графики по запросу имеют 30-дневный срок хранения. Запланируйте повторяющееся задание или запустите новую сборку.