Erste Schritte mit benutzerdefinierten Graphen in Microsoft Sentinel (Vorschau)

Benutzerdefinierte Diagramme in Microsoft Sentinel es Sicherheitsexperten und Analysten ermöglichen, maßgeschneiderte Graphdarstellungen ihrer Sicherheitsdaten zu erstellen. Durch das Erstellen benutzerdefinierter Diagramme können Sie bestimmte Angriffsmuster modellieren, Bedrohungen untersuchen und erweiterte Graphalgorithmen ausführen, um verborgene Beziehungen in Ihrer digitalen Umgebung aufzudecken. Dieser Leitfaden führt Sie durch die Schritte zum Erstellen und Verwalten von benutzerdefinierten Graphen mithilfe von Jupyter Notebooks in der Microsoft Sentinel Visual Studio Code-Erweiterung.

Dieser Artikel konzentriert sich auf die manuelle Erstellung benutzerdefinierter Diagramme mithilfe von Code. Eine KI-gesteuerte Erfahrung finden Sie unter KI-gestützte benutzerdefinierte Grapherstellung in Microsoft Sentinel.

Voraussetzungen

Zum Erstellen benutzerdefinierter Diagramme in Microsoft Sentinel sind folgende Komponenten erforderlich:

Aktivieren Sie den Microsoft Entra ID Connector, um die Microsoft Entra Ressourcentabellen zu erfassen, die im Beispielcode dieses Artikels verwendet werden. Weitere Informationen finden Sie unter Erfassung von Ressourcendaten im Microsoft Sentinel Data Lake.

Berechtigungen

Für die Interaktion mit benutzerdefinierten Graphen benötigen Sie die folgenden XDR-Berechtigungen in Sentinel Data Lake. In der folgenden Tabelle sind die Berechtigungsanforderungen für allgemeine Graphvorgänge aufgeführt:

Graphvorgang Erforderliche Berechtigungen
Modellieren und Erstellen eines Notebookgraphen Verwenden Sie eine benutzerdefinierte Microsoft Defender XDR einheitliche RBAC-Rolle mit Datenberechtigungen (Verwalten) für die Microsoft Sentinel Datensammlung.
Beibehalten eines Graphen im Mandanten Verwenden Sie eine der folgenden Microsoft Entra ID Rollen:
Sicherheitsoperator
Sicherheitsadministrator
Globaler Administrator
Abfragen eines persistenten Graphen Verwenden Sie eine benutzerdefinierte Microsoft Defender XDR einheitliche RBAC-Rolle mit Berechtigungen für Sicherheitsdatengrundlagen (Lesen) für die Microsoft Sentinel Datensammlung.

Wichtig

Sie müssen über Berechtigungen zum Lesen der im Diagramm verwendeten Daten verfügen. Wenn Sie keinen Zugriff auf ein bestimmtes Dataset haben, werden diese Daten nicht in das Diagramm eingeschlossen. Zum Erstellen eines Graphen dürfen Sie nicht durch einen Sentinel Bereich eingeschränkt werden. Ein bereichsbezogener Benutzer kann keinen benutzerdefinierten Graphen erstellen.

Microsoft Entra ID Rollen bieten umfassenden Zugriff auf alle Arbeitsbereiche im Data Lake. Weitere Informationen finden Sie unter Rollen und Berechtigungen in Microsoft Sentinel.

Installieren von Visual Studio Code und der Microsoft Sentinel-Erweiterung

Erstellen Sie benutzerdefinierte Diagramme mithilfe von Jupyter Notebooks in der Microsoft Sentinel Visual Studio Code-Erweiterung. Weitere Informationen finden Sie unter Installieren von Visual Studio Code und der Microsoft Sentinel-Erweiterung.

Erstellen eines benutzerdefinierten Graphen

Führen Sie die folgenden Schritte aus, um benutzerdefinierte Diagramme zu erstellen und damit zu arbeiten:

  1. Modellieren eines benutzerdefinierten Graphen
  2. Beibehalten des benutzerdefinierten Graphen durch Planen eines Graphauftrags
  3. Anzeigen und Verwalten von benutzerdefinierten Diagrammen

