ASP.NET Core 中的 Azure Key Vault 設定提供者Azure Key Vault Configuration Provider in ASP.NET Core

Andrew Stanton-護士By Andrew Stanton-Nurse

本檔說明如何使用Microsoft Azure Key Vault設定提供者,從 Azure Key Vault 秘密載入應用程式設定值。This document explains how to use the Microsoft Azure Key Vault Configuration Provider to load app configuration values from Azure Key Vault secrets. Azure Key Vault 是一種雲端式服務,可協助保護應用程式和服務所使用的密碼編譯金鑰和密碼。Azure Key Vault is a cloud-based service that assists in safeguarding cryptographic keys and secrets used by apps and services. 搭配 ASP.NET Core 應用程式使用 Azure Key Vault 的常見案例包括:Common scenarios for using Azure Key Vault with ASP.NET Core apps include:

  • 控制敏感性設定資料的存取權。Controlling access to sensitive configuration data.
  • 當儲存設定資料時,符合 FIPS 140-2 Level 2 驗證的硬體安全性模組(HSM)的需求。Meeting the requirement for FIPS 140-2 Level 2 validated Hardware Security Modules (HSM's) when storing configuration data.

查看或下載範例程式碼如何下載View or download sample code (how to download)

套件Packages

將套件參考新增至Microsoft.Extensions.Configuration。AzureKeyVault封裝。Add a package reference to the Microsoft.Extensions.Configuration.AzureKeyVault package.

範例應用程式Sample app

範例應用程式會以 Program.cs 檔案頂端的語句所決定的兩種模式之一來執行 #defineProgram.csThe sample app runs in either of two modes determined by the #define statement at the top of the Program.cs file:

  • Certificate:示範如何使用 Azure Key Vault 的用戶端識別碼和 x.509 憑證,來存取儲存在 Azure Key Vault 中的秘密。Certificate: Demonstrates the use of an Azure Key Vault Client ID and X.509 certificate to access secrets stored in Azure Key Vault. 這個版本的範例可以從任何位置執行,部署至 Azure App Service 或任何能夠提供 ASP.NET Core 應用程式的主機。This version of the sample can be run from any location, deployed to Azure App Service or any host capable of serving an ASP.NET Core app.
  • Managed:示範如何使用適用于 Azure 資源的受控識別來驗證應用程式,以在未儲存于應用程式代碼或設定中的認證 Azure AD 驗證 Azure Key Vault。Managed: Demonstrates how to use Managed identities for Azure resources to authenticate the app to Azure Key Vault with Azure AD authentication without credentials stored in the app's code or configuration. 使用受控識別進行驗證時,不需要 Azure AD 應用程式識別碼和密碼(用戶端密碼)。When using managed identities to authenticate, an Azure AD Application ID and Password (Client Secret) aren't required. Managed範例的版本必須部署至 Azure。The Managed version of the sample must be deployed to Azure. 請遵循使用適用于 Azure 資源的受控識別一節中的指導方針。Follow the guidance in the Use the Managed identities for Azure resources section.

如需有關如何使用預處理器指示詞()來設定範例應用程式的詳細資訊 #define ,請參閱 ASP.NET Core 簡介For more information on how to configure a sample app using preprocessor directives (#define), see ASP.NET Core 簡介.

開發環境中的秘密儲存Secret storage in the Development environment

使用秘密管理員工具在本機設定秘密。Set secrets locally using the Secret Manager tool. 當範例應用程式在開發環境中的本機電腦上執行時,會從本機密碼管理員存放區載入秘密。When the sample app runs on the local machine in the Development environment, secrets are loaded from the local Secret Manager store.

「密碼管理員」工具需要 <UserSecretsId> 應用程式專案檔中的屬性。The Secret Manager tool requires a <UserSecretsId> property in the app's project file. 將屬性值( {GUID} )設定為任何唯一的 GUID:Set the property value ({GUID}) to any unique GUID:

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

密碼會以名稱/值組的形式建立。Secrets are created as name-value pairs. 階層式值(設定區段)使用 : (冒號)做為ASP.NET Core設定機碼名稱中的分隔符號。Hierarchical values (configuration sections) use a : (colon) as a separator in ASP.NET Core configuration key names.

密碼管理員會從開啟的命令 shell 使用到專案的內容根目錄,其中 {SECRET NAME} 是名稱,而 {SECRET VALUE} 是值:The Secret Manager is used from a command shell opened to the project's content root, where {SECRET NAME} is the name and {SECRET VALUE} is the value:

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

在命令 shell 中,從專案的內容根目錄執行下列命令,以設定範例應用程式的秘密:Execute the following commands in a command shell from the project's content root to set the secrets for the sample app:

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

當這些秘密儲存在具有 Azure Key Vault 區段之生產環境中的秘密儲存Azure Key Vault 中時, _dev 尾碼會變更為 _prodWhen these secrets are stored in Azure Key Vault in the Secret storage in the Production environment with Azure Key Vault section, the _dev suffix is changed to _prod. 尾碼會在應用程式的輸出中提供視覺提示,指出設定值的來源。The suffix provides a visual cue in the app's output indicating the source of the configuration values.

在生產環境中使用 Azure Key Vault 的秘密儲存Secret storage in the Production environment with Azure Key Vault

以下摘要說明快速入門:從 Azure Key Vault 使用 Azure CLI 主題設定和取出秘密,以建立 Azure Key Vault 並儲存範例應用程式所使用的秘密。The instructions provided by the Quickstart: Set and retrieve a secret from Azure Key Vault using Azure CLI topic are summarized here for creating an Azure Key Vault and storing secrets used by the sample app. 如需進一步的詳細資料,請參閱主題。Refer to the topic for further details.

  1. 使用下列其中一種方法,在Azure 入口網站中開啟 Azure Cloud shell:Open Azure Cloud shell using any one of the following methods in the Azure portal:

    • 選取程式碼區塊右上角的 [試試看]。Select Try It in the upper-right corner of a code block. 在文字方塊中使用搜尋字串 "Azure CLI"。Use the search string "Azure CLI" in the text box.
    • 使用 [啟動 Cloud Shell ] 按鈕,在瀏覽器中開啟 Cloud Shell。Open Cloud Shell in your browser with the Launch Cloud Shell button.
    • 選取 Azure 入口網站右上角功能表上的 [Cloud Shell] 按鈕。Select the Cloud Shell button on the menu in the upper-right corner of the Azure portal.

    如需詳細資訊,請參閱Azure Cloud Shell 的 Azure CLI和總覽。For more information, see Azure CLI and Overview of Azure Cloud Shell.

  2. 如果您尚未驗證,請使用命令登入 az loginIf you aren't already authenticated, sign in with the az login command.

  3. 使用下列命令建立資源群組,其中 {RESOURCE GROUP NAME} 是新資源群組的資源組名,而 {LOCATION} 是 Azure 區域(datacenter):Create a resource group with the following command, where {RESOURCE GROUP NAME} is the resource group name for the new resource group and {LOCATION} is the Azure region (datacenter):

    az group create --name "{RESOURCE GROUP NAME}" --location {LOCATION}
    
  4. 使用下列命令在資源群組中建立 key vault,其中 {KEY VAULT NAME} 是新金鑰保存庫的名稱,而 {LOCATION} 是 Azure 區域(datacenter):Create a key vault in the resource group with the following command, where {KEY VAULT NAME} is the name for the new key vault and {LOCATION} is the Azure region (datacenter):

    az keyvault create --name {KEY VAULT NAME} --resource-group "{RESOURCE GROUP NAME}" --location {LOCATION}
    
  5. 在金鑰保存庫中建立秘密,做為名稱/值配對。Create secrets in the key vault as name-value pairs.

    Azure Key Vault 秘密名稱僅限於英數位元和連字號。Azure Key Vault secret names are limited to alphanumeric characters and dashes. 階層式值(設定區段)使用 -- (兩個虛線)做為分隔符號。Hierarchical values (configuration sections) use -- (two dashes) as a separator. 冒號,通常用來從ASP.NET Core設定中的子機碼分隔區段,但不允許用在金鑰保存庫密碼名稱中。Colons, which are normally used to delimit a section from a subkey in ASP.NET Core configuration, aren't allowed in key vault secret names. 因此,當密碼載入應用程式的設定時,會使用兩個破折號並交換冒號。Therefore, two dashes are used and swapped for a colon when the secrets are loaded into the app's configuration.

    下列秘密可用於範例應用程式。The following secrets are for use with the sample app. 這些值包含後置詞 _prod ,以區別它們與 _dev 開發環境中從使用者秘密載入的尾碼值。The values include a _prod suffix to distinguish them from the _dev suffix values loaded in the Development environment from User Secrets. 將取代 {KEY VAULT NAME} 為您在上一個步驟中建立的金鑰保存庫名稱:Replace {KEY VAULT NAME} with the name of the key vault that you created in the prior step:

    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"
    

將應用程式識別碼和 x.509 憑證用於非 Azure 託管的應用程式Use Application ID and X.509 certificate for non-Azure-hosted apps

設定 Azure AD、Azure Key Vault 和應用程式,以在應用程式裝載于Azure 外部時,使用 Azure Active Directory 應用程式識別碼和 x.509 憑證來驗證金鑰保存庫。Configure Azure AD, Azure Key Vault, and the app to use an Azure Active Directory Application ID and X.509 certificate to authenticate to a key vault when the app is hosted outside of Azure. 如需詳細資訊,請參閱關於金鑰、祕密和憑證For more information, see About keys, secrets, and certificates.

注意

雖然 Azure 中裝載的應用程式支援使用應用程式識別碼和 x.509 憑證,但建議您在 Azure 中裝載應用程式時,使用適用于 azure 資源的受控識別。Although using an Application ID and X.509 certificate is supported for apps hosted in Azure, we recommend using Managed identities for Azure resources when hosting an app in Azure. 受控識別不需要在應用程式中或在開發環境中儲存憑證。Managed identities don't require storing a certificate in the app or in the development environment.

#define Program.cs檔案頂端的語句設定為時,範例應用程式會使用應用程式識別碼和 x.509 憑證 CertificateThe sample app uses an Application ID and X.509 certificate when the #define statement at the top of the Program.cs file is set to Certificate.

  1. 建立 PKCS # 12 封存檔案(.pfx)憑證。Create a PKCS#12 archive (.pfx) certificate. 建立憑證的選項包括WindowsOpenSSL上的 MakeCert。Options for creating certificates include MakeCert on Windows and OpenSSL.
  2. 將憑證安裝到目前使用者的個人憑證存儲。Install the certificate into the current user's personal certificate store. 將金鑰標示為可匯出是選擇性的。Marking the key as exportable is optional. 記下憑證的指紋,這會在此程式稍後使用。Note the certificate's thumbprint, which is used later in this process.
  3. 將 PKCS # 12 封存(.pfx)憑證匯出為 DER 編碼憑證(.cer)。Export the PKCS#12 archive (.pfx) certificate as a DER-encoded certificate (.cer).
  4. 使用 Azure AD (應用程式註冊)註冊應用程式。Register the app with Azure AD (App registrations).
  5. 將 DER 編碼的憑證(.cer)上傳至 Azure AD:Upload the DER-encoded certificate (.cer) to Azure AD:
    1. 在 Azure AD 中選取應用程式。Select the app in Azure AD.
    2. 流覽至 [憑證 & 密碼]。Navigate to Certificates & secrets.
    3. 選取 [上傳憑證] 來上傳包含公開金鑰的憑證。Select Upload certificate to upload the certificate, which contains the public key. .Cerpem.crt憑證是可接受的。A .cer, .pem, or .crt certificate is acceptable.
  6. 將金鑰保存庫名稱、應用程式識別碼和憑證指紋儲存在應用程式的appsettings.js檔案中。Store the key vault name, Application ID, and certificate thumbprint in the app's appsettings.json file.
  7. 流覽至 Azure 入口網站中的 [金鑰保存庫]。Navigate to Key vaults in the Azure portal.
  8. 選取您在生產環境中使用 Azure Key Vault一節所建立的金鑰保存庫。Select the key vault that you created in the Secret storage in the Production environment with Azure Key Vault section.
  9. 選取 [存取原則]。Select Access policies.
  10. 選取 [新增存取原則]。Select Add Access Policy.
  11. 開啟 [秘密許可權],並提供具有 [取得] 和 [列出] 許可權的應用程式。Open Secret permissions and provide the app with Get and List permissions.
  12. 選取 [選取主體],然後依名稱選取已註冊的應用程式。Select Select principal and select the registered app by name. 選取 [選取] 按鈕。Select the Select button.
  13. 選取 [確定] 。Select OK.
  14. 選取 [儲存] 。Select Save.
  15. 部署應用程式。Deploy the app.

Certificate範例應用程式會從 IConfigurationRoot 使用與秘密名稱相同的名稱取得其設定值:The Certificate sample app obtains its configuration values from IConfigurationRoot with the same name as the secret name:

  • 非階層式值:的值 SecretName 是使用取得 config["SecretName"]Non-hierarchical values: The value for SecretName is obtained with config["SecretName"].
  • 階層式值(區段):使用 : (冒號)標記法或 GetSection 擴充方法。Hierarchical values (sections): Use : (colon) notation or the GetSection extension method. 使用下列其中一種方法來取得設定值:Use either of these approaches to obtain the configuration value:
    • config["Section:SecretName"]
    • config.GetSection("Section")["SecretName"]

X.509 憑證是由作業系統所管理。The X.509 certificate is managed by the OS. 應用程式會 AddAzureKeyVault 使用appsettings.json file 所提供的值來呼叫:The app calls AddAzureKeyVault with values supplied by the appsettings.json file:

// using System.Linq;
// using System.Security.Cryptography.X509Certificates;
// using Microsoft.Extensions.Configuration;

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(
                        $"https://{builtConfig["KeyVaultName"]}.vault.azure.net/",
                        builtConfig["AzureADApplicationId"],
                        certs.OfType<X509Certificate2>().Single());

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

範例值:Example values:

  • 金鑰保存庫名稱:contosovaultKey vault name: contosovault
  • 應用程式識別碼:627e911e-43cc-61d4-992e-12db9c81b413Application ID: 627e911e-43cc-61d4-992e-12db9c81b413
  • 憑證指紋:fe14593dd66b2406c5269d742d04b6e1ab03adb1Certificate thumbprint: fe14593dd66b2406c5269d742d04b6e1ab03adb1

appsettings.jsappsettings.json:

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

當您執行應用程式時,網頁會顯示已載入的密碼值。When you run the app, a webpage shows the loaded secret values. 在開發環境中,秘密值會以 _dev 尾碼載入。In the Development environment, secret values load with the _dev suffix. 在生產環境中,值會以後綴載入 _prodIn the Production environment, the values load with the _prod suffix.

使用適用于 Azure 資源的受控識別Use Managed identities for Azure resources

部署至 azure 的應用程式可以利用Azure 資源的受控識別,讓應用程式使用 Azure AD 驗證,而不需要在應用程式中儲存認證(應用程式識別碼和密碼/用戶端密碼)來驗證 Azure Key Vault。An app deployed to Azure can take advantage of Managed identities for Azure resources, which allows the app to authenticate with Azure Key Vault using Azure AD authentication without credentials (Application ID and Password/Client Secret) stored in the app.

#define Program.cs檔案頂端的語句設定為時,範例應用程式會使用適用于 Azure 資源的受控識別 ManagedThe sample app uses Managed identities for Azure resources when the #define statement at the top of the Program.cs file is set to Managed.

在檔案的應用程式appsettings.js中輸入保存庫名稱。Enter the vault name into the app's appsettings.json file. 在設定為版本時,範例應用程式不需要應用程式識別碼和密碼(用戶端密碼) Managed ,因此您可以忽略這些設定專案。The sample app doesn't require an Application ID and Password (Client Secret) when set to the Managed version, so you can ignore those configuration entries. 應用程式會部署至 Azure,而 Azure 只會使用儲存在檔案appsettings.js中的保存庫名稱來驗證應用程式,以存取 Azure Key Vault。The app is deployed to Azure, and Azure authenticates the app to access Azure Key Vault only using the vault name stored in the appsettings.json file.

將範例應用程式部署至 Azure App Service。Deploy the sample app to Azure App Service.

部署到 Azure App Service 的應用程式會在建立服務時,自動向 Azure AD 註冊。An app deployed to Azure App Service is automatically registered with Azure AD when the service is created. 從部署取得物件識別碼,以便在下列命令中使用。Obtain the Object ID from the deployment for use in the following command. 物件識別碼會顯示在 App Service 面板的 Azure 入口網站中 IdentityThe Object ID is shown in the Azure portal on the Identity panel of the App Service.

使用 Azure CLI 和應用程式的物件識別碼,提供應用程式 listget 存取金鑰保存庫的許可權:Using Azure CLI and the app's Object ID, provide the app with list and get permissions to access the key vault:

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

使用 Azure CLI、PowerShell 或 Azure 入口網站重新開機應用程式Restart the app using Azure CLI, PowerShell, or the Azure portal.

範例應用程式:The sample app:

  • 建立 AzureServiceTokenProvider 不含連接字串之類別的實例。Creates an instance of the AzureServiceTokenProvider class without a connection string. 未提供連接字串時,提供者會嘗試從 Azure 資源的受控識別取得存取權杖。When a connection string isn't provided, the provider attempts to obtain an access token from Managed identities for Azure resources.
  • 新的 KeyVaultClient 會使用 AzureServiceTokenProvider 實例 token 回呼來建立。A new KeyVaultClient is created with the AzureServiceTokenProvider instance token callback.
  • KeyVaultClient實例是與的預設執行搭配使用 IKeyVaultSecretManager ,它會載入所有秘密值,並 -- 以冒號()取代索引 : 鍵名稱中的雙破折號()。The KeyVaultClient instance is used with a default implementation of IKeyVaultSecretManager that loads all secret values and replaces double-dashes (--) with colons (:) in key names.
// using Microsoft.Azure.KeyVault;
// using Microsoft.Azure.Services.AppAuthentication;
// using Microsoft.Extensions.Configuration.AzureKeyVault;

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

                var azureServiceTokenProvider = new AzureServiceTokenProvider();
                var keyVaultClient = new KeyVaultClient(
                    new KeyVaultClient.AuthenticationCallback(
                        azureServiceTokenProvider.KeyVaultTokenCallback));

                config.AddAzureKeyVault(
                    $"https://{builtConfig["KeyVaultName"]}.vault.azure.net/",
                    keyVaultClient,
                    new DefaultKeyVaultSecretManager());
            }
        })
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        });

