Usare le identità gestite assegnate dal sistema per accedere ai dati di Azure Cosmos DB

SI APPLICA A: NoSQL

In questo articolo si configurerà una soluzione affidabile e indipendente dalla rotazione delle chiavi per accedere alle chiavi di Azure Cosmos DB usando le identità gestite e il controllo degli accessi in base al ruolo del piano dati. L'esempio in questo articolo usa Funzioni di Azure, ma è possibile usare qualsiasi servizio che supporti le identità gestite.

Si apprenderà come creare un'app per le funzioni in grado di accedere ai dati di Azure Cosmos DB senza dover copiare chiavi di Azure Cosmos DB. L'app per le funzioni viene attivata quando viene effettuata una richiesta HTTP e quindi vengono elencati tutti i database esistenti.

Prerequisiti

  • Un account Azure con una sottoscrizione attiva. Creare un account gratuitamente.

  • Un'API di Azure Cosmos DB per l'account NoSQL. Creare un'API di Azure Cosmos DB per l'account NoSQL

  • Un'app per le funzioni di Funzioni di Azure esistente. Creare la prima funzione nel portale di Azure

  • Azure Functions Core Tools

  • Per eseguire i passaggi illustrati in questo articolo, installare l'interfaccia della riga di comando di Azure e accedere ad Azure.

    Controllo dei prerequisiti

    1. In un terminale o in una finestra di comando archiviare i nomi dell'app per le funzioni di Funzioni di Azure, dell'account Azure Cosmos DB e del gruppo di risorse come variabili della shell denominate functionName, cosmosName e resourceGroupName.

      # Variable for function app name
      functionName="msdocs-function-app"
      
      # Variable for Azure Cosmos DB account name
      cosmosName="msdocs-cosmos-app"
      
      # Variable for resource group name
      resourceGroupName="msdocs-cosmos-functions-dotnet-identity"
      

      Nota

      Queste variabili vengono riutilizzate nei passaggi successivi. Questo esempio presuppone che il nome dell'account Azure Cosmos DB sia msdocs-cosmos-app, il nome dell'app per le funzioni sia msdocs-function-app e il nome del gruppo di risorse sia msdocs-cosmos-functions-dotnet-identity.

    2. Visualizzare le proprietà dell'app per le funzioni usando il comando az functionapp show.

      az functionapp show \
          --resource-group $resourceGroupName \
          --name $functionName
      
    3. Visualizzare le proprietà dell'identità gestita assegnata dal sistema per l'app per le funzioni usando az webapp identity show.

      az webapp identity show \
          --resource-group $resourceGroupName \
          --name $functionName
      
    4. Visualizzare le proprietà dell'account Azure Cosmos DB usando az cosmosdb show.

      az cosmosdb show \
          --resource-group $resourceGroupName \
          --name $cosmosName
      

Creare un'API di Azure Cosmos DB per database NoSQL

In questo passaggio vengono creati due database.

  1. In un terminale o in una finestra di comando creare un nuovo database products usando az cosmosdb sql database create.

    az cosmosdb sql database create \
        --resource-group $resourceGroupName \
        --name products \
        --account-name $cosmosName
    
  2. Creare un nuovo database customers.

    az cosmosdb sql database create \
        --resource-group $resourceGroupName \
        --name customers \
        --account-name $cosmosName
    

Ottenere l'API di Azure Cosmos DB per l'endpoint NoSQL

In questo passaggio si esegue una query sull'endpoint del documento per l'account API per NoSQL.

  1. Usare az cosmosdb show con il parametro di query impostato su documentEndpoint. Registrare il risultato. Questo valore verrà usato in un passaggio successivo.

    az cosmosdb show \
        --resource-group $resourceGroupName \
        --name $cosmosName \
        --query documentEndpoint
    
    cosmosEndpoint=$(
        az cosmosdb show \
            --resource-group $resourceGroupName \
            --name $cosmosName \
            --query documentEndpoint \
            --output tsv
    )
    
    echo $cosmosEndpoint
    

    Nota

    Questa variabile viene riutilizzata in un passaggio successivo.