Modellieren eines benutzerdefinierten Graphen

Erstellen Sie ein benutzerdefiniertes Diagramm mithilfe eines Jupyter Notebooks in der Microsoft Sentinel Visual Studio Code-Erweiterung.

Die folgenden Schritte führen Sie durch die Erstellung Ihres ersten benutzerdefinierten Graphen mithilfe eines Beispielnotebooks.

Einrichten Ihres Notebooks und Herstellen einer Verbindung mit dem Data Lake

  1. Wählen Sie in Visual Studio Code mit installierter Microsoft Sentinel-Erweiterung im linken Menü das symbol Microsoft Sentinel aus.

  2. Wählen Sie Anmelden aus, um Diagramme anzuzeigen.

  3. Es wird ein Dialogfeld mit dem Text Die Erweiterung "Microsoft Sentinel" möchte sich mit Microsoft anmelden angezeigt. Wählen Sie Zulassen aus, um sich anzumelden.

  4. Melden Sie sich mit Ihren Anmeldeinformationen an.

  5. Wählen Sie nach der Anmeldung die Option +Neues Notizbuch erstellen aus.

  6. Benennen Sie die Notebookdatei, und speichern Sie sie an einem geeigneten Speicherort in Ihrem Arbeitsbereich.

    Screenshot der Anmeldeseite für Diagramme in Visual Studio Code.

  7. Wählen Sie oben rechts im Notebookfenster Kernel auswählen aus, um einen Spark-Computepool auszuwählen.

  8. Wählen Sie Microsoft Sentinel und dann einen der verfügbaren Spark-Pools aus.

    Screenshot der Seite

    Tipp

    Sie können KI-Eingabeaufforderungen verwenden, um ein benutzerdefiniertes Graphnotebook zu erstellen. Weitere Informationen finden Sie unter KI-gestützte erstellung von benutzerdefinierten Graphen in Microsoft Sentinel.

  9. Führen Sie eine Zelle zu aus, indem Sie links neben der Zelle das Dreieckssymbol "Zelle ausführen" auswählen. Wenn Sie eine Zelle zum ersten Mal ausführen, werden Sie möglicherweise aufgefordert, einen Kernel auszuwählen, wenn Sie noch keinen ausgewählt haben.

    Das erste Mal, wenn Sie eine Zelle ausführen, dauert etwa fünf Minuten, um die Spark-Sitzung zu starten.

    Screenshot: Ausführung der ersten Zelle in Visual Studio Code

Erstellen eines Diagramms

