Exercício – Acessar os segredos armazenados no Azure Key Vault

Concluído

Você sabe como habilitar identidades gerenciadas para recursos do Azure cria uma identidade para seu aplicativo usar para autenticação. Agora, crie um aplicativo que use essa identidade para acessar segredos no cofre.

Ler segredos em um aplicativo ASP.NET Core

A API do Azure Key Vault é uma API REST que lida com todo o gerenciamento e o uso de chaves e cofres. Cada segredo em um cofre tem uma URL exclusiva. Os valores de segredo são recuperados com solicitações HTTP GET.

O cliente oficial do Key Vault para .NET Core é a classe SecretClient no pacote NuGet Azure.Security.KeyVault.Secrets. No entanto, você não precisa usá-lo diretamente. Com o método AddAzureKeyVault do ASP.NET Core, você pode carregar todos os segredos de um cofre na API de Configuração durante a inicialização. Essa técnica permite acessar todos os segredos pelo nome usando a mesma interface IConfiguration que você usa para o restante da configuração. Os aplicativos que usam AddAzureKeyVault exigem permissões Get e List para o cofre.

Dica

Independentemente da estrutura ou da linguagem usada para a criação do aplicativo, você deve projetá-lo para armazenar em cache os valores secretos localmente ou carregá-los na memória na inicialização, a menos que você tenha um motivo específico para não fazer isso. É desnecessariamente lento e caro lê-los diretamente do cofre sempre que você precisa deles.

AddAzureKeyVault requer apenas o nome do cofre como uma entrada, que você obtém da configuração do aplicativo local. Ele também cuida automaticamente da autenticação de identidade gerenciada. Quando usado em um aplicativo implantado no Serviço de Aplicativo do Azure com identidades gerenciadas para recursos do Azure habilitados, ele detecta o serviço de token de identidades gerenciadas e o usa para autenticar. É uma boa opção para a maioria dos cenários e implementa todas as práticas recomendadas. Você o usa no exercício desta unidade.

Ler segredos em um aplicativo Node.js

A API do Azure Key Vault é uma API REST que lida com todo o gerenciamento e o uso de chaves e cofres. Cada segredo em um cofre tem uma URL exclusiva. Os valores de segredo são recuperados com solicitações HTTP GET.

O cliente oficial do Key Vault para aplicativos Node.js é a classe SecretClient no pacote npm @azure/keyvault-secrets. Aplicativos que incluem nomes de segredo em sua configuração ou código geralmente usam seu método getSecret, que carrega um valor de segredo dado o seu nome. getSecret exige que a identidade do aplicativo tenha a permissão Get no cofre. Os aplicativos projetados para carregar todos os segredos de um cofre também usam o método listPropertiesOfSecrets, que carrega uma lista de segredos e requer a permissão List.

Antes que o aplicativo possa criar uma instância SecretClient, ele precisará obter um objeto de credencial para autenticação no cofre. Para se autenticar, use a DefaultAzureCredential fornecida pelo pacote npm @azure/identity. O DefaultAzureCredential é apropriado para a maioria dos cenários em que o aplicativo se destina a ser executado no Azure Cloud porque o DefaultAzureCredential combina credenciais normalmente usadas para autenticação durante a implantação, com credenciais usadas para autenticação em um ambiente de desenvolvimento. DefaultAzureCredential tenta autenticar usando os seguintes mecanismos, nesta ordem:

  • Ambiente. O DefaultAzureCredential lê informações da conta especificadas usando variáveis de ambiente e as usa para autenticar.
  • Identidade gerenciada. Se o aplicativo for implantado em um host do Azure com a Identidade Gerenciada habilitada, o DefaultAzureCredential será autenticado com essa conta.
  • Visual Studio Code. Se o desenvolvedor for autenticado usando o plug-in da Conta do Azure do Visual Studio Code, o DefaultAzureCredential será autenticado com essa conta.
  • CLI do Azure. Se o desenvolvedor autenticar uma conta usando o comando da CLI do Azure az login, o DefaultAzureCredential será autenticado com essa conta.

Para obter mais informações, confira a documentação.

Dica

Independentemente da estrutura ou da linguagem usada para a criação do aplicativo, você deve projetá-lo para armazenar em cache os valores secretos localmente ou carregá-los na memória na inicialização, a menos que você tenha um motivo específico para não fazer isso. É desnecessariamente lento e caro lê-los diretamente do cofre sempre que você precisa deles.

