Azure Key Vault-Konfigurationsanbieter in ASP.NET Core

In diesem Artikel wird erläutert, wie Sie den Azure Key Vault-Konfigurationsanbieter verwenden, um App-Konfigurationswerte aus Azure Key Vault-Geheimnissen zu laden. Azure Key Vault ist ein cloudbasierter Dienst, der hilft, kryptografische Schlüssel und Geheimnisse zu schützen, die von Cloud-Apps und Clouddiensten verwendet werden. Zu den gängigen Szenarien für die Verwendung von Azure Key Vault mit ASP.NET Core-Apps gehören:

  • Kontrolle des Zugriffs auf vertrauliche Konfigurationsdaten.
  • Erfüllen der Anforderung für FIPS 140-2 Level 2-überprüfte Hardwaresicherheitsmodule (HSMs) beim Speichern von Konfigurationsdaten.

Packages

Fügen Sie Paketverweise für folgende Pakete hinzu:

Beispiel-App

Die Beispiel-App wird in einem von zwei Modi ausgeführt, der von der #define- Präprozessoranweisung am Anfang von Program.cs bestimmt wird:

  • Certificate: Veranschaulicht die Verwendung einer Azure Key Vault-Client-ID und eines X.509-Zertifikats für den Zugriff auf Geheimnisse, die in Azure Key Vault gespeichert sind. Dieses Beispiel kann von jedem beliebigen Speicherort aus ausgeführt werden, unabhängig davon, ob es auf Azure App Service bereitgestellt ist oder auf einem beliebigen Host, der eine ASP.NET Core-Anwendung unterstützen kann.
  • Managed: Veranschaulicht, wie verwaltete Identitäten für Azure-Ressourcen verwendet werden. Die verwaltete Identität authentifiziert die App bei Azure Key Vault mit Azure Active Directory (AD)-Authentifizierung, ohne Anmeldeinformationen im Code oder der Konfiguration der App zu speichern. Die Managed-Version des Beispiels muss in Azure bereitgestellt sein. Befolgen Sie den Leitfaden im Abschnitt Verwenden der verwalteten Identitäten für Azure-Ressourcen .

Weitere Informationen zum Konfigurieren einer Beispiel-App mithilfe von Präprozessoranweisungen (#define) finden Sie unter Übersicht über ASP.NET Core.

Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)

Geheimnisspeicher in der Entwicklungsumgebung

Legen Sie Geheimnisse mithilfe des Geheimnismanagers lokal fest. Wenn die Beispiel-App auf dem lokalen Computer in der Entwicklungsumgebung ausgeführt wird, werden Geheimnisse aus dem lokalen Benutzergeheimnisspeicher geladen.

Der Geheimnismanager erfordert eine <UserSecretsId>-Eigenschaft in der Projektdatei der App. Legen Sie den Eigenschaftswert ({GUID}) auf eine beliebige eindeutige GUID fest:

<PropertyGroup>
  <UserSecretsId>{GUID}</UserSecretsId>
</PropertyGroup>

Geheimnisse werden als Name/Wert-Paare erstellt. Hierarchische Werte (Konfigurationsabschnitte) verwenden einen : (Doppelpunkt) als Trennzeichen in Schlüsselnamen der ASP.NET Core-Konfiguration.

Der Geheimnismanager wird aus einer Befehlsshell verwendet, die im Inhaltsstamm des Projekts geöffnet wird, wobei {SECRET NAME} der Name und {SECRET VALUE} der Wert ist:

dotnet user-secrets set "{SECRET NAME}" "{SECRET VALUE}"

Führen Sie die folgenden Befehle in einer Befehlsshell aus dem Inhaltsstamm des Projekts aus, um die Geheimnisse für die Beispiel-App festzulegen:

dotnet user-secrets set "SecretName" "secret_value_1_dev"
dotnet user-secrets set "Section:SecretName" "secret_value_2_dev"

Wenn diese Geheimnisse in Azure Key Vault im Abschnitt Geheimnisspeicher in der Produktionsumgebung mit Azure Key Vault gespeichert werden, wird das _dev-Suffix in _prod geändert. Das Suffix stellt einen visuellen Hinweis in der Ausgabe der App bereit, der auf die Quelle der Konfigurationswerte hindeutet.

Geheimnisspeicher in der Produktionsumgebung mit Azure Key Vault

Führen Sie die folgenden Schritte aus, um einen Azure Key Vault zu erstellen und die Geheimnisse der Beispiel-App darin zu speichern. Weitere Informationen finden Sie unter Schnellstart: Festlegen und Abrufen eines Geheimnisses aus Azure Key Vault mithilfe der Azure CLI.

  1. Öffnen Sie Azure Cloud Shell mit einer der folgenden Methoden im Azure-Portal:

    • Klicken Sie in der rechten oberen Ecke eines Codeblocks auf Ausprobieren. Verwenden Sie die Suchzeichenfolge „Azure CLI“ im Textfeld.
    • Öffnen Sie Cloud Shell in Ihrem Browser mit der Schaltfläche Cloud Shell starten.
    • Wählen Sie im Menü in der rechten oberen Ecke im Azure-Portal die Schaltfläche Cloud Shell aus.

    Weitere Informationen finden Sie in unter Azure CLI und Übersicht über Azure Cloud Shell.

  2. Wenn Sie noch nicht authentifiziert sind, melden Sie sich mit dem az login-Befehl an.

  3. Erstellen Sie eine Ressourcengruppe mit dem folgenden Befehl, wobei {RESOURCE GROUP NAME} der Name der neuen Ressourcengruppe und {LOCATION} die Azure-Region ist:

    az group create --name "{RESOURCE GROUP NAME}" --location {LOCATION}
    
  4. Erstellen Sie mit dem folgenden Befehl einen Schlüsseltresor in der Ressourcengruppe, wobei {KEY VAULT NAME} der Name des neuen Tresors und {LOCATION} die Azure-Region ist:

    az keyvault create --name {KEY VAULT NAME} --resource-group "{RESOURCE GROUP NAME}" --location {LOCATION}
    
  5. Erstellen Sie Geheimnisse im Tresor als Name/Wert-Paare.

    Azure Key Vault-Geheimnisnamen sind auf alphanumerische Zeichen und Bindestriche beschränkt. Hierarchische Werte (Konfigurationsabschnitte) verwenden -- (zwei Bindestriche) als Trennzeichen, da Doppelpunkte in Key Vault-Geheimnisnamen nicht zulässig sind. Doppelpunkte trennen einen Abschnitt von einem Unterschlüssel in der ASP.NET Core-Konfiguration. Die Sequenz mit zwei Strichen wird durch einen Doppelpunkt ersetzt, wenn die Geheimnisse in die Konfiguration der App geladen werden.

    Die folgenden Geheimnisse sind für die Verwendung mit der Beispiel-App vorgesehen. Die Werte enthalten ein _prod-Suffix, um sie von den Werten des _dev-Suffixes zu unterscheiden, die vom Geheimnismanager in der Entwicklungsumgebung geladen wurden. Ersetzen Sie {KEY VAULT NAME} durch den Namen des Schlüsseltresors, den Sie im vorherigen Schritt erstellt haben:

    az keyvault secret set --vault-name {KEY VAULT NAME} --name "SecretName" --value "secret_value_1_prod"
    az keyvault secret set --vault-name {KEY VAULT NAME} --name "Section--SecretName" --value "secret_value_2_prod"
    

Verwenden der Anwendungs-ID und des X.509-Zertifikats für nicht von Azure gehostete Apps

