Compartilhar via


Introdução aos gráficos personalizados no Microsoft Sentinel (pré-visualização)

Os gráficos personalizados no Microsoft Sentinel permitem que investigadores e analistas de segurança criem representações de gráficos personalizadas dos respetivos dados de segurança. Ao criar gráficos personalizados, pode modelar padrões de ataque específicos, investigar ameaças e executar algoritmos de gráfico avançados para descobrir relações ocultas no seu ambiente digital. Este guia orienta-o ao longo dos passos para criar e gerir gráficos personalizados com os blocos de notas do Jupyter na extensão Microsoft Sentinel Visual Studio Code.

Este artigo centra-se na criação manual de gráficos personalizados com código. Para obter uma experiência orientada por IA, veja Criação de grafos personalizados assistidos por IA no Microsoft Sentinel.

Pré-requisitos

Para criar gráficos personalizados no Microsoft Sentinel:

Ative o conector Microsoft Entra ID para ingerir as tabelas de recursos Microsoft Entra utilizadas no código de exemplo deste artigo. Para obter mais informações, veja Ingestão de dados de recursos no data lake do Microsoft Sentinel.

Permissões

Para interagir com gráficos personalizados, precisa das seguintes permissões XDR no Sentinel data lake. A tabela seguinte lista os requisitos de permissão para operações de grafos comuns:

Operação de gráfico Permissões obrigatórias
Modelar e criar um gráfico de bloco de notas Utilize uma função RBAC unificada Microsoft Defender XDR personalizada com permissões de dados (gerir) através da recolha de dados Microsoft Sentinel.
Manter um gráfico no inquilino Utilize uma das seguintes funções de Microsoft Entra ID:
Operador de segurança
Administrador de segurança
Administrador global
Consultar um gráfico persistente Utilize uma função RBAC unificada Microsoft Defender XDR personalizada com permissões básicas de dados de segurança (leitura) através da recolha de dados Microsoft Sentinel.

Importante

Tem de ter permissões para ler os dados utilizados no gráfico. Se não tiver acesso a um conjunto de dados específico, esses dados não serão incluídos no gráfico. Para criar um gráfico, não pode ser restringido por um âmbito de Sentinel. Um utilizador com âmbito não consegue criar um gráfico personalizado.

Microsoft Entra ID funções fornecem acesso amplo a todas as áreas de trabalho no data lake. Para obter mais informações, veja Funções e permissões no Microsoft Sentinel.

Instalar Visual Studio Code e a extensão Microsoft Sentinel

Crie gráficos personalizados com blocos de notas do Jupyter na extensão Microsoft Sentinel Visual Studio Code. Para obter mais informações, veja Instalar Visual Studio Code e a extensão Microsoft Sentinel

Criar um gráfico personalizado

Para criar e trabalhar com gráficos personalizados, conclua os seguintes passos:

  1. Modelar um gráfico personalizado
  2. Manter o gráfico personalizado ao agendar uma tarefa de gráfico
  3. Ver e gerir gráficos personalizados

Modelar um gráfico personalizado

Crie um gráfico personalizado com um bloco de notas do Jupyter na extensão Microsoft Sentinel Visual Studio Code.

Os passos seguintes explicam como criar o seu primeiro gráfico personalizado com um bloco de notas de exemplo.

Configurar o seu bloco de notas e ligar ao data lake

  1. Em Visual Studio Code com a extensão Microsoft Sentinel instalada, selecione o ícone Microsoft Sentinel no menu esquerdo.

  2. Selecione Iniciar sessão para ver gráficos

  3. É apresentada uma caixa de diálogo com o texto A extensão "Microsoft Sentinel" quer iniciar sessão com a Microsoft. Selecione Permitir para iniciar sessão.

  4. Inicie sessão com as suas credenciais.

  5. Depois de iniciar sessão, selecione +Criar novo bloco de notas.

  6. Dê um nome ao ficheiro do bloco de notas e guarde-o numa localização adequada na área de trabalho.

    Uma captura de ecrã da página de início de sessão para gráficos no Visual Studio Code.

  7. Selecione Selecionar kernel no canto superior direito da janela do bloco de notas para selecionar um conjunto de computação spark.

  8. Selecione Microsoft Sentinel e, em seguida, selecione qualquer um dos conjuntos do Spark disponíveis.

    Uma captura de ecrã da página selecionar kernel no Visual Studio Code.

    Dica

    Pode utilizar pedidos de IA para o ajudar a criar um bloco de notas de gráficos personalizado. Para obter mais informações, veja Criação de grafos personalizados assistidos por IA no Microsoft Sentinel.

  9. Execute uma célula para ao selecionar o ícone de triângulo da célula de execução à esquerda da célula. Na primeira vez que executar uma célula, poderá ser-lhe pedido que selecione um kernel se ainda não tiver selecionado um.

    A primeira vez que executar uma célula demora cerca de cinco minutos a iniciar a sessão do Spark.

    Uma captura de ecrã a mostrar a execução da primeira célula no Visual Studio Code.

Criar um gráfico

