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 Ejecutar cuadernos en el lago de datos de Microsoft Sentinel.
- Extensión de Jupyter para Visual Studio Code.
- Lago de datos de Microsoft Sentinel configurado con los permisos adecuados. Para obtener más información, consulte Incorporación al lago de datos de Microsoft Sentinel.
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.
Permisos
Para poder interactuar con gráficos personalizados, necesita los siguientes permisos de XDR en el lago de datos de Sentinel. En la tabla siguiente se enumeran los requisitos de permisos para las operaciones comunes de grafos:
| Operación de grafos | Permisos necesarios |
|---|---|
| Diseñar y crear un grafo de cuaderno | Utilice una rol RBAC unificado personalizado de Microsoft Defender XDR con permisos de datos (administrar) sobre la recopilación de datos de Microsoft Sentinel. |
| Conservar un gráfico 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 de RBAC unificado y personalizado de Microsoft Defender XDR con permisos de acceso a datos básicos de seguridad (lectura) para la recopilación de datos de 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 grafo, no debe estar restringido por un filtro de acceso de Sentinel. Un usuario con permisos restringidos 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 grafo 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.
Configura tu cuaderno y conéctalo al lago de datos
Siga estos pasos para crear un cuaderno y conectarse al lago de datos de Microsoft Sentinel.
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 esquina superior derecha de la ventana del cuaderno de notas para seleccionar un grupo de procesos 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 través del icono de reproducción con forma de triángulo situado 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, iniciar la sesión de Spark tarda unos cinco minutos.
Creación de un gráfico
En el siguiente ejemplo se crea un grafo para recorrer las pertenencias a grupos de Microsoft Entra y comprender las relaciones entre grupos anidados. El código de ejemplo le ayuda a empezar con un caso de uso sencillo para conocer la capacidad de gráfico personalizado y aprovechar la potencia del recorrido de grafos en sus investigaciones. Puede crear un gráfico a partir de cualquier tabla disponible en el lago de datos de Sentinel.
Conéctese a su área de trabajo y lea las tablas de recursos de Entra para empezar a crear el grafo.
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"))) )Defina el esquema del grafo y vincúlelo a los DataFrames de nodos y aristas que ha preparado anteriormente en este procedimiento.
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 grafo en el cuaderno.
El siguiente ejemplo de Python ejecuta una consulta de Lenguaje de Consulta de Grafos (GQL) sobre el grafo que acabas de crear para explorar relaciones de grupos anidados. Utiliza consultas como esta tras la creación de grafos para atravesar jerarquías de membresía y descubrir rutas de acceso indirectas. Para probarlo, pega el código en una nueva celda de cuaderno y ejecutalo. Esta consulta de ejemplo recorre membresías anidadas de grupos de Microsoft Entra hasta ocho niveles de profundidad y muestra las relaciones resultantes:
# 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 grafo, se puede acceder a él desde: la experiencia de grafos en el portal de Microsoft Defender, en Sentinel, los blocs de notas de Visual Studio Code y las API de consulta de grafos.
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, introduzca el nombre del grafo y la descripción, y compruebe que el cuaderno de grafos correcto esté incluido 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 una frecuencia de repetición del 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 grafos 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, podrá ver y administrar el grafo en su inquilino mediante la extensión de 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 su grafo desde la visualización del grafo en Microsoft Sentinel en el portal de Defender. Para obtener más información, consulte Visualizar gráficos en Microsoft Sentinel Graph (versión preliminar).
Actualización de gráficos personalizados
Después de actualizar el código de grafo del cuaderno, ejecute el cuaderno localmente para validar los cambios antes de actualizar una tarea de grafo.
Edición de los detalles del grafo personalizado existentes
Use este flujo de trabajo para editar un trabajo de grafo existente.
En el panel Microsoft Sentinel Graph de Visual Studio Code, seleccione Editar trabajo de grafo para el grafo que desea actualizar y, a continuación, vaya a Nombre del grafo>Detalles del trabajo.
Actualice los campos que desea cambiar:
- Nombre del grafo (opcional). Al actualizar el nombre del grafo se crea un nuevo grafo en el inquilino. El gráfico existente permanece sin cambios.
- Descripción (opcional). Al actualizar la descripción, se reemplaza la descripción del gráfico actual y se vuelve a generar el gráfico.
- Configuración del clúster (opcional). La actualización de la configuración del clúster cambia el tamaño de proceso y vuelve a generar el gráfico.
- Frecuencia del trabajo (opcional). La actualización de la frecuencia del trabajo cambia la programación periódica y vuelve a generar el gráfico.
Sobrescribir un grafo personalizado existente
Use este flujo de trabajo cuando desee volver a crear un grafo y sobrescribir un grafo existente con el mismo nombre.
Abra el cuaderno actualizado.
Seleccione Crear trabajo programado en la experiencia del cuaderno de Sentinel y, a continuación, seleccione Crear un trabajo de grafo.
En el formulario Crear grafo , proporcione un nombre de grafo.
- Si indica un nuevo nombre de grafo, se crea un nuevo grafo en el tenant y el grafo existente sigue estando disponible.
- Si reutiliza un nombre de grafo existente para un inquilino, el grafo existente se sobrescribe tras la confirmación. Los nombres de grafo son únicos y no se admiten nombres de grafos duplicados.
Compruebe que Path hace referencia al cuaderno actualizado.
Actualice la descripción del gráfico.
Seleccione Configuración del clúster y Frecuencia de trabajo, similar a la creación de un grafo.
Actualice la información de programación , si es necesario.
Vuelva a actualizar el campo Descripción según sea necesario.
Seleccione Enviar para volver a crear Graph en su tenant.
Contenido relacionado
- Creación de gráficos personalizados asistidos por IA en Microsoft Sentinel
- Referencia de la biblioteca del proveedor de grafos de Microsoft Sentinel
- Referencia del lenguaje de consulta de grafos (GQL) para el gráfico personalizado de Sentinel
- Visualizar gráficos en el gráfico de Microsoft Sentinel (versión preliminar)