金鑰保存庫名稱範例值:contosovaultKey vault name example value: contosovault

appsettings.jsappsettings.json:

{
  "KeyVaultName": "Key Vault Name"
}

當您執行應用程式時,網頁會顯示已載入的密碼值。When you run the app, a webpage shows the loaded secret values. 在開發環境中,秘密值具有 _dev 尾碼,因為它們是由使用者密碼提供。In the Development environment, secret values have the _dev suffix because they're provided by User Secrets. 在生產環境中,值是以後綴載入, _prod 因為它們是由 Azure Key Vault 所提供。In the Production environment, the values load with the _prod suffix because they're provided by Azure Key Vault.

如果您收到 Access denied 錯誤,請確認已向 Azure AD 註冊應用程式,並提供金鑰保存庫的存取權。If you receive an Access denied error, confirm that the app is registered with Azure AD and provided access to the key vault. 確認您已在 Azure 中重新開機服務。Confirm that you've restarted the service in Azure.

如需將提供者與受控識別和 Azure DevOps 管線搭配使用的詳細資訊,請參閱使用受控服務識別建立 VM 的 Azure Resource Manager 服務連線。For information on using the provider with a managed identity and an Azure DevOps pipeline, see Create an Azure Resource Manager service connection to a VM with a managed service identity.