Konfigurieren Sie Azure AD, Azure Key Vault und die App für die Verwendung einer Azure AD-Anwendungs-ID und eines X.509-Zertifikats für die Authentifizierung bei einem Tresor, wenn die App außerhalb von Azure gehostet wird. Weitere Informationen finden Sie im Artikel Informationen zu Schlüsseln, Geheimnissen und Zertifikaten.

Hinweis

Obwohl die Verwendung einer Anwendungs-ID und eines X.509-Zertifikats für in Azure gehostete Apps unterstützt wird, wird dies nicht empfohlen. Verwenden Sie stattdessen Verwaltete Identitäten für Azure-Ressourcen, wenn Sie eine App in Azure hosten. Verwaltete Identitäten erfordern kein Speichern eines Zertifikats in der App oder in der Entwicklungsumgebung.

Die Beispiel-App verwendet eine Anwendungs-ID und ein X.509-Zertifikat, wenn die #define-Präprozessoranweisung oben in Program.cs auf Certificate festgelegt ist.

  1. Erstellen Sie ein PKCS#12-Archivzertifikat (.pfx). Optionen zum Erstellen von Zertifikaten umfassen New-SelfSignedCertificate unter Windows und OpenSSL.
  2. Installieren Sie das Zertifikat im persönlichen Zertifikatspeicher des aktuellen Benutzers. Das Markieren des Schlüssels als exportierbar ist optional. Notieren Sie sich den Fingerabdruck des Zertifikats, der später in diesem Prozess verwendet wird.
  3. Exportieren Sie das PKCS#12-Archivzertifikat (.pfx) als DER-codiertes Zertifikat (.cer).
  4. Registrieren Sie die App mit Azure AD (App-Registrierungen).
  5. Laden Sie das DER-codierte Zertifikat (.cer) in Azure AD hoch:
    1. Wählen Sie die App in Azure AD aus.
    2. Navigieren Sie zu Zertifikate und Geheimnisse.
    3. Wählen Sie Zertifikat hochladen aus, um das Zertifikat hochzuladen, das den öffentlichen Schlüssel enthält. Ein .cer-, .pem- oder .crt-Zertifikat ist akzeptabel.
  6. Speichern Sie den Schlüsseltresornamen, die Anwendungs-ID und den Zertifikatfingerabdruck in der Datei appsettings.json der App.
  7. Navigieren Sie im Azure-Portal zu Schlüsseltresore.
  8. Wählen Sie den Schlüsseltresor aus, den Sie im Abschnitt Geheimnisspeicher in der Produktionsumgebung mit Azure Key Vault erstellt haben.
  9. Klicken Sie auf Zugriffsrichtlinien.
  10. Wählen Sie Zugriffsrichtlinie hinzufügen aus.
  11. Öffnen Sie Geheimnisberechtigungen, und stellen Sie der App die Berechtigungen Abrufen und Auflisten bereit.
  12. Wählen Sie Prinzipal auswählen aus, und wählen Sie dann die registrierte App anhand des Namens aus. Wählen Sie die Schaltfläche Auswählen aus.
  13. Klicken Sie auf OK.
  14. Wählen Sie Speichern aus.
  15. Stellen Sie die App bereit.

Die Certificate-Beispiel-App erhält ihre Konfigurationswerte von IConfigurationRoot mit demselben Namen wie der Geheimnisname:

  • Nicht hierarchische Werte: Der Wert für SecretName wird mit config["SecretName"] erhalten.
  • Hierarchische Werte (Abschnitte): Verwenden Sie die : (Doppelpunkt)-Notation oder die GetSection-Methode. Verwenden Sie einen der folgenden Ansätze, um den Konfigurationswert zu erhalten:
    • config["Section:SecretName"]
    • config.GetSection("Section")["SecretName"]

Das X.509-Zertifikat wird vom Betriebssystem verwaltet. Die App ruft AddAzureKeyVault mit Werten auf, die von der appsettings.json-Datei bereitgestellt werden:


using System.Security.Cryptography.X509Certificates;
using Azure.Identity;

var builder = WebApplication.CreateBuilder(args);

if (builder.Environment.IsProduction())
{
    using var x509Store = new X509Store(StoreLocation.CurrentUser);

    x509Store.Open(OpenFlags.ReadOnly);

    var x509Certificate = x509Store.Certificates
        .Find(
            X509FindType.FindByThumbprint,
            builder.Configuration["AzureADCertThumbprint"],
            validOnly: false)
        .OfType<X509Certificate2>()
        .Single();

    builder.Configuration.AddAzureKeyVault(
        new Uri($"https://{builder.Configuration["KeyVaultName"]}.vault.azure.net/"),
        new ClientCertificateCredential(
            builder.Configuration["AzureADDirectoryId"],
            builder.Configuration["AzureADApplicationId"],
            x509Certificate));
}

var app = builder.Build();

Beispielwerte:

  • Name des Schlüsseltresors: contosovault
  • Anwendungs-ID: 627e911e-43cc-61d4-992e-12db9c81b413
  • Zertifikatfingerabdruck: fe14593dd66b2406c5269d742d04b6e1ab03adb1

appsettings.json:

{
  "KeyVaultName": "Key Vault Name",
  "AzureADApplicationId": "Azure AD Application ID",
  "AzureADCertThumbprint": "Azure AD Certificate Thumbprint",
  "AzureADDirectoryId": "Azure AD Directory ID"
}

Wenn Sie die App ausführen, werden auf einer Webseite die geladenen Geheimniswerte angezeigt. In der Entwicklungsumgebung werden Geheimniswerte mit dem _dev-Suffix geladen. In der Produktionsumgebung werden die Werte mit dem _prod-Suffix geladen.

Verwenden von verwalteten Identitäten für Azure-Ressourcen

Eine in Azure bereitgestellte App kann verwaltete Identitäten für Azure-Ressourcen nutzen. Eine verwaltete Identität ermöglicht es der App, sich bei Azure Key Vault mithilfe der Azure AD-Authentifizierung zu authentifizieren, ohne Anmeldeinformationen im Code oder der Konfiguration der App zu speichern.

Die Beispiel-App verwendet eine systemseitig zugewiesene verwaltete Identität, wenn die #define-Präprozessoranweisung oben in Program.cs auf Managed festgelegt ist. Informationen zum Erstellen einer verwalteten Identität für eine Azure App Service-App finden Sie unter Verwenden von verwalteten Identitäten für App Service und Azure Functions. Nachdem die verwaltete Identität erstellt wurde, notieren Sie sich die Objekt-ID der App, die im Identity-Bereich von App Service im Azure-Portal angezeigt wird.

Geben Sie den Tresornamen in die appsettings.json-Datei der App ein. Die Beispiel-App erfordert keine Anwendungs-ID und kein Kennwort (geheimer Clientschlüssel), wenn sie auf die Managed-Version festgelegt ist, sodass Sie diese Konfigurationseinträge ignorieren können. Die App wird in Azure bereitgestellt, und Azure authentifiziert die App für den Zugriff auf Azure Key Vault nur mithilfe des in der appsettings.json-Datei gespeicherten Tresornamens.

Stellen Sie die Beispiel-App in Azure App Service bereit.

Weisen Sie der App mithilfe der Azure-Befehlszeilenschnittstelle und der Objekt-ID der App die Berechtigungen list und get für den Zugriff auf den Schlüsseltresor zu:

az keyvault set-policy --name {KEY VAULT NAME} --object-id {OBJECT ID} --secret-permissions get list

Starten Sie die App neu mittels der Azure CLI, PowerShell oder dem Azure-Portal.

