Partager via


Utilisez un principal de service avec le connecteur Spark 3 pour Azure Cosmos DB for NoSQL

Cet article explique comment créer une application et un principal de service Microsoft Entra pouvant être utilisés avec le contrôle d’accès en fonction du rôle. Vous pouvez ensuite utiliser ce principal de service pour vous connecter à un compte Azure Cosmos DB for NoSQL à partir de Spark 3.

Prérequis

Créer une clé secrète et enregistrer des informations d’identification

Dans cette section, vous pouvez créer une clé secrète client et enregistrer la valeur à utiliser ultérieurement.

  1. Ouvrez le portail Azure.

  2. Rendez-vous sur votre application Microsoft Entra existante.

  3. Rendez-vous sur la page Certificats et clés secrètes. Ensuite, créez un secret. Enregistrez la valeur de clé secrète client à utiliser plus loin dans cet article.

  4. Allez à la page Vue d’ensemble. Recherchez et enregistrez les valeurs de l’ID d’application (client), de l’ID d’objet et de l’ID de répertoire (locataire). Vous utilisez également ces valeurs plus loin dans cet article.

  5. Rendez-vous sur votre compte Azure Cosmos DB for NoSQL existant.

  6. Enregistrez la valeur d’URI sur la page Vue d’ensemble. Enregistrez également les valeurs d’ID d’abonnement et de Groupe de ressources. Vous utilisez ces valeurs plus tard dans cet article.

Créer une définition et une affectation

Dans cette section, vous créerez une définition de rôle Microsoft Entra ID. Ensuite, vous attribuerez ce rôle avec des autorisations pour lire et écrire des éléments dans les conteneurs.

  1. Créez un rôle en utilisant la commande az role definition create. Transmettez le nom et le groupe de ressources du compte Azure Cosmos DB for NoSQL, suivis d’un corps de JSON qui définit le rôle personnalisé. Le rôle est également étendu au niveau du compte en utilisant /. Vérifiez que vous fournissez un nom unique pour votre rôle en utilisant la RoleNamepropriété du corps de la demande.

    az cosmosdb sql role definition create \
        --resource-group "<resource-group-name>" \
        --account-name "<account-name>" \
        --body '{
            "RoleName": "<role-definition-name>",
            "Type": "CustomRole",
            "AssignableScopes": ["/"],
            "Permissions": [{
                "DataActions": [
                    "Microsoft.DocumentDB/databaseAccounts/readMetadata",
                    "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*",
                    "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*"
                ]
            }]
        }'
    
  2. Répertoriez la définition de rôle que vous avez créée pour récupérer son identificateur unique dans la sortie JSON. Enregistrez la valeur id de la sortie JSON.

    az cosmosdb sql role definition list \
        --resource-group "<resource-group-name>" \
        --account-name "<account-name>"
    
    [
      {
        ...,
        "id": "/subscriptions/<subscription-id>/resourceGroups/<resource-grou-name>/providers/Microsoft.DocumentDB/databaseAccounts/<account-name>/sqlRoleDefinitions/<role-definition-id>",
        ...
        "permissions": [
          {
            "dataActions": [
              "Microsoft.DocumentDB/databaseAccounts/readMetadata",
              "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*",
              "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*"
            ],
            "notDataActions": []
          }
        ],
        ...
      }
    ]
    
  3. Utilisez az cosmosdb sql role assignment create pour créer une attribution de rôle. Remplacez <aad-principal-id> par l’ID d’objet que vous avez enregistré précédemment dans cet article. Remplacez également <role-definition-id> par la valeur id extraite de l’exécution de la commande az cosmosdb sql role definition list à l’étape précédente.

    az cosmosdb sql role assignment create \
        --resource-group "<resource-group-name>" \
        --account-name "<account-name>" \
        --scope "/" \
        --principal-id "<account-name>" \
        --role-definition-id "<role-definition-id>"
    

Utiliser un principal de service