設定選項Configuration options

AddAzureKeyVault可以接受 AzureKeyVaultConfigurationOptionsAddAzureKeyVault can accept an AzureKeyVaultConfigurationOptions:

config.AddAzureKeyVault(
    new AzureKeyVaultConfigurationOptions()
    {
        ...
    });
屬性Property 說明Description
Client KeyVaultClient用來抓取值。KeyVaultClient to use for retrieving values.
Manager IKeyVaultSecretManager用來控制密碼載入的實例。IKeyVaultSecretManager instance used to control secret loading.
ReloadInterval Timespan在輪詢金鑰保存庫以進行變更的嘗試之間等待。Timespan to wait between attempts at polling the key vault for changes. 預設值為 null (不重載設定)。The default value is null (configuration isn't reloaded).
Vault 金鑰保存庫 URI。Key vault URI.

使用索引鍵名稱前置詞Use a key name prefix

AddAzureKeyVault提供接受的執行的多載 IKeyVaultSecretManager ,可讓您控制如何將金鑰保存庫密碼轉換成設定金鑰。AddAzureKeyVault provides an overload that accepts an implementation of 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.

警告

請勿在金鑰保存庫秘密上使用前置詞,將多個應用程式的秘密放入相同的金鑰保存庫,或將環境秘密(例如開發生產密碼)放入相同的保存庫中。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.

在下列範例中,會在金鑰保存庫中建立秘密(並使用適用于開發環境的秘密管理員工具)來進行 5000-AppSecret (金鑰保存庫密碼名稱中不允許週期)。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). 此秘密代表應用程式版本5.0.0.0 的應用程式密碼。This secret represents an app secret for version 5.0.0.0 of the app. 針對其他版本的應用程式(5.1.0.0),會將密碼新增至金鑰保存庫(並使用密碼管理員工具)來進行 5100-AppSecretFor 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. 每個應用程式版本都會將其版本設定的秘密值載入至其設定中 AppSecret ,因為它會在載入秘密時去除版本。Each app version loads its versioned secret value into its configuration as AppSecret, stripping off the version as it loads the secret.

AddAzureKeyVault使用自訂進行呼叫 IKeyVaultSecretManagerAddAzureKeyVault is called with a custom IKeyVaultSecretManager:

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