Die Beispiel-App erstellt eine Instanz der DefaultAzureCredential-Klasse. Die Anmeldeinformationen versuchen, ein Zugriffstoken aus der Umgebung für Azure-Ressourcen abzurufen:

using Azure.Identity;

var builder = WebApplication.CreateBuilder(args);

if (builder.Environment.IsProduction())
{
    builder.Configuration.AddAzureKeyVault(
        new Uri($"https://{builder.Configuration["KeyVaultName"]}.vault.azure.net/"),
        new DefaultAzureCredential());
}

Beispielwert für den Schlüsseltresornamen: contosovault

appsettings.json:

{
  "KeyVaultName": "Key Vault Name"
}

Konfigurieren Sie für Apps, die eine benutzerseitig zugewiesene verwaltete Identität verwenden, die Client-ID der verwalteten Identität mit einem der folgenden Ansätze:

  1. Legen Sie die Umgebungsvariable AZURE_CLIENT_ID fest.

  2. Legen Sie die DefaultAzureCredentialOptions.ManagedIdentityClientId-Eigenschaft beim Aufrufen von AddAzureKeyVault fest:

    builder.Configuration.AddAzureKeyVault(
        new Uri($"https://{builder.Configuration["KeyVaultName"]}.vault.azure.net/"),
        new DefaultAzureCredential(new DefaultAzureCredentialOptions
        {
            ManagedIdentityClientId = builder.Configuration["AzureADManagedIdentityClientId"]
        }));
    

Wenn Sie die App ausführen, werden auf einer Webseite die geladenen Geheimniswerte angezeigt. In der Entwicklungsumgebung haben Geheimniswerte das _dev-Suffix, da sie vom Geheimnismanager bereitgestellt werden. In der Produktionsumgebung werden die Werte mit dem _prod-Suffix geladen, da sie von Azure Key Vault bereitgestellt werden.

Wenn Sie einen Access denied-Fehler erhalten, vergewissern Sie sich, dass die App bei Azure AD registriert ist und Zugriff auf den Tresor erhalten hat. Vergewissern Sie sich, dass Sie den Dienst in Azure neu gestartet haben.

Informationen zur Verwendung des Anbieters mit einer verwalteten Identität und Azure Pipelines finden Sie unter Erstellen einer Azure Resource Manager-Dienstverbindung mit einer VM mit einer verwalteten Dienstidentität.

Konfigurationsoptionen

AddAzureKeyVault kann ein AzureKeyVaultConfigurationOptions-Objekt akzeptieren:

// using Azure.Extensions.AspNetCore.Configuration.Secrets;

builder.Configuration.AddAzureKeyVault(
    new Uri($"https://{builder.Configuration["KeyVaultName"]}.vault.azure.net/"),
    new DefaultAzureCredential(),
    new AzureKeyVaultConfigurationOptions
    {
        // ...
    });

Das AzureKeyVaultConfigurationOptions-Objekt enthält die folgenden Eigenschaften:

Eigenschaft Beschreibung
Manager KeyVaultSecretManager-Instanz, die zum Steuern des Ladevorgangs für Geheimnisse verwendet wird.
ReloadInterval TimeSpan zum Warten zwischen Versuchen, den Tresor auf Änderungen abzurufen. Der Standardwert ist null (die Konfiguration wird nicht neu geladen).

Verwenden eines Schlüsselnamenpräfixes

AddAzureKeyVault stellt eine Überladung bereit, die eine Implementierung von KeyVaultSecretManager akzeptiert, mit der Sie steuern können, wie Key Vault-Geheimnisse in Konfigurationsschlüssel konvertiert werden. Beispielsweise können Sie die Schnittstelle implementieren, um Geheimniswerte basierend auf einem Präfixwert zu laden, den Sie beim Starten der App angeben. Mit dieser Technik können Sie beispielsweise Geheimnisse basierend auf der Version der App laden.

Warnung

Verwenden Sie Präfixe für Key Vault-Geheimnisse nicht für Folgendes:

  • Platzieren von Geheimnissen für mehrere Apps im selben Tresor.
  • Platzieren von Umgebungsgeheimnissen (z. B. Geheimnisse für Entwicklung und Produktion) im selben Tresor.

Verschiedene Apps und Entwicklungs-/Produktionsumgebungen sollten separate Schlüsseltresore verwenden, um App-Umgebungen für ein Höchstmaß an Sicherheit zu isolieren.

Im folgenden Beispiel wird in Key Vault (und mit dem Geheimnis-Manager für die Entwicklungsumgebung) ein Geheimnis für 5000-AppSecret erstellt (Punkte sind in Key Vault-Geheimnisnamen nicht zulässig). Dieses Geheimnis stellt ein App-Geheimnis für Version 5.0.0.0 der App dar. Für eine andere Version der App (5.1.0.0) wird dem Tresor (und mit dem Geheimnis-Manager) ein Geheimnis für 5100-AppSecret hinzugefügt. Jede App-Version lädt ihren versionierten Geheimniswert in ihre Konfiguration als AppSecret, wobei die Version entfernt wird, wenn sie das Geheimnis lädt.

AddAzureKeyVault wird mit einer benutzerdefinierten KeyVaultSecretManager-Implementierung aufgerufen:

// using Azure.Extensions.AspNetCore.Configuration.Secrets;

builder.Configuration.AddAzureKeyVault(
    new Uri($"https://{builder.Configuration["KeyVaultName"]}.vault.azure.net/"),
    new DefaultAzureCredential(),
    new SamplePrefixKeyVaultSecretManager("5000"));

Die Implementierung reagiert auf die Versionspräfixe von Geheimnissen, um das richtige Geheimnis in die Konfiguration zu laden:

  • Load lädt ein Geheimnis, wenn sein Name mit dem Präfix beginnt. Andere Geheimnisse werden nicht geladen.
  • GetKey:
    • Entfernt das Präfix aus dem Geheimnisnamen.
    • Ersetzt zwei Bindestriche in einem beliebigen Namen durch das in der Konfiguration verwendete Trennzeichen KeyDelimiter (normalerweise ein Doppelpunkt). Azure Key Vault lässt keinen Doppelpunkt in Geheimnisnamen zu.
public class SamplePrefixKeyVaultSecretManager : KeyVaultSecretManager
{
    private readonly string _prefix;

    public SamplePrefixKeyVaultSecretManager(string prefix)
        => _prefix = $"{prefix}-";

    public override bool Load(SecretProperties properties)
        => properties.Name.StartsWith(_prefix);

    public override string GetKey(KeyVaultSecret secret)
        => secret.Name[_prefix.Length..].Replace("--", ConfigurationPath.KeyDelimiter);
}

Die Load-Methode wird von einem Anbieteralgorithmus aufgerufen, der die Geheimnisse im Tresor durchläuft, um die Geheimnisse mit Versionspräfix zu finden. Wenn ein Versionspräfix mit Load gefunden wird, verwendet der Algorithmus die GetKey-Methode, um den Konfigurationsnamen des Geheimnisnamens zurückzugeben. Er entfernt das Versionspräfix aus dem Namen des Geheimnisses. Der Rest des Geheimnisnamens wird zum Laden in die Name/Wert-Paare der Konfiguration der App zurückgegeben.