Maintenant que vous avez créé une application et un principal de service Microsoft Entra, généré un rôle personnalisé et attribué ces autorisations de rôle à votre compte Azure Cosmos DB for NoSQL, vous devriez être en mesure d’exécuter un notebook.

  1. Ouvrez votre espace de travail Azure Databricks.

  2. Dans l’interface de l’espace de travail, créez un cluster. Configurez le cluster avec ces paramètres, au minimum :

    Version Valeur
    Version du runtime 13.3 LTS (Scala 2.12, Spark 3.4.1)
  3. Utilisez l’interface de l’espace de travail pour rechercher les packages Maven à partir de Maven Central avec l’ID de groupe com.azure.cosmos.spark. Installez sur le cluster le package prévu spécifiquement pour Spark 3.4 dont l’ID d’artefact est précédé du préfixe azure-cosmos-spark_3-4.

  4. Pour finir, créez un notebook.

    Conseil

    Par défaut, le notebook est attaché au cluster récemment créé.

  5. Dans le notebook, définissez les paramètres de configuration du connecteur Spark Azure Cosmos DB pour le point de terminaison de compte NoSQL, le nom de la base de données et le nom du conteneur. Utilisez l’ID d’abonnement, le Groupe de ressources, l’ID d’application (client), l’ID de répertoire (locataire) et les valeurs de clé secrète client enregistrées précédemment dans cet article.

    # Set configuration settings
    config = {
      "spark.cosmos.accountEndpoint": "<nosql-account-endpoint>",
      "spark.cosmos.auth.type": "ServicePrincipal",
      "spark.cosmos.account.subscriptionId": "<subscription-id>",
      "spark.cosmos.account.resourceGroupName": "<resource-group-name>",
      "spark.cosmos.account.tenantId": "<entra-tenant-id>",
      "spark.cosmos.auth.aad.clientId": "<entra-app-client-id>",
      "spark.cosmos.auth.aad.clientSecret": "<entra-app-client-secret>",
      "spark.cosmos.database": "<database-name>",
      "spark.cosmos.container": "<container-name>"        
    }    
    
    // Set configuration settings
    val config = Map(
      "spark.cosmos.accountEndpoint" -> "<nosql-account-endpoint>",
      "spark.cosmos.auth.type" -> "ServicePrincipal",
      "spark.cosmos.account.subscriptionId" -> "<subscription-id>",
      "spark.cosmos.account.resourceGroupName" -> "<resource-group-name>",
      "spark.cosmos.account.tenantId" -> "<entra-tenant-id>",
      "spark.cosmos.auth.aad.clientId" -> "<entra-app-client-id>",
      "spark.cosmos.auth.aad.clientSecret" -> "<entra-app-client-secret>",
      "spark.cosmos.database" -> "<database-name>",
      "spark.cosmos.container" -> "<container-name>" 
    )
    
  6. Configurez l’API Catalogue afin de gérer les ressources d’API pour NoSQL en utilisant Spark.

    # Configure Catalog Api
    spark.conf.set("spark.sql.catalog.cosmosCatalog", "com.azure.cosmos.spark.CosmosCatalog")
    spark.conf.set("spark.sql.catalog.cosmosCatalog.spark.cosmos.accountEndpoint", "<nosql-account-endpoint>")
    spark.conf.set("spark.sql.catalog.cosmosCatalog.spark.cosmos.auth.type", "ServicePrincipal")
    spark.conf.set("spark.sql.catalog.cosmosCatalog.spark.cosmos.account.subscriptionId", "<subscription-id>")
    spark.conf.set("spark.sql.catalog.cosmosCatalog.spark.cosmos.account.resourceGroupName", "<resource-group-name>")
    spark.conf.set("spark.sql.catalog.cosmosCatalog.spark.cosmos.account.tenantId", "<entra-tenant-id>")
    spark.conf.set("spark.sql.catalog.cosmosCatalog.spark.cosmos.auth.aad.clientId", "<entra-app-client-id>")
    spark.conf.set("spark.sql.catalog.cosmosCatalog.spark.cosmos.auth.aad.clientSecret", "<entra-app-client-secret>")
    
    // Configure Catalog Api
    spark.conf.set(s"spark.sql.catalog.cosmosCatalog", "com.azure.cosmos.spark.CosmosCatalog")
    spark.conf.set(s"spark.sql.catalog.cosmosCatalog.spark.cosmos.accountEndpoint", "<nosql-account-endpoint>")
    spark.conf.set(s"spark.sql.catalog.cosmosCatalog.spark.cosmos.auth.type", "ServicePrincipal")
    spark.conf.set(s"spark.sql.catalog.cosmosCatalog.spark.cosmos.account.subscriptionId", "<subscription-id>")
    spark.conf.set(s"spark.sql.catalog.cosmosCatalog.spark.cosmos.account.resourceGroupName", "<resource-group-name>")
    spark.conf.set(s"spark.sql.catalog.cosmosCatalog.spark.cosmos.account.tenantId", "<entra-tenant-id>")
    spark.conf.set(s"spark.sql.catalog.cosmosCatalog.spark.cosmos.auth.aad.clientId", "<entra-app-client-id>")
    spark.conf.set(s"spark.sql.catalog.cosmosCatalog.spark.cosmos.auth.aad.clientSecret", "<entra-app-client-secret>")
    
  7. Créez une base de données à l’aide de CREATE DATABASE IF NOT EXISTS. Vérifiez que vous fournissez le nom de votre base de données.

    # Create a database using the Catalog API
    spark.sql("CREATE DATABASE IF NOT EXISTS cosmosCatalog.{};".format("<database-name>"))
    
    // Create a database using the Catalog API
    spark.sql(s"CREATE DATABASE IF NOT EXISTS cosmosCatalog.<database-name>;")
    
  8. Créez un conteneur à l’aide du nom de la base de données, du nom du conteneur, du chemin d’accès à la clé de partition et des valeurs de débit que vous spécifiez.

    # Create a products container using the Catalog API
    spark.sql("CREATE TABLE IF NOT EXISTS cosmosCatalog.{}.{} USING cosmos.oltp TBLPROPERTIES(partitionKeyPath = '{}', manualThroughput = '{}')".format("<database-name>", "<container-name>", "<partition-key-path>", "<throughput>"))
    
    // Create a products container using the Catalog API
    spark.sql(s"CREATE TABLE IF NOT EXISTS cosmosCatalog.<database-name>.<container-name> using cosmos.oltp TBLPROPERTIES(partitionKeyPath = '<partition-key-path>', manualThroughput = '<throughput>')")
    
  9. Créer un exemple de jeu de données.

    # Create sample data    
    products = (
      ("68719518391", "gear-surf-surfboards", "Yamba Surfboard", 12, 850.00, False),
      ("68719518371", "gear-surf-surfboards", "Kiama Classic Surfboard", 25, 790.00, True)
    )
    
    // Create sample data
    val products = Seq(
      ("68719518391", "gear-surf-surfboards", "Yamba Surfboard", 12, 850.00, false),
      ("68719518371", "gear-surf-surfboards", "Kiama Classic Surfboard", 25, 790.00, true)
    )
    
  10. Utilisez spark.createDataFrame et la configuration de traitements transactionnels en ligne (OLTP) précédemment enregistrée pour ajouter des exemples de données au conteneur cible.

    # Ingest sample data    
    spark.createDataFrame(products) \
      .toDF("id", "category", "name", "quantity", "price", "clearance") \
      .write \
      .format("cosmos.oltp") \
      .options(config) \
      .mode("APPEND") \
      .save()
    
    // Ingest sample data
    spark.createDataFrame(products)
      .toDF("id", "category", "name", "quantity", "price", "clearance")
      .write
      .format("cosmos.oltp")
      .options(config)
      .mode("APPEND")
      .save()
    

    Conseil

    Dans cet exemple de démarrage rapide, les informations d’identification sont affectées à des variables en texte clair. Pour des raisons de sécurité, nous vous recommandons d’utiliser des clés secrètes. Pour plus d’informations sur la manière de configurer des clés secrètes, consultez Ajouter des secrets à votre configuration Spark.