Упражнение. Доступ к секретам, хранящимся в Azure Key Vault

Завершено

Вы знаете, как включение управляемых удостоверений для ресурсов Azure создает удостоверение для приложения, используемого для проверки подлинности. Теперь создайте приложение, которое использует это удостоверение для доступа к секретам в хранилище.

Чтение секретов в приложении ASP.NET Core

API Azure Key Vault — это REST API, который обслуживает все операции администрирования и использования ключей и хранилищ. Каждый секрет в хранилище имеет уникальный URL-адрес. Значения секретов извлекаются с помощью HTTP-запросов GET.

Официальный клиент Key Vault для .NET Core — это SecretClient класс в пакете Azure.Security.KeyVault.Secrets NuGet. Однако использовать его напрямую не нужно. С помощью метода AddAzureKeyVault ASP.NET Core можно загрузить все секреты из хранилища в API конфигурации при запуске. Этот способ позволит вам получить доступ ко всем своим секретам по имени, используя тот же интерфейс IConfiguration, что и в остальной части конфигурации. Приложения, которые используются, AddAzureKeyVault требуют обоих Get и List разрешений для хранилища.

Совет

Независимо от того, какую платформу или язык вы используете для создания своего приложения, приложение следует разработать так, чтобы оно кэшировало значения секретов локально или загружало их в память при запуске (кроме случаев, когда вам нужна другая конфигурация). Считывание секретов из хранилища каждый раз, когда в них возникнет необходимость, отнимает слишком много времени и ресурсов.

AddAzureKeyVault Требуется только имя хранилища в качестве входных данных, которое вы получаете из конфигурации локального приложения. Оно также автоматически обрабатывает проверку подлинности управляемого удостоверения. При использовании в приложении, развернутом в службе приложение Azure с управляемыми удостоверениями для ресурсов Azure, она обнаруживает службу маркеров управляемых удостоверений и использует ее для проверки подлинности. Это хорошо подходит для большинства сценариев и реализует все рекомендации. Вы используете его в упражнении этого урока.

Чтение секретов в приложении Node.js

API Azure Key Vault — это REST API, который обслуживает все операции администрирования и использования ключей и хранилищ. Каждый секрет в хранилище имеет уникальный URL-адрес. Значения секретов извлекаются с помощью HTTP-запросов GET.

Официальный клиент Key Vault для приложений Node.js — это класс SecretClient в пакете npm @azure/keyvault-secrets. Приложения, содержащие имена секретов в конфигурации или коде, обычно используют его getSecret метод, который загружает значение секрета, заданное его именем. getSecret требует, чтобы удостоверение вашего приложения было Get иметь разрешение на хранилище. Приложения, предназначенные для загрузки всех секретов из хранилища, также используют listPropertiesOfSecrets метод, который загружает список секретов и требует List разрешения.

Прежде чем приложение сможет создать экземпляр SecretClient, оно должно получить объект учетных данных для проверки подлинности в хранилище. Для проверки подлинности используйте класс DefaultAzureCredential, предоставленный пакетом npm @azure/identity. Это DefaultAzureCredential подходит для большинства сценариев, когда приложение предназначено для конечного запуска в облаке Azure, так как DefaultAzureCredential объединяет учетные данные, часто используемые для проверки подлинности при развертывании, с учетными данными, используемыми для проверки подлинности в среде разработки. Попытки DefaultAzureCredential проверки подлинности с помощью следующих механизмов в порядке:

  • Среда. Данные DefaultAzureCredential учетной записи считываются с помощью переменных среды и используются для проверки подлинности.
  • Управляемое удостоверение. Если приложение развернуто на узле Azure с включенным управляемым удостоверением, DefaultAzureCredential проверка подлинности выполняется с помощью этой учетной записи.
  • Visual Studio Code. Если разработчик прошел проверку подлинности с помощью подключаемого модуля учетной записи Azure Visual Studio Code, DefaultAzureCredential проверка подлинности выполняется с помощью этой учетной записи.
  • Azure CLI. Если разработчик прошел проверку подлинности учетной записи с помощью команды Azure CLI az login , DefaultAzureCredential проверка подлинности выполняется с помощью этой учетной записи.

Дополнительные сведения см. в документации.

Совет

Независимо от того, какую платформу или язык вы используете для создания своего приложения, приложение следует разработать так, чтобы оно кэшировало значения секретов локально или загружало их в память при запуске (кроме случаев, когда вам нужна другая конфигурация). Считывание секретов из хранилища каждый раз, когда в них возникнет необходимость, отнимает слишком много времени и ресурсов.

Обработка секретов в приложении

