Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Les graphiques personnalisés dans Microsoft Sentinel permettent aux chercheurs et aux analystes en sécurité de créer des représentations graphiques personnalisées de leurs données de sécurité. En créant des graphiques personnalisés, vous pouvez modéliser des modèles d’attaque spécifiques, examiner les menaces et exécuter des algorithmes de graphe avancés pour découvrir les relations cachées au sein de votre environnement numérique. Ce guide vous guide tout au long des étapes de création et de gestion de graphiques personnalisés à l’aide de notebooks Jupyter dans l’extension Microsoft Sentinel Visual Studio Code.
Cet article se concentre sur la création manuelle de graphiques personnalisés à l’aide de code. Pour une expérience pilotée par l’IA, consultez Création de graphiques personnalisés assistés par IA dans Microsoft Sentinel.
Configuration requise
Les éléments suivants sont nécessaires pour créer des graphiques personnalisés dans Microsoft Sentinel :
- extension Microsoft Sentinel pour Visual Studio Code. Pour plus d’informations, consultez Exécuter des notebooks sur le lac de données Microsoft Sentinel.
- Extension Jupyter pour Visual Studio Code.
- Microsoft Sentinel lac de données configuré avec les autorisations appropriées. Pour plus d’informations, consultez Intégrer à Microsoft Sentinel lac de données.
Activez le connecteur Microsoft Entra ID pour ingérer les tables de ressources Microsoft Entra utilisées dans l’exemple de code de cet article. Pour plus d’informations, consultez Ingestion de données de ressources dans le lac de données Microsoft Sentinel.
Autorisations
Pour interagir avec des graphiques personnalisés, vous avez besoin des autorisations XDR suivantes dans Sentinel lac de données. Le tableau suivant répertorie les exigences d’autorisation pour les opérations de graphe courantes :
| Opération de graphe | Autorisations requises |
|---|---|
| Modéliser et générer un graphe de notebook | Utilisez un rôle RBAC unifié Microsoft Defender XDR personnalisé avec des autorisations de données (gérer) sur la collecte de données Microsoft Sentinel. |
| Conserver un graphique dans le locataire | Utilisez l’un des rôles Microsoft Entra ID suivants : Opérateur de sécurité Administrateur de sécurité Administrateur général |
| Interroger un graphe persistant | Utilisez un rôle RBAC personnalisé Microsoft Defender XDR unifié avec des autorisations de base des données de sécurité (lecture) sur la collecte de données Microsoft Sentinel. |
Importante
Vous devez disposer des autorisations nécessaires pour lire les données utilisées dans le graphique. Si vous n’avez pas accès à un jeu de données spécifique, ces données ne seront pas incluses dans le graphique. Pour créer un graphique, vous ne devez pas être limité par une étendue Sentinel. Un utilisateur délimité n’est pas en mesure de créer un graphe personnalisé.
Microsoft Entra ID rôles fournissent un accès étendu à tous les espaces de travail du lac de données. Pour plus d’informations, consultez Rôles et autorisations dans Microsoft Sentinel.
Installer Visual Studio Code et l’extension Microsoft Sentinel
Créez des graphiques personnalisés à l’aide de notebooks Jupyter dans l’extension Microsoft Sentinel Visual Studio Code. Pour plus d’informations, consultez Installer Visual Studio Code et l’extension Microsoft Sentinel
Créer un graphe personnalisé
Pour créer et utiliser des graphiques personnalisés, procédez comme suit :
- Modéliser un graphe personnalisé
- Conserver le graphe personnalisé en planifiant un travail de graphe
- Afficher et gérer des graphiques personnalisés
Modéliser un graphe personnalisé
Créez un graphique personnalisé à l’aide d’un notebook Jupyter dans l’extension Microsoft Sentinel Visual Studio Code.
Les étapes suivantes vous guident tout au long de la création de votre premier graphe personnalisé à l’aide d’un exemple de notebook.
Configurer votre notebook et se connecter au lac de données
Dans Visual Studio Code avec l’extension Microsoft Sentinel installée, sélectionnez l’icône Microsoft Sentinel dans le menu de gauche.
Sélectionnez Se connecter pour afficher les graphiques
Une boîte de dialogue s’affiche avec le texte L’extension « Microsoft Sentinel » souhaite se connecter à l’aide de Microsoft. Sélectionnez Autoriser à se connecter.
Connectez-vous avec vos informations d’identification.
Après vous être connecté, sélectionnez +Créer un bloc-notes.
Nommez le fichier de bloc-notes et enregistrez-le à un emplacement approprié dans votre espace de travail.
Sélectionnez Sélectionner un noyau en haut à droite de la fenêtre du notebook pour sélectionner un pool de calcul Spark.
Sélectionnez Microsoft Sentinel, puis sélectionnez l’un des pools Spark disponibles.
Conseil
Vous pouvez utiliser des invites IA pour vous aider à créer un notebook de graphique personnalisé. Pour plus d’informations, consultez Création de graphiques personnalisés assistés par IA dans Microsoft Sentinel.
Exécutez une cellule dans en sélectionnant l’icône exécuter le triangle de cellule à gauche de la cellule. La première fois que vous exécutez une cellule, vous pouvez être invité à sélectionner un noyau si vous n’en avez pas déjà sélectionné un.
La première fois que vous exécutez une cellule, le démarrage de la session Spark prend environ cinq minutes.
Créer un graphique
L’exemple suivant crée un graphique pour parcourir Microsoft Entra appartenances aux groupes et comprendre les relations de groupes imbriqués. L’exemple de code vous aide à démarrer avec un cas d’usage simple pour apprendre la fonctionnalité de graphe personnalisé et tirer parti de la puissance de la traversée de graphe pour vos investigations. Vous pouvez créer un graphique à partir de n’importe quelle table disponible dans le lac de données Sentinel.
Connectez-vous à votre espace de travail et lisez Entra tables de ressources pour commencer à créer le graphe.
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")Préparer les dataframes de nœud et de périphérie nécessaires à la création du graphe
# ============================================================ # 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"))) )Définir votre schéma de graphe et le lier aux DataFrames créés à l’étape précédente
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()Valider le schéma de graphe
# Check the schema of the graph spec to ensure it's correct entra_group_graph_spec.show_schema()Générer le graphe, y compris la préparation des données et la publication du graphe
# 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)Remarque
Les graphiques créés pendant les sessions interactives de notebook sont supprimés lorsque la session de notebook est fermée. Pour conserver le graphe à des fins de réutilisation et de partage, consultez Conserver votre graphe personnalisé
Vous avez maintenant créé un graphique dans le notebook.
Pour afficher une représentation visuelle du graphe, dans une nouvelle cellule, collez et exécutez le code suivant :
# 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()
Ce code exécute un exemple de requête GQL (Graph Query Language) pour récupérer toutes les appartenances de groupe imbriquées jusqu’à 8 niveaux de profondeur. Le graphe obtenu est visualisé dans la sortie
Conserver votre graphe personnalisé
Une fois que vous avez créé le code du graphe dans le notebook, vous pouvez exécuter le bloc-notes dans une session interactive ou planifier un travail de graphe. Les graphiques créés pendant la session de bloc-notes interactive sont temporaires et sont disponibles uniquement dans le contexte de la session de bloc-notes. Pour enregistrer votre graphique et le partager avec votre équipe, planifiez un travail de graphe pour reconstruire votre graphe fréquemment. Une fois le graphe enregistré, il est accessible à partir de : l’expérience graphique dans Microsoft Defender portail sous Sentinel, Visual Studio Code Notebooks et API de requête Graph.
Dans votre bloc-notes de graphique, sélectionnez Créer un travail planifié, puis Créer un travail de graphe.
Dans le formulaire Créer un travail de graphe, entrez le nom du graphique et la description, puis vérifiez que le bloc-notes de graphe correct est inclus dans Chemin d’accès.
Pour générer le graphe sans configurer une planification d’actualisation, sélectionnez À la demande dans la section Planification , puis envoyer pour créer le graphe.
Remarque
Les graphiques créés à l’aide de la planification à la demande ont une rétention par défaut de 30 jours et sont supprimés à l’expiration.
Pour générer le graphe où les données du graphique sont actualisées régulièrement, sélectionnez Planifié dans la section Planification .
Sélectionnez une fréquence de répétition pour le travail. Vous pouvez choisir entre Par minute, Toutes les heures, Hebdomadaires, Quotidiennes ou Mensuelles.
D’autres options s’affichent pour configurer la planification, en fonction de la fréquence que vous sélectionnez. Par exemple, le jour de la semaine, l’heure de la journée ou le jour du mois.
Sélectionnez un bouton Démarrer à l’heure pour que la planification commence à s’exécuter.
Sélectionnez fin à l’heure pour que la planification cesse de s’exécuter. Si vous ne souhaitez pas définir d’heure de fin pour la planification, sélectionnez Définir le travail à exécuter indéfiniment. Les dates et heures se trouvent dans votre fuseau horaire.
Sélectionnez Envoyer pour enregistrer la configuration du travail et publier le travail. Le processus de création de graphe commence dans votre locataire. Affichez le graphique nouvellement créé et sa dernière status dans l’extension Sentinel.
Afficher et gérer des graphiques personnalisés
Après avoir créé un travail de graphe, vous pouvez afficher et gérer le graphe dans votre locataire à partir de l’extension Microsoft Sentinel dans Visual Studio Code.
Dans la liste des graphiques, sélectionnez votre graphe matérialisé pour afficher ses détails.
Sélectionnez l’onglet Détails du travail pour afficher les status du travail de graphe, y compris l’heure de la dernière exécution, l’heure de la prochaine exécution et les erreurs rencontrées pendant le processus de génération.
Sélectionnez Exécuter maintenant pour déclencher manuellement une génération de graphique en dehors des heures planifiées. L’état passe à En file d’attente, puis « En cours » pendant la génération du graphique.
Une fois la génération du graphe terminée, l’état passe à Prêt. Sélectionnez l’onglet Détails du graphique pour afficher des informations sur le graphique.
Vous pouvez désormais interroger et visualiser votre graphe à partir de la visualisation de graphe dans Microsoft Sentinel dans le portail Defender. Pour plus d’informations, consultez Visualiser des graphiques dans Microsoft Sentinel graphe (préversion).
Articles connexes
- Création de graphiques personnalisés assistées par l’IA dans Microsoft Sentinel
- Informations de référence sur la bibliothèque de fournisseurs de graphe Microsoft Sentinel
- Informations de référence sur le langage de requête graph (GQL) pour Sentinel graphe personnalisé
- Visualiser des graphiques dans Microsoft Sentinel graphique (préversion)