Tworzenie niestandardowych rozwiązań dla platform grafowych

Note

Ta funkcja jest obecnie dostępna w wersji zapoznawczej. Zobacz Dodatkowe warunki użytkowania dla wersji zapoznawczych platformy Microsoft Azure.

Niestandardowe rozwiązanie grafowe w usłudze Microsoft Sentinel to rozwiązanie oparte na notesach, które definiuje węzły i krawędzie na podstawie tabel jeziora danych usługi Microsoft Sentinel, tworzy graf i umożliwia użytkownikom wykonywanie zapytań względem tego grafu za pomocą języka zapytań grafowych (GQL).

Skorzystaj z tego przewodnika, aby skompilować, przetestować, zmaterializować, spakować i opublikować niestandardowe rozwiązanie grafu jako ofertę SaaS w Microsoft Partner Center, aby klienci mogli je odnaleźć w sklepie rozwiązania zabezpieczające firmy Microsoft Store.

Wymagania wstępne

Aby tworzyć rozwiązania Custom Graph, musisz zostać wdrożony do usługi Data Lake. Aby uzyskać więcej informacji, zobacz Jak wdrożyć usługę Microsoft Sentinel Data Lake.

Permissions

W poniższej tabeli wymieniono wymagane uprawnienia dla każdej operacji lub zakresu w tym przewodniku.

Operation Wymagana rola
Dołączanie do usługi Data Lake usługi Sentinel Microsoft Entra ID — administrator zabezpieczeń lub administrator globalny
Dołączanie obszaru roboczego usługi Sentinel do portalu Defender Właściciel subskrypcji lub administrator dostępu użytkowników na poziomie subskrypcji oraz współautor Microsoft Sentinel na poziomie subskrypcji lub grupy zasobów
Dołącz obszar roboczy Sentinel do jeziora danych Właściciel subskrypcji lub współautor usługi Microsoft Sentinel na poziomie subskrypcji lub grupy zasobów
Modelowanie i tworzenie grafu notesnika Niestandardowa ujednolicona rola RBAC w Microsoft Defender XDR z uprawnieniem data (manage) w zakresie zbierania danych Microsoft Sentinel
Utrwalanie (materializowanie) grafu Operator zabezpieczeń, administrator zabezpieczeń lub administrator globalny
Wykonywanie zapytań dotyczących utrwalonego grafu Niestandardowa ujednolicona rola RBAC rozwiązania Microsoft Defender XDR z uprawnieniami do security data basics (read) zbierania danych Microsoft Sentinel
Publikowanie niestandardowego rozwiązania Graph Konto wydawcy w witrynie Marketplace w Centrum partnerskim Microsoft

Tools

Do kompilowania i publikowania niestandardowego rozwiązania grafu wymagane są następujące narzędzia:

Wskazówka

Użyj ponownie istniejącego jeziora danych, jeśli Twój dzierżawca został już wdrożony do obsługi zapytań KQL, notatników lub agenta Security Copilot. Każdy dzierżawca ma jedno jezioro danych. W portalu Defender przejdź do pozycjiUstawienia>systemowe>Microsoft Sentinel>Data lake. Jeśli stan to Udostępniono, pomiń zadanie 1.

Tworzenie przepływu pracy

Poniższy przepływ pracy zawiera opis kroków tworzenia i publikowania niestandardowego rozwiązania grafu.

  1. Zaimportuj przykładowe dane do tabel modelowanych przez Twój graf.
  2. Zweryfikuj łączność za pomocą prostego notesu.
  3. Utwórz graf niestandardowy.
  4. Przetestuj notatnik grafów.
  5. Zaplanuj zadanie dla grafu, aby zmaterializować ten graf.
  6. Wykonywanie zapytań i wizualizowanie grafu z poziomu Eksploratora programu Graph.
  7. Spakuj i opublikuj niestandardowe rozwiązanie wykresu.

Importowanie przykładowych danych

To zadanie pozyskuje tabele zasobów Microsoft Entra ID używane przez przykładowy wykres w tym przewodniku: EntraUsers, EntraGroups, EntraServicePrincipals i EntraMembers.

  1. W portalu Defender przejdź do pozycji Ustawienia systemowe>Microsoft Sentinel>Łączniki>danych.
  2. Włącz łącznik Microsoft Entra ID, aby tabele zasobów Entra były importowane do jeziora danych. Więcej informacji znajduje się w artykule Dane zasobów w jeziorze danych Microsoft Sentinel.
  3. Upewnij się, że te tabele są wyświetlane w eksploratorze usługi Data Lake:
    • EntraUsers
    • EntraGroups
    • EntraServicePrincipals
    • EntraMembers
  4. Te tabele są dostępne w obszarze roboczym Tabele systemowe .
  5. Opcjonalnie: pozyskaj dane z innych łączników i zastąp nazwy tabel w kolejnych krokach, jeśli Twój scenariusz korzysta z innych danych.