Manipular segredos em um aplicativo

Cabe ao aplicativo tratar o segredo com segurança após ele ser carregado em seu aplicativo. No aplicativo criado neste módulo, você grava seu valor de segredo na resposta do cliente e, para demonstrar que ele foi carregado com êxito, você o exibe em um navegador da Web. O retorno de um valor secreto para o cliente não é algo que você normalmente faria! Normalmente, você usa segredos para fazer coisas como inicializar bibliotecas de clientes para bancos de dados ou APIs remotas.

Importante

Examine sempre o código cuidadosamente para garantir que seu aplicativo nunca grave segredos em nenhum tipo de saída, incluindo logs, armazenamento e respostas.

Exercício

Para carregar o segredo de nosso cofre, crie uma nova API Web do ASP.NET Core e use AddAzureKeyVault.

Criar o aplicativo

  1. Para criar um novo aplicativo de API Web do ASP.NET Core e abri-lo no editor, execute os comandos a seguir no Azure Cloud Shell.

    dotnet new webapi -o KeyVaultDemoApp
    cd KeyVaultDemoApp
    code .
    
  2. Depois que o editor for carregado, adicione o pacote NuGet que contém AddAzureKeyVault e restaure todas as dependências do aplicativo. No Azure Cloud Shell, execute os comandos a seguir.

    dotnet add package Azure.Identity
    dotnet add package Azure.Extensions.AspNetCore.Configuration.Secrets
    dotnet restore
    

Adicionar um código para carregar e usar segredos

Para demonstrar um bom uso do Key Vault, modificaremos nosso aplicativo para carregar os segredos do cofre na inicialização. Você também adiciona um novo controlador com um ponto de extremidade que obtém seu segredo SecretPassword do cofre.

  1. Para a inicialização do aplicativo, insira o comando a seguir para iniciar o editor.

    code .
    
  2. Abra Program.cs, exclua o conteúdo e substitua-o pelo código a seguir.

    using System;
    using Azure.Identity;
    using Microsoft.AspNetCore;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.Hosting;
    
    namespace KeyVaultDemoApp
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                CreateHostBuilder(args).Build().Run();
            }
    
            public static IHostBuilder CreateHostBuilder(string[] args) =>
                Host.CreateDefaultBuilder(args)
                    .ConfigureWebHostDefaults(webBuilder =>
                    {
                        webBuilder.UseStartup<Startup>();
                    })
                    .ConfigureAppConfiguration((context, config) =>
                    {
                        // Build the current set of configuration to load values from
                        // JSON files and environment variables, including VaultName.
                        var builtConfig = config.Build();
    
                        // Use VaultName from the configuration to create the full vault URI.
                        var vaultName = builtConfig["VaultName"];
                        Uri vaultUri = new Uri($"https://{vaultName}.vault.azure.net/");
    
                        // Load all secrets from the vault into configuration. This will automatically
                        // authenticate to the vault using a managed identity. If a managed identity
                        // is not available, it will check if Visual Studio and/or the Azure CLI are
                        // installed locally and see if they are configured with credentials that can
                        // access the vault.
                        config.AddAzureKeyVault(vaultUri, new DefaultAzureCredential());
                    });
        }
    }
    

    Importante

    Salve os arquivos quando terminar de editá-los. Você pode salvar arquivos por meio do menu "..." ou a tecla aceleradora (Ctrl+S no Windows e Linux, Cmd+S no macOS).

    A única alteração no código inicial é a adição de ConfigureAppConfiguration. Esse elemento é onde carregamos o nome do cofre da configuração e chamamos AddAzureKeyVault com ele.

  3. Para o controlador, crie um arquivo na pasta Controllers chamado SecretTestController.cs e cole o código a seguir nele.

    Dica

    Para criar um arquivo, use o comando touch no Cloud Shell. Nesse caso, execute o comando touch Controllers/SecretTestController.cs. Para vê-lo no canto superior direito do painel Arquivos do editor, selecione o ícone Atualizar.

    using System;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Configuration;
    
    namespace KeyVaultDemoApp.Controllers
    {
        [Route("api/[controller]")]
        public class SecretTestController : ControllerBase
        {
            private readonly IConfiguration _configuration;
    
            public SecretTestController(IConfiguration configuration)
            {
                _configuration = configuration;
            }
    
            [HttpGet]
            public IActionResult Get()
            {
                // Get the secret value from configuration. This can be done anywhere
                // we have access to IConfiguration. This does not call the Key Vault
                // API, because the secrets were loaded at startup.
                var secretName = "SecretPassword";
                var secretValue = _configuration[secretName];
    
                if (secretValue == null)
                {
                    return StatusCode(
                        StatusCodes.Status500InternalServerError,
                        $"Error: No secret named {secretName} was found...");
                }
                else {
                    return Content($"Secret value: {secretValue}" +
                        Environment.NewLine + Environment.NewLine +
                        "This is for testing only! Never output a secret " +
                        "to a response or anywhere else in a real app!");
                }
            }
        }
    }
    
  4. Execute o comando dotnet build no Azure Cloud Shell para garantir que tudo seja compilado. O aplicativo está pronto para ser executado. Agora é hora de entrar no Azure!