執行動作會 IKeyVaultSecretManager 回應秘密的版本前置詞,以將適當的密碼載入設定中:The IKeyVaultSecretManager implementation reacts to the version prefixes of secrets to load the proper secret into configuration:

  • Load在名稱開頭為前置詞時,載入密碼。Load loads a secret when its name starts with the prefix. 其他秘密則不會載入。Other secrets aren't loaded.
  • GetKey:GetKey:
    • 移除秘密名稱中的前置詞。Removes the prefix from the secret name.
    • 將任何名稱中的兩個破折號取代為 KeyDelimiter ,這是設定中使用的分隔符號(通常是冒號)。Replaces two dashes in any name with the KeyDelimiter, which is the delimiter used in configuration (usually a colon). Azure Key Vault 在密碼名稱中不允許冒號。Azure Key Vault doesn't allow a colon in secret names.
public class PrefixKeyVaultSecretManager : IKeyVaultSecretManager
{
    private readonly string _prefix;

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

    public bool Load(SecretItem secret)
    {
        return secret.Identifier.Name.StartsWith(_prefix);
    }

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

Load方法是由可逐一查看保存庫密碼的提供者演算法所呼叫,以尋找具有版本前置詞的金鑰。The Load method is called by a provider algorithm that iterates through the vault secrets to find the ones that have the version prefix. 當找到版本前置詞時 Load ,演算法會使用 GetKey 方法來傳回密碼名稱的設定名稱。When a version prefix is found with Load, the algorithm uses the GetKey method to return the configuration name of the secret name. 它會從密碼的名稱中去除版本前置詞,並傳回其餘的秘密名稱,以載入至應用程式的設定名稱/值配對。It strips off the version prefix from the secret's name and returns the rest of the secret name for loading into the app's configuration name-value pairs.

當此方法執行時:When this approach is implemented:

  1. 應用程式的專案檔中指定的應用程式版本。The app's version specified in the app's project file. 在下列範例中,應用程式的版本會設定為 5.0.0.0In the following example, the app's version is set to 5.0.0.0:

    <PropertyGroup>
      <Version>5.0.0.0</Version>
    </PropertyGroup>
    
  2. 確認 <UserSecretsId> 屬性存在於應用程式的專案檔中,其中 {GUID} 是使用者提供的 GUID:Confirm that a <UserSecretsId> property is present in the app's project file, where {GUID} is a user-supplied GUID:

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

    使用秘密管理員工具在本機儲存下列秘密:Save the following secrets locally with the Secret Manager tool:

    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. 使用下列 Azure CLI 命令,將秘密儲存在 Azure Key Vault 中:Secrets are saved in Azure Key Vault using the following Azure CLI commands:

    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. 當應用程式執行時,會載入金鑰保存庫密碼。When the app is run, the key vault secrets are loaded. 的字串秘密 5000-AppSecret 會符合應用程式的專案檔()中指定的應用程式版本 5.0.0.0The string secret for 5000-AppSecret is matched to the app's version specified in the app's project file (5.0.0.0).

  5. 版本 5000 (含破折號)會從索引鍵名稱中移除。The version, 5000 (with the dash), is stripped from the key name. 在整個應用程式中,使用金鑰來讀取設定會 AppSecret 載入秘密值。Throughout the app, reading configuration with the key AppSecret loads the secret value.

  6. 如果應用程式的版本已在專案檔中變更為 5.1.0.0 ,且應用程式再次執行,則傳回的秘密值會 5.1.0.0_secret_value_dev 在開發環境和 5.1.0.0_secret_value_prod 生產環境中。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.

注意

您也可以將自己的 KeyVaultClient 實作為提供給 AddAzureKeyVaultYou can also provide your own KeyVaultClient implementation to AddAzureKeyVault. 自訂用戶端允許跨應用程式共用單一用戶端實例。A custom client permits sharing a single instance of the client across the app.

將陣列繫結到類別Bind an array to a class

提供者能夠將設定值讀入陣列中,以系結至 POCO 陣列。The provider is capable of reading configuration values into an array for binding to a POCO array.

從允許金鑰包含冒號()分隔符號的設定來源讀取時 : ,會使用數值索引鍵區段來區別組成陣列的索引鍵( :0::1: 、 … :{n}: )。When reading from a configuration source that allows keys to contain colon (:) separators, a numeric key segment is used to distinguish the keys that make up an array (:0:, :1:, … :{n}:). 如需詳細資訊,請參閱Configuration:將陣列系結至類別For more information, see Configuration: Bind an array to a class.

Azure Key Vault 索引鍵不能使用冒號做為分隔符號。Azure Key Vault keys can't use a colon as a separator. 本主題中所述的方法會使用雙虛線( -- )做為階層式值的分隔符號(區段)。The approach described in this topic uses double dashes (--) as a separator for hierarchical values (sections). 陣列索引鍵會以雙虛線和數位索引鍵區段( --0----1-- 、 … --{n}-- )儲存在 Azure Key Vault 中。Array keys are stored in Azure Key Vault with double dashes and numeric key segments (--0--, --1--, … --{n}--).

檢查 JSON 檔案所提供的下列Serilog記錄提供者設定。Examine the following Serilog logging provider configuration provided by a JSON file. 陣列中定義了兩個物件常值 WriteTo ,以反映兩個 Serilog接收,其中描述記錄輸出的目的地:There are two object literals defined in the WriteTo array that reflect two Serilog sinks, which describe destinations for logging output:

"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=="
      }
    }
  ]
}

先前 JSON 檔案中顯示的設定會使用雙虛線( -- )標記法和數值區段儲存在 Azure Key Vault 中:The configuration shown in the preceding JSON file is stored in Azure Key Vault using double dash (--) notation and numeric segments:

KeyKey Value
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==

重載秘密Reload secrets

會快取密碼,直到 IConfigurationRoot.Reload() 呼叫為止。Secrets are cached until IConfigurationRoot.Reload() is called. 在執行之前,應用程式不會遵守金鑰保存庫中已過期、已停用及更新的秘密 ReloadExpired, disabled, and updated secrets in the key vault are not respected by the app until Reload is executed.

Configuration.Reload();

已停用和過期的秘密Disabled and expired secrets

已停用和過期的秘密會擲回 KeyVaultErrorExceptionDisabled and expired secrets throw a KeyVaultErrorException. 若要防止應用程式擲回,請使用不同的設定提供者來提供設定,或更新已停用或已過期的密碼。To prevent the app from throwing, provide the configuration using a different configuration provider or update the disabled or expired secret.

疑難排解Troubleshoot

當應用程式無法使用提供者載入設定時,會將錯誤訊息寫入ASP.NET Core 記錄基礎結構When the app fails to load configuration using the provider, an error message is written to the ASP.NET Core Logging infrastructure. 下列條件將導致無法載入設定:The following conditions will prevent configuration from loading:

  • 應用程式或憑證未在 Azure Active Directory 中正確設定。The app or certificate isn't configured correctly in Azure Active Directory.
  • 金鑰保存庫不存在於 Azure Key Vault 中。The key vault doesn't exist in Azure Key Vault.
  • 應用程式未獲授權,無法存取金鑰保存庫。The app isn't authorized to access the key vault.
  • 存取原則不包含 GetList 許可權。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.
  • 應用程式具有錯誤的金鑰保存庫名稱( KeyVaultName )、Azure AD 應用程式識別碼( AzureADApplicationId ),或 Azure AD 憑證指紋( AzureADCertThumbprint )。The app has the wrong key vault name (KeyVaultName), Azure AD Application Id (AzureADApplicationId), or Azure AD certificate thumbprint (AzureADCertThumbprint).
  • 在應用程式中,設定金鑰(名稱)不正確,因為您嘗試載入的值。The configuration key (name) is incorrect in the app for the value you're trying to load.
  • 將應用程式的存取原則新增至金鑰保存庫時,已建立原則,但未在 [存取原則] UI 中選取 [儲存] 按鈕。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.

