Začínáme s vlastními grafy v Microsoft Sentinel (Preview)

Vlastní grafy v Microsoft Sentinel umožňují výzkumníkům a analytikům v oblasti zabezpečení vytvářet přizpůsobené grafové znázornění dat zabezpečení. Vytvářením vlastních grafů můžete modelovat konkrétní vzory útoků, zkoumat hrozby a spouštět pokročilé grafové algoritmy, které odhalí skryté vztahy v digitálním prostředí. Tato příručka vás provede postupem vytváření a správy vlastních grafů pomocí poznámkových bloků Jupyter v rozšíření Microsoft Sentinel Visual Studio Code.

Tento článek se zaměřuje na ruční vytváření vlastních grafů pomocí kódu. Informace o prostředí založeném na umělé inteligenci najdete v tématu Vlastní vytváření grafů s asistencí umělé inteligence v Microsoft Sentinel.

Požadavky

K vytvoření vlastních grafů v Microsoft Sentinel jsou potřeba následující:

Povolte konektor Microsoft Entra ID, aby načítal tabulky prostředků Microsoft Entra používané v ukázkovém kódu v tomto článku. Další informace najdete v tématu Ingestování dat assetů v datovém jezeře Microsoft Sentinel.

Oprávnění

Pokud chcete pracovat s vlastními grafy, potřebujete v Sentinel Data Lake následující oprávnění XDR. Následující tabulka uvádí požadavky na oprávnění pro běžné operace s grafy:

Operace s grafem Požadovaná oprávnění
Modelování a sestavení grafu poznámkového bloku Použijte vlastní jednotnou roli RBAC služby Microsoft Defender XDR s oprávněním data (manage) pro kolekci dat Microsoft Sentinel.
Zachování grafu v tenantovi Použijte jednu z následujících Microsoft Entra ID rolí:
Operátor zabezpečení
Správce zabezpečení
Globální správce
Dotazování perzistentního grafu Použijte vlastní sjednocenou roli RBAC Microsoft Defenderu XDR s oprávněními základní data zabezpečení (čtení) nad kolekcí dat Microsoft Sentinelu.

Důležité

Ke čtení dat použitých v grafu musíte mít oprávnění. Pokud nemáte přístup ke konkrétní datové sadě, tato data se do grafu nezahrnou. Pokud chcete vytvořit graf, nesmíte být omezeni oborem Sentinel. Uživatel s vymezeným oborem nemůže vytvořit vlastní graf.

Microsoft Entra ID role poskytují široký přístup ke všem pracovním prostorům v data lake. Další informace najdete v tématu Role a oprávnění v Microsoft Sentinel.

Instalace editoru Visual Studio Code a rozšíření Microsoft Sentinel

Vytvářejte vlastní grafy pomocí poznámkových bloků Jupyter v rozšíření Microsoft Sentinel Visual Studio Code. Další informace najdete v tématu Instalace editoru Visual Studio Code a rozšíření Microsoft Sentinel.

Vytvoření vlastního grafu

Pokud chcete vytvořit vlastní grafy a pracovat s těmito grafy, proveďte následující kroky:

  1. Modelování vlastního grafu
  2. Zachování vlastního grafu naplánováním úlohy grafu
  3. Zobrazení a správa vlastních grafů

Modelování vlastního grafu

Vytvořte vlastní graf pomocí poznámkového bloku Jupyter v rozšíření Microsoft Sentinel Visual Studio Code.

Následující kroky vás provedou vytvořením prvního vlastního grafu pomocí ukázkového poznámkového bloku.

Nastavte si notebook a připojte se k datovému jezeru

Pomocí následujícího postupu vytvořte poznámkový blok a připojte se k Microsoft Sentinel data lake.

  1. V editoru Visual Studio Code s nainstalovaným rozšířením Microsoft Sentinel vyberte v nabídce vlevo ikonu Microsoft Sentinel.

  2. Výběrem možnosti Přihlásit se zobrazíte grafy.

  3. Zobrazí se dialogové okno s textem Rozšíření "Microsoft Sentinel" se chce přihlásit pomocí Microsoftu. Vyberte Povolit a přihlaste se.

  4. Přihlaste se pomocí svých přihlašovacích údajů.

  5. Po přihlášení vyberte + a pak vyberte Vytvořit nový poznámkový blok.

  6. Pojmenujte soubor poznámkového bloku a uložte ho do vhodného umístění v pracovním prostoru.

    Snímek obrazovky s přihlašovací stránkou pro grafy v editoru Visual Studio Code

  7. V pravém horním rohu okna poznámkového bloku vyberte možnost Vybrat jádro a poté vyberte výpočetní fond Spark.

  8. Vyberte Microsoft Sentinel a pak vyberte některý z dostupných fondů Spark.

    Snímek obrazovky se stránkou výběru jádra v editoru Visual Studio Code

    Tip

    Pomocí pokynů AI můžete vytvořit vlastní grafový poznámkový blok. Další informace najdete v tématu Vlastní vytváření grafů s asistencí umělé inteligence v Microsoft Sentinel.

  9. Buňku spustíte výběrem trojúhelníkové ikony Spustit buňku vlevo od buňky. Při prvním spuštění buňky se může zobrazit výzva k výběru jádra, pokud jste ho ještě nevybrali.

    Při prvním spuštění buňky trvá spuštění relace Spark přibližně pět minut.

    Snímek obrazovky znázorňující spuštění první buňky v editoru Visual Studio Code