Wenn dieser Ansatz implementiert wird:

  1. Die in der Projektdatei der App angegebene Version der App. Im folgenden Beispiel ist die Version der App auf 5.0.0.0 festgelegt:

    <PropertyGroup>
      <Version>5.0.0.0</Version>
    </PropertyGroup>
    
  2. Vergewissern Sie sich, dass eine <UserSecretsId>-Eigenschaft in der Projektdatei der App vorhanden ist, wobei {GUID} eine vom Benutzer bereitgestellte GUID ist:

    <PropertyGroup>
      <UserSecretsId>{GUID}</UserSecretsId>
    </PropertyGroup>
    

    Speichern Sie die folgenden Geheimnisse lokal mit dem Geheimnismanager:

    dotnet user-secrets set "5000-AppSecret" "5.0.0.0_secret_value_dev"
    dotnet user-secrets set "5100-AppSecret" "5.1.0.0_secret_value_dev"
    
  3. Geheimnisse werden mithilfe der folgenden Azure CLI-Befehle im Azure Key Vault gespeichert:

    az keyvault secret set --vault-name {KEY VAULT NAME} --name "5000-AppSecret" --value "5.0.0.0_secret_value_prod"
    az keyvault secret set --vault-name {KEY VAULT NAME} --name "5100-AppSecret" --value "5.1.0.0_secret_value_prod"
    
  4. Wenn die App ausgeführt wird, werden die Key Vault-Geheimnisse geladen. Das Zeichenfolgengeheimnis für 5000-AppSecret wird mit der Version der App abgeglichen, die in der Projektdatei der App (5.0.0.0) angegeben ist.

  5. Die Version 5000 (mit dem Bindestrich) wird aus dem Schlüsselnamen entfernt. In der gesamten App wird beim Lesen der Konfiguration mit dem Schlüssel AppSecret der Geheimniswert geladen.

  6. Wenn die Version der App in der Projektdatei in 5.1.0.0 geändert wird und die App erneut ausgeführt wird, ist der zurückgegebene Geheimwert in der Entwicklungsumgebung 5.1.0.0_secret_value_dev und 5.1.0.0_secret_value_prod in der Produktion.

Hinweis

Sie können auch Ihre eigene SecretClient-Implementierung für AddAzureKeyVault bereitstellen. Ein benutzerdefinierter Client ermöglicht die Freigabe einer einzelnen Instanz des Clients in der gesamten App.

Binden eines Arrays an eine Klasse

Der Anbieter kann Konfigurationswerte für die Bindung an ein POCO-Array in ein Array einlesen.

Beim Lesen aus einer Konfigurationsquelle, die es Schlüsseln erlaubt, Doppelpunkte (:) als Trennzeichen zu enthalten, wird ein numerisches Schlüsselsegment verwendet, um die Schlüssel zu unterscheiden, die ein Array bilden (:0:, :1:, ... :{n}:). Weitere Informationen finden Sie unter Konfiguration: Binden eines Arrays an eine Klasse.

Azure Key Vault-Schlüssel dürfen keinen Doppelpunkt als Trennzeichen verwenden. Der in diesem Artikel beschriebene Ansatz verwendet doppelte Bindestriche (--) als Trennzeichen für hierarchische Werte (Abschnitte). Arrayschlüssel werden in Azure Key Vault mit doppelten Bindestrichen und numerischen Schlüsselsegmenten (--0--, --1--, ... --{n}--) gespeichert.

Untersuchen Sie die folgende Konfiguration des Serilog-Protokollierungsanbieters, die von einer JSON-Datei bereitgestellt wird. Im WriteTo-Array sind zwei Objektliterale definiert, die zwei Serilog-Senken widerspiegeln, welche die Ziele für die Protokollierungsausgabe beschreiben:

"Serilog": {
  "WriteTo": [
    {
      "Name": "AzureTableStorage",
      "Args": {
        "storageTableName": "logs",
        "connectionString": "DefaultEnd...ountKey=Eby8...GMGw=="
      }
    },
    {
      "Name": "AzureDocumentDB",
      "Args": {
        "endpointUrl": "https://contoso.documents.azure.com:443",
        "authorizationKey": "Eby8...GMGw=="
      }
    }
  ]
}

Die in der vorherigen JSON-Datei gezeigte Konfiguration wird in Azure Key Vault mittels doppelter Bindestrich (--)-Notation und numerischen Segmenten gespeichert:

Schlüssel Wert
Serilog--WriteTo--0--Name AzureTableStorage
Serilog--WriteTo--0--Args--storageTableName logs
Serilog--WriteTo--0--Args--connectionString DefaultEnd...ountKey=Eby8...GMGw==
Serilog--WriteTo--1--Name AzureDocumentDB
Serilog--WriteTo--1--Args--endpointUrl https://contoso.documents.azure.com:443
Serilog--WriteTo--1--Args--authorizationKey Eby8...GMGw==

Erneutes Laden von Geheimnissen

Standardmäßig werden Geheimnisse vom Konfigurationsanbieter für die Lebensdauer der App zwischengespeichert. Geheimnisse, die anschließend im Tresor deaktiviert oder aktualisiert wurden, werden von der App ignoriert.

Rufen Sie zum erneuten Laden von Geheimnissen IConfigurationRoot.Reload auf:

config.Reload();

Legen Sie die AzureKeyVaultConfigurationOptions.ReloadInterval-Eigenschaft fest, um Geheimnisse regelmäßig in einem bestimmten Intervall erneut zu laden. Weitere Informationen finden Sie unter Konfigurationsoptionen.

Deaktivierte und abgelaufene Geheimnisse

Abgelaufene Geheimnisse sind standardmäßig im Konfigurationsanbieter enthalten. Um Werte für diese Geheimnisse in der App-Konfiguration auszuschließen, aktualisieren Sie das abgelaufene Geheimnis, oder stellen Sie die Konfiguration mithilfe eines benutzerdefinierten Konfigurationsanbieters bereit:

class SampleKeyVaultSecretManager : KeyVaultSecretManager
{
  public override bool Load(SecretProperties properties) =>
    properties.ExpiresOn.HasValue &&
    properties.ExpiresOn.Value > DateTimeOffset.Now;
}

Übergeben Sie diesen benutzerdefinierten KeyVaultSecretManager an AddAzureKeyVault:

// using Azure.Extensions.AspNetCore.Configuration.Secrets;

builder.Configuration.AddAzureKeyVault(
    new Uri($"https://{builder.Configuration["KeyVaultName"]}.vault.azure.net/"),
    new DefaultAzureCredential(),
    new SampleKeyVaultSecretManager());

Deaktivierte Geheimnisse können nicht aus Key Vault abgerufen werden und sind nie enthalten.

Problembehandlung

Wenn die App die Konfiguration mittels dem Anbieter nicht laden kann, wird eine Fehlermeldung in die ASP.NET Core-Protokollierungsinfrastruktur geschrieben. Die folgenden Bedingungen verhindern, dass die Konfiguration geladen werden kann:

  • Die App oder das Zertifikat ist in Azure AD nicht ordnungsgemäß konfiguriert.
  • Der Tresor ist in Azure Key Vault nicht vorhanden.
  • Die App ist nicht für den Zugriff auf den Tresor autorisiert.
  • Die Zugriffsrichtlinie enthält keine Get- und List-Berechtigungen.
  • Im Tresor sind die Konfigurationsdaten (Name/Wert-Paar) falsch benannt, fehlen oder wurden deaktiviert.
  • Die App weist den falschen Schlüsseltresornamen (KeyVaultName), die falsche Azure AD-Anwendungs-ID (AzureADApplicationId), den falschen Azure AD-Zertifikatfingerabdruck (AzureADCertThumbprint) oder die falsche Azure AD-Verzeichnis-ID (AzureADDirectoryId) auf.
  • Beim Hinzufügen der Key Vault-Zugriffsrichtlinie für die App wurde die Richtlinie zwar erstellt, aber die Schaltfläche Speichern wurde auf der Benutzeroberfläche Zugriffsrichtlinien nicht ausgewählt.