Note

Jeśli tabela nie jest wyświetlana w Eksploratorze usługi Data Lake, nie możesz jej używać do tworzenia grafów, a pomoc dotycząca sztucznej inteligencji nie będzie się do niej odwoływać.

Zweryfikuj połączenie za pomocą prostego notatnika

Utwórz i uruchom minimalny notatnik, aby zweryfikować łączność usługi Data Lake przed tworzeniem grafu.

  1. Otwórz Visual Studio Code i zaloguj się do rozszerzenia Microsoft Sentinel przy użyciu tego samego konta, które ma dostęp do usługi Data Lake.

  2. W Visual Studio Code w obszarze Rozszerzenie usługi Sentinel — Grafy wybierz pozycję Utwórz nowy notes. Zrzut ekranu przedstawiający opcję tworzenia nowego notesu w programie VS Code.

  3. Zapisz notatnik, na przykład hello-world-show-tables.ipynb.

  4. Wybierz Wybierz jądro, wybierz Microsoft Sentinel i wybierz dostępną pulę Spark. Zrzut ekranu przedstawiający opcję wybierz jądro w programie VS Code.

  5. Dodaj następujące komórki w kolejności.

Komórka 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

Komórka 2 - Kod (połącz się i skonfiguruj obszar roboczy):

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}")

Komórka 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.

Komórka 4 — Kod (odczyt tabeli i pokazywanie wierszy):

# 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)

Komórka 5 — Kod (opcjonalne zliczenia kontrolne):

# Confirm the read returned data and inspect the schema.
print("Row count:", df_groups.df.count())
df_groups.df.printSchema()
  1. Uruchom wszystkie komórki u góry do dołu.
  2. Upewnij się, że każda komórka zostanie ukończona bez czerwonego śledzenia zwrotnego, wyświetlane są dane podglądu tabeli, a liczba wierszy nie jest równa zero.

Note

Jeśli odczyt zakończy się niepowodzeniem lub nie zwróci żadnych wierszy, upewnij się, że łącznik z sekcji Przykładowe dane pozyskiwania zakończył swoją pierwszą migawkę, LOG_ANALYTICS_WORKSPACE pasuje do rzeczywistego obszaru roboczego, a Konto ma dostęp do odczytu. Sprawdź zawartość tabeli za pomocą języka KQL w portalu Defender, aby potwierdzić, że dane są obecne. Aby uzyskać więcej informacji, zobacz Run KQL queries on the Microsoft Sentinel data lake (Uruchamianie zapytań KQL w usłudze data lake Microsoft Sentinel).

Tworzenie wykresu niestandardowego

Utwórz w jeden z następujących sposobów:

  • Tworzenie wykresów wspomaganych przez sztuczną inteligencję.
  • Autor ręcznie.

Tworzenie wykresów wspomaganych przez sztuczną inteligencję

Aby utworzyć graf z pomocą sztucznej inteligencji, wykonaj następujące kroki:

  1. W Visual Studio Code otwórz Copilot Chat GitHub.

  2. Uruchom monit za pomocą pomocnika @sentinel /graph-authoring tworzenia grafu i opisz graf w zwykłym języku:

    @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.
    

    Zrzut ekranu przedstawiający tworzenie grafu wspomaganego przez sztuczną inteligencję w programie VS Code.

    Copilot generuje następujące komórki dla cyklu życia tworzenia grafu:

    Etap cyklu życia Wygenerowane dane wyjściowe
    Konfiguracja środowiska Weryfikuje wymagane pakiety i informacje o połączeniu
    Ładowanie danych Odczytuje nazwane tabele z usługi Data Lake usługi Sentinel
    Transformacja danych Przygotowuje dane węzłów i krawędzi
    Schemat grafu Definiuje węzły i krawędzie
    Weryfikacja schematu Weryfikuje definicję grafu
    Tworzenie grafu Tworzy graf dla sesji
    Zapytanie grafu Uruchamia przykładowe zapytanie GQL i wizualizuje wynik
  3. Kontynuuj udoskonalanie notatnika za pomocą takich monitów jak poniższe:

    Goal Podpowiedź
    Dodaj relację @sentinel Add an edge from User to IPAddress
    Filtrowanie danych @sentinel Filter the data to show only failed sign-ins
    Zmień zakres czasu @sentinel Change the time range to the last 7 days
    Naprawianie błędu kompilacji @sentinel Fix the error in the graph build step
    Omówienie kodu @sentinel Explain how edge keys are defined
    Wyszukiwanie interfejsu API bez edytowania What parameters does build_graph_with_data() accept? #Sentinel

