|
|
|
@ -15,7 +15,7 @@ By [Andrew Stanton-Nurse](https://github.com/anurse)
|
|
|
|
|
|
|
|
|
|
::: moniker range=">= aspnetcore-3.0"
|
|
|
|
|
|
|
|
|
|
This document explains how to use the [Microsoft Azure Key Vault](https://azure.microsoft.com/services/key-vault/) Configuration Provider to load app configuration values from Azure Key Vault secrets. Azure Key Vault is a cloud-based service that assists in safeguarding cryptographic keys and secrets used by apps and services. Common scenarios for using Azure Key Vault with ASP.NET Core apps include:
|
|
|
|
|
This document explains how to use the [Azure Key Vault](https://azure.microsoft.com/services/key-vault/) Configuration Provider to load app configuration values from Azure Key Vault secrets. Azure Key Vault is a cloud-based service that assists in safeguarding cryptographic keys and secrets used by apps and services. Common scenarios for using Azure Key Vault with ASP.NET Core apps include:
|
|
|
|
|
|
|
|
|
|
* Controlling access to sensitive configuration data.
|
|
|
|
|
* Meeting the requirement for FIPS 140-2 Level 2 validated Hardware Security Modules (HSM's) when storing configuration data.
|
|
|
|
@ -24,7 +24,7 @@ This document explains how to use the [Microsoft Azure Key Vault](https://azure.
|
|
|
|
|
|
|
|
|
|
## Packages
|
|
|
|
|
|
|
|
|
|
Add a package reference to the [Microsoft.Extensions.Configuration.AzureKeyVault](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.AzureKeyVault/) package.
|
|
|
|
|
Add a package reference to the [Azure.Extensions.AspNetCore.Configuration.Secrets](https://www.nuget.org/packages/Azure.Extensions.AspNetCore.Configuration.Secrets/) package.
|
|
|
|
|
|
|
|
|
|
## Sample app
|
|
|
|
|
|
|
|
|
@ -136,9 +136,9 @@ The `Certificate` sample app obtains its configuration values from `IConfigurati
|
|
|
|
|
* `config["Section:SecretName"]`
|
|
|
|
|
* `config.GetSection("Section")["SecretName"]`
|
|
|
|
|
|
|
|
|
|
The X.509 certificate is managed by the OS. The app calls <xref:Microsoft.Extensions.Configuration.AzureKeyVaultConfigurationExtensions.AddAzureKeyVault*> with values supplied by the *appsettings.json* file:
|
|
|
|
|
The X.509 certificate is managed by the OS. The app calls **AddAzureKeyVault** with values supplied by the *appsettings.json* file:
|
|
|
|
|
|
|
|
|
|
[!code-csharp[](key-vault-configuration/samples/3.x/SampleApp/Program.cs?name=snippet1&highlight=20-23)]
|
|
|
|
|
[!code-csharp[](key-vault-configuration/samples/3.x/SampleApp/Program.cs?name=snippet1&highlight=46-49)]
|
|
|
|
|
|
|
|
|
|
Example values:
|
|
|
|
|
|
|
|
|
@ -174,14 +174,14 @@ az keyvault set-policy --name {KEY VAULT NAME} --object-id {OBJECT ID} --secret-
|
|
|
|
|
|
|
|
|
|
The sample app:
|
|
|
|
|
|
|
|
|
|
* Creates an instance of the `AzureServiceTokenProvider` class without a connection string. When a connection string isn't provided, the provider attempts to obtain an access token from Managed identities for Azure resources.
|
|
|
|
|
* A new <xref:Microsoft.Azure.KeyVault.KeyVaultClient> is created with the `AzureServiceTokenProvider` instance token callback.
|
|
|
|
|
* The <xref:Microsoft.Azure.KeyVault.KeyVaultClient> instance is used with a default implementation of <xref:Microsoft.Extensions.Configuration.AzureKeyVault.IKeyVaultSecretManager> that loads all secret values and replaces double-dashes (`--`) with colons (`:`) in key names.
|
|
|
|
|
* Creates an instance of the `DefaultAzureCredential` class, the credential attempts to obtain an access token from environment for Azure resources.
|
|
|
|
|
* A new <xref:Azure.Security.KeyVault.Secrets.Secrets> is created with the `DefaultAzureCredential` instance.
|
|
|
|
|
* The <xref:Azure.Security.KeyVault.Secrets.Secrets> instance is used with a default implementation of <xref:Azure.Extensions.Aspnetcore.Configuration.Secrets> that loads all secret values and replaces double-dashes (`--`) with colons (`:`) in key names.
|
|
|
|
|
|
|
|
|
|
[!code-csharp[](key-vault-configuration/samples/3.x/SampleApp/Program.cs?name=snippet2&highlight=13-21)]
|
|
|
|
|
[!code-csharp[](key-vault-configuration/samples/3.x/SampleApp/Program.cs?name=snippet2&highlight=12-14)]
|
|
|
|
|
|
|
|
|
|
Key vault name example value: `contosovault`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*appsettings.json*:
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
@ -198,11 +198,11 @@ For information on using the provider with a managed identity and an Azure DevOp
|
|
|
|
|
|
|
|
|
|
## Configuration options
|
|
|
|
|
|
|
|
|
|
<xref:Microsoft.Extensions.Configuration.AzureKeyVaultConfigurationExtensions.AddAzureKeyVault*> can accept an <xref:Microsoft.Extensions.Configuration.AzureKeyVault.AzureKeyVaultConfigurationOptions>:
|
|
|
|
|
AddAzureKeyVault can accept an AzureKeyVaultConfigurationOptions:
|
|
|
|
|
|
|
|
|
|
```csharp
|
|
|
|
|
config.AddAzureKeyVault(
|
|
|
|
|
new AzureKeyVaultConfigurationOptions()
|
|
|
|
|
config.AddAzureKeyVault(new SecretClient(new URI("Your Key Vault Endpoint"), new DefaultAzureCredential()),
|
|
|
|
|
new AzureKeyVaultConfigurationOptions())
|
|
|
|
|
{
|
|
|
|
|
...
|
|
|
|
|
});
|
|
|
|
@ -210,25 +210,23 @@ config.AddAzureKeyVault(
|
|
|
|
|
|
|
|
|
|
| Property | Description |
|
|
|
|
|
| ---------------- | ----------- |
|
|
|
|
|
| `Client` | <xref:Microsoft.Azure.KeyVault.KeyVaultClient> to use for retrieving values. |
|
|
|
|
|
| `Manager` | <xref:Microsoft.Extensions.Configuration.AzureKeyVault.IKeyVaultSecretManager> instance used to control secret loading. |
|
|
|
|
|
| `Manager` | <xref:Azure.Extensions.Aspnetcore.Configuration.Secrets> instance used to control secret loading. |
|
|
|
|
|
| `ReloadInterval` | `Timespan` to wait between attempts at polling the key vault for changes. The default value is `null` (configuration isn't reloaded). |
|
|
|
|
|
| `Vault` | Key vault URI. |
|
|
|
|
|
|
|
|
|
|
## Use a key name prefix
|
|
|
|
|
|
|
|
|
|
<xref:Microsoft.Extensions.Configuration.AzureKeyVaultConfigurationExtensions.AddAzureKeyVault*> provides an overload that accepts an implementation of <xref:Microsoft.Extensions.Configuration.AzureKeyVault.IKeyVaultSecretManager>, which allows you to control how key vault secrets are converted into configuration keys. For example, you can implement the interface to load secret values based on a prefix value you provide at app startup. This allows you, for example, to load secrets based on the version of the app.
|
|
|
|
|
AddAzureKeyVault provides an overload that accepts an implementation of <xref:Azure.Extensions.Aspnetcore.Configuration.Secrets>, which allows you to control how key vault secrets are converted into configuration keys. For example, you can implement the interface to load secret values based on a prefix value you provide at app startup. This allows you, for example, to load secrets based on the version of the app.
|
|
|
|
|
|
|
|
|
|
> [!WARNING]
|
|
|
|
|
> Don't use prefixes on key vault secrets to place secrets for multiple apps into the same key vault or to place environmental secrets (for example, *development* versus *production* secrets) into the same vault. We recommend that different apps and development/production environments use separate key vaults to isolate app environments for the highest level of security.
|
|
|
|
|
|
|
|
|
|
In the following example, a secret is established in the key vault (and using the Secret Manager tool for the Development environment) for `5000-AppSecret` (periods aren't allowed in key vault secret names). This secret represents an app secret for version 5.0.0.0 of the app. For another version of the app, 5.1.0.0, a secret is added to the key vault (and using the Secret Manager tool) for `5100-AppSecret`. Each app version loads its versioned secret value into its configuration as `AppSecret`, stripping off the version as it loads the secret.
|
|
|
|
|
|
|
|
|
|
<xref:Microsoft.Extensions.Configuration.AzureKeyVaultConfigurationExtensions.AddAzureKeyVault*> is called with a custom <xref:Microsoft.Extensions.Configuration.AzureKeyVault.IKeyVaultSecretManager>:
|
|
|
|
|
AddAzureKeyVault is called with a custom <xref:Azure.Extensions.Aspnetcore.Configuration.Secrets>:
|
|
|
|
|
|
|
|
|
|
[!code-csharp[](key-vault-configuration/samples_snapshot/Program.cs)]
|
|
|
|
|
|
|
|
|
|
The <xref:Microsoft.Extensions.Configuration.AzureKeyVault.IKeyVaultSecretManager> implementation reacts to the version prefixes of secrets to load the proper secret into configuration:
|
|
|
|
|
The <xref:Azure.Extensions.Aspnetcore.Configuration.Secrets> implementation reacts to the version prefixes of secrets to load the proper secret into configuration:
|
|
|
|
|
|
|
|
|
|
* `Load` loads a secret when its name starts with the prefix. Other secrets aren't loaded.
|
|
|
|
|
* `GetKey`:
|
|
|
|
@ -278,7 +276,7 @@ When this approach is implemented:
|
|
|
|
|
1. If the app's version is changed in the project file to `5.1.0.0` and the app is run again, the secret value returned is `5.1.0.0_secret_value_dev` in the Development environment and `5.1.0.0_secret_value_prod` in Production.
|
|
|
|
|
|
|
|
|
|
> [!NOTE]
|
|
|
|
|
> You can also provide your own <xref:Microsoft.Azure.KeyVault.KeyVaultClient> implementation to <xref:Microsoft.Extensions.Configuration.AzureKeyVaultConfigurationExtensions.AddAzureKeyVault*>. A custom client permits sharing a single instance of the client across the app.
|
|
|
|
|
> You can also provide your own <xref:Azure.Security.KeyVault.Secrets.SecretClient> implementation to AddAzureKeyVault. A custom client permits sharing a single instance of the client across the app.
|
|
|
|
|
|
|
|
|
|
## Bind an array to a class
|
|
|
|
|
|
|
|
|
@ -332,7 +330,7 @@ Configuration.Reload();
|
|
|
|
|
|
|
|
|
|
## Disabled and expired secrets
|
|
|
|
|
|
|
|
|
|
Disabled and expired secrets throw a <xref:Microsoft.Azure.KeyVault.Models.KeyVaultErrorException>. To prevent the app from throwing, provide the configuration using a different configuration provider or update the disabled or expired secret.
|
|
|
|
|
Disabled and expired secrets throw a <xref:Azure.RequestFailedException>. To prevent the app from throwing, provide the configuration using a different configuration provider or update the disabled or expired secret.
|
|
|
|
|
|
|
|
|
|
## Troubleshoot
|
|
|
|
|
|
|
|
|
@ -343,7 +341,7 @@ When the app fails to load configuration using the provider, an error message is
|
|
|
|
|
* The app isn't authorized to access the key vault.
|
|
|
|
|
* The access policy doesn't include `Get` and `List` permissions.
|
|
|
|
|
* In the key vault, the configuration data (name-value pair) is incorrectly named, missing, disabled, or expired.
|
|
|
|
|
* The app has the wrong key vault name (`KeyVaultName`), Azure AD Application Id (`AzureADApplicationId`), or Azure AD certificate thumbprint (`AzureADCertThumbprint`).
|
|
|
|
|
* The app has the wrong key vault name (`KeyVaultName`), Azure AD Application Id (`AzureADApplicationId`), or Azure AD certificate thumbprint (`AzureADCertThumbprint`), or Azure AD DirectoryId (`AzureADDirectoryId`).
|
|
|
|
|
* The configuration key (name) is incorrect in the app for the value you're trying to load.
|
|
|
|
|
* When adding the access policy for the app to the key vault, the policy was created, but the **Save** button wasn't selected in the **Access policies** UI.
|
|
|
|
|
|
|
|
|
@ -685,4 +683,3 @@ When the app fails to load configuration using the provider, an error message is
|
|
|
|
|
* [Tutorial: How to use Azure Key Vault with Azure Windows Virtual Machine in .NET](/azure/key-vault/tutorial-net-windows-virtual-machine)
|
|
|
|
|
|
|
|
|
|
::: moniker-end
|
|
|
|
|
|
|
|
|
|