Zusätzliche Ressourcen

In diesem Artikel wird erläutert, wie Sie den Azure Key Vault-Konfigurationsanbieter verwenden, um App-Konfigurationswerte aus Azure Key Vault-Geheimnissen zu laden. Azure Key Vault ist ein cloudbasierter Dienst, der hilft, kryptografische Schlüssel und Geheimnisse zu schützen, die von Cloud-Apps und Clouddiensten verwendet werden. Zu den gängigen Szenarien für die Verwendung von Azure Key Vault mit ASP.NET Core-Apps gehören:

  • Kontrolle des Zugriffs auf vertrauliche Konfigurationsdaten.
  • Erfüllen der Anforderung für FIPS 140-2 Level 2-überprüfte Hardwaresicherheitsmodule (HSMs) beim Speichern von Konfigurationsdaten.

Packages

Fügen Sie Paketverweise für folgende Pakete hinzu:

Beispiel-App

Die Beispiel-App wird in einem von zwei Modi ausgeführt, der von der #define- Präprozessoranweisung am Anfang von Program.cs bestimmt wird:

  • Certificate: Veranschaulicht die Verwendung einer Azure Key Vault-Client-ID und eines X.509-Zertifikats für den Zugriff auf Geheimnisse, die in Azure Key Vault gespeichert sind. Dieses Beispiel kann von jedem beliebigen Speicherort aus ausgeführt werden, unabhängig davon, ob es auf Azure App Service bereitgestellt ist oder auf einem beliebigen Host, der eine ASP.NET Core-Anwendung unterstützen kann.
  • Managed: Veranschaulicht, wie verwaltete Identitäten für Azure-Ressourcen verwendet werden. Die verwaltete Identität authentifiziert die App bei Azure Key Vault mit der Azure Active Directory (AD)-Authentifizierung ohne im Code oder der Konfiguration der App gespeicherte Anmeldeinformationen. Wenn Sie verwaltete Identitäten zur Authentifizierung verwenden, sind keine Azure AD-Anwendungs-ID und kein Kennwort (geheimer Clientschlüssel) erforderlich. Die Managed-Version des Beispiels muss in Azure bereitgestellt sein. Befolgen Sie den Leitfaden im Abschnitt Verwenden der verwalteten Identitäten für Azure-Ressourcen .

Weitere Informationen zum Konfigurieren einer Beispiel-App mithilfe von Präprozessoranweisungen (#define) finden Sie unter Übersicht über ASP.NET Core.

Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)

Geheimnisspeicher in der Entwicklungsumgebung

Legen Sie Geheimnisse mithilfe des Geheimnismanagers lokal fest. Wenn die Beispiel-App auf dem lokalen Computer in der Entwicklungsumgebung ausgeführt wird, werden Geheimnisse aus dem lokalen Benutzergeheimnisspeicher geladen.

Der Geheimnismanager erfordert eine <UserSecretsId>-Eigenschaft in der Projektdatei der App. Legen Sie den Eigenschaftswert ({GUID}) auf eine beliebige eindeutige GUID fest:

<PropertyGroup>
  <UserSecretsId>{GUID}</UserSecretsId>
</PropertyGroup>

Geheimnisse werden als Name/Wert-Paare erstellt. Hierarchische Werte (Konfigurationsabschnitte) verwenden einen : (Doppelpunkt) als Trennzeichen in Schlüsselnamen der ASP.NET Core-Konfiguration.

Der Geheimnismanager wird aus einer Befehlsshell verwendet, die im Inhaltsstamm des Projekts geöffnet wird, wobei {SECRET NAME} der Name und {SECRET VALUE} der Wert ist:

dotnet user-secrets set "{SECRET NAME}" "{SECRET VALUE}"

Führen Sie die folgenden Befehle in einer Befehlsshell aus dem Inhaltsstamm des Projekts aus, um die Geheimnisse für die Beispiel-App festzulegen:

dotnet user-secrets set "SecretName" "secret_value_1_dev"
dotnet user-secrets set "Section:SecretName" "secret_value_2_dev"

Wenn diese Geheimnisse in Azure Key Vault im Abschnitt Geheimnisspeicher in der Produktionsumgebung mit Azure Key Vault gespeichert werden, wird das _dev-Suffix in _prod geändert. Das Suffix stellt einen visuellen Hinweis in der Ausgabe der App bereit, der auf die Quelle der Konfigurationswerte hindeutet.

Geheimnisspeicher in der Produktionsumgebung mit Azure Key Vault

Führen Sie die folgenden Schritte aus, um einen Azure Key Vault zu erstellen und die Geheimnisse der Beispiel-App darin zu speichern. Weitere Informationen finden Sie unter Schnellstart: Festlegen und Abrufen eines Geheimnisses aus Azure Key Vault mithilfe der Azure CLI.

  1. Öffnen Sie Azure Cloud Shell mit einer der folgenden Methoden im Azure-Portal:

    • Klicken Sie in der rechten oberen Ecke eines Codeblocks auf Ausprobieren. Verwenden Sie die Suchzeichenfolge „Azure CLI“ im Textfeld.
    • Öffnen Sie Cloud Shell in Ihrem Browser mit der Schaltfläche Cloud Shell starten.
    • Wählen Sie im Menü in der rechten oberen Ecke im Azure-Portal die Schaltfläche Cloud Shell aus.

    Weitere Informationen finden Sie in unter Azure CLI und Übersicht über Azure Cloud Shell.

  2. Wenn Sie noch nicht authentifiziert sind, melden Sie sich mit dem az login-Befehl an.

  3. Erstellen Sie eine Ressourcengruppe mit dem folgenden Befehl, wobei {RESOURCE GROUP NAME} der Name der neuen Ressourcengruppe und {LOCATION} die Azure-Region ist:

    az group create --name "{RESOURCE GROUP NAME}" --location {LOCATION}
    
  4. Erstellen Sie mit dem folgenden Befehl einen Schlüsseltresor in der Ressourcengruppe, wobei {KEY VAULT NAME} der Name des neuen Tresors und {LOCATION} die Azure-Region ist:

    az keyvault create --name {KEY VAULT NAME} --resource-group "{RESOURCE GROUP NAME}" --location {LOCATION}
    
  5. Erstellen Sie Geheimnisse im Tresor als Name/Wert-Paare.

    Azure Key Vault-Geheimnisnamen sind auf alphanumerische Zeichen und Bindestriche beschränkt. Hierarchische Werte (Konfigurationsabschnitte) verwenden -- (zwei Bindestriche) als Trennzeichen, da Doppelpunkte in Key Vault-Geheimnisnamen nicht zulässig sind. Doppelpunkte trennen einen Abschnitt von einem Unterschlüssel in der ASP.NET Core-Konfiguration. Die Sequenz mit zwei Strichen wird durch einen Doppelpunkt ersetzt, wenn die Geheimnisse in die Konfiguration der App geladen werden.

    Die folgenden Geheimnisse sind für die Verwendung mit der Beispiel-App vorgesehen. Die Werte enthalten ein _prod-Suffix, um sie von den Werten des _dev-Suffixes zu unterscheiden, die vom Geheimnismanager in der Entwicklungsumgebung geladen wurden. Ersetzen Sie {KEY VAULT NAME} durch den Namen des Schlüsseltresors, den Sie im vorherigen Schritt erstellt haben:

    az keyvault secret set --vault-name {KEY VAULT NAME} --name "SecretName" --value "secret_value_1_prod"
    az keyvault secret set --vault-name {KEY VAULT NAME} --name "Section--SecretName" --value "secret_value_2_prod"
    