Wskazówka

Użyj @sentinel /graph-authoring, aby tworzyć lub modyfikować komórki w notesie. Jeśli potrzebujesz wyjaśnień dotyczących interfejsu API lub przykładowych zapytań, zapytaj Copilota i dodaj #Sentinel, aby uzyskać odpowiedzi dotyczące usługi Sentinel.

Utwórz ręcznie

Aby ręcznie utworzyć graf, wykonaj następujące kroki:

  1. Łączenie z tabelami zasobów i odczytywanie ich.

    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. Przygotuj ramki danych węzłów i krawędzi.

    # 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. Definiowanie schematu grafu i wiązanie ramek danych.

    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. Skompiluj graf.

    # 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"
    

    Note

    Graph.build() przygotowuje dane i publikuje je w jednym wywołaniu. Aby sprawdzić przygotowane węzły i krawędzie przed publikacją, wywołaj metodę Graph.prepare(spec), sprawdź graph.nodes i graph.edges, a następnie wywołaj metodę graph.publish().

  5. Uruchom zapytanie 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()
    

Przetestuj notatnik grafów

Przetestuj notatnik, aby upewnić się, że generuje oczekiwany wykres:

  1. Uruchom ponownie jądro i uruchom wszystkie komórki u góry do dołu. Zrzut ekranu przedstawiający przycisk uruchom ponownie jądro.

  2. Upewnij się, że każda komórka zostanie pomyślnie ukończona.

  3. Jeśli komórki transformacji działają dłużej niż 5 minut w ramach małej puli, zawęź filtry migawek i ogranicz projekcję kolumn przed zwiększeniem skali.

  4. Potwierdź, że show_schema() zwraca oczekiwane węzły i krawędzie.

  5. Uruchom przykładowe zapytanie GQL i zweryfikuj wizualizację i dane wyjściowe tabelaryczne.

  6. Zweryfikuj przypadki brzegowe:

    • Puste dane wejściowe.
    • Zmiany schematu.
    • Brak dostępu do tabeli.

Wskazówka

Dodaj komórki Markdown powyżej każdej sekcji kodu, aby udokumentować jej cel, dane wejściowe, dane wyjściowe oraz generowane węzły lub krawędzie.

Zaplanuj zadanie grafowe, aby zmaterializować graf

Wykresy utworzone w sesji interakcyjnej są efemeryczne. Zaplanuj zadanie grafu w celu utrwalania i odświeżania grafu. Aby uzyskać więcej informacji, zobacz Planowanie zadań grafu Microsoft Sentinel i zarządzanie nimi.

  1. W notesie grafu wybierz pozycję Utwórz zaplanowane zadanie>utwórz zadanie grafu. Zrzut ekranu przedstawiający przycisk „Utwórz zadanie grafu”.

  2. Wprowadź nazwę grafu i opis i zweryfikuj ścieżkę notesu.

  3. Wybierz harmonogram:

    • Na żądanie: jednorazowa kompilacja z domyślnym 30-dniowym okresem przechowywania.
    • Zaplanowane: wybierz cykl powtarzania i godziny rozpoczęcia/zakończenia.
  4. Wybierz Prześlij.

  5. Otwórz graf w rozszerzeniu usługi Sentinel i monitoruj szczegóły zadania.

  6. Użyj Uruchom teraz, aby w razie potrzeby uruchomić poza harmonogramem.

  7. Potwierdź postęp stanu z Queued do In Progress .Ready

Important

Przesłane zadania nie są powiązane z lokalnym notatnikiem. Edytowanie lokalnego .ipynb nie powoduje zaktualizowania zaplanowanego zadania. Aby zaktualizować notatnik zadania, pobierz go z panelu Graphs, edytuj, a następnie wybierz Edytuj zadanie>Prześlij.