Im folgenden Beispiel wird ein Diagramm erstellt, um Microsoft Entra Gruppenmitgliedschaften zu durchlaufen und geschachtelte Gruppenbeziehungen zu verstehen. Der Beispielcode hilft Ihnen bei den ersten Schritten mit einem einfachen Anwendungsfall, um die benutzerdefinierte Graphfunktion zu erlernen und die Leistungsfähigkeit des Graphdurchlaufs für Ihre Untersuchungen zu nutzen. Sie können ein Diagramm aus einer beliebigen Tabelle erstellen, die im Sentinel Data Lake verfügbar ist.

  1. Stellen Sie eine Verbindung mit Ihrem Arbeitsbereich her, und lesen Sie Entra Ressourcentabellen, um mit der Erstellung des Graphen zu beginnen.

    from pyspark.sql import functions as F
    from sentinel_lake.providers import MicrosoftSentinelProvider
    
    lake_provider = MicrosoftSentinelProvider(spark=spark)
    
    # Use the "System tables" workspace which contains the Entra* Assets tables
    # If you are data is in a different workspace, update this variable accordingly and ensure the tables are present
    LOG_ANALYTICS_WORKSPACE = "System tables"
    
    # Dynamically get the latest snapshot time from EntraUsers
    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"))
    
    # Load EntraMembers - 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"))
        )
    )
    
    # Load EntraGroups - nodes
    df_groups = (
        lake_provider.read_table("EntraGroups", LOG_ANALYTICS_WORKSPACE)
        .filter(snapshot_filter)
        .select("id", "displayName", "mailEnabled")
    )
    
    # Load EntraUsers - nodes
    df_users = (
        lake_provider.read_table("EntraUsers", LOG_ANALYTICS_WORKSPACE)
        .filter(snapshot_filter)
        .select("id", "accountEnabled", "displayName", "department",
                "lastPasswordChangeDateTime", "userPrincipalName", "usageLocation")
    )
    
    # Load EntraServicePrincipals - nodes
    df_service_principals = (
        lake_provider.read_table("EntraServicePrincipals", LOG_ANALYTICS_WORKSPACE)
        .filter(snapshot_filter)
        .select("accountEnabled", "id", "displayName", "servicePrincipalType",
                "tenantId", "organizationId")
    )
    
    # Fix for Spark 3.x Parquet datetime rebase issue. Required when reading Parquet files
    # written by Spark 2.x which used the Julian calendar, whereas Spark 3.x uses Proleptic
    # Gregorian. Without these settings, timestamp columns (e.g. lastPasswordChangeDateTime)
    # may throw errors or return incorrect values. Safe to remove if all data was written by
    # Spark 3.x (typical for current Fabric/Sentinel environments).
    spark.conf.set("spark.sql.parquet.datetimeRebaseModeInRead", "CORRECTED")
    spark.conf.set("spark.sql.parquet.datetimeRebaseModeInWrite", "CORRECTED")
    spark.conf.set("spark.sql.parquet.int96RebaseModeInRead", "CORRECTED")
    spark.conf.set("spark.sql.parquet.int96RebaseModeInWrite", "CORRECTED")
    
  2. Vorbereiten der Knoten- und Edge-DataFrames, die zum Erstellen des Graphen erforderlich sind

    # ============================================================
    # NODE PREPARATION
    # ============================================================
    
    # EntraUser nodes - keyed by user id
    user_nodes = (
        df_users.df
        .select(
            F.col("id"),
            F.col("displayName"),
            F.col("accountEnabled"),
            F.col("department"),
            F.col("lastPasswordChangeDateTime"),
            F.col("userPrincipalName"),
            F.col("usageLocation")
        )
    )
    
    # EntraGroup nodes - keyed by group id
    group_nodes = (
        df_groups.df
        .select(
            F.col("id"),
            F.col("displayName"),
            F.col("mailEnabled")
        )
    )
    
    # EntraServicePrincipal nodes - keyed by SP id
    sp_nodes = (
        df_service_principals.df
        .select(
            F.col("id"),
            F.col("displayName"),
            F.col("accountEnabled"),
            F.col("servicePrincipalType"),
            F.col("tenantId"),
            F.col("organizationId")
        )
    )
    
    # ============================================================
    # EDGE PREPARATION
    # ============================================================
    
    # Edge: EntraGroup --Contains--> EntraUser
    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: EntraGroup --Contains--> EntraGroup (nested groups)
    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")))
    )
    
    # Edge: EntraGroup --Contains--> EntraServicePrincipal
    edge_group_contains_sp = (
        df_members.df
        .filter(F.col("targetType") == "servicePrincipal")
        .select(
            F.col("sourceId").alias("SourceGroupId"),
            F.col("targetId").alias("TargetSPId")
        )
        .distinct()
        .withColumn("EdgeKey", F.concat_ws("_", F.col("SourceGroupId"), F.col("TargetSPId")))
    )
    
  3. Definieren Des Diagrammschemas und Binden an die im vorherigen Schritt erstellten DataFrames

    from sentinel_graph import GraphSpecBuilder, Graph
    
    # Define the graph schema 
    
    entra_group_graph_spec = (
        GraphSpecBuilder.start()
    
        # === NODES ===
    
        .add_node("EntraUser")
        .from_dataframe(user_nodes)  # Native Spark DataFrame (from .df + .select + .distinct)
        .with_columns(
            "id", "displayName", "accountEnabled",
            "department", "lastPasswordChangeDateTime", "userPrincipalName", "usageLocation",
            key="id", display="displayName"
        )
    
        .add_node("EntraGroup")
        .from_dataframe(group_nodes)  # Native Spark DataFrame
        .with_columns(
            "id", "displayName", "mailEnabled",
            key="id", display="displayName"
        )
    
        .add_node("EntraServicePrincipal")
        .from_dataframe(sp_nodes)  # Native Spark DataFrame
        .with_columns(
            "id", "displayName", "accountEnabled",
            "servicePrincipalType", "tenantId", "organizationId",
            key="id", display="displayName"
        )
    
        # === EDGES ===
    
        # EntraGroup --ContainsUser--> EntraUser
        .add_edge("ContainsUser")
        .from_dataframe(edge_group_contains_user)  # Native Spark DataFrame
        .source(id_column="SourceGroupId", node_type="EntraGroup")
        .target(id_column="TargetUserId", node_type="EntraUser")
        .with_columns("SourceGroupId", "TargetUserId", "EdgeKey",
                      key="EdgeKey", display="EdgeKey")
    
        # EntraGroup --ContainsGroup--> EntraGroup (nested groups)
        .add_edge("ContainsGroup")
        .from_dataframe(edge_group_contains_group)  # Native Spark DataFrame
        .source(id_column="SourceGroupId", node_type="EntraGroup")
        .target(id_column="TargetGroupId", node_type="EntraGroup")
        .with_columns("SourceGroupId", "TargetGroupId", "EdgeKey",
                      key="EdgeKey", display="EdgeKey")
    
        # EntraGroup --ContainsServicePrincipal--> EntraServicePrincipal
        .add_edge("ContainsServicePrincipal")
        .from_dataframe(edge_group_contains_sp)  # Native Spark DataFrame
        .source(id_column="SourceGroupId", node_type="EntraGroup")
        .target(id_column="TargetSPId", node_type="EntraServicePrincipal")
        .with_columns("SourceGroupId", "TargetSPId", "EdgeKey",
                      key="EdgeKey", display="EdgeKey")
    
    ).done()
    
  4. Überprüfen des Diagrammschemas

    # Check the schema of the graph spec to ensure it's correct
    entra_group_graph_spec.show_schema()
    
  5. Erstellen des Graphen, einschließlich Vorbereiten der Daten und Veröffentlichen des Graphen

    # Build the graph from the spec - this will validate the spec and prepare it for querying
    # Alter options is to use Graph.prepare() to prepare the graph nodes and edges in the lake
    # and then use Graph.publish() to create the graph. You would typically call prepare() and publish()
    # seperately to understand the cost of Graph API calls that are triggeterd by Graph.publish()
    # see https://learn.microsoft.com/azure/sentinel/billing?tabs=simplified%2Ccommitment-tiers
    intra_group_graph = Graph.build(entra_group_graph_spec)
    

    Hinweis

    Diagramme, die während interaktiver Notebooksitzungen erstellt wurden, werden entfernt, wenn die Notebooksitzung geschlossen wird. Informationen zum Beibehalten des Graphen für die Wiederverwendung und Freigabe finden Sie unter Beibehalten des benutzerdefinierten Graphen.

