Usar identidades gerenciadas atribuídas pelo sistema para acessar os dados do Azure Cosmos DB

APLICA-SE A: NoSQL

Neste artigo, você configurará uma solução independente e eficiente de rotação de chave para acessar chaves do Azure Cosmos DB usando identidades gerenciadas e controle de acesso baseado em função do plano de dados. O exemplo neste artigo usa o Azure Functions, mas você pode usar qualquer serviço que dê suporte a identidades gerenciadas.

Você aprenderá a criar um aplicativo de funções que pode acessar dados do Azure Cosmos DB sem a necessidade de copiar nenhuma chave desse serviço. O aplicativo de funções será acionado quando uma solicitação HTTP for feita e, em seguida, listará todos os bancos de dados existentes.

Pré-requisitos

  • Uma conta do Azure com uma assinatura ativa. Crie uma conta gratuitamente.

  • Uma conta da API do Azure Cosmos DB para NoSQL. Criar uma conta da API do Azure Cosmos DB para NoSQL

  • Um aplicativo de funções do Azure Functions existente. Criar sua primeira função no portal do Azure

  • Azure Functions Core Tools

  • Para executar as etapas deste artigo, instale a CLI do Azure e entre no Azure.

    Verificação de pré-requisitos

    1. Em um terminal ou janela de comando, armazene os nomes de seu aplicativo de funções do Azure Functions, conta do Azure Cosmos DB e grupo de recursos como variáveis de shell nomeadas 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"
      

      Observação

      Essas variáveis serão reutilizadas em etapas posteriores. Este exemplo pressupõe que o nome da conta do Azure Cosmos DB seja msdocs-cosmos-app, o nome do aplicativo de funções é msdocs-function-app e o nome do grupo de recursos é msdocs-cosmos-functions-dotnet-identity.

    2. Exiba as propriedades do aplicativo de funções usando o comando az functionapp show.

      az functionapp show \
          --resource-group $resourceGroupName \
          --name $functionName
      
    3. Exiba as propriedades da identidade gerenciada atribuída pelo sistema para seu aplicativo de funções usando az webapp identity show.

      az webapp identity show \
          --resource-group $resourceGroupName \
          --name $functionName
      
    4. Exiba as propriedades da conta do Azure Cosmos DB usando az cosmosdb show.

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

Criar a API do Azure Cosmos DB para bancos de dados NoSQL

Nesta etapa, você criará dois bancos de dados.

  1. Em um terminal ou janela de comando, crie um novo products banco de dados usando az cosmosdb sql database create.

    az cosmosdb sql database create \
        --resource-group $resourceGroupName \
        --name products \
        --account-name $cosmosName
    
  2. Criar um novo banco de dados customers.

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

Obter a API do Azure Cosmos DB para ponto de extremidade NoSQL

Nesta etapa, você consultará o ponto de extremidade do documento para a conta da API para NoSQL.

  1. Use az cosmosdb show com o parâmetro de consulta definido como documentEndpoint. Registre o resultado. Você usa esse valor em uma etapa posterior.

    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
    

    Observação

    Essa variável será usada novamente em uma etapa posterior.

Conceder acesso à sua conta do Azure Cosmos DB

Nesta etapa, você atribuirá uma função à identidade gerenciada atribuída pelo sistema do aplicativo de funções. O Azure Cosmos DB tem várias funções internas que você pode atribuir à identidade gerenciada para acesso ao painel de controle. Para acesso ao plano de dados, você criará uma função personalizada com acesso para ler os metadados.

Dica

Para obter mais informações sobre a importância do acesso de privilégios mínimos, confira o artigo Menor exposição de contas com privilégios.

  1. Use az cosmosdb show com o parâmetro de consulta definido como id. Armazene o resultado em uma variável de shell chamada scope.

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

    Observação

    Essa variável será usada novamente em uma etapa posterior.

  2. Use az webapp identity show com o parâmetro de consulta definido como principalId. Armazene o resultado em uma variável de shell chamada principal.

    principal=$(
        az webapp identity show \
            --resource-group $resourceGroupName \
            --name $functionName \
            --query principalId \
            --output tsv
    )
    
    echo $principal
    
  3. Crie um novo arquivo JSON com a configuração da nova função personalizada.

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

    Dica

    Você pode criar um arquivo no Azure Cloud Shell usando touch <filename> ou o editor interno (code .). Para obter mais informações, confira Editor do Azure Cloud Shell

  4. Use az cosmosdb sql role definition create para criar uma definição de função denominada Read Azure Cosmos DB Metadata usando o objeto JSON personalizado.

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

    Observação

    Neste exemplo, a definição de função é definida em um arquivo chamado definition.json.

  5. Use az role assignment create para atribuir a função Read Azure Cosmos DB Metadata à identidade gerenciada atribuída pelo 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
    

Acessar programaticamente as chaves do Azure Cosmos DB

Agora temos um aplicativo de funções que tem uma identidade gerenciada atribuída pelo sistema com a função personalizada. O aplicativo de funções a seguir consultará a conta do Azure Cosmos DB para obter uma lista de bancos de dados.

  1. Criar um projeto de função local com o parâmetro --dotnet em uma pasta chamada csmsfunc. Alterar o diretório do shell

    func init csmsfunc --dotnet
    
    cd csmsfunc
    
  2. Crie uma nova função com o parâmetro de modelo definido como httptrigger e o nome definido como readdatabases.

    func new --template httptrigger --name readdatabases
    
  3. Adicione o pacote NuGet Azure.Identity e Microsoft.Azure.Cosmos ao projeto .NET. Compile o projeto usando o dotnet build.

    dotnet add package Azure.Identity
    
    dotnet add package Microsoft.Azure.Cosmos
    
    dotnet build
    
  4. Abra o código de função em um IDE (ambiente de desenvolvedor integrado).

    Dica

    Se você estiver usando a CLI do Azure localmente ou no Azure Cloud Shell, poderá abrir Visual Studio Code.

    code .
    
  5. Substitua o código no arquivo readdatabases.cs por essa implementação de função de exemplo. Salve o arquivo atualizado.

    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);
            }
        }
    }
    

(Opcional) Executar a função localmente

Em um ambiente local, a classe DefaultAzureCredential usará várias credenciais locais para determinar a identidade atual. Embora a execução local não seja necessária para as instruções, você pode desenvolver localmente usando sua própria identidade ou uma entidade de serviço.

  1. No arquivo local.settings.json, adicione uma nova configuração nomeada COSMOS_ENDPOINT no objeto Valores. O valor da configuração deve ser o ponto de extremidade do documento que você registrou anteriormente neste guia de instruções.

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

    Observação

    Este objeto JSON foi encurtado para resumir. Esse objeto JSON também inclui um valor de exemplo que pressupõe que o nome da conta seja msdocs-cosmos-app.

  2. Executar o aplicativo de funções

    func start
    

Implantar no Azure

Depois de publicada, a classe DefaultAzureCredential usará credenciais do ambiente ou de uma identidade gerenciada. Para este guia, a identidade gerenciada atribuída pelo sistema será usada como uma credencial para o construtor CosmosClient.

  1. Defina a configuração COSMOS_ENDPOINT no aplicativo de funções já implantada no Azure.

    az functionapp config appsettings set \
        --resource-group $resourceGroupName \
        --name $functionName \
        --settings "COSMOS_ENDPOINT=$cosmosEndpoint"
    
  2. Implante seu aplicativo de funções no Azure reutilizando a variável de shell functionName:

    func azure functionapp publish $functionName
    
  3. Testar a sua função no portal do Azure.