其他資源Additional resources

本檔說明如何使用Microsoft Azure Key Vault設定提供者,從 Azure Key Vault 秘密載入應用程式設定值。This document explains how to use the Microsoft Azure Key Vault Configuration Provider to load app configuration values from Azure Key Vault secrets. Azure Key Vault 是一種雲端式服務,可協助保護應用程式和服務所使用的密碼編譯金鑰和密碼。Azure Key Vault is a cloud-based service that assists in safeguarding cryptographic keys and secrets used by apps and services. 搭配 ASP.NET Core 應用程式使用 Azure Key Vault 的常見案例包括:Common scenarios for using Azure Key Vault with ASP.NET Core apps include:

  • 控制敏感性設定資料的存取權。Controlling access to sensitive configuration data.
  • 當儲存設定資料時,符合 FIPS 140-2 Level 2 驗證的硬體安全性模組(HSM)的需求。Meeting the requirement for FIPS 140-2 Level 2 validated Hardware Security Modules (HSM's) when storing configuration data.

查看或下載範例程式碼如何下載View or download sample code (how to download)

套件Packages

將套件參考新增至Microsoft.Extensions.Configuration。AzureKeyVault封裝。Add a package reference to the Microsoft.Extensions.Configuration.AzureKeyVault package.

範例應用程式Sample app

範例應用程式會以 Program.cs 檔案頂端的語句所決定的兩種模式之一來執行 #defineProgram.csThe sample app runs in either of two modes determined by the #define statement at the top of the Program.cs file:

  • Certificate:示範如何使用 Azure Key Vault 的用戶端識別碼和 x.509 憑證,來存取儲存在 Azure Key Vault 中的秘密。Certificate: Demonstrates the use of an Azure Key Vault Client ID and X.509 certificate to access secrets stored in Azure Key Vault. 這個版本的範例可以從任何位置執行,部署至 Azure App Service 或任何能夠提供 ASP.NET Core 應用程式的主機。This version of the sample can be run from any location, deployed to Azure App Service or any host capable of serving an ASP.NET Core app.
  • Managed:示範如何使用適用于 Azure 資源的受控識別來驗證應用程式,以在未儲存于應用程式代碼或設定中的認證 Azure AD 驗證 Azure Key Vault。Managed: Demonstrates how to use Managed identities for Azure resources to authenticate the app to Azure Key Vault with Azure AD authentication without credentials stored in the app's code or configuration. 使用受控識別進行驗證時,不需要 Azure AD 應用程式識別碼和密碼(用戶端密碼)。When using managed identities to authenticate, an Azure AD Application ID and Password (Client Secret) aren't required. Managed範例的版本必須部署至 Azure。The Managed version of the sample must be deployed to Azure. 請遵循使用適用于 Azure 資源的受控識別一節中的指導方針。Follow the guidance in the Use the Managed identities for Azure resources section.

如需有關如何使用預處理器指示詞()來設定範例應用程式的詳細資訊 #define ,請參閱 ASP.NET Core 簡介For more information on how to configure a sample app using preprocessor directives (#define), see ASP.NET Core 簡介.

開發環境中的秘密儲存Secret storage in the Development environment

使用秘密管理員工具在本機設定秘密。Set secrets locally using the Secret Manager tool. 當範例應用程式在開發環境中的本機電腦上執行時,會從本機密碼管理員存放區載入秘密。When the sample app runs on the local machine in the Development environment, secrets are loaded from the local Secret Manager store.

「密碼管理員」工具需要 <UserSecretsId> 應用程式專案檔中的屬性。The Secret Manager tool requires a <UserSecretsId> property in the app's project file. 將屬性值( {GUID} )設定為任何唯一的 GUID:Set the property value ({GUID}) to any unique GUID:

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

密碼會以名稱/值組的形式建立。Secrets are created as name-value pairs. 階層式值(設定區段)使用 : (冒號)做為ASP.NET Core設定機碼名稱中的分隔符號。Hierarchical values (configuration sections) use a : (colon) as a separator in ASP.NET Core configuration key names.

密碼管理員會從開啟的命令 shell 使用到專案的內容根目錄,其中 {SECRET NAME} 是名稱,而 {SECRET VALUE} 是值:The Secret Manager is used from a command shell opened to the project's content root, where {SECRET NAME} is the name and {SECRET VALUE} is the value:

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

在命令 shell 中,從專案的內容根目錄執行下列命令,以設定範例應用程式的秘密:Execute the following commands in a command shell from the project's content root to set the secrets for the sample app:

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

當這些秘密儲存在具有 Azure Key Vault 區段之生產環境中的秘密儲存Azure Key Vault 中時, _dev 尾碼會變更為 _prodWhen these secrets are stored in Azure Key Vault in the Secret storage in the Production environment with Azure Key Vault section, the _dev suffix is changed to _prod. 尾碼會在應用程式的輸出中提供視覺提示,指出設定值的來源。The suffix provides a visual cue in the app's output indicating the source of the configuration values.

在生產環境中使用 Azure Key Vault 的秘密儲存Secret storage in the Production environment with Azure Key Vault

以下摘要說明快速入門:從 Azure Key Vault 使用 Azure CLI 主題設定和取出秘密,以建立 Azure Key Vault 並儲存範例應用程式所使用的秘密。The instructions provided by the Quickstart: Set and retrieve a secret from Azure Key Vault using Azure CLI topic are summarized here for creating an Azure Key Vault and storing secrets used by the sample app. 如需進一步的詳細資料,請參閱主題。Refer to the topic for further details.

  1. 使用下列其中一種方法,在Azure 入口網站中開啟 Azure Cloud shell:Open Azure Cloud shell using any one of the following methods in the Azure portal:

    • 選取程式碼區塊右上角的 [試試看]。Select Try It in the upper-right corner of a code block. 在文字方塊中使用搜尋字串 "Azure CLI"。Use the search string "Azure CLI" in the text box.
    • 使用 [啟動 Cloud Shell ] 按鈕,在瀏覽器中開啟 Cloud Shell。Open Cloud Shell in your browser with the Launch Cloud Shell button.
    • 選取 Azure 入口網站右上角功能表上的 [Cloud Shell] 按鈕。Select the Cloud Shell button on the menu in the upper-right corner of the Azure portal.

    如需詳細資訊,請參閱Azure Cloud Shell 的 Azure CLI和總覽。For more information, see Azure CLI and Overview of Azure Cloud Shell.

  2. 如果您尚未驗證,請使用命令登入 az loginIf you aren't already authenticated, sign in with the az login command.

  3. 使用下列命令建立資源群組,其中 {RESOURCE GROUP NAME} 是新資源群組的資源組名,而 {LOCATION} 是 Azure 區域(datacenter):Create a resource group with the following command, where {RESOURCE GROUP NAME} is the resource group name for the new resource group and {LOCATION} is the Azure region (datacenter):

    az group create --name "{RESOURCE GROUP NAME}" --location {LOCATION}
    
  4. 使用下列命令在資源群組中建立 key vault,其中 {KEY VAULT NAME} 是新金鑰保存庫的名稱,而 {LOCATION} 是 Azure 區域(datacenter):Create a key vault in the resource group with the following command, where {KEY VAULT NAME} is the name for the new key vault and {LOCATION} is the Azure region (datacenter):

    az keyvault create --name {KEY VAULT NAME} --resource-group "{RESOURCE GROUP NAME}" --location {LOCATION}
    
  5. 在金鑰保存庫中建立秘密,做為名稱/值配對。Create secrets in the key vault as name-value pairs.

    Azure Key Vault 秘密名稱僅限於英數位元和連字號。Azure Key Vault secret names are limited to alphanumeric characters and dashes. 階層式值(設定區段)使用 -- (兩個虛線)做為分隔符號。Hierarchical values (configuration sections) use -- (two dashes) as a separator. 冒號,通常用來從ASP.NET Core設定中的子機碼分隔區段,但不允許用在金鑰保存庫密碼名稱中。Colons, which are normally used to delimit a section from a subkey in ASP.NET Core configuration, aren't allowed in key vault secret names. 因此,當密碼載入應用程式的設定時,會使用兩個破折號並交換冒號。Therefore, two dashes are used and swapped for a colon when the secrets are loaded into the app's configuration.

    下列秘密可用於範例應用程式。The following secrets are for use with the sample app. 這些值包含後置詞 _prod ,以區別它們與 _dev 開發環境中從使用者秘密載入的尾碼值。The values include a _prod suffix to distinguish them from the _dev suffix values loaded in the Development environment from User Secrets. 將取代 {KEY VAULT NAME} 為您在上一個步驟中建立的金鑰保存庫名稱:Replace {KEY VAULT NAME} with the name of the key vault that you created in the prior step:

    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"
    

將應用程式識別碼和 x.509 憑證用於非 Azure 託管的應用程式Use Application ID and X.509 certificate for non-Azure-hosted apps

設定 Azure AD、Azure Key Vault 和應用程式,以在應用程式裝載于Azure 外部時,使用 Azure Active Directory 應用程式識別碼和 x.509 憑證來驗證金鑰保存庫。Configure Azure AD, Azure Key Vault, and the app to use an Azure Active Directory Application ID and X.509 certificate to authenticate to a key vault when the app is hosted outside of Azure. 如需詳細資訊,請參閱關於金鑰、祕密和憑證For more information, see About keys, secrets, and certificates.

注意

雖然 Azure 中裝載的應用程式支援使用應用程式識別碼和 x.509 憑證,但建議您在 Azure 中裝載應用程式時,使用適用于 azure 資源的受控識別。Although using an Application ID and X.509 certificate is supported for apps hosted in Azure, we recommend using Managed identities for Azure resources when hosting an app in Azure. 受控識別不需要在應用程式中或在開發環境中儲存憑證。Managed identities don't require storing a certificate in the app or in the development environment.

#define Program.cs檔案頂端的語句設定為時,範例應用程式會使用應用程式識別碼和 x.509 憑證 CertificateThe sample app uses an Application ID and X.509 certificate when the #define statement at the top of the Program.cs file is set to Certificate.

  1. 建立 PKCS # 12 封存檔案(.pfx)憑證。Create a PKCS#12 archive (.pfx) certificate. 建立憑證的選項包括WindowsOpenSSL上的 MakeCert。Options for creating certificates include MakeCert on Windows and OpenSSL.
  2. 將憑證安裝到目前使用者的個人憑證存儲。Install the certificate into the current user's personal certificate store. 將金鑰標示為可匯出是選擇性的。Marking the key as exportable is optional. 記下憑證的指紋,這會在此程式稍後使用。Note the certificate's thumbprint, which is used later in this process.
  3. 將 PKCS # 12 封存(.pfx)憑證匯出為 DER 編碼憑證(.cer)。Export the PKCS#12 archive (.pfx) certificate as a DER-encoded certificate (.cer).
  4. 使用 Azure AD (應用程式註冊)註冊應用程式。Register the app with Azure AD (App registrations).
  5. 將 DER 編碼的憑證(.cer)上傳至 Azure AD:Upload the DER-encoded certificate (.cer) to Azure AD:
    1. 在 Azure AD 中選取應用程式。Select the app in Azure AD.
    2. 流覽至 [憑證 & 密碼]。Navigate to Certificates & secrets.
    3. 選取 [上傳憑證] 來上傳包含公開金鑰的憑證。Select Upload certificate to upload the certificate, which contains the public key. .Cerpem.crt憑證是可接受的。A .cer, .pem, or .crt certificate is acceptable.
  6. 將金鑰保存庫名稱、應用程式識別碼和憑證指紋儲存在應用程式的appsettings.js檔案中。Store the key vault name, Application ID, and certificate thumbprint in the app's appsettings.json file.
  7. 流覽至 Azure 入口網站中的 [金鑰保存庫]。Navigate to Key vaults in the Azure portal.
  8. 選取您在生產環境中使用 Azure Key Vault一節所建立的金鑰保存庫。Select the key vault that you created in the Secret storage in the Production environment with Azure Key Vault section.
  9. 選取 [存取原則]。Select Access policies.
  10. 選取 [新增存取原則]。Select Add Access Policy.
  11. 開啟 [秘密許可權],並提供具有 [取得] 和 [列出] 許可權的應用程式。Open Secret permissions and provide the app with Get and List permissions.
  12. 選取 [選取主體],然後依名稱選取已註冊的應用程式。Select Select principal and select the registered app by name. 選取 [選取] 按鈕。Select the Select button.
  13. 選取 [確定] 。Select OK.
  14. 選取 [儲存] 。Select Save.
  15. 部署應用程式。Deploy the app.

Certificate範例應用程式會從 IConfigurationRoot 使用與秘密名稱相同的名稱取得其設定值:The Certificate sample app obtains its configuration values from IConfigurationRoot with the same name as the secret name:

  • 非階層式值:的值 SecretName 是使用取得 config["SecretName"]Non-hierarchical values: The value for SecretName is obtained with config["SecretName"].
  • 階層式值(區段):使用 : (冒號)標記法或 GetSection 擴充方法。Hierarchical values (sections): Use : (colon) notation or the GetSection extension method. 使用下列其中一種方法來取得設定值:Use either of these approaches to obtain the configuration value:
    • config["Section:SecretName"]
    • config.GetSection("Section")["SecretName"]

X.509 憑證是由作業系統所管理。The X.509 certificate is managed by the OS. 應用程式會 AddAzureKeyVault 使用appsettings.json file 所提供的值來呼叫:The app calls AddAzureKeyVault with values supplied by the appsettings.json file:

// using System.Linq;
// using System.Security.Cryptography.X509Certificates;
// using Microsoft.Extensions.Configuration;

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.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(
                        $"https://{builtConfig["KeyVaultName"]}.vault.azure.net/",
                        builtConfig["AzureADApplicationId"],
                        certs.OfType<X509Certificate2>().Single());

                    store.Close();
                }
            }
        })
        .UseStartup<Startup>();