Sie haben nun ein Diagramm im Notebook erstellt.

Um eine visuelle Darstellung des Graphen anzuzeigen, fügen Sie in eine neue Zelle den folgenden Code ein, und führen Sie ihn aus:

# Query 1: Find nested group relationships nexting 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 *
"""
intra_group_graph.query(query_nested_groups).show()

Dieser Code führt eine GQL-Beispielabfrage (Graph Query Language) aus, um die gesamte geschachtelte Gruppenmitgliedschaft mit einer Tiefe von bis zu acht Ebenen abzurufen. Das resultierende Diagramm wird in der Ausgabe visualisiert.

Screenshot: Visualisierung eines Graphen in Visual Studio Code

Beibehalten des benutzerdefinierten Graphen

Nachdem Sie den Graphcode im Notebook erstellt haben, können Sie das Notebook in einer interaktiven Sitzung ausführen oder einen Graphauftrag planen. Graphen, die während der interaktiven Notebooksitzung erstellt wurden, sind temporär und nur im Kontext der Notebooksitzung verfügbar. Um Ihr Diagramm zu speichern und für Ihr Team zu teilen, planen Sie einen Graphauftrag, um Den Graphen häufig neu zu erstellen. Nachdem das Diagramm gespeichert wurde, ist der Zugriff auf das Diagramm über Microsoft Defender Portal unter Sentinel, Visual Studio Code-Notebooks und Graph-Abfrage-APIs möglich.

  1. Wählen Sie in Ihrem Graph-Notebook Die Option Geplanten Auftrag erstellen und dann Graphauftrag erstellen aus.

    Screenshot: Schaltfläche

  2. Geben Sie im Formular Graphauftrag erstellen den Graphnamen und die Beschreibung ein, und vergewissern Sie sich, dass das richtige Graphnotebook im Pfad enthalten ist.

  3. Um den Graphen zu erstellen, ohne einen Aktualisierungszeitplan zu konfigurieren, wählen Sie im Abschnitt Zeitplan die Option Bei Bedarf und dann Übermitteln aus, um den Graphen zu erstellen.

    Hinweis

    Diagramme, die mit einem bedarfsgesteuerten Zeitplan erstellt wurden, haben eine Standardaufbewahrung von 30 Tagen und werden nach Ablauf gelöscht.

  4. Wählen Sie zum Erstellen des Graphen, in dem die Graphdaten regelmäßig aktualisiert werden, im Abschnitt Zeitplan die Option Geplant aus.

    1. Wählen Sie eine Wiederholungshäufigkeit für den Auftrag aus. Sie können zwischen Minuten, Stündlich, Wöchentlich, Täglich oder Monatlich wählen.

    2. Je nach ausgewählter Häufigkeit werden weitere Optionen zum Konfigurieren des Zeitplans angezeigt. Beispiel: Wochentag, Tageszeit oder Monatstag.

    3. Wählen Sie einen Startzeitpunkt für die Ausführung des Zeitplans aus.

    4. Wählen Sie eine End-on-Time aus, um die Ausführung des Zeitplans zu beenden. Wenn Sie keine Endzeit für den Zeitplan festlegen möchten, wählen Sie Auftrag auf unbestimmte Ausführung festlegen aus. Datums- und Uhrzeitangaben befinden sich in Ihrer Zeitzone.

    5. Wählen Sie Senden aus, um die Auftragskonfiguration zu speichern und den Auftrag zu veröffentlichen. Der Diagrammerstellungsprozess beginnt in Ihrem Mandanten. Zeigen Sie das neu erstellte Diagramm und dessen neueste status in der Sentinel-Erweiterung an.

    Screenshot der Seite

Anzeigen und Verwalten von benutzerdefinierten Diagrammen

Nachdem Sie einen Graphauftrag erstellt haben, können Sie den Graphen in Ihrem Mandanten über die Microsoft Sentinel-Erweiterung in Visual Studio Code anzeigen und verwalten.

  1. Wählen Sie in der Liste der Diagramme Ihr materialisiertes Diagramm aus, um seine Details anzuzeigen.

  2. Wählen Sie die Registerkarte Auftragsdetails aus, um die status des Graphauftrags anzuzeigen, einschließlich der letzten Ausführungszeit, der nächsten Laufzeit und aller Fehler, die während des Buildprozesses aufgetreten sind.

  3. Wählen Sie Jetzt ausführen aus, um einen Graphbuild außerhalb der geplanten Zeiten manuell auszulösen. Der Status ändert sich in Warteschlange und dann in "In Bearbeitung", während der Graph erstellt wird.

    Screenshot der Registerkarte

  4. Wenn der Graphbuild abgeschlossen ist, wird der Status in Bereit aktualisiert. Wählen Sie die Registerkarte Diagrammdetails aus, um Informationen zum Diagramm anzuzeigen.

    Screenshot der Registerkarte

  5. Sie können ihr Diagramm jetzt über die Graphvisualisierung in Microsoft Sentinel im Defender-Portal abfragen und visualisieren. Weitere Informationen finden Sie unter Visualisieren von Diagrammen in Microsoft Sentinel (Vorschau).