Verwenden der Anwendungs-ID und des X.509-Zertifikats für nicht von Azure gehostete Apps

Konfigurieren Sie Azure AD, Azure Key Vault und die App für die Verwendung einer Azure AD-Anwendungs-ID und eines X.509-Zertifikats für die Authentifizierung bei einem Tresor, wenn die App außerhalb von Azure gehostet wird. Weitere Informationen finden Sie im Artikel Informationen zu Schlüsseln, Geheimnissen und Zertifikaten.

Hinweis

Obwohl die Verwendung einer Anwendungs-ID und eines X.509-Zertifikats für in Azure gehostete Apps unterstützt wird, wird dies nicht empfohlen. Verwenden Sie stattdessen Verwaltete Identitäten für Azure-Ressourcen, wenn Sie eine App in Azure hosten. Verwaltete Identitäten erfordern kein Speichern eines Zertifikats in der App oder in der Entwicklungsumgebung.

Die Beispiel-App verwendet eine Anwendungs-ID und ein X.509-Zertifikat, wenn die #define-Präprozessoranweisung oben in Program.cs auf Certificate festgelegt ist.

  1. Erstellen Sie ein PKCS#12-Archivzertifikat (.pfx). Optionen zum Erstellen von Zertifikaten umfassen New-SelfSignedCertificate unter Windows und OpenSSL.
  2. Installieren Sie das Zertifikat im persönlichen Zertifikatspeicher des aktuellen Benutzers. Das Markieren des Schlüssels als exportierbar ist optional. Notieren Sie sich den Fingerabdruck des Zertifikats, der später in diesem Prozess verwendet wird.
  3. Exportieren Sie das PKCS#12-Archivzertifikat (.pfx) als DER-codiertes Zertifikat (.cer).
  4. Registrieren Sie die App mit Azure AD (App-Registrierungen).
  5. Laden Sie das DER-codierte Zertifikat (.cer) in Azure AD hoch:
    1. Wählen Sie die App in Azure AD aus.
    2. Navigieren Sie zu Zertifikate und Geheimnisse.
    3. Wählen Sie Zertifikat hochladen aus, um das Zertifikat hochzuladen, das den öffentlichen Schlüssel enthält. Ein .cer-, .pem- oder .crt-Zertifikat ist akzeptabel.
  6. Speichern Sie den Schlüsseltresornamen, die Anwendungs-ID und den Zertifikatfingerabdruck in der Datei appsettings.json der App.
  7. Navigieren Sie im Azure-Portal zu Schlüsseltresore.
  8. Wählen Sie den Schlüsseltresor aus, den Sie im Abschnitt Geheimnisspeicher in der Produktionsumgebung mit Azure Key Vault erstellt haben.
  9. Klicken Sie auf Zugriffsrichtlinien.
  10. Wählen Sie Zugriffsrichtlinie hinzufügen aus.
  11. Öffnen Sie Geheimnisberechtigungen, und stellen Sie der App die Berechtigungen Abrufen und Auflisten bereit.
  12. Wählen Sie Prinzipal auswählen aus, und wählen Sie dann die registrierte App anhand des Namens aus. Wählen Sie die Schaltfläche Auswählen aus.
  13. Klicken Sie auf OK.
  14. Wählen Sie Speichern aus.
  15. Stellen Sie die App bereit.

Die Certificate-Beispiel-App erhält ihre Konfigurationswerte von IConfigurationRoot mit demselben Namen wie der Geheimnisname:

  • Nicht hierarchische Werte: Der Wert für SecretName wird mit config["SecretName"] erhalten.
  • Hierarchische Werte (Abschnitte): Verwenden Sie die : (Doppelpunkt)-Notation oder die GetSection-Methode. Verwenden Sie einen der folgenden Ansätze, um den Konfigurationswert zu erhalten:
    • config["Section:SecretName"]
    • config.GetSection("Section")["SecretName"]

Das X.509-Zertifikat wird vom Betriebssystem verwaltet. Die App ruft AddAzureKeyVault mit Werten auf, die von der appsettings.json-Datei bereitgestellt werden:

// using System.Linq;
// using System.Security.Cryptography.X509Certificates;
// using Azure.Extensions.AspNetCore.Configuration.Secrets;
// using Azure.Identity;

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((context, config) =>
        {
            if (context.HostingEnvironment.IsProduction())
            {
                var builtConfig = config.Build();

                using var store = new X509Store(StoreLocation.CurrentUser);
                store.Open(OpenFlags.ReadOnly);
                var certs = store.Certificates.Find(
                    X509FindType.FindByThumbprint,
                    builtConfig["AzureADCertThumbprint"], false);

                config.AddAzureKeyVault(new Uri($"https://{builtConfig["KeyVaultName"]}.vault.azure.net/"),
                                        new ClientCertificateCredential(builtConfig["AzureADDirectoryId"], builtConfig["AzureADApplicationId"], certs.OfType<X509Certificate2>().Single()),
                                        new KeyVaultSecretManager());

                store.Close();
            }
        })
        .ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup<Startup>());

Beispielwerte:

  • Name des Schlüsseltresors: contosovault
  • Anwendungs-ID: 627e911e-43cc-61d4-992e-12db9c81b413
  • Zertifikatfingerabdruck: fe14593dd66b2406c5269d742d04b6e1ab03adb1

appsettings.json:

{
  "KeyVaultName": "Key Vault Name",
  "AzureADApplicationId": "Azure AD Application ID",
  "AzureADCertThumbprint": "Azure AD Certificate Thumbprint",
  "AzureADDirectoryId": "Azure AD Directory ID"
}

Wenn Sie die App ausführen, werden auf einer Webseite die geladenen Geheimniswerte angezeigt. In der Entwicklungsumgebung werden Geheimniswerte mit dem _dev-Suffix geladen. In der Produktionsumgebung werden die Werte mit dem _prod-Suffix geladen.

Verwenden von verwalteten Identitäten für Azure-Ressourcen

Eine in Azure bereitgestellte App kann verwaltete Identitäten für Azure-Ressourcen nutzen. Eine verwaltete Identität ermöglicht der App die Authentifizierung bei Azure Key Vault mithilfe der Azure AD-Authentifizierung ohne in der App gespeicherte Anmeldeinformationen (Anwendungs-ID und Kennwort/Clientgeheimnis).

Die Beispiel-App verwendet verwaltete Identitäten für Azure-Ressourcen, wenn die #define Präprozessoranweisung oben in Program.cs auf Managed festgelegt ist.

Geben Sie den Tresornamen in die appsettings.json-Datei der App ein. Die Beispiel-App erfordert keine Anwendungs-ID und kein Kennwort (geheimer Clientschlüssel), wenn sie auf die Managed-Version festgelegt ist, sodass Sie diese Konfigurationseinträge ignorieren können. Die App wird in Azure bereitgestellt, und Azure authentifiziert die App für den Zugriff auf Azure Key Vault nur mithilfe des in der appsettings.json-Datei gespeicherten Tresornamens.

Stellen Sie die Beispiel-App in Azure App Service bereit.

Eine in Azure App Service bereitgestellte App wird automatisch bei Azure AD registriert, wenn der Dienst erstellt wird. Rufen Sie die Objekt-ID aus der Bereitstellung zur Verwendung im folgenden Befehl ab. Die Objekt-ID wird im Azure-Portal im Identity Bereich von App Service angezeigt.