Concedere l'accesso all'account Azure Cosmos DB

In questo passaggio si assegna un ruolo all'identità gestita assegnata dal sistema dell'app per le funzioni. Azure Cosmos DB include più ruoli predefiniti che è possibile assegnare all'identità gestita per l'accesso al piano di controllo. Per l'accesso al piano dati, si crea un nuovo ruolo personalizzato con accesso ai metadati di lettura.

Suggerimento

Per altre informazioni sull'importanza dell'accesso con privilegi minimi, vedere l'articolo Ridurre l'esposizione degli account con privilegi.

  1. Usare az cosmosdb show con il parametro di query impostato su id. Archiviare il risultato in una variabile della shell denominata scope.

    scope=$(
        az cosmosdb show \
            --resource-group $resourceGroupName \
            --name $cosmosName \
            --query id \
            --output tsv
    )
    
    echo $scope
    

    Nota

    Questa variabile viene riutilizzata in un passaggio successivo.

  2. Usare az webapp identity show con il parametro di query impostato su principalId. Archiviare il risultato in una variabile della shell denominata principal.

    principal=$(
        az webapp identity show \
            --resource-group $resourceGroupName \
            --name $functionName \
            --query principalId \
            --output tsv
    )
    
    echo $principal
    
  3. Creare un nuovo file JSON con la configurazione del nuovo ruolo personalizzato.

    {
        "RoleName": "Read Azure Cosmos DB Metadata",
        "Type": "CustomRole",
        "AssignableScopes": ["/"],
        "Permissions": [{
            "DataActions": [
                "Microsoft.DocumentDB/databaseAccounts/readMetadata"
            ]
        }]
    }
    

    Suggerimento

    È possibile creare un file in Azure Cloud Shell usando touch <filename> o l'editor predefinito (code .). Per altre informazioni, vedere Editor di Azure Cloud Shell

  4. Usare az cosmosdb sql role definition create per creare una nuova definizione di ruolo denominata Read Azure Cosmos DB Metadata usando l'oggetto JSON personalizzato.

    az cosmosdb sql role definition create \
        --resource-group $resourceGroupName \
        --account-name $cosmosName \
        --body @definition.json
    

    Nota

    In questo esempio la definizione del ruolo viene definita in un file denominato definition.json.

  5. Usare az role assignment create per assegnare il ruolo Read Azure Cosmos DB Metadata all'identità gestita assegnata dal sistema.

    az cosmosdb sql role assignment create \
        --resource-group $resourceGroupName \
        --account-name $cosmosName \
        --role-definition-name "Read Azure Cosmos DB Metadata" \
        --principal-id $principal \
        --scope $scope
    

Accedere alle chiavi di Azure Cosmos DB a livello di codice