範例值:Example values:

  • 金鑰保存庫名稱:contosovaultKey vault name: contosovault
  • 應用程式識別碼:627e911e-43cc-61d4-992e-12db9c81b413Application ID: 627e911e-43cc-61d4-992e-12db9c81b413
  • 憑證指紋:fe14593dd66b2406c5269d742d04b6e1ab03adb1Certificate thumbprint: fe14593dd66b2406c5269d742d04b6e1ab03adb1

appsettings.jsappsettings.json:

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

當您執行應用程式時,網頁會顯示已載入的密碼值。When you run the app, a webpage shows the loaded secret values. 在開發環境中,秘密值會以 _dev 尾碼載入。In the Development environment, secret values load with the _dev suffix. 在生產環境中,值會以後綴載入 _prodIn the Production environment, the values load with the _prod suffix.

使用適用于 Azure 資源的受控識別Use Managed identities for Azure resources

部署至 azure 的應用程式可以利用Azure 資源的受控識別,讓應用程式使用 Azure AD 驗證,而不需要在應用程式中儲存認證(應用程式識別碼和密碼/用戶端密碼)來驗證 Azure Key Vault。An app deployed to Azure can take advantage of Managed identities for Azure resources, which allows the app to authenticate with Azure Key Vault using Azure AD authentication without credentials (Application ID and Password/Client Secret) stored in the app.

