Ćwiczenie — uzyskiwanie dostępu do wpisów tajnych przechowywanych w usłudze Azure Key Vault

Ukończone

Wiesz, jak włączenie tożsamości zarządzanych dla zasobów platformy Azure powoduje utworzenie tożsamości używanej przez aplikację do uwierzytelniania. Teraz utwórz aplikację, która używa tej tożsamości do uzyskiwania dostępu do wpisów tajnych w magazynie.

Odczytywanie wpisów tajnych w aplikacji ASP.NET Core

Interfejs API usługi Azure Key Vault to interfejs API REST, który obsługuje wszystkie zarządzanie i użycie kluczy i magazynów. Każdy wpis tajny w magazynie ma unikatowy adres URL. Wartości wpisów tajnych są pobierane za pomocą żądań HTTP GET.

Oficjalny klient usługi Key Vault dla platformy .NET Core jest klasą SecretClient w pakiecie Azure.Security.KeyVault.Secrets NuGet. Nie musisz jednak używać go bezpośrednio. Za pomocą metody ASP.NET Core AddAzureKeyVault możesz załadować wszystkie wpisy tajne z magazynu do interfejsu API konfiguracji podczas uruchamiania. Ta technika umożliwia dostęp do wszystkich wpisów tajnych przy użyciu nazwy przy użyciu tego samego IConfiguration interfejsu, który jest używany w pozostałej części konfiguracji. Aplikacje, które używają AddAzureKeyVault , wymagają zarówno uprawnień, jak Get i List do magazynu.

Napiwek

Niezależnie od struktury lub języka używanego do kompilowania aplikacji, należy zaprojektować ją w celu buforowania wartości wpisów tajnych lokalnie lub załadowania ich do pamięci podczas uruchamiania, chyba że masz określony powód, aby nie. Odczytywanie ich bezpośrednio z magazynu za każdym razem, gdy są potrzebne, jest niepotrzebnie wolne i kosztowne.

AddAzureKeyVault Usługa wymaga tylko nazwy magazynu jako danych wejściowych, które są uzyskiwane z lokalnej konfiguracji aplikacji. Automatycznie obsługuje również uwierzytelnianie tożsamości zarządzanej. W przypadku użycia w aplikacji wdrożonej w usłudze aplikacja systemu Azure z włączonymi tożsamościami zarządzanymi dla zasobów platformy Azure wykrywa usługę tokenu tożsamości zarządzanych i używa jej do uwierzytelniania. Jest to dobre rozwiązanie dla większości scenariuszy i implementuje wszystkie najlepsze rozwiązania. Zostanie ona użyta w ćwiczeniu tej lekcji.

Odczytywanie wpisów tajnych w aplikacji Node.js

Interfejs API usługi Azure Key Vault to interfejs API REST, który obsługuje wszystkie zarządzanie i użycie kluczy i magazynów. Każdy wpis tajny w magazynie ma unikatowy adres URL. Wartości wpisów tajnych są pobierane za pomocą żądań HTTP GET.

Oficjalny klient usługi Key Vault dla aplikacji środowiska Node.js to klasa SecretClient w pakiecie npm @azure/keyvault-secrets. Aplikacje, które zawierają nazwy wpisów tajnych w swojej konfiguracji lub kodzie, zwykle używają jej getSecret metody, która ładuje wartość wpisu tajnego nadaną jej nazwie. getSecret wymaga, aby tożsamość aplikacji miała Get uprawnienia do magazynu. Aplikacje przeznaczone do ładowania wszystkich wpisów tajnych z magazynu używają listPropertiesOfSecrets również metody , która ładuje listę wpisów tajnych i wymaga List uprawnień.