È ora disponibile un'app per le funzioni con un'identità gestita assegnata dal sistema con il ruolo personalizzato. L'app per le funzioni seguente eseguirà una query sull'account Azure Cosmos DB per un elenco di database.

  1. Creare un progetto di funzione locale con il parametro --dotnet in una cartella denominata csmsfunc. Modificare la directory della shell

    func init csmsfunc --dotnet
    
    cd csmsfunc
    
  2. Creare una nuova funzione con il parametro modello impostato su httptrigger e il nome impostato su readdatabases.

    func new --template httptrigger --name readdatabases
    
  3. Aggiungere i pacchetti NuGet Azure.Identity e Microsoft.Azure.Cosmos al progetto .NET. Compilare il progetto tramite dotnet build.

    dotnet add package Azure.Identity
    
    dotnet add package Microsoft.Azure.Cosmos
    
    dotnet build
    
  4. Aprire il codice della funzione in un ambiente di sviluppo integrato (IDE).

    Suggerimento

    Se si usa l'interfaccia della riga di comando di Azure in locale o in Azure Cloud Shell, è possibile aprire Visual Studio Code.

    code .
    
  5. Sostituire il codice nel file readdatabases.cs con questa implementazione della funzione di esempio. Salvare il file aggiornato.

    using System;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    using Azure.Identity;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Azure.Cosmos;
    using Microsoft.Azure.WebJobs;
    using Microsoft.Azure.WebJobs.Extensions.Http;
    using Microsoft.AspNetCore.Http;
    using Microsoft.Extensions.Logging;
    
    namespace csmsfunc
    {
        public static class readdatabases
        {
            [FunctionName("readdatabases")]
            public static async Task<IActionResult> Run(
                [HttpTrigger(AuthorizationLevel.Anonymous, "get")] HttpRequest req,
                ILogger log)
            {
                log.LogTrace("Start function");
    
                CosmosClient client = new CosmosClient(
                    accountEndpoint: Environment.GetEnvironmentVariable("COSMOS_ENDPOINT", EnvironmentVariableTarget.Process),
                    new DefaultAzureCredential()
                );
    
                using FeedIterator<DatabaseProperties> iterator = client.GetDatabaseQueryIterator<DatabaseProperties>();
    
                List<(string name, string uri)> databases = new();
                while(iterator.HasMoreResults)
                {
                    foreach(DatabaseProperties database in await iterator.ReadNextAsync())
                    {
                        log.LogTrace($"[Database Found]\t{database.Id}");
                        databases.Add((database.Id, database.SelfLink));
                    }
                }
    
                return new OkObjectResult(databases);
            }
        }
    }
    

(Facoltativo) Eseguire la funzione in locale

In un ambiente locale, la classe DefaultAzureCredential usa varie credenziali locali per determinare l'identità corrente. Anche se l'esecuzione in locale non è necessaria per le procedure, è possibile sviluppare localmente usando la propria identità o un'entità servizio.

  1. Ottenere l'identificatore dell'entità di sicurezza dell'account locale usando az ad signed-in-user show.

    az ad signed-in-user show --query "id"
    
  2. Assegnare l'accesso al controllo degli accessi in base al ruolo dell'account locale all'account Azure Cosmos DB usando il comando az cosmosdb sql role assignment create. Usare il ruolo predefinito "Collaboratore dati Cosmos DB" con un ID di 00000000-0000-0000-0000-000000000002.

    az cosmosdb sql role assignment create \
        --resource-group $resourceGroupName \
        --account-name $cosmosName \
        --role-definition-id "00000000-0000-0000-0000-000000000002" \
        --principal-id "<your-principal-id>" \
        --scope "/"
    
  3. Nel file local.settings.json aggiungere una nuova impostazione denominata COSMOS_ENDPOINT nell'oggetto Valori. Il valore dell'impostazione deve essere l'endpoint del documento registrato in precedenza in questa guida pratica.

    ...
    "Values": {
        ...
        "COSMOS_ENDPOINT": "https://msdocs-cosmos-app.documents.azure.com:443/",
        ...
    }
    ...
    

    Nota

    Questo oggetto JSON è stato abbreviato per semplicità. Questo oggetto JSON include anche un valore di esempio che presuppone che il nome dell'account sia msdocs-cosmos-app.

  4. Eseguire l'app per le funzioni

    func start
    

Distribuire in Azure

Dopo la pubblicazione, la classe DefaultAzureCredential usa le credenziali dell'ambiente o un'identità gestita. Per questa guida, l'identità gestita assegnata dal sistema verrà usata come credenziale per il costruttore CosmosClient.

  1. Impostare l'impostazione COSMOS_ENDPOINT nell'app per le funzioni già distribuita in Azure.

    az functionapp config appsettings set \
        --resource-group $resourceGroupName \
        --name $functionName \
        --settings "COSMOS_ENDPOINT=$cosmosEndpoint"
    
  2. Distribuire l'app per le funzioni in Azure riutilizzando la variabile shell functionName:

    func azure functionapp publish $functionName
    
  3. Testare la funzione nel portale di Azure.