#define Program.cs檔案頂端的語句設定為時,範例應用程式會使用適用于 Azure 資源的受控識別 ManagedThe sample app uses Managed identities for Azure resources when the #define statement at the top of the Program.cs file is set to Managed.

在檔案的應用程式appsettings.js中輸入保存庫名稱。Enter the vault name into the app's appsettings.json file. 在設定為版本時,範例應用程式不需要應用程式識別碼和密碼(用戶端密碼) Managed ,因此您可以忽略這些設定專案。The sample app doesn't require an Application ID and Password (Client Secret) when set to the Managed version, so you can ignore those configuration entries. 應用程式會部署至 Azure,而 Azure 只會使用儲存在檔案appsettings.js中的保存庫名稱來驗證應用程式,以存取 Azure Key Vault。The app is deployed to Azure, and Azure authenticates the app to access Azure Key Vault only using the vault name stored in the appsettings.json file.

將範例應用程式部署至 Azure App Service。Deploy the sample app to Azure App Service.

部署到 Azure App Service 的應用程式會在建立服務時,自動向 Azure AD 註冊。An app deployed to Azure App Service is automatically registered with Azure AD when the service is created. 從部署取得物件識別碼,以便在下列命令中使用。Obtain the Object ID from the deployment for use in the following command. 物件識別碼會顯示在 App Service 面板的 Azure 入口網站中 IdentityThe Object ID is shown in the Azure portal on the Identity panel of the App Service.

使用 Azure CLI 和應用程式的物件識別碼,提供應用程式 listget 存取金鑰保存庫的許可權:Using Azure CLI and the app's Object ID, provide the app with list and get permissions to access the key vault:

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

使用 Azure CLI、PowerShell 或 Azure 入口網站重新開機應用程式Restart the app using Azure CLI, PowerShell, or the Azure portal.

範例應用程式:The sample app:

  • 建立 AzureServiceTokenProvider 不含連接字串之類別的實例。Creates an instance of the AzureServiceTokenProvider class without a connection string. 未提供連接字串時,提供者會嘗試從 Azure 資源的受控識別取得存取權杖。When a connection string isn't provided, the provider attempts to obtain an access token from Managed identities for Azure resources.
  • 新的 KeyVaultClient 會使用 AzureServiceTokenProvider 實例 token 回呼來建立。A new KeyVaultClient is created with the AzureServiceTokenProvider instance token callback.
  • KeyVaultClient實例是與的預設執行搭配使用 IKeyVaultSecretManager ,它會載入所有秘密值,並 -- 以冒號()取代索引 : 鍵名稱中的雙破折號()。The KeyVaultClient instance is used with a default implementation of IKeyVaultSecretManager that loads all secret values and replaces double-dashes (--) with colons (:) in key names.
// using Microsoft.Azure.KeyVault;
// using Microsoft.Azure.Services.AppAuthentication;
// using Microsoft.Extensions.Configuration.AzureKeyVault;

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

                var azureServiceTokenProvider = new AzureServiceTokenProvider();
                var keyVaultClient = new KeyVaultClient(
                    new KeyVaultClient.AuthenticationCallback(
                        azureServiceTokenProvider.KeyVaultTokenCallback));

                config.AddAzureKeyVault(
                    $"https://{builtConfig["KeyVaultName"]}.vault.azure.net/",
                    keyVaultClient,
                    new DefaultKeyVaultSecretManager());
            }
        })
        .UseStartup<Startup>();

金鑰保存庫名稱範例值:contosovaultKey vault name example value: contosovault

appsettings.jsappsettings.json:

{
  "KeyVaultName": "Key Vault Name"
}

當您執行應用程式時,網頁會顯示已載入的密碼值。When you run the app, a webpage shows the loaded secret values. 在開發環境中,秘密值具有 _dev 尾碼,因為它們是由使用者密碼提供。In the Development environment, secret values have the _dev suffix because they're provided by User Secrets. 在生產環境中,值是以後綴載入, _prod 因為它們是由 Azure Key Vault 所提供。In the Production environment, the values load with the _prod suffix because they're provided by Azure Key Vault.

如果您收到 Access denied 錯誤,請確認已向 Azure AD 註冊應用程式,並提供金鑰保存庫的存取權。If you receive an Access denied error, confirm that the app is registered with Azure AD and provided access to the key vault. 確認您已在 Azure 中重新開機服務。Confirm that you've restarted the service in Azure.

如需將提供者與受控識別和 Azure DevOps 管線搭配使用的詳細資訊,請參閱使用受控服務識別建立 VM 的 Azure Resource Manager 服務連線。For information on using the provider with a managed identity and an Azure DevOps pipeline, see Create an Azure Resource Manager service connection to a VM with a managed service identity.

使用索引鍵名稱前置詞Use a key name prefix

AddAzureKeyVault提供接受的執行的多載 IKeyVaultSecretManager ,可讓您控制如何將金鑰保存庫密碼轉換成設定金鑰。AddAzureKeyVault provides an overload that accepts an implementation of 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.

警告

請勿在金鑰保存庫秘密上使用前置詞,將多個應用程式的秘密放入相同的金鑰保存庫,或將環境秘密(例如開發生產密碼)放入相同的保存庫中。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.

在下列範例中,會在金鑰保存庫中建立秘密(並使用適用于開發環境的秘密管理員工具)來進行 5000-AppSecret (金鑰保存庫密碼名稱中不允許週期)。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). 此秘密代表應用程式版本5.0.0.0 的應用程式密碼。This secret represents an app secret for version 5.0.0.0 of the app. 針對其他版本的應用程式(5.1.0.0),會將密碼新增至金鑰保存庫(並使用密碼管理員工具)來進行 5100-AppSecretFor 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. 每個應用程式版本都會將其版本設定的秘密值載入至其設定中 AppSecret ,因為它會在載入秘密時去除版本。Each app version loads its versioned secret value into its configuration as AppSecret, stripping off the version as it loads the secret.

AddAzureKeyVault使用自訂進行呼叫 IKeyVaultSecretManagerAddAzureKeyVault is called with a custom IKeyVaultSecretManager:

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

執行動作會 IKeyVaultSecretManager 回應秘密的版本前置詞,以將適當的密碼載入設定中:The IKeyVaultSecretManager implementation reacts to the version prefixes of secrets to load the proper secret into configuration:

  • Load在名稱開頭為前置詞時,載入密碼。Load loads a secret when its name starts with the prefix. 其他秘密則不會載入。Other secrets aren't loaded.
  • GetKey:GetKey:
    • 移除秘密名稱中的前置詞。Removes the prefix from the secret name.
    • 將任何名稱中的兩個破折號取代為 KeyDelimiter ,這是設定中使用的分隔符號(通常是冒號)。Replaces two dashes in any name with the KeyDelimiter, which is the delimiter used in configuration (usually a colon). Azure Key Vault 在密碼名稱中不允許冒號。Azure Key Vault doesn't allow a colon in secret names.