Wykonywanie zapytań i wizualizowanie z poziomu Eksploratora programu Graph

Gdy stan zadania grafu ma wartość Ready, możesz wykonywać zapytania i wizualizować dane w portalu Defender, notatnikach i interfejsach API REST.

  1. W portalu Defender w sekcji Microsoft Sentinel otwórz widok grafu i wybierz graf materializowany.
  2. Uruchamiaj zapytania GQL, sprawdzaj schemat, przełączaj między widokiem wizualnym a tabelarycznym oraz przechodź do następnego przeskoku.
  3. Skorzystaj z tego krótkiego przewodnika po GQL:
Wzorzec lub klauzula Przykład
Węzeł z etykietą (g:EntraGroup)
Typowana krawędź skierowana -[c:ContainsUser]->
Ścieżka o zmiennej długości (od 1 do 8 przeskoków) (a)-[e]->{1,8}(b)
Filter WHERE g.displayName = 'Finance Admins'
Projekcja, sortowanie, ograniczenie RETURN g.displayName ORDER BY g.displayName LIMIT 10
Wyrażenia etykiet (:EntraUser \| EntraServicePrincipal)

Note

Każde zapytanie GQL rozpoczyna się od MATCH. Silnik działa w formacie UTC. Użyj ZONED_DATETIME(...) do literałów daty i godziny. INSERT i CREATE nie są obsługiwane. Wykresy są tylko do odczytu.

  1. Wykonywanie zapytań z notesu.

    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. Wykonywanie zapytań przy użyciu interfejsów API REST programu 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 steruje kształtem wyjściowym. "Table" Zwraca wiersze, "Graph" zwraca węzły i krawędzie oraz ["Table", "Graph"] zwraca oba.

Aby uzyskać więcej informacji, zobacz Graph REST APIs for custom graphs (Interfejsy API REST programu Graph dla grafów niestandardowych).

Spakuj i opublikuj swoje rozwiązanie oparte na grafie

Gdy graf zostanie przetestowany i zmaterializowany, spakuj go do wdrożenia dla klientów. Aby uzyskać szczegółowe instrukcje dotyczące tworzenia pakietów, zobacz Tworzenie pakietów i publikowanie rozwiązań Microsoft Sentinel dla grafów i notesów.

Troubleshooting

Skorzystaj z poniższych tabel, aby zdiagnozować typowe problemy według objawów.

Tworzenie grafu

Objaw Prawdopodobna przyczyna i poprawka
MicrosoftSentinelProvider lub sentinel_graph nie znaleziono Zaloguj się ponownie do rozszerzenia i upewnij się, że wybrano jądro Microsoft Sentinel.
Komórka zawiesza się na etapie „Uruchamianie sesji Spark” Pierwsze uruchomienie może potrwać od 3 do 5 minut. Jeśli trwa to dłużej niż 6 minut, sprawdź pojemność puli i spróbuj ponownie.
show_schema() jest pusta lub Graph.build() kończy się niepowodzeniem Upewnij się, że kolumny klucza i wyświetlane istnieją i nie zawierają wartości null oraz że wartości node_type w źródle i miejscu docelowym odpowiadają aliasom węzłów.
Zapytanie GQL nie zwraca wierszy Potwierdź, że wartości filtru istnieją w wybranej migawce, i zweryfikuj filtrowanie migawki.
publish() kończy się niepowodzeniem z odmową uprawnień Upewnij się, że masz rolę Operator zabezpieczeń, Administrator zabezpieczeń lub Administrator globalny.

Tworzenie wspomagane przez sztuczną inteligencję

Objaw Prawdopodobna przyczyna i poprawka
@sentinel /graph-authoring nic nie robi Upewnij się, że GitHub Copilot i rozszerzenia Jupyter są zainstalowane i aktywne, a masz plan Copilot Business lub Enterprise.
Wygenerowany kod odwołuje się do brakującej tabeli Potwierdź konfigurację łącznika i sprawdź, czy tabela jest wyświetlana w eksploratorze usługi Data Lake.

Planowanie zadań

Objaw Prawdopodobna przyczyna i poprawka
Zmiany w lokalnym notatniku nie są uwzględniane w zadaniu Pobierz notes zadania z panelu Graphs, edytuj go, a następnie użyj pozycji Edytuj zadanie>Prześlij.
Zmaterializowany graf zniknął Wykresy na żądanie mają 30-dniowe przechowywanie. Zaplanuj zadanie cykliczne lub uruchom nową kompilację.