Vytvoření grafu

Následující ukázka vytvoří graf pro procházení členství ve skupinách v Microsoft Entra a porozumění vztahům mezi vnořenými skupinami. Ukázkový kód vám pomůže začít na jednoduchém příkladu použití, abyste se seznámili s možnostmi vlastního grafu a využili procházení grafu při vašich šetřeních. Graf můžete vytvořit z libovolné tabulky dostupné v Sentinel Data Lake.

  1. Připojte se k pracovnímu prostoru a načtěte tabulky prostředků Entra, abyste mohli začít sestavovat graf.

    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. Připravte datové rámce uzlů a hran potřebné pro sestavení grafu

    # ============================================================
    # 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. Definujte schéma grafu a vytvořte vazbu k uzlům a hraničním datovým rámcům, které jste připravili dříve v tomto postupu.

    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. Ověření schématu grafu

    # Check the schema of the graph spec to ensure it's correct
    entra_group_graph_spec.show_schema()
    
  5. Sestavení grafu, včetně přípravy dat a publikování grafu

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

    Poznámka

    Grafy vytvořené během interaktivních relací poznámkového bloku se po zavření relace poznámkového bloku odeberou. Pokud chcete graf zachovat pro opakované použití a sdílení, přečtěte si téma Zachování vlastního grafu.

V poznámkovém bloku jste teď vytvořili graf.

Následující příklad Python spouští dotaz v Graph Query Language (GQL) proti právě vytvořenému grafu, aby prozkoumal vnořené skupinové vztahy. Použijte dotazy jako tento po vytvoření grafu k procházení hierarchií členství a odhalování nepřímých přístupových cest. Pro vyzkoušení vložte kód do nové buňky notebooku a spusťte ho. Tento ukázkový dotaz prochází vnořené členství ve skupinách Microsoft Entra až do osmi úrovní a zobrazuje výsledné vztahy:

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

Tento kód spustí ukázkový dotaz jazyka GQL (Graph Query Language), který načte všechny vnořené členství ve skupinách až do hloubky 8 úrovní. Výsledný graf je vizualizován ve výstupu.

Snímek obrazovky znázorňující vizualizaci grafu v editoru Visual Studio Code

Zachování vlastního grafu

Jakmile v poznámkovém bloku vytvoříte kód grafu, můžete poznámkový blok spustit v interaktivní relaci nebo naplánovat grafovou úlohu. Grafy vytvořené během interaktivní relace poznámkového bloku jsou dočasné a jsou dostupné jenom v kontextu relace poznámkového bloku. Chcete-li graf uložit a sdílet ho se svým týmem, naplánujte úlohu pro sestavení grafu tak, aby se graf často znovu sestavoval. Po uložení je graf přístupný z těchto míst: z grafického rozhraní na portálu Microsoft Defender v rámci Sentinel, z Poznámkových bloků ve Visual Studio Code a z rozhraní API pro dotazy v Graphu.

  1. V poznámkovém bloku grafu vyberte Vytvořit naplánovanou úlohu a pak vyberte Vytvořit úlohu grafu.

    Snímek obrazovky znázorňující tlačítko vytvořit naplánovanou úlohu v poznámkovém bloku grafu

  2. Ve formuláři Vytvořit úlohu grafu zadejte Název grafu a Popis a ověřte, že je v poli Cesta uveden správný poznámkový blok grafu.

  3. Pokud chcete vytvořit graf bez konfigurace plánu aktualizace, vyberte na vyžádání v části Plán a pak vyberte Odeslat a vytvořte graf.

    Poznámka

    Grafy vytvořené pomocí plánu na vyžádání mají výchozí uchovávání 30 dnů a po vypršení platnosti se odstraní.

  4. Pokud chcete vytvořit graf, ve kterém se data grafu pravidelně aktualizují, vyberte v části Plánmožnost Naplánované.

    1. Vyberte frekvenci opakování pro úlohu. Můžete si vybrat podle minut, Hodinově, Týdně, Denně nebo Měsíčně.

    2. V závislosti na vybrané frekvenci se zobrazí další možnosti konfigurace plánu. Například den v týdnu, denní čas nebo den v měsíci.

    3. Vyberte čas Spustit od, kdy se má plán začít spouštět.

    4. Vyberte čas Datum ukončení, aby se plán přestal spouštět. Pokud nechcete nastavit čas ukončení plánu, vyberte Nastavit úlohu, která se bude spouštět po neomezenou dobu. Data a časy jsou ve vašem časovém pásmu.

    5. Výběrem možnosti Odeslat uložte konfiguraci úlohy a publikujte úlohu. Proces vytváření grafu začíná ve vašem tenantu. Podívejte se na nově vytvořený graf a jeho nejnovější stav v rozšíření Sentinel.

    Snímek obrazovky se stránkou úlohy vytvoření grafu