Aby aplikacja mogła utworzyć wystąpienie SecretClient, musi uzyskać obiekt poświadczeń umożliwiający uwierzytelnianie w magazynie. Aby przeprowadzić uwierzytelnianie, użyj elementu DefaultAzureCredential dostarczonego w pakiecie npm @azure/identity. Jest DefaultAzureCredential to odpowiednie w przypadku większości scenariuszy, w których aplikacja ma ostatecznie działać w chmurze platformy Azure, ponieważ DefaultAzureCredential łączy poświadczenia często używane do uwierzytelniania podczas wdrażania, z poświadczeniami używanymi do uwierzytelniania w środowisku projektowym. Próby DefaultAzureCredential uwierzytelnienia przy użyciu następujących mechanizmów są następujące:

  • Środowiska. Odczytuje DefaultAzureCredential informacje o koncie określone przy użyciu zmiennych środowiskowych i używa ich do uwierzytelniania.
  • Tożsamość zarządzana. Jeśli aplikacja zostanie wdrożona na hoście platformy Azure z włączoną tożsamością zarządzaną, DefaultAzureCredential uwierzytelnia się przy użyciu tego konta.
  • Visual Studio Code. Jeśli deweloper uwierzytelniony przy użyciu wtyczki konta platformy Azure programu Visual Studio Code, DefaultAzureCredential uwierzytelnia się przy użyciu tego konta.
  • Interfejs wiersza polecenia platformy Azure. Jeśli deweloper uwierzytelnił konto przy użyciu polecenia interfejsu wiersza polecenia az login platformy Azure, DefaultAzureCredential uwierzytelnia się przy użyciu tego konta.

Więcej informacji zawiera strona dokumentacji.

Napiwek

Niezależnie od struktury lub języka używanego do kompilowania aplikacji, należy zaprojektować ją w celu buforowania wartości wpisów tajnych lokalnie lub załadowania ich do pamięci podczas uruchamiania, chyba że masz określony powód, aby nie. Odczytywanie ich bezpośrednio z magazynu za każdym razem, gdy są potrzebne, jest niepotrzebnie wolne i kosztowne.

Obsługa wpisów tajnych w aplikacji

Po załadowaniu wpisu tajnego do aplikacji to aplikacja powinna obsługiwać go w bezpieczny sposób. W aplikacji utworzonej w tym module zapisujesz wartość wpisu tajnego w odpowiedzi klienta i pokazujesz, że załadowano pomyślnie, wyświetlasz ją w przeglądarce internetowej. Zwracanie wartości wpisu tajnego do klienta nie jest typowym podejściem! Zazwyczaj wpisy tajne służą do wykonywania takich czynności, jak inicjowanie bibliotek klienckich dla baz danych lub zdalnych interfejsów API.

Ważne

Zawsze uważnie przejrzyj kod, aby upewnić się, że aplikacja nigdy nie zapisuje wpisów tajnych w dowolnych danych wyjściowych, w tym dzienników, magazynu i odpowiedzi.

Ćwiczenie

Aby załadować wpis tajny z naszego magazynu, utworzysz nowy internetowy interfejs API platformy ASP.NET Core i użyj polecenia AddAzureKeyVault.

Tworzenie aplikacji

  1. Aby utworzyć nową aplikację internetowego interfejsu API platformy ASP.NET Core i otworzyć ją w edytorze, uruchom następujące polecenia w usłudze Azure Cloud Shell.

    dotnet new webapi -o KeyVaultDemoApp
    cd KeyVaultDemoApp
    code .
    
  2. Po załadowaniu edytora dodaj pakiet NuGet zawierający AddAzureKeyVault i przywróć wszystkie zależności aplikacji. W usłudze Azure Cloud Shell uruchom następujące polecenia.

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

Dodawanie kodu w celu załadowania i użycia wpisów tajnych