Weisen Sie der App mithilfe der Azure-Befehlszeilenschnittstelle und der Objekt-ID der App die Berechtigungen list und get für den Zugriff auf den Schlüsseltresor zu:

az keyvault set-policy --name {KEY VAULT NAME} --object-id {OBJECT ID} --secret-permissions get list

Starten Sie die App neu mittels der Azure CLI, PowerShell oder dem Azure-Portal.

Die Beispiel-App:

  • Erstellt eine Instanz der DefaultAzureCredential-Klasse. Die Anmeldeinformationen versuchen, ein Zugriffstoken aus der Umgebung für Azure-Ressourcen abzurufen.
  • Ein neues SecretClient wird mit der DefaultAzureCredential-Instanz erstellt.
  • Die SecretClient-Instanz wird mit einer KeyVaultSecretManager-Instanz verwendet, die Geheimniswerte lädt und doppelte Bindestriche (--) durch Doppelpunkte (:) in Schlüsselnamen ersetzt.
// using Azure.Security.KeyVault.Secrets;
// using Azure.Identity;
// using Azure.Extensions.AspNetCore.Configuration.Secrets;

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((context, config) =>
        {
            if (context.HostingEnvironment.IsProduction())
            {
                var builtConfig = config.Build();
                var secretClient = new SecretClient(
                    new Uri($"https://{builtConfig["KeyVaultName"]}.vault.azure.net/"),
                    new DefaultAzureCredential());
                config.AddAzureKeyVault(secretClient, new KeyVaultSecretManager());
            }
        })
        .ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup<Startup>());

Beispielwert für den Schlüsseltresornamen: contosovault

appsettings.json:

{
  "KeyVaultName": "Key Vault Name"
}

Wenn Sie die App ausführen, werden auf einer Webseite die geladenen Geheimniswerte angezeigt. In der Entwicklungsumgebung haben Geheimniswerte das _dev-Suffix, da sie vom Geheimnismanager bereitgestellt werden. In der Produktionsumgebung werden die Werte mit dem _prod-Suffix geladen, da sie von Azure Key Vault bereitgestellt werden.

Wenn Sie einen Access denied-Fehler erhalten, vergewissern Sie sich, dass die App bei Azure AD registriert ist und Zugriff auf den Tresor erhalten hat. Vergewissern Sie sich, dass Sie den Dienst in Azure neu gestartet haben.

Informationen zur Verwendung des Anbieters mit einer verwalteten Identität und Azure Pipelines finden Sie unter Erstellen einer Azure Resource Manager-Dienstverbindung mit einer VM mit einer verwalteten Dienstidentität.

Konfigurationsoptionen

AddAzureKeyVault kann ein AzureKeyVaultConfigurationOptions-Objekt akzeptieren:

config.AddAzureKeyVault(
    new SecretClient(
        new Uri("Your Key Vault Endpoint"),
        new DefaultAzureCredential(),
        new AzureKeyVaultConfigurationOptions())
    {
        ...
    });

Das AzureKeyVaultConfigurationOptions-Objekt enthält die folgenden Eigenschaften.

Eigenschaft Beschreibung
Manager KeyVaultSecretManager-Instanz, die zum Steuern des Ladevorgangs für Geheimnisse verwendet wird.
ReloadInterval TimeSpan zum Warten zwischen Versuchen, den Tresor auf Änderungen abzurufen. Der Standardwert ist null (die Konfiguration wird nicht neu geladen).

Verwenden eines Schlüsselnamenpräfixes

AddAzureKeyVault stellt eine Überladung bereit, die eine Implementierung von KeyVaultSecretManager akzeptiert, mit der Sie steuern können, wie Key Vault-Geheimnisse in Konfigurationsschlüssel konvertiert werden. Beispielsweise können Sie die Schnittstelle implementieren, um Geheimniswerte basierend auf einem Präfixwert zu laden, den Sie beim Starten der App angeben. Mit dieser Technik können Sie beispielsweise Geheimnisse basierend auf der Version der App laden.

Warnung

Verwenden Sie Präfixe für Key Vault-Geheimnisse nicht für Folgendes:

  • Platzieren von Geheimnissen für mehrere Apps im selben Tresor.
  • Platzieren von Umgebungsgeheimnissen (z. B. Geheimnisse für Entwicklung und Produktion) im selben Tresor.

Verschiedene Apps und Entwicklungs-/Produktionsumgebungen sollten separate Schlüsseltresore verwenden, um App-Umgebungen für ein Höchstmaß an Sicherheit zu isolieren.

Im folgenden Beispiel wird in Key Vault (und mit dem Geheimnis-Manager für die Entwicklungsumgebung) ein Geheimnis für 5000-AppSecret erstellt (Punkte sind in Key Vault-Geheimnisnamen nicht zulässig). Dieses Geheimnis stellt ein App-Geheimnis für Version 5.0.0.0 der App dar. Für eine andere Version der App (5.1.0.0) wird dem Tresor (und mit dem Geheimnis-Manager) ein Geheimnis für 5100-AppSecret hinzugefügt. Jede App-Version lädt ihren versionierten Geheimniswert in ihre Konfiguration als AppSecret, wobei die Version entfernt wird, wenn sie das Geheimnis lädt.

AddAzureKeyVault wird mit einer benutzerdefinierten KeyVaultSecretManager-Implementierung aufgerufen:

config.AddAzureKeyVault(
    $"https://{builtConfig["KeyVaultName"]}.vault.azure.net/",
    builtConfig["AzureADApplicationId"],
    certs.OfType<X509Certificate2>().Single(),
    new PrefixKeyVaultSecretManager(versionPrefix));

Die Implementierung reagiert auf die Versionspräfixe von Geheimnissen, um das richtige Geheimnis in die Konfiguration zu laden:

  • Load lädt ein Geheimnis, wenn sein Name mit dem Präfix beginnt. Andere Geheimnisse werden nicht geladen.
  • GetKey:
    • Entfernt das Präfix aus dem Geheimnisnamen.
    • Ersetzt zwei Bindestriche in einem beliebigen Namen durch das in der Konfiguration verwendete Trennzeichen KeyDelimiter (normalerweise ein Doppelpunkt). Azure Key Vault lässt keinen Doppelpunkt in Geheimnisnamen zu.
public class PrefixKeyVaultSecretManager : KeyVaultSecretManager
{
    private readonly string _prefix;

    public PrefixKeyVaultSecretManager(string prefix)
    {
        _prefix = $"{prefix}-";
    }

    public override bool Load(SecretProperties secret)
    {
        return secret.Name.StartsWith(_prefix);
    }

    public override string GetKey(KeyVaultSecret secret)
    {
        return secret.Name
            .Substring(_prefix.Length)
            .Replace("--", ConfigurationPath.KeyDelimiter);
    }
}

Die Load-Methode wird von einem Anbieteralgorithmus aufgerufen, der die Geheimnisse im Tresor durchläuft, um die Geheimnisse mit Versionspräfix zu finden. Wenn ein Versionspräfix mit Load gefunden wird, verwendet der Algorithmus die GetKey-Methode, um den Konfigurationsnamen des Geheimnisnamens zurückzugeben. Er entfernt das Versionspräfix aus dem Namen des Geheimnisses. Der Rest des Geheimnisnamens wird zum Laden in die Name/Wert-Paare der Konfiguration der App zurückgegeben.