O exemplo seguinte cria um gráfico para percorrer Microsoft Entra associações a grupos e compreender as relações de grupo aninhadas. O código de exemplo ajuda-o a começar com um caso de utilização simples para aprender a capacidade de gráfico personalizado e tirar partido do poder do percurso de grafos para as suas investigações. Pode criar um gráfico a partir de qualquer tabela disponível no Sentinel data lake.

  1. Ligue-se à área de trabalho e leia Entra tabelas de recursos para começar a criar o gráfico.

    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. Preparar o nó e os DataFrames de extremidade necessários para a criação do gráfico

    # ============================================================
    # 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. Definir o esquema do gráfico e vincular aos DataFrames criados no passo anterior

    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. Validar o esquema do gráfico

    # Check the schema of the graph spec to ensure it's correct
    entra_group_graph_spec.show_schema()
    
  5. Criar o gráfico, incluindo preparar os dados e publicar o gráfico

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

    Observação

    Os gráficos criados durante sessões interativas do bloco de notas são removidos quando a sessão do bloco de notas é fechada. Para manter o gráfico para reutilização e partilha, consulte Manter o gráfico personalizado

Acabou de criar um gráfico no bloco de notas.

Para mostrar uma representação visual do gráfico, cole uma nova célula e execute o seguinte código:

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

Este código executa uma consulta GQL (Graph Query Language) de exemplo para obter todas as associações a grupos aninhadas até 8 níveis de profundidade O gráfico resultante é visualizado na saída

Uma captura de ecrã a mostrar a visualização de um gráfico no Visual Studio Code.

Manter o gráfico personalizado

Depois de criar o código do gráfico no bloco de notas, pode executar o bloco de notas numa sessão interativa ou agendar uma tarefa de gráfico. Os gráficos criados durante a sessão interativa do bloco de notas são temporários e só estão disponíveis no contexto da sessão do bloco de notas. Para guardar o seu gráfico e partilhar com a sua equipa, agende uma tarefa de gráfico para reconstruir o seu gráfico com frequência. Assim que o gráfico for guardado, é acessível a partir de: a experiência de gráfico no portal do Microsoft Defender em Sentinel, Visual Studio Code Notebooks e Graph query APIs.

  1. No seu bloco de notas de gráficos, selecione Criar Tarefa Agendada e, em seguida, selecione Criar uma tarefa de gráfico.

    Captura de ecrã a mostrar o botão criar tarefa agendada num bloco de notas de gráficos.

  2. No formulário Criar tarefa de gráfico , introduza o Nome do gráfico e a Descrição e verifique se o bloco de notas de grafos correto está incluído em Caminho.

  3. Para criar o gráfico sem configurar uma agenda de atualização, selecione A pedido na secção Agenda e, em seguida, selecione Submeter para criar o gráfico.

    Observação

    Os gráficos criados com base na agenda a pedido têm uma retenção predefinida de 30 dias e são eliminados após a expiração.

  4. Para criar o gráfico onde os dados do gráfico são atualizados regularmente, selecione Agendado na secção Agenda .

    1. Selecione uma Frequência de repetição para a tarefa. Pode escolher entre Por minuto, Hora a Hora, Semanalmente, Diário ou Mensalmente.

    2. São apresentadas mais opções para configurar a agenda, consoante a frequência que selecionar. Por exemplo, dia da semana, hora do dia ou dia do mês.

    3. Selecione um Início a tempo para que a agenda comece a ser executada.

    4. Selecione um Fim a tempo para que a agenda deixe de ser executada. Se não quiser definir uma hora de fim para a agenda, selecione Definir tarefa para ser executada indefinidamente. As datas e horas estão no seu fuso horário.

    5. Selecione Submeter para guardar a configuração da tarefa e publicar a tarefa. O processo de criação de gráficos é iniciado no seu inquilino. Veja o gráfico recentemente criado e o respetivo status mais recente na extensão Sentinel.

    Uma captura de ecrã da página criar tarefa de gráfico.

Ver e gerir gráficos personalizados

Depois de criar uma tarefa de gráfico, pode ver e gerir o gráfico no seu inquilino a partir da extensão Microsoft Sentinel no Visual Studio Code.

  1. Na lista de gráficos, selecione o gráfico materializado para ver os respetivos detalhes.

  2. Selecione o separador Detalhes da Tarefa para ver o status da tarefa de gráfico, incluindo a hora da última execução, a hora da próxima execução e quaisquer erros encontrados durante o processo de compilação.

  3. Selecione Executar Agora para acionar manualmente uma compilação de gráficos fora das horas agendadas. O Estado muda para Em fila e, em seguida, "Em Curso" enquanto o gráfico está a ser criado.

    Captura de ecrã a mostrar o separador detalhes da tarefa de gráfico no Visual Studio Code.

  4. Quando a compilação do gráfico estiver concluída, o Estado é atualizado para Pronto. Selecione o separador Detalhes do Graph para ver informações sobre o gráfico.

    Uma captura de ecrã do separador detalhes do gráfico.

  5. Agora pode consultar e visualizar o gráfico a partir da visualização de grafos no Microsoft Sentinel no portal do Defender. Para obter mais informações, veja Visualizar gráficos no gráfico Microsoft Sentinel (pré-visualização).