Aby zademonstrować dobre użycie usługi Key Vault, zmodyfikuj aplikację tak, aby ładowała wpisy tajne z magazynu podczas uruchamiania. Dodasz również nowy kontroler z punktem końcowym, który pobiera wpis SecretPassword tajny z magazynu.

  1. W przypadku uruchamiania aplikacji wprowadź następujące polecenie, aby uruchomić edytor.

    code .
    
  2. Otwórz Program.csplik , usuń zawartość i zastąp je następującym kodem.

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

    Ważne

    Pamiętaj, aby zapisać pliki po zakończeniu ich edycji. Pliki można zapisywać za pomocą ciągu "..." menu lub klawisz skrótu (Ctrl+S w systemach Windows i Linux, Cmd+S w systemie macOS).

    Jedyna zmiana w kodzie uruchomieniowym to dodanie ConfigureAppConfiguration. Ten element to miejsce, w którym załadujemy nazwę magazynu z konfiguracji i wywołamy AddAzureKeyVault ją za pomocą polecenia .

  3. W przypadku kontrolera utwórz nowy plik w Controllers folderze o nazwie SecretTestController.csi wklej następujący kod.

    Napiwek

    Aby utworzyć nowy plik, użyj touch polecenia w usłudze Cloud Shell. W takim przypadku uruchom touch Controllers/SecretTestController.cs polecenie . Aby znaleźć go w prawym górnym rogu okienka Pliki edytora, wybierz ikonę Odśwież.

    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. dotnet build Uruchom polecenie w usłudze Azure Cloud Shell, aby upewnić się, że wszystko jest kompilowane. Aplikacja jest gotowa do uruchomienia. Teraz nadszedł czas, aby dostać się na platformę Azure!

Utwórz nowy internetowy interfejs API za pomocą pliku Express.js i użyj @azure/keyvault-secrets pakietów i @azure/identity , aby załadować wpis tajny z naszego magazynu.

Tworzenie aplikacji

Uruchom następujący kod w usłudze Azure Cloud Shell, aby zainicjować nową aplikację Node.js, zainstalować wymagane pakiety i otworzyć nowy plik w edytorze.

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

Dodawanie kodu w celu załadowania i użycia wpisów tajnych

Aby zademonstrować dobre użycie usługi Key Vault, aplikacja ładuje wpisy tajne z magazynu podczas uruchamiania. Aby zademonstrować, że wpisy tajne zostały załadowane, utwórz punkt końcowy, który wyświetla wartość wpisu tajnego SecretPassword .

  1. Aby skonfigurować aplikację, wklej następujący kod do edytora. Ten kod importuje niezbędne pakiety, skonfiguruj konfigurację portu i identyfikatora URI magazynu oraz utwórz nowy obiekt do przechowywania nazw i wartości wpisów tajnych.

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

    Ważne

    Pamiętaj o zapisywaniu plików podczas pracy z nimi, a szczególnie po jej zakończeniu. Pliki można zapisywać za pomocą ciągu "..." menu lub klawisz skrótu (Ctrl+S w systemach Windows i Linux, Cmd+S w systemie macOS).

  2. Następnie dodaj kod w celu uwierzytelnienia w magazynie i załaduj wpisy tajne. Ten kod należy dodać jako dwie oddzielne funkcje. Wstaw kilka pustych wierszy po wcześniej dodanym kodzie, a następnie wklej następujący kod.

    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. Aby sprawdzić, czy nasz wpis tajny został załadowany, utwórz punkt końcowy platformy Express. Wklej ten kod.

    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. Wywołaj funkcje, aby załadować wpisy tajne z naszego magazynu, a następnie uruchom aplikację. Aby ukończyć aplikację, wklej ostatni fragment kodu.

    (async () =>  {
      await getKeyVaultSecrets();
      app.listen(port, () => {
        console.log(`Server running at http://localhost:${port}`);
      });
    })().catch(err => console.log(err));
    
  5. Po zakończeniu pisania kodu pamiętaj o zapisaniu pliku.

Aplikacja jest gotowa do uruchomienia. Teraz nadszedł czas, aby dostać się na platformę Azure!