Zobrazení a správa vlastních grafů

Po vytvoření úlohy grafu můžete graf zobrazit a spravovat ve vašem tenantovi v rozšíření Microsoft Sentinel v aplikaci Visual Studio Code.

  1. V seznamu grafů vyberte materializovaný graf a zobrazte jeho podrobnosti.

  2. Vyberte kartu Podrobnosti úlohy a zobrazte stav úlohy grafu, včetně času posledního spuštění, času dalšího spuštění a všech chyb, ke kterým došlo během procesu sestavení.

  3. Vyberte Spustit, pokud chcete ručně aktivovat sestavení grafu mimo naplánované časy. Stav se během sestavování grafu změní na Ve frontě a poté na Probíhá.

    Snímek obrazovky zobrazující kartu Podrobnosti úlohy grafu v editoru Visual Studio Code.

  4. Po dokončení sestavení grafu se stav aktualizuje na Připraveno. Vyberte kartu Podrobnosti grafu a zobrazte informace o grafu.

    Snímek obrazovky záložky podrobností grafu.

  5. Teď můžete v Microsoft Sentinelu na portálu Defender spouštět dotazy nad grafem a vizualizovat ho v zobrazení vizualizace grafu. Další informace najdete v tématu Vizualizovat grafy v grafu Microsoft Sentinel (preview).

Aktualizace vlastních grafů

Po aktualizaci kódu grafu poznámkového bloku spusťte poznámkový blok místně a ověřte změny před aktualizací úlohy grafu.

Úprava existujících podrobností vlastního grafu

Pomocí tohoto pracovního postupu můžete upravit existující úlohu grafu.

  1. Na panelu Visual Studio Code Microsoft Sentinel Graph vyberte Upravit úlohu grafu pro graf, který chcete aktualizovat, a pak přejděte naPodrobnosti úlohy> grafu.

  2. Aktualizujte pole, která chcete změnit:

    • Název grafu (volitelné) Aktualizace názvu grafu vytvoří nový graf ve vašem tenantovi. Existující graf zůstává beze změny.
    • Popis (volitelný) Aktualizace popisu nahradí aktuální popis grafu a graf znovu sestaví.
    • Konfigurace clusteru (volitelné) Aktualizace konfigurace clusteru změní velikost výpočetních prostředků a graf znovu sestaví.
    • Frekvence úloh (volitelné) Aktualizace frekvence úlohy změní plán opakování a graf se znovu sestaví.

Snímek obrazovky zobrazující pracovní postup úlohy grafu Edit v panelu Graph služby Microsoft Sentinel ve Visual Studio Code.

Přepsání existujícího vlastního grafu

Tento pracovní postup použijte, pokud chcete graf znovu vytvořit a přepsat existující graf se stejným názvem.

  1. Otevřete aktualizovaný poznámkový blok.

  2. V prostředí poznámkového bloku Sentinelu vyberte Vytvořit naplánovanou úlohu a pak vyberte Vytvořit úlohu grafu.

  3. Ve formuláři Vytvořit graf zadejte název grafu.

    • Pokud zadáte nový název grafu, vytvoří se v tenantovi nový graf a stávající graf zůstane dostupný.
    • Pokud znovu použijete existující název grafu pro tenanta, stávající graf se po potvrzení přepíše. Názvy grafů jsou jedinečné, duplicitní názvy grafů se nepodporují.
  4. Ověřte, že cesta odkazuje na aktualizovaný poznámkový blok.

  5. Aktualizujte popis grafu.

  6. Vyberte konfiguraci clusteru a frekvenci úloh, podobně jako vytvoření nového grafu.

  7. V případě potřeby aktualizujte informace o plánu .

  8. Podle potřeby aktualizujte pole Popis znovu.

  9. Vyberte Odeslat, chcete-li graf ve svém tenantovi znovu vytvořit.

Snímek obrazovky znázorňující formulář Vytvořit graf použitý k přepsání existujícího vlastního grafu v Visual Studio Code