練習 - 存取 Azure Key Vault 中儲存的祕密
您知道啟用 Azure 資源的受控識別如何為您的應用程式建立用於驗證的身分識別。 現在,建立使用該身分識別來存取保存庫中秘密的應用程式。
讀取 ASP.NET Core 應用程式中的祕密
Azure Key Vault API 是一種 REST API,可處理金鑰與保存庫的所有管理和使用方式。 保存庫中的每個秘密都具有唯一的 URL。 秘密值會使用 HTTP GET 要求來擷取。
適用於 .NET Core 的官方 Key Vault 用戶端是 Azure.Security.KeyVault.Secrets
NuGet 套件中的 SecretClient
類別。 不過,您不需要直接使用它。 透過 ASP.NET Core 的 AddAzureKeyVault
方法,您即可在啟動時將保存庫中的所有祕密載入設定 API。 此技術可讓您與設定的其餘部分一樣使用 IConfiguration
介面,依名稱來存取所有祕密。 使用 AddAzureKeyVault
的應用程式同時需要保存庫的 Get
和 List
權限。
提示
不論使用何種架構或語言來建立應用程式,都應該設計成在本機快取祕密值,或在啟動時將祕密值載入記憶體中,除非有具體理由不這麼做。 在每次需要時直接從保存庫中讀取它們,會造成不必要的速度延遲與成本增加。
AddAzureKeyVault
只需要保存庫名稱作為輸入,您是從本機應用程式設定中取得該名稱。 另外還自動處理受控識別驗證。 當 API 用於部署至 Azure App Service 且已啟用 Azure 資源受控識別的應用程式中時。 其會偵測受控識別權杖服務,並使用它來進行驗證。 這很適合用於大部分的案例,而且能實作所有的最佳做法。 您會在此單元的練習中加以使用。
讀取 Node.js 應用程式中的祕密
Azure Key Vault API 是一種 REST API,可處理金鑰與保存庫的所有管理和使用方式。 保存庫中的每個秘密都具有唯一的 URL。 秘密值會使用 HTTP GET 要求來擷取。
適用於 Node.js 應用程式的官方 Key Vault 用戶端是 @azure/keyvault-secrets
npm 套件中的 SecretClient
類別。 如果應用程式的設定或程式碼中包含祕密名稱,則應用程式通常會使用其 getSecret
方法,以根據名稱載入祕密值。 getSecret
要求您應用程式的身分識別必須具有保存庫的 Get
權限。 旨在從保存庫載入所有祕密的應用程式也會使用 listPropertiesOfSecrets
方法,以載入祕密清單並要求 List
權限。
應用程式必須先取得認證物件來向保存庫驗證,才能建立 SecretClient
執行個體。 請使用 @azure/identity
npm 套件提供的 DefaultAzureCredential
驗證身分。 DefaultAzureCredential
適用於應用程式最終要在 Azure 雲端中執行的大多數案例,因為 DefaultAzureCredential
會結合部署時通常用於身份驗證的認證,以及在開發環境中用於身份驗證的認證。 DefaultAzureCredential
嘗試依序使用下列機制進行驗證:
- 環境。
DefaultAzureCredential
會讀取使用環境變數指定的帳戶資訊,並使用它來進行驗證。 - 受控識別。 如果應用程式部署到已啟用受控識別的 Azure 主機,則
DefaultAzureCredential
會使用該帳戶進行驗證。 - Visual Studio Code \(英文\)。 如果開發人員使用 Visual Studio Code Azure 帳戶外掛程式進行驗證,則
DefaultAzureCredential
會使用該帳戶進行驗證。 - Azure CLI。 如果開發人員使用 Azure CLI
az login
命令驗證帳戶,則DefaultAzureCredential
會使用該帳戶進行驗證。
如需詳細資訊,請參閱 文件。
提示
不論使用何種架構或語言來建立應用程式,都應該設計成在本機快取祕密值,或在啟動時將祕密值載入記憶體中,除非有具體理由不這麼做。 在每次需要時直接從保存庫中讀取它們,會造成不必要的速度延遲與成本增加。
處理應用程式中的祕密
在將祕密載入到您的應用程式之後,應用程式必須負責安全地處理祕密。 在您於本課程模組中建置的應用程式內,您會將祕密值寫出到用戶端回應,並在網頁瀏覽器中進行檢視,以證明祕密值已成功載入。 將祕密值傳回給用戶端「不是」您通常應執行的作業! 通常,您會使用祕密來執行一些作業,例如初始化資料庫或遠端 API 的用戶端程式庫。
重要
請務必仔細檢閱程式碼,以確保應用程式絕不會將祕密寫入任何一種輸出,包括記錄、儲存體和回應。
練習
為了從我們的保存庫中載入祕密,您會建立新的 ASP.NET Core Web API,並使用 AddAzureKeyVault
。
建立 應用程式
若要建立新的 ASP.NET Core Web API 應用程式並在編輯器中開啟,請在 Azure Cloud Shell 中執行下列命令。
dotnet new webapi -o KeyVaultDemoApp cd KeyVaultDemoApp code .
編輯器載入後,請新增包含
AddAzureKeyVault
的 NuGet 套件,並還原應用程式的所有相依性。 在 Azure Cloud Shell 中,執行下列命令。dotnet add package Azure.Identity dotnet add package Azure.Extensions.AspNetCore.Configuration.Secrets dotnet restore
新增載入和使用祕密的程式碼
為了示範正確使用 Key Vault,請將應用程式修改成在啟動時從保存庫載入祕密。 您也會新增控制站,而其端點會從保存庫取得 SecretPassword
祕密。
針對應用程式啟動,輸入下列命令以啟動編輯器。
code .
開啟
Program.cs
,刪除內容,換成下列程式碼。using System; using Azure.Identity; using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; namespace KeyVaultDemoApp { public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }) .ConfigureAppConfiguration((context, config) => { // Build the current set of configuration to load values from // JSON files and environment variables, including VaultName. var builtConfig = config.Build(); // Use VaultName from the configuration to create the full vault URI. var vaultName = builtConfig["VaultName"]; Uri vaultUri = new Uri($"https://{vaultName}.vault.azure.net/"); // Load all secrets from the vault into configuration. This will automatically // authenticate to the vault using a managed identity. If a managed identity // is not available, it will check if Visual Studio and/or the Azure CLI are // installed locally and see if they are configured with credentials that can // access the vault. config.AddAzureKeyVault(vaultUri, new DefaultAzureCredential()); }); } }
重要
完成編輯後,請務必儲存檔案。 您可以透過 [...] 功能表或快速鍵 (Windows 和 Linux 上的 Ctrl+S,macOS 上的 Cmd+S) 來儲存檔案。
起始程式碼的唯一變更是新增了
ConfigureAppConfiguration
。 此元素是我們從設定載入保存庫名稱並使用其呼叫AddAzureKeyVault
的位置。針對控制器,在名為
SecretTestController.cs
的Controllers
資料夾中建立新的檔案,並將下列程式碼貼上。提示
若要建立新的檔案,請在 Cloud Shell 中使用
touch
命令。 在此案例中,執行touch Controllers/SecretTestController.cs
命令。 若要在編輯器的 [檔案] 窗格右上角找到它,請選取 [重新整理] 圖示。using System; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; namespace KeyVaultDemoApp.Controllers { [Route("api/[controller]")] public class SecretTestController : ControllerBase { private readonly IConfiguration _configuration; public SecretTestController(IConfiguration configuration) { _configuration = configuration; } [HttpGet] public IActionResult Get() { // Get the secret value from configuration. This can be done anywhere // we have access to IConfiguration. This does not call the Key Vault // API, because the secrets were loaded at startup. var secretName = "SecretPassword"; var secretValue = _configuration[secretName]; if (secretValue == null) { return StatusCode( StatusCodes.Status500InternalServerError, $"Error: No secret named {secretName} was found..."); } else { return Content($"Secret value: {secretValue}" + Environment.NewLine + Environment.NewLine + "This is for testing only! Never output a secret " + "to a response or anywhere else in a real app!"); } } } }
在 Azure Cloud Shell 中執行
dotnet build
命令,並確保所有項目皆能編譯。 應用程式已就緒可執行。 現在是時候將其放入 Azure 了!
使用 Express.js 建立新的 Web API 並使用 @azure/keyvault-secrets
與 @azure/identity
套件從保存庫載入祕密。
建立 應用程式
在 Azure Cloud Shell 中執行下列程式碼,以初始化新的 Node.js 應用程式、安裝需要的套件,然後在編輯器中開啟新檔案。
mkdir KeyVaultDemoApp
cd KeyVaultDemoApp
npm init -y
npm install @azure/identity @azure/keyvault-secrets express
touch app.js
code app.js
新增載入和使用祕密的程式碼
為了示範正確使用 Key Vault,應用程式會在啟動時從保存庫載入祕密。 為了示範您的祕密已載入,請建立顯示 SecretPassword
祕密值的端點。
若要設定應用程式,請將下列程式碼貼到編輯器中。 此程式碼會匯入必要的套件、進行連接埠和保存庫 URI 設定,然後建立新物件以保留祕密名稱和值。
// Importing dependencies const { DefaultAzureCredential } = require("@azure/identity"); const { SecretClient } = require("@azure/keyvault-secrets"); const app = require('express')(); // Initialize port const port = process.env.PORT || 3000; // Create Vault URI from App Settings const vaultUri = `https://${process.env.VaultName}.vault.azure.net/`; // Map of key vault secret names to values let vaultSecretsMap = {};
重要
處理檔案時請務必儲存檔案,特別是當您完成時。 您可以透過 [...] 功能表或快速鍵 (Windows 和 Linux 上的 Ctrl+S,macOS 上的 Cmd+S) 來儲存檔案。
接著,新增程式碼以向保存庫驗證並載入祕密。 您會將此程式碼新增為兩個不同的函式。 在您先前新增的程式碼後方插入一些空白行,然後貼上下列程式碼。
const getKeyVaultSecrets = async () => { // Create a key vault secret client let secretClient = new SecretClient(vaultUri, new DefaultAzureCredential()); try { // Iterate through each secret in the vault listPropertiesOfSecrets = secretClient.listPropertiesOfSecrets(); while (true) { let { done, value } = await listPropertiesOfSecrets.next(); if (done) { break; } // Only load enabled secrets - getSecret will return an error for disabled secrets if (value.enabled) { const secret = await secretClient.getSecret(value.name); vaultSecretsMap[value.name] = secret.value; } } } catch(err) { console.log(err.message) } }
若要測試我們的祕密是否已載入,請建立 Express 端點。 貼上此程式碼。
app.get('/api/SecretTest', (req, res) => { let secretName = 'SecretPassword'; let response; if (secretName in vaultSecretsMap) { response = `Secret value: ${vaultSecretsMap[secretName]}\n\nThis is for testing only! Never output a secret to a response or anywhere else in a real app!`; } else { response = `Error: No secret named ${secretName} was found...` } res.type('text'); res.send(response); });
呼叫函式以從保存庫載入祕密,然後啟動應用程式。 請貼上這個最後的程式碼片段以完成應用程式。
(async () => { await getKeyVaultSecrets(); app.listen(port, () => { console.log(`Server running at http://localhost:${port}`); }); })().catch(err => console.log(err));
您已完成撰寫程式碼,因此請務必儲存檔案。
應用程式已就緒可執行。 現在是時候將其放入 Azure 了!