public class PrefixKeyVaultSecretManager : IKeyVaultSecretManager
{
    private readonly string _prefix;

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

    public bool Load(SecretItem secret)
    {
        return secret.Identifier.Name.StartsWith(_prefix);
    }

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

Load方法是由可逐一查看保存庫密碼的提供者演算法所呼叫,以尋找具有版本前置詞的金鑰。The Load method is called by a provider algorithm that iterates through the vault secrets to find the ones that have the version prefix. 當找到版本前置詞時 Load ,演算法會使用 GetKey 方法來傳回密碼名稱的設定名稱。When a version prefix is found with Load, the algorithm uses the GetKey method to return the configuration name of the secret name. 它會從密碼的名稱中去除版本前置詞,並傳回其餘的秘密名稱,以載入至應用程式的設定名稱/值配對。It strips off the version prefix from the secret's name and returns the rest of the secret name for loading into the app's configuration name-value pairs.

當此方法執行時:When this approach is implemented:

  1. 應用程式的專案檔中指定的應用程式版本。The app's version specified in the app's project file. 在下列範例中,應用程式的版本會設定為 5.0.0.0In the following example, the app's version is set to 5.0.0.0:

    <PropertyGroup>
      <Version>5.0.0.0</Version>
    </PropertyGroup>
    
  2. 確認 <UserSecretsId> 屬性存在於應用程式的專案檔中,其中 {GUID} 是使用者提供的 GUID:Confirm that a <UserSecretsId> property is present in the app's project file, where {GUID} is a user-supplied GUID:

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

    使用秘密管理員工具在本機儲存下列秘密:Save the following secrets locally with the Secret Manager tool:

    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. 使用下列 Azure CLI 命令,將秘密儲存在 Azure Key Vault 中:Secrets are saved in Azure Key Vault using the following Azure CLI commands:

    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. 當應用程式執行時,會載入金鑰保存庫密碼。When the app is run, the key vault secrets are loaded. 的字串秘密 5000-AppSecret 會符合應用程式的專案檔()中指定的應用程式版本 5.0.0.0The string secret for 5000-AppSecret is matched to the app's version specified in the app's project file (5.0.0.0).

  5. 版本 5000 (含破折號)會從索引鍵名稱中移除。The version, 5000 (with the dash), is stripped from the key name. 在整個應用程式中,使用金鑰來讀取設定會 AppSecret 載入秘密值。Throughout the app, reading configuration with the key AppSecret loads the secret value.

  6. 如果應用程式的版本已在專案檔中變更為 5.1.0.0 ,且應用程式再次執行,則傳回的秘密值會 5.1.0.0_secret_value_dev 在開發環境和 5.1.0.0_secret_value_prod 生產環境中。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.

注意

您也可以將自己的 KeyVaultClient 實作為提供給 AddAzureKeyVaultYou can also provide your own KeyVaultClient implementation to AddAzureKeyVault. 自訂用戶端允許跨應用程式共用單一用戶端實例。A custom client permits sharing a single instance of the client across the app.

將陣列繫結到類別Bind an array to a class

提供者能夠將設定值讀入陣列中,以系結至 POCO 陣列。The provider is capable of reading configuration values into an array for binding to a POCO array.

從允許金鑰包含冒號()分隔符號的設定來源讀取時 : ,會使用數值索引鍵區段來區別組成陣列的索引鍵( :0::1: 、 … :{n}: )。When reading from a configuration source that allows keys to contain colon (:) separators, a numeric key segment is used to distinguish the keys that make up an array (:0:, :1:, … :{n}:). 如需詳細資訊,請參閱Configuration:將陣列系結至類別For more information, see Configuration: Bind an array to a class.

Azure Key Vault 索引鍵不能使用冒號做為分隔符號。Azure Key Vault keys can't use a colon as a separator. 本主題中所述的方法會使用雙虛線( -- )做為階層式值的分隔符號(區段)。The approach described in this topic uses double dashes (--) as a separator for hierarchical values (sections). 陣列索引鍵會以雙虛線和數位索引鍵區段( --0----1-- 、 … --{n}-- )儲存在 Azure Key Vault 中。Array keys are stored in Azure Key Vault with double dashes and numeric key segments (--0--, --1--, … --{n}--).

檢查 JSON 檔案所提供的下列Serilog記錄提供者設定。Examine the following Serilog logging provider configuration provided by a JSON file. 陣列中定義了兩個物件常值 WriteTo ,以反映兩個 Serilog接收,其中描述記錄輸出的目的地:There are two object literals defined in the WriteTo array that reflect two Serilog sinks, which describe destinations for logging output:

"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=="
      }
    }
  ]
}

先前 JSON 檔案中顯示的設定會使用雙虛線( -- )標記法和數值區段儲存在 Azure Key Vault 中:The configuration shown in the preceding JSON file is stored in Azure Key Vault using double dash (--) notation and numeric segments:

KeyKey Value
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==

重載秘密Reload secrets

會快取密碼,直到 IConfigurationRoot.Reload() 呼叫為止。Secrets are cached until IConfigurationRoot.Reload() is called. 在執行之前,應用程式不會遵守金鑰保存庫中已過期、已停用及更新的秘密 ReloadExpired, disabled, and updated secrets in the key vault are not respected by the app until Reload is executed.

Configuration.Reload();

已停用和過期的秘密Disabled and expired secrets

已停用和過期的秘密會擲回 KeyVaultErrorExceptionDisabled and expired secrets throw a KeyVaultErrorException. 若要防止應用程式擲回,請使用不同的設定提供者來提供設定,或更新已停用或已過期的密碼。To prevent the app from throwing, provide the configuration using a different configuration provider or update the disabled or expired secret.

疑難排解Troubleshoot

當應用程式無法使用提供者載入設定時,會將錯誤訊息寫入ASP.NET Core 記錄基礎結構When the app fails to load configuration using the provider, an error message is written to the ASP.NET Core Logging infrastructure. 下列條件將導致無法載入設定:The following conditions will prevent configuration from loading:

  • 應用程式或憑證未在 Azure Active Directory 中正確設定。The app or certificate isn't configured correctly in Azure Active Directory.
  • 金鑰保存庫不存在於 Azure Key Vault 中。The key vault doesn't exist in Azure Key Vault.
  • 應用程式未獲授權,無法存取金鑰保存庫。The app isn't authorized to access the key vault.
  • 存取原則不包含 GetList 許可權。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.
  • 應用程式具有錯誤的金鑰保存庫名稱( KeyVaultName )、Azure AD 應用程式識別碼( AzureADApplicationId ),或 Azure AD 憑證指紋( AzureADCertThumbprint )。The app has the wrong key vault name (KeyVaultName), Azure AD Application Id (AzureADApplicationId), or Azure AD certificate thumbprint (AzureADCertThumbprint).
  • 在應用程式中,設定金鑰(名稱)不正確,因為您嘗試載入的值。The configuration key (name) is incorrect in the app for the value you're trying to load.
  • 將應用程式的存取原則新增至金鑰保存庫時,已建立原則,但未在 [存取原則] UI 中選取 [儲存] 按鈕。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.

其他資源Additional resources