Compartir a través de


Uso de una entidad de servicio con el conector Spark 3 para Azure Cosmos DB for NoSQL

En este artículo, aprenderá a crear una aplicación de Microsoft Entra y una entidad de servicio que se puede usar con el control de acceso basado en rol. Después, puede usar esta entidad de servicio para conectarse a una cuenta de Azure Cosmos DB for NoSQL desde Spark 3.

Requisitos previos

Crear un secreto y registrar credenciales

En esta sección, crearemos un secreto de cliente y registraremos el valor para usarlo más adelante.

  1. Abra Azure Portal.

  2. Vaya a la aplicación Microsoft Entra existente.

  3. Ve a la página Certificados y secretos. Después, cree un secreto. Guarde el secreto de cliente para usarlo más adelante en esta guía.

  4. Vaya a la página Información general. Busque y registre los valores de Id. de aplicación (cliente), Id. de objeto e Id. de directorio (inquilino). También usarás estos valores más adelante en este artículo.

  5. Diríjase a su cuenta existente de Azure Cosmos DB for NoSQL.

  6. Registre el valor del URI en la página Información general. Registre también los valores de Id. de suscripción y Grupo de recursos. Usted utilizará estos valores más adelante en este artículo.

Creación de una definición y una asignación

En esta sección, creas una definición de rol de Microsoft Entra ID. A continuación, asigne ese rol con permisos para leer y escribir elementos en los contenedores.

  1. Cree un rol utilizando el comando az role definition create. Pase el nombre de la cuenta y el grupo de recursos de Azure Cosmos DB for NoSQL, seguido de un cuerpo de JSON que defina el rol personalizado. El rol también tiene como ámbito el nivel de cuenta mediante /. Asegúrese de asignar un nombre único a su rol utilizando la propiedad RoleName del cuerpo de la solicitud.

    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. Enumere la definición de rol que creó para capturar su identificador único en la salida JSON. Registre el valor id de la salida 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. Use az cosmosdb sql role assignment create para crear una asignación de roles. Reemplace <aad-principal-id> por el ID de objeto que registró anteriormente en este artículo. Además, reemplace <role-definition-id> por el valor id capturado al ejecutar el comando az cosmosdb sql role definition list que ejecutó en un paso anterior.

    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>"
    

Uso de una entidad de servicio

Ahora que ha creado una aplicación de Microsoft Entra y una entidad de servicio, ha creado un rol personalizado y ha asignado los permisos de ese rol a su cuenta de Azure Cosmos DB for NoSQL, debería ser capaz de ejecutar un cuaderno.

  1. Abra el área de trabajo de Azure Databricks.

  2. En la interfaz del área de trabajo, cree un nuevo clúster. Configure el clúster con estas opciones, como mínimo:

    Versión Value
    Versión del entorno de ejecución 13.3 LTS (Scala 2.12, Spark 3.4.1)
  3. Utilice la interfaz del área de trabajo para buscar paquetes de Maven desde Maven Central con un ID de grupo de com.azure.cosmos.spark. Instale el paquete específicamente para Spark 3.4 con unId.de Artefacto prefijo con azure-cosmos-spark_3-4 en el clúster.

  4. Por último, cree un nuevo cuaderno.

    Sugerencia

    De manera predeterminada, el cuaderno está asociado al clúster creado recientemente.

  5. Dentro del cuaderno, establezca los ajustes de configuración del conector Spark de Azure Cosmos DB para el punto final de la cuenta NoSQL, el nombre de la base de datos y el nombre del contenedor. Use los valores Id.de suscripción, Grupo de recursos, Id. de aplicación (cliente), Id.de directorio (inquilino) y Secreto de cliente registrados anteriormente en esta guía.

    # 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. Configure la API de catálogo para administrar la API para recursos NoSQL mediante 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. Cree una nueva base de datos mediante CREATE DATABASE IF NOT EXISTS. Asegúrese de proporcionar el nombre de la base de datos.

    # 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. Cree un nuevo contenedor mediante el nombre de la base de datos, el nombre del contenedor, la ruta de acceso de clave de partición y los valores de rendimiento que especifique.

    # 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. Cree un conjunto de datos de ejemplo.

    # 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. Use spark.createDataFrame y la configuración de procesamiento de transacciones en línea (OLTP) guardadas anteriormente para agregar datos de ejemplo al contenedor de destino.

    # 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()
    

    Sugerencia

    En este ejemplo de inicio rápido, las credenciales se asignan a variables en texto no cifrado. Por motivos de seguridad, se recomienda usar secretos. Para más información sobre cómo configurar secretos, consulte Adición de secretos a la configuración de Spark.