Développer des solutions de plateforme graphique personnalisées

Note

Cette fonctionnalité est actuellement en préversion. Consultez Conditions d’utilisation supplémentaires pour les préversions de Microsoft Azure.

Une solution de graphique personnalisée Microsoft Sentinel est une solution basée sur un notebook qui définit des nœuds et des arêtes à partir de Microsoft Sentinel tables data lake, génère un graphe et permet aux utilisateurs d’interroger ce graphique avec le langage de requête Graph (GQL).

Utilisez ce guide pour créer, tester, matérialiser, empaqueter et publier une solution de graphique personnalisée en tant qu’offre SaaS dans Microsoft Partner Center afin que les clients puissent le découvrir dans Sécurité Microsoft Store.

Logiciels requis

Vous devez être intégré au lac de données pour créer des solutions Graph personnalisées. Pour plus d’informations, consultez Comment intégrer le lac de données Microsoft Sentinel.

Permissions

Le tableau suivant répertorie les autorisations requises pour chaque opération ou étendue dans ce guide.

Opération Rôle requis
Intégration au lac de données Sentinel Microsoft Entra ID - Administrateur de sécurité ou Administrateur général
Intégrer l’espace de travail Sentinel au portail Defender Propriétaire de l’abonnement, ou Administrateur de l’accès utilisateur au niveau de l’abonnement, et Contributeur Microsoft Sentinel au niveau de l’abonnement ou du groupe de ressources
Intégrer l’espace de travail Sentinel au lac de données Propriétaire de l’abonnement ou contributeur Microsoft Sentinel au niveau de l’étendue de l’abonnement ou du groupe de ressources
Modéliser et créer un graphe de bloc-notes Rôle RBAC unifié Microsoft Defender XDR personnalisé avec l'autorisation data (manage) sur la collecte de données Microsoft Sentinel
Conserver (matérialiser) un graphique Opérateur de sécurité, administrateur de sécurité ou administrateur général
Interroger un graphe persistant Rôle RBAC unifié Microsoft Defender XDR personnalisé avec security data basics (read) sur la collecte de données Microsoft Sentinel
Publication d’une solution Graph personnalisée Compte éditeur Marketplace sur Microsoft Partner Center

Tools

Les outils suivants sont nécessaires pour générer et publier une solution de graphe personnalisée :

Tip

Réutilisez un lac de données existant si votre locataire est déjà intégré pour les requêtes KQL, les notebooks ou un agent Security Copilot. Il existe un lac de données par locataire. Dans le portail Defender, accédez àParamètres>système>Microsoft Sentinel>Data lake. Si l’état est provisionné, ignorez la tâche 1.

Générer un flux de travail

Le flux de travail suivant décrit les étapes à suivre pour générer et publier une solution de graphe personnalisée.

  1. Importez des données d’exemple dans les tables modélisées par vos modèles de graphe.
  2. Validez la connectivité avec un bloc-notes simple.
  3. Créez le graphique personnalisé.
  4. Testez le carnet de graphiques.
  5. Planifiez un travail de graphe pour matérialiser le graphique.
  6. Interrogez et visualisez le graphique à partir de l’Explorateur Graph.
  7. Empaqueter et publier la solution de graphe personnalisée.

Ingérer des exemples de données

Cette tâche ingère les tables de ressources Microsoft Entra ID utilisées par le graphique d’exemple dans ce guide : EntraUsers, EntraGroups, EntraServicePrincipals et EntraMembers.

  1. Dans le portail Defender, accédez à Système>Paramètres>Microsoft Sentinel>Connecteurs de données.
  2. Activez le connecteur Microsoft Entra ID afin que les tables de ressources Entra soient ingérées dans le lac de données. Pour plus d’informations, voir Données d’actifs dans le lac de données Microsoft Sentinel.
  3. Vérifiez que ces tables apparaissent dans data lake Explorer :
    • EntraUsers
    • EntraGroups
    • EntraServicePrincipals
    • EntraMembers
  4. Ces tables sont stockées dans l'espace de travail Tables système.
  5. Facultatif : ingérer d’autres connecteurs et remplacer les noms de tables dans les étapes ultérieures si votre scénario utilise des données différentes.