После того как секрет будет загружен в приложение, именно от приложения будет зависеть безопасность его использования. В приложении, которое вы создаете в этом модуле, вы записываете значение секрета в ответ клиента и демонстрируете, что оно загружено успешно, вы просматриваете его в веб-браузере. На практике значение секрета в клиент не передается! Обычно секреты используются для выполнения таких действий, как инициализация клиентских библиотек для баз данных или удаленных API.

Важно!

Всегда тщательно проверяйте свой код и следите, чтобы ваше приложение не записывало секреты ни в какие выходные данные, включая журналы, хранилища и ответы.

Упражнения

Чтобы загрузить секрет из нашего хранилища, создайте новый веб-API ASP.NET Core и используйте AddAzureKeyVault.

Создание приложения

  1. Чтобы создать новое веб-приложение ASP.NET Core и открыть его в редакторе, выполните следующие команды в Azure Cloud Shell.

    dotnet new webapi -o KeyVaultDemoApp
    cd KeyVaultDemoApp
    code .
    
  2. После того, как загрузится редактор добавьте пакет NuGet, содержащий AddAzureKeyVault, и восстановите все зависимости приложения. В Azure Cloud Shell выполните следующие команды.

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

Добавление кода для загрузки и использования секретов

Чтобы продемонстрировать надлежащее использование Key Vault, измените ваше приложение таким образом, чтобы секреты загружались из хранилища при запуске. Вы также добавляете новый контроллер с конечной точкой, которая получает SecretPassword секрет из хранилища.

  1. Для запуска приложения введите следующую команду, чтобы запустить редактор.

    code .
    
  2. Для этого откройте Program.cs, удалите содержимое и замените его следующим кодом:

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

    Важно!

    Закончив редактирование, обязательно сохраните файлы. Файлы можно сохранить с помощью "..." меню или клавиша акселератора (CTRL+S в Windows и Linux, Cmd+S в macOS).

    Единственное изменение по сравнению с начальным кодом — это добавление ConfigureAppConfiguration. В этом элементе мы загружаем имя хранилища из конфигурации и вызываем AddAzureKeyVault его.

  3. Для контроллера создайте новый файл в папке Controllers с именем SecretTestController.cs и вставьте в него представленный ниже код.

    Совет

    Чтобы создать файл, выполните в Cloud Shell команду touch. В данном случае выполните команду touch Controllers/SecretTestController.cs. Чтобы его найти, в правом верхнем углу панели Файлы редактора щелкните значок "Обновить".

    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. Выполните в Azure Cloud Shell команду dotnet build, чтобы убедиться в том, что компиляция прошла успешно. Приложение готово к выполнению. Теперь пришло время получить его в Azure!

Создайте новый веб-API с помощью Express.js и используйте @azure/keyvault-secrets@azure/identity пакеты для загрузки секрета из нашего хранилища.

Создание приложения

Выполните в Azure Cloud Shell следующий код, чтобы инициализировать новое приложение Node.js, установить необходимые пакеты и открыть новый файл в редакторе.

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

Добавление кода для загрузки и использования секретов

Чтобы продемонстрировать хорошее использование Key Vault, приложение загружает секреты из хранилища при запуске. Чтобы продемонстрировать загрузку секретов, создайте конечную точку, отображающую значение секрета SecretPassword .

  1. Чтобы настроить приложение, вставьте следующий код в редактор. Этот код импортирует необходимые пакеты, настраивает конфигурацию порта и хранилища URI и создает новый объект для хранения имен и значений секретов.

    // 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 = {};
    

    Важно!

    Обязательно сохраняйте файлы в процессе работы и особенно после ее завершения. Файлы можно сохранить с помощью "..." меню или клавиша акселератора (CTRL+S в Windows и Linux, Cmd+S в macOS).

  2. Затем добавьте код для проверки подлинности в хранилище и загрузите секреты. Этот код добавляется в виде двух отдельных функций. Вставьте две пустые строки после кода, который вы добавили ранее, и после них вставьте следующий код.

    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. Теперь создайте конечную точку Express, которая будет использоваться для проверки загрузки секрета. Далее вставьте следующий код.

    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. Вызовите функции для загрузки секретов из нашего хранилища, а затем запустите приложение. Вставьте этот последний фрагмент кода, чтобы завершить создание приложения.

    (async () =>  {
      await getKeyVaultSecrets();
      app.listen(port, () => {
        console.log(`Server running at http://localhost:${port}`);
      });
    })().catch(err => console.log(err));
    
  5. Написание кода завершено, поэтому обязательно сохраните файл.

Приложение готово к выполнению. Теперь пришло время получить его в Azure!