Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Los gráficos personalizados de Microsoft Sentinel permiten a los investigadores y analistas de seguridad crear representaciones de grafos personalizadas de sus datos de seguridad. Mediante la creación de gráficos personalizados, puede modelar patrones de ataque específicos, investigar amenazas y ejecutar algoritmos de grafos avanzados para descubrir relaciones ocultas dentro del entorno digital. Esta guía le guiará por los pasos para crear y administrar gráficos personalizados mediante cuadernos de Jupyter Notebook en la extensión Microsoft Sentinel Visual Studio Code.
Este artículo se centra en la creación manual de gráficos personalizados mediante código. Para obtener una experiencia basada en la inteligencia artificial, consulte Creación de gráficos personalizados asistidos por IA en Microsoft Sentinel.
Requisitos previos
Los siguientes son necesarios para crear gráficos personalizados en Microsoft Sentinel:
- Microsoft Sentinel extensión para Visual Studio Code. Para obtener más información, consulte Ejecución de cuadernos en el lago de datos de Microsoft Sentinel.
- Extensión de Jupyter para Visual Studio Code.
- Microsoft Sentinel lago de datos configurado con los permisos adecuados. Para obtener más información, consulte Incorporación a Microsoft Sentinel lago de datos.
Habilite el conector de Microsoft Entra ID para ingerir las tablas de recursos de Microsoft Entra que se usan en el código de ejemplo de este artículo. Para obtener más información, consulte Ingesta de datos de activos en el lago de datos de Microsoft Sentinel.
Permissions
Para interactuar con gráficos personalizados, necesita los siguientes permisos XDR en Sentinel lago de datos. En la tabla siguiente se enumeran los requisitos de permisos para las operaciones comunes de grafos:
| Operación de grafo | Permisos necesarios |
|---|---|
| Modelar y compilar un gráfico de cuaderno | Use un rol RBAC unificado de Microsoft Defender XDR personalizado con permisos de datos (administrar) a través de la recopilación de datos Microsoft Sentinel. |
| Conservar un grafo en el inquilino | Use uno de los siguientes roles de Microsoft Entra ID: Operador de seguridad Administrador de seguridad Administrador global |
| Consulta de un gráfico persistente | Use un rol RBAC personalizado Microsoft Defender XDR unificado con permisos básicos de datos de seguridad (lectura) sobre la recopilación de datos Microsoft Sentinel. |
Importante
Debe tener permisos para leer los datos usados en el gráfico. Si no tiene acceso a un conjunto de datos específico, esos datos no se incluirán en el gráfico. Para crear un gráfico, no debe estar restringido por un ámbito de Sentinel. Un usuario con ámbito no puede crear un gráfico personalizado.
Microsoft Entra ID roles proporcionan un acceso amplio a todas las áreas de trabajo del lago de datos. Para obtener más información, vea Roles y permisos en Microsoft Sentinel.
Instalar Visual Studio Code y la extensión Microsoft Sentinel
Cree gráficos personalizados mediante cuadernos de Jupyter Notebook en la extensión Microsoft Sentinel Visual Studio Code. Para obtener más información, vea Instalar Visual Studio Code y la extensión Microsoft Sentinel
Creación de un gráfico personalizado
Para crear y trabajar con gráficos personalizados, siga estos pasos:
- Modelar un gráfico personalizado
- Conservar el gráfico personalizado mediante la programación de un trabajo de grafo
- Visualización y administración de gráficos personalizados
Modelar un gráfico personalizado
Cree un gráfico personalizado mediante un cuaderno de Jupyter Notebook en la extensión Microsoft Sentinel Visual Studio Code.
Los pasos siguientes le guiarán a través de la creación del primer gráfico personalizado mediante un cuaderno de ejemplo.
Configuración del cuaderno y conexión al lago de datos
En Visual Studio Code con la extensión Microsoft Sentinel instalada, seleccione el icono Microsoft Sentinel en el menú de la izquierda.
Seleccione Iniciar sesión para ver los gráficos.
Aparece un cuadro de diálogo con el texto La extensión "Microsoft Sentinel" quiere iniciar sesión con Microsoft. Seleccione Permitir para iniciar sesión.
Inicie sesión con sus credenciales.
Después de iniciar sesión, seleccione +Crear nuevo cuaderno.
Asigne al archivo del cuaderno el nombre y guárdelo en una ubicación adecuada del área de trabajo.
Seleccione Seleccionar kernel en la parte superior derecha de la ventana del cuaderno para seleccionar un grupo de proceso de Spark.
Seleccione Microsoft Sentinel y, a continuación, seleccione cualquiera de los grupos de Spark disponibles.
Sugerencia
Puede usar solicitudes de inteligencia artificial para ayudarle a crear un cuaderno de grafos personalizado. Para obtener más información, consulte Creación de gráficos personalizados asistidos por IA en Microsoft Sentinel.
Ejecute una celda a seleccionando el icono ejecutar triángulo de celda a la izquierda de la celda. La primera vez que ejecute una celda, es posible que se le pida que seleccione un kernel si aún no ha seleccionado una.
La primera vez que ejecute una celda, tarda unos cinco minutos en iniciar la sesión de Spark.
Creación de un gráfico
En el ejemplo siguiente se crea un gráfico para recorrer Microsoft Entra pertenencias a grupos y comprender las relaciones de grupo anidadas. El código de ejemplo le ayuda a empezar a usar un caso de uso sencillo para aprender la funcionalidad de gráfico personalizado y aprovechar la eficacia del recorrido de grafos para las investigaciones. Puede crear un gráfico a partir de cualquier tabla disponible en el lago de datos de Sentinel.
Conéctese al área de trabajo y lea Entra tablas de recursos para empezar a compilar el 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")Preparación de los dataframes perimetrales y de nodo necesarios para compilar el 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"))) )Definir el esquema del grafo y enlazar a los dataframes creados en el paso 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()Validación del esquema del grafo
# Check the schema of the graph spec to ensure it's correct entra_group_graph_spec.show_schema()Compilación del gráfico, incluida la preparación de los datos y la publicación del 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)Nota:
Los gráficos creados durante las sesiones interactivas de cuadernos se quitan cuando se cierra la sesión del cuaderno. Para conservar el gráfico para su reutilización y uso compartido, consulte Conservación del gráfico personalizado.
Ahora ha creado un gráfico en el cuaderno.
Para mostrar una representación visual del gráfico, en una nueva celda pegue y ejecute el código siguiente:
# 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 ejecuta una consulta de ejemplo del Lenguaje de consulta de Graph (GQL) para recuperar toda la pertenencia a grupos anidados hasta 8 niveles de profundidad El gráfico resultante se visualiza en la salida.
Conservar el gráfico personalizado
Una vez creado el código de grafo en el cuaderno, puede ejecutar el cuaderno en una sesión interactiva o programar un trabajo de grafo. Los gráficos creados durante la sesión interactiva del cuaderno son temporales y solo están disponibles en el contexto de la sesión del cuaderno. Para guardar el gráfico y compartirlo con su equipo, programe un trabajo de grafo para volver a generar el gráfico con frecuencia. Una vez guardado el gráfico, es accesible desde: la experiencia del grafo en Microsoft Defender portal en Sentinel, Visual Studio Code Notebooks y graph query API.
En el cuaderno de grafos, seleccione Crear trabajo programado y, a continuación, seleccione Crear un trabajo de grafo.
En el formulario Crear trabajo de grafo , escriba el nombre del gráfico y la descripción, y compruebe que el cuaderno de grafos correcto se incluye en Ruta de acceso.
Para compilar el gráfico sin configurar una programación de actualización, seleccione A petición en la sección Programación y, a continuación, seleccione Enviar para crear el gráfico.
Nota:
Los gráficos creados mediante la programación a petición tienen una retención predeterminada de 30 días y se eliminan al expirar.
Para compilar el gráfico en el que los datos del grafo se actualizan periódicamente, seleccione Programado en la sección Programación .
Seleccione repetir frecuencia para el trabajo. Puede elegir entre Por minuto, Por hora, Semanal, Diario o Mensual.
Se muestran más opciones para configurar la programación, en función de la frecuencia que seleccione. Por ejemplo, día de la semana, hora del día o día del mes.
Seleccione una hora de inicio para que la programación empiece a ejecutarse.
Seleccione una hora de finalización para que la programación deje de ejecutarse. Si no desea establecer una hora de finalización para la programación, seleccione Establecer trabajo para que se ejecute indefinidamente. Las fechas y horas están en la zona horaria.
Seleccione Enviar para guardar la configuración del trabajo y publicar el trabajo. El proceso de creación de gráficos se inicia en el inquilino. Vea el gráfico recién creado y su estado más reciente en la extensión Sentinel.
Visualización y administración de gráficos personalizados
Después de crear un trabajo de grafo, puede ver y administrar el grafo en el inquilino desde la extensión Microsoft Sentinel en Visual Studio Code.
En la lista de gráficos, seleccione el gráfico materializado para ver sus detalles.
Seleccione la pestaña Detalles del trabajo para ver el estado del trabajo de grafo, incluido el tiempo de última ejecución, el siguiente tiempo de ejecución y los errores detectados durante el proceso de compilación.
Seleccione Ejecutar ahora para desencadenar manualmente una compilación de grafos fuera de las horas programadas. El estado cambia a En cola y, a continuación, "En curso" mientras se compila el gráfico.
Una vez completada la compilación del grafo, el estado se actualiza a Listo. Seleccione la pestaña Detalles del gráfico para ver información sobre el gráfico.
Ahora puede consultar y visualizar el gráfico desde la visualización del gráfico en Microsoft Sentinel en el portal de Defender. Para obtener más información, consulte Visualización de gráficos en Microsoft Sentinel gráfico (versión preliminar).
Artículos relacionados
- Creación de gráficos personalizados asistidos por IA en Microsoft Sentinel
- Microsoft Sentinel referencia de biblioteca de proveedores de grafos
- Referencia del lenguaje de consulta de gráficos (GQL) para Sentinel gráfico personalizado
- Visualización de gráficos en Microsoft Sentinel gráfico (versión preliminar)