Note

Si une table n’apparaît pas dans data lake Explorer, vous ne pouvez pas l’utiliser pour la création de graphiques, et l’assistance ia ne la référencera pas.

Valider la connectivité avec un bloc-notes simple

Créez et exécutez un bloc-notes minimal pour vérifier la connectivité data lake avant la création de graphiques.

  1. Ouvrez Visual Studio Code et connectez-vous à l’extension Microsoft Sentinel avec le même compte qui a accès au lac de données.

  2. Dans Visual Studio Code, sous Extension Sentinel– Graphs, sélectionnez Créer un bloc-notes. Capture d’écran montrant l’option créer un bloc-notes dans VS Code.

  3. Enregistrez le bloc-notes, par exemple hello-world-show-tables.ipynb.

  4. Sélectionnez Sélectionner le noyau, sélectionnez Microsoft Sentinel et sélectionnez un pool Spark disponible. Capture d’écran montrant l’option sélectionner le noyau dans VS Code.

  5. Ajoutez les cellules suivantes dans l’ordre.

Cellule 1 - Markdown :

# Hello World: Show Tables
A minimal connectivity test for the Microsoft Sentinel data lake.
If every cell below runs without error, your environment is ready
to author custom graphs.
Steps:
1. Connect to the data lake with the Microsoft Sentinel provider
2. Point at your workspace
3. Read a table and show a few rows

Cellule 2 - Code (connecter et définir votre espace de travail) :

from sentinel_lake.providers import MicrosoftSentinelProvider
# The provider gives the notebook access to data lake tables.
lake_provider = MicrosoftSentinelProvider(spark=spark)
# >>> ADD YOUR WORKSPACE HERE <<<
# Replace with the Log Analytics workspace that holds your tables.
# Entra asset tables (EntraUsers, EntraGroups, ...) live in "System tables".
LOG_ANALYTICS_WORKSPACE = "System tables"
print(f"Using workspace: {LOG_ANALYTICS_WORKSPACE}")

Cellule 3 - Markdown :

## Read a table and show rows
Reading a known table is the fastest way to confirm the extension
can reach the lake with your permissions. Swap EntraGroups for any
table that exists in your workspace.

Cellule 4 - Code (lire un tableau et afficher les lignes) :

# Read a table from the data lake into a Spark DataFrame.
df_groups = lake_provider.read_table("EntraGroups", LOG_ANALYTICS_WORKSPACE)
# Show a sample. .df exposes the underlying Spark DataFrame.
df_groups.df.select("id", "displayName", "mailEnabled").show(20, truncate=False)

Cellule 5 - Code (vérifications de cohérence facultatives) :

# Confirm the read returned data and inspect the schema.
print("Row count:", df_groups.df.count())
df_groups.df.printSchema()
  1. Exécutez toutes les cellules de haut en bas.
  2. Vérifiez que chaque cellule se termine sans trace rouge, les données d’aperçu du tableau s’affichent et le nombre de lignes n’est pas égal à zéro.

Note

Si les lectures échouent ou ne renvoient aucune ligne, vérifiez que le connecteur de la section Intégrer des exemples de données a effectué sa première capture instantanée, que LOG_ANALYTICS_WORKSPACE correspond à un espace de travail réel et que votre compte dispose des droits de lecture. Vérifiez le contenu de la table avec KQL dans le portail Defender pour confirmer que les données sont présentes. Pour plus d’informations, consultez Exécuter des requêtes KQL sur le lac de données Microsoft Sentinel.

Créer le graphe personnalisé

Rédigez de l’une de ces façons :

  • Création de graphiques assistées par l’IA.
  • Créer manuellement

Création de graphiques assistées par l’IA