Crie uma nova API Web com o Express.js e use o e os pacotes @azure/keyvault-secrets e @azure/identity para carregar o segredo de nosso cofre.

Crie o aplicativo

Execute o código a seguir no Azure Cloud Shell para inicializar um novo aplicativo do Node.js, instale os pacotes necessários, e abra um novo arquivo no editor.

mkdir KeyVaultDemoApp
cd KeyVaultDemoApp
npm init -y
npm install @azure/identity @azure/keyvault-secrets express
touch app.js
code app.js

Adicionar um código para carregar e usar segredos

Para demonstrar o bom uso do Key Vault, seu aplicativo carrega segredos do cofre na inicialização. Para demonstrar que seus segredos foram carregados, crie um ponto de extremidade que exiba o valor do segredo SecretPassword.

  1. Cole o código a seguir no editor para configurar o aplicativo. Esse código importa os pacotes necessários, configura a configuração de URI da porta e do cofre e cria um novo objeto para armazenar os nomes e valores de segredo.

    // Importing dependencies
    const { DefaultAzureCredential } = require("@azure/identity");
    const { SecretClient } = require("@azure/keyvault-secrets");
    const app = require('express')();
    
    // Initialize port
    const port = process.env.PORT || 3000;
    
    // Create Vault URI from App Settings
    const vaultUri = `https://${process.env.VaultName}.vault.azure.net/`;
    
    // Map of key vault secret names to values
    let vaultSecretsMap = {};
    

    Importante

    Certifique-se de salvar os arquivos enquanto você trabalha neles, especialmente quando tiver terminado. Você pode salvar arquivos por meio do menu "..." ou a tecla aceleradora (Ctrl+S no Windows e Linux, Cmd+S no macOS).

  2. Em seguida, adicione o código para autenticar no cofre e carregar os segredos. Você adiciona esse código como duas funções separadas. Insira algumas linhas em branco após o código adicionado anteriormente e cole o código a seguir.

    const getKeyVaultSecrets = async () => {
      // Create a key vault secret client
      let secretClient = new SecretClient(vaultUri, new DefaultAzureCredential());
      try {
        // Iterate through each secret in the vault
        listPropertiesOfSecrets = secretClient.listPropertiesOfSecrets();
        while (true) {
          let { done, value } = await listPropertiesOfSecrets.next();
          if (done) {
            break;
          }
          // Only load enabled secrets - getSecret will return an error for disabled secrets
          if (value.enabled) {
            const secret = await secretClient.getSecret(value.name);
            vaultSecretsMap[value.name] = secret.value;
          }
        }
      } catch(err) {
        console.log(err.message)
      }
    }
    
  3. Crie o ponto de extremidade da opção Expresso para testar se o segredo foi carregado. Cole neste código.

    app.get('/api/SecretTest', (req, res) => {
      let secretName = 'SecretPassword';
      let response;
      if (secretName in vaultSecretsMap) {
        response = `Secret value: ${vaultSecretsMap[secretName]}\n\nThis is for testing only! Never output a secret to a response or anywhere else in a real app!`;
      } else {
        response = `Error: No secret named ${secretName} was found...`
      }
      res.type('text');
      res.send(response);
    });
    
  4. Chame suas funções para carregar os segredos do cofre e inicie o aplicativo. Cole este último snippet para concluir o aplicativo.

    (async () =>  {
      await getKeyVaultSecrets();
      app.listen(port, () => {
        console.log(`Server running at http://localhost:${port}`);
      });
    })().catch(err => console.log(err));
    
  5. Você terminou de escrever o código, portanto, verifique se salvou o arquivo.

O aplicativo está pronto para ser executado. Agora é hora de entrar no Azure!