Wenn dieser Ansatz implementiert wird:

  1. Die in der Projektdatei der App angegebene Version der App. Im folgenden Beispiel ist die Version der App auf 5.0.0.0 festgelegt:

    <PropertyGroup>
      <Version>5.0.0.0</Version>
    </PropertyGroup>
    
  2. Vergewissern Sie sich, dass eine <UserSecretsId>-Eigenschaft in der Projektdatei der App vorhanden ist, wobei {GUID} eine vom Benutzer bereitgestellte GUID ist:

    <PropertyGroup>
      <UserSecretsId>{GUID}</UserSecretsId>
    </PropertyGroup>
    

    Speichern Sie die folgenden Geheimnisse lokal mit dem Geheimnismanager:

    dotnet user-secrets set "5000-AppSecret" "5.0.0.0_secret_value_dev"
    dotnet user-secrets set "5100-AppSecret" "5.1.0.0_secret_value_dev"
    
  3. Geheimnisse werden mithilfe der folgenden Azure CLI-Befehle im Azure Key Vault gespeichert:

    az keyvault secret set --vault-name {KEY VAULT NAME} --name "5000-AppSecret" --value "5.0.0.0_secret_value_prod"
    az keyvault secret set --vault-name {KEY VAULT NAME} --name "5100-AppSecret" --value "5.1.0.0_secret_value_prod"
    
  4. Wenn die App ausgeführt wird, werden die Key Vault-Geheimnisse geladen. Das Zeichenfolgengeheimnis für 5000-AppSecret wird mit der Version der App abgeglichen, die in der Projektdatei der App (5.0.0.0) angegeben ist.

  5. Die Version 5000 (mit dem Bindestrich) wird aus dem Schlüsselnamen entfernt. In der gesamten App wird beim Lesen der Konfiguration mit dem Schlüssel AppSecret der Geheimniswert geladen.

  6. Wenn die Version der App in der Projektdatei in 5.1.0.0 geändert wird und die App erneut ausgeführt wird, ist der zurückgegebene Geheimwert in der Entwicklungsumgebung 5.1.0.0_secret_value_dev und 5.1.0.0_secret_value_prod in der Produktion.

Hinweis

Sie können auch Ihre eigene SecretClient-Implementierung für AddAzureKeyVault bereitstellen. Ein benutzerdefinierter Client ermöglicht die Freigabe einer einzelnen Instanz des Clients in der gesamten App.

Binden eines Arrays an eine Klasse

Der Anbieter kann Konfigurationswerte für die Bindung an ein POCO-Array in ein Array einlesen.

Beim Lesen aus einer Konfigurationsquelle, die es Schlüsseln erlaubt, Doppelpunkte (:) als Trennzeichen zu enthalten, wird ein numerisches Schlüsselsegment verwendet, um die Schlüssel zu unterscheiden, die ein Array bilden (:0:, :1:, ... :{n}:). Weitere Informationen finden Sie unter Konfiguration: Binden eines Arrays an eine Klasse.

Azure Key Vault-Schlüssel dürfen keinen Doppelpunkt als Trennzeichen verwenden. Der in diesem Artikel beschriebene Ansatz verwendet doppelte Bindestriche (--) als Trennzeichen für hierarchische Werte (Abschnitte). Arrayschlüssel werden in Azure Key Vault mit doppelten Bindestrichen und numerischen Schlüsselsegmenten (--0--, --1--, ... --{n}--) gespeichert.

Untersuchen Sie die folgende Konfiguration des Serilog-Protokollierungsanbieters, die von einer JSON-Datei bereitgestellt wird. Im WriteTo-Array sind zwei Objektliterale definiert, die zwei Serilog-Senken widerspiegeln, welche die Ziele für die Protokollierungsausgabe beschreiben:

"Serilog": {
  "WriteTo": [
    {
      "Name": "AzureTableStorage",
      "Args": {
        "storageTableName": "logs",
        "connectionString": "DefaultEnd...ountKey=Eby8...GMGw=="
      }
    },
    {
      "Name": "AzureDocumentDB",
      "Args": {
        "endpointUrl": "https://contoso.documents.azure.com:443",
        "authorizationKey": "Eby8...GMGw=="
      }
    }
  ]
}

Die in der vorherigen JSON-Datei gezeigte Konfiguration wird in Azure Key Vault mittels doppelter Bindestrich (--)-Notation und numerischen Segmenten gespeichert:

Schlüssel Wert
Serilog--WriteTo--0--Name AzureTableStorage
Serilog--WriteTo--0--Args--storageTableName logs
Serilog--WriteTo--0--Args--connectionString DefaultEnd...ountKey=Eby8...GMGw==
Serilog--WriteTo--1--Name AzureDocumentDB
Serilog--WriteTo--1--Args--endpointUrl https://contoso.documents.azure.com:443
Serilog--WriteTo--1--Args--authorizationKey Eby8...GMGw==

Erneutes Laden von Geheimnissen

Geheimnisse werden zwischengespeichert, bis IConfigurationRoot.Reload aufgerufen wird. Im Nachhinein deaktivierte oder aktualisierte Geheimnisse im Tresor werden von der App erst berücksichtigt, wenn Reload ausgeführt wird.

Configuration.Reload();

Deaktivierte und abgelaufene Geheimnisse

Abgelaufene Geheimnisse sind standardmäßig im Konfigurationsanbieter enthalten. Um Werte für diese Geheimnisse in der App-Konfiguration auszuschließen, aktualisieren Sie das abgelaufene Geheimnis, oder stellen Sie die Konfiguration mithilfe eines benutzerdefinierten Konfigurationsanbieters bereit:

class SampleKeyVaultSecretManager : KeyVaultSecretManager
{
  public override bool Load(SecretProperties properties) =>
    properties.ExpiresOn.HasValue &&
    properties.ExpiresOn.Value > DateTimeOffset.Now;
}

Übergeben Sie diesen benutzerdefinierten KeyVaultSecretManager an AddAzureKeyVault:

// using Azure.Extensions.AspNetCore.Configuration.Secrets;

config.AddAzureKeyVault(
    new Uri($"https://{builder.Configuration["KeyVaultName"]}.vault.azure.net/"),
    new DefaultAzureCredential(),
    new SampleKeyVaultSecretManager());

Deaktivierte Geheimnisse können nicht aus Key Vault abgerufen werden und sind nie enthalten.

Problembehandlung

Wenn die App die Konfiguration mittels dem Anbieter nicht laden kann, wird eine Fehlermeldung in die ASP.NET Core-Protokollierungsinfrastruktur geschrieben. Die folgenden Bedingungen verhindern, dass die Konfiguration geladen werden kann:

  • Die App oder das Zertifikat ist in Azure AD nicht ordnungsgemäß konfiguriert.
  • Der Tresor ist in Azure Key Vault nicht vorhanden.
  • Die App ist nicht für den Zugriff auf den Tresor autorisiert.
  • Die Zugriffsrichtlinie enthält keine Get- und List-Berechtigungen.
  • Im Tresor sind die Konfigurationsdaten (Name/Wert-Paar) falsch benannt, fehlen oder wurden deaktiviert.
  • Die App weist den falschen Schlüsseltresornamen (KeyVaultName), die falsche Azure AD-Anwendungs-ID (AzureADApplicationId), den falschen Azure AD-Zertifikatfingerabdruck (AzureADCertThumbprint) oder die falsche Azure AD-Verzeichnis-ID (AzureADDirectoryId) auf.
  • Beim Hinzufügen der Key Vault-Zugriffsrichtlinie für die App wurde die Richtlinie zwar erstellt, aber die Schaltfläche Speichern wurde auf der Benutzeroberfläche Zugriffsrichtlinien nicht ausgewählt.

Zusätzliche Ressourcen