Pour créer un graphique avec l’aide de l’IA, procédez comme suit :

  1. Dans Visual Studio Code, ouvrez GitHub Copilot Chat.

  2. Commencez votre requête avec l’outil d’aide à la création de graphiques @sentinel /graph-authoring et décrivez votre graphique en langage naturel :

    @sentinel /graph-authoring Create a graph that maps Entra groups to
    their member users, groups, and service principals using EntraGroups,
    EntraUsers, EntraServicePrincipals, and EntraMembers from the
    "System tables" workspace.
    

    Capture d’écran montrant la création de graphiques assistées par IA dans VS Code.

    Copilot génère les cellules suivantes pour le cycle de vie de création de graphe :

    Phase du cycle de vie Sortie générée
    Configuration de l’environnement Vérifie les packages requis et les informations de connexion
    Chargement des données Lit les tables nommées dans le lac de données Sentinel
    Transformation des données Prépare les données de nœud et de périphérie
    Schéma de graphe Définit les nœuds et les arêtes
    Validation du schéma Valide la définition du graphique
    Génération de graphe Matérialise le graphique pour la session
    Requête de graphe Exécute un exemple de requête GQL et visualise le résultat
  3. Continuez à affiner le carnet avec des instructions comme celles-ci :

    Objectif Prompt
    Ajouter une relation @sentinel Add an edge from User to IPAddress
    Filtrer les données @sentinel Filter the data to show only failed sign-ins
    Modifier l’intervalle de temps @sentinel Change the time range to the last 7 days
    Corriger l’erreur de compilation @sentinel Fix the error in the graph build step
    Comprendre le code @sentinel Explain how edge keys are defined
    Rechercher une API sans modification What parameters does build_graph_with_data() accept? #Sentinel

Tip

Permet @sentinel /graph-authoring de créer ou de modifier des cellules de bloc-notes. Si vous avez besoin d’explications sur les API ou d’exemples de requêtes, demandez à Copilot et incluez #Sentinel pour obtenir des réponses spécifiques à Sentinel.

Créer manuellement

Pour créer un graphique manuellement, procédez comme suit :

  1. Connectez et lisez les tables de ressources.

    from pyspark.sql import functions as F
    from sentinel_lake.providers import MicrosoftSentinelProvider
    lake_provider = MicrosoftSentinelProvider(spark=spark)
    # Entra asset tables live in the "System tables" workspace.
    # If your data is elsewhere, update this and ensure the tables exist.
    LOG_ANALYTICS_WORKSPACE = "System tables"
    # Use the latest snapshot of EntraUsers as the point-in-time for all tables.
    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"))
    # 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"))
        )
    )
    # Nodes
    df_groups = (
        lake_provider.read_table("EntraGroups", LOG_ANALYTICS_WORKSPACE)
        .filter(snapshot_filter)
        .select("id", "displayName", "mailEnabled")
    )
    df_users = (
        lake_provider.read_table("EntraUsers", LOG_ANALYTICS_WORKSPACE)
        .filter(snapshot_filter)
        .select("id", "accountEnabled", "displayName", "department",
                "userPrincipalName", "usageLocation")
    )
    
  2. Préparez des dataFrames de nœud et de périphérie.

    # NODES
    user_nodes = df_users.df.select(
        "id", "displayName", "accountEnabled", "department",
        "userPrincipalName", "usageLocation")
    group_nodes = df_groups.df.select("id", "displayName", "mailEnabled")
    # EDGES
    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_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")))
    )
    
  3. Définissez le schéma de graphe et liez des DataFrames.

    from sentinel_graph import GraphSpecBuilder, Graph
    entra_group_graph_spec = (
        GraphSpecBuilder.start()
        # === NODES ===
        .add_node("EntraUser").from_dataframe(user_nodes)
        .with_columns("id", "displayName", "accountEnabled", "department",
                      "userPrincipalName", "usageLocation",
                      key="id", display="displayName")
        .add_node("EntraGroup").from_dataframe(group_nodes)
        .with_columns("id", "displayName", "mailEnabled",
                      key="id", display="displayName")
        # === EDGES ===
        .add_edge("ContainsUser").from_dataframe(edge_group_contains_user)
        .source(id_column="SourceGroupId", node_type="EntraGroup")
        .target(id_column="TargetUserId", node_type="EntraUser")
        .with_columns("SourceGroupId", "TargetUserId", "EdgeKey",
                      key="EdgeKey", display="EdgeKey")
        .add_edge("ContainsGroup").from_dataframe(edge_group_contains_group)
        .source(id_column="SourceGroupId", node_type="EntraGroup")
        .target(id_column="TargetGroupId", node_type="EntraGroup")
        .with_columns("SourceGroupId", "TargetGroupId", "EdgeKey",
                      key="EdgeKey", display="EdgeKey")
    ).done()
    # Validate the schema before building.
    entra_group_graph_spec.show_schema()
    
  4. Générez le graphique.

    # Build = prepare data + publish for the session.
    entra_group_graph = Graph.build(entra_group_graph_spec)
    print(entra_group_graph.build_status.status)   # "published" or "prepared"
    

    Note

    Graph.build() prépare les données et les publie en un seul appel. Pour examiner les nœuds et les arêtes préparés avant la publication, appelez Graph.prepare(spec), examinez graph.nodes et graph.edges, puis appelez graph.publish().

  5. Exécutez une requête GQL.

    # Find nested group relationships 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 * 
    """ 
    entra_group_graph.query(query_nested_groups).show()
    

Tester le notebook de graphique

Testez le notebook pour vous assurer qu’il produit la sortie de graphique attendue :

  1. Redémarrez le noyau et exécutez toutes les cellules en haut en bas. Capture d’écran montrant le bouton redémarrer le noyau.

  2. Vérifiez que chaque cellule s’exécute avec succès.

  3. Si l'exécution des cellules de transformation prend plus de 5 minutes sur un petit pool, réduisez les filtres d'instantané et le nombre de colonnes projetées avant de passer à une plus grande échelle.

  4. Vérifiez que show_schema() renvoie les nœuds et les arêtes attendus.

  5. Exécutez un exemple de requête GQL et vérifiez la visualisation et la sortie tabulaire.

  6. Valider les cas limites :

    • Entrée vide.
    • Dérive du schéma.
    • Accès à la table manquant.

Tip

Ajoutez des cellules markdown au-dessus de chaque section de code pour documenter l’objectif, les entrées, les sorties et les nœuds ou les arêtes produits.

Planifier une tâche de graphe pour matérialiser le graphe

Les graphiques créés dans une session interactive sont éphémères. Planifiez un travail de graphique pour conserver et actualiser le graphique. Pour plus d’informations, consultez Planification et gestion des travaux de graphe Microsoft Sentinel.

  1. Dans votre carnet de graphiques, sélectionnez Créer une tâche planifiée>Créer une tâche de graphe. Capture d’écran montrant le bouton Créer un travail de graphe.

  2. Entrez le nom et la description du graphique, puis vérifiez le chemin du bloc-notes.

  3. Sélectionnez une planification :

    • À la demande : génère une fois, avec une rétention par défaut de 30 jours.
    • Planifié : sélectionnez la cadence de répétition et les heures de début/de fin.
  4. Cliquez sur Envoyer.

  5. Ouvrez le graphique dans l’extension Sentinel et surveillez les détails du travail.

  6. Utilisez Run Now pour exécuter en dehors de la planification si nécessaire.

  7. Confirmer la progression de l’état de Queued jusqu’à In ProgressReady.

Important

Les travaux envoyés sont découplés de votre bloc-notes local. La modification du local .ipynb ne met pas à jour la tâche planifiée. Pour mettre à jour un bloc-notes de travail, téléchargez-le à partir du panneau Graphs, modifiez-le, puis utilisez Modifier la tâche>Envoyer.

Interroger et visualiser à partir de l’Explorateur Graph

Une fois que l'état du travail de graphique est Ready, interrogez et visualisez les données dans le portail Defender, les notebooks et les API REST.

  1. Dans le portail Defender, sous Microsoft Sentinel, ouvrez l’expérience Graph et sélectionnez votre graphe matérialisé.
  2. Exécutez des requêtes GQL, inspectez le schéma, changez de sorties visuelles et tabulaires, puis parcourez le tronçon suivant.
  3. Utilisez cette référence rapide GQL :
Motif ou clause Exemple :
Nœud avec étiquette (g:EntraGroup)
Arête orientée et typée -[c:ContainsUser]->
Chemin de longueur variable (1 à 8 sauts) (a)-[e]->{1,8}(b)
Filter WHERE g.displayName = 'Finance Admins'
Projeter, trier, limiter RETURN g.displayName ORDER BY g.displayName LIMIT 10
Expressions d’étiquette (:EntraUser \| EntraServicePrincipal)

Note

Chaque requête GQL commence par MATCH. Le moteur fonctionne au format UTC. Utiliser ZONED_DATETIME(...) pour les littéraux de date et d’heure. INSERT et CREATE ne sont pas pris en charge. Les graphiques sont en lecture seule.

  1. Exécuter une requête depuis un bloc-notes.

    from sentinel_graph import Graph
    # Attach to an already-materialized graph by name.
    graph = Graph.get("entra_group_membership")
    graph.query("MATCH (g:EntraGroup)-[c:ContainsUser]->(u:EntraUser) RETURN g, c, u").show()
    # Purpose-built security algorithms are available too:
    graph.blast_radius(source_property_value="Finance Admins", min_hop_count=1).show()
    
  2. Interroger à l’aide d’API REST Graph.

    GET https://api.securityplatform.microsoft.com/graphs/graph-instances?graphTypes=Custom
    Authorization: Bearer <access_token>
    
    POST https://api.securityplatform.microsoft.com/graphs/graph-instances/{graphName}/query
    Authorization: Bearer <access_token>
    Content-Type: application/json
    {
      "query": "MATCH (g:EntraGroup)-[c:ContainsUser]->(u) RETURN g, c, u LIMIT 100",
      "responseFormats": ["Table", "Graph"],
      "queryLanguage": "GQL"
    }
    

responseFormats contrôle la forme de sortie. "Table" retourne des lignes, "Graph" retourne des nœuds et des arêtes, et ["Table", "Graph"] retourne les deux.

Pour plus d’informations, consultez les API REST Graph pour les graphiques personnalisés.

Empaqueter et publier votre solution de graphe

Une fois que votre graphe est testé et matérialisé, empaquetez-le pour le déploiement auprès des clients. Pour obtenir des instructions détaillées sur l’empaquetage, consultez Empaqueter et publier des solutions de graphiques et de notebooks Microsoft Sentinel.

Résolution des problèmes

Utilisez les tableaux suivants pour diagnostiquer les problèmes courants par symptôme.

Création de graphiques

Symptôme Cause et correction probables
MicrosoftSentinelProvider ou sentinel_graph introuvable Reconnectez-vous à l’extension et vérifiez qu’un noyau Microsoft Sentinel est sélectionné.
La cellule reste bloquée sur « Démarrage de la session Spark » Le premier démarrage peut prendre 3 à 5 minutes. S’il dépasse 6 minutes, vérifiez la capacité du pool et réessayez.
show_schema() est vide ou Graph.build() échoue Vérifiez que les colonnes clés et d’affichage existent et qu’elles ne sont pas null, et que les valeurs source et cible node_type correspondent aux alias de nœud.
La requête GQL ne retourne aucune ligne Vérifiez que les valeurs de filtre existent dans l’instantané sélectionné et vérifiez le filtrage des instantanés.
publish() échoue avec une erreur « Autorisation refusée » Vérifiez que vous disposez d’un rôle d’opérateur de sécurité, d’administrateur de sécurité ou d’administrateur général.

Création assistée par IA

Symptôme Cause et correction probables
@sentinel /graph-authoring ne fait rien Vérifiez que GitHub Copilot et les extensions Jupyter sont installées et actives, et que vous disposez d’un plan d’entreprise ou d’entreprise Copilot.
Le code généré fait référence à une table manquante Vérifiez la configuration du connecteur et vérifiez que la table s’affiche dans data lake Explorer.

Planification de tâche

Symptôme Cause et correction probables
Les modifications de bloc-notes locales ne sont pas reflétées dans le travail Téléchargez le bloc-notes de travail à partir du panneau Graphs, modifiez-le, puis utilisez Modifier la tâche>Envoyer.
Le graphe matérialisé a disparu Les graphiques à la demande ont une rétention de 30 jours. Planifiez une tâche récurrente ou lancez une nouvelle compilation.