.Net Framework 4/4.5应用中不依赖ClientID与ClientSecret获取访问令牌,调用Azure Key Vault REST API获取密钥的实现方案
.Net Framework 4/4.5应用中不依赖ClientID与ClientSecret获取访问令牌,调用Azure Key Vault REST API获取密钥的实现方案
我完全懂你的顾虑——用客户端密钥去换Key Vault的访问令牌,本质上还是在代码里硬编码了另一个敏感凭据,根本没解决“密钥蔓延”的问题。托管身份确实是更安全的零凭据方案,而且针对你的.Net Framework 4/4.5环境,不管是部署在Azure App Service还是VM上,都有可行的实现方式,不用再存任何明文凭据。
下面分两种部署环境给你详细讲实现步骤和代码:
一、前置准备(两种环境通用)
首先得给你的Azure资源(App Service/VM)启用托管身份,并给它分配Key Vault的访问权限:
- 启用系统分配托管身份:在Azure Portal里找到你的App Service/VM,进入「身份」选项卡,切换到「系统分配」标签,把状态设为「开启」,点击保存。系统会自动给这个资源创建一个AD身份。
- 配置Key Vault访问策略:打开你的Key Vault,进入「访问策略」,点击「添加访问策略」:
- 权限选择「机密权限」里的「获取」(根据你的需求添加其他权限);
- 主体选择刚才创建的托管身份(名称和你的App Service/VM名称一致);
- 保存策略。
二、代码实现:通过托管身份获取令牌并调用Key Vault REST API
因为.Net Framework 4/4.5不支持最新的Azure.Identity SDK,我们直接通过调用Azure Instance Metadata Service(IMDS)的端点来获取托管身份令牌,全程不需要硬编码任何凭据。
1. 获取托管身份访问令牌的方法
这个方法适用于App Service和VM两种环境:
using System.Net.Http; using System.Threading.Tasks; using Newtonsoft.Json; // 需要安装Newtonsoft.Json NuGet包 public async Task<string> GetManagedIdentityAccessToken() { using (var client = new HttpClient()) { // 必须添加Metadata请求头,否则IMDS端点会拒绝请求 client.DefaultRequestHeaders.Add("Metadata", "true"); // 请求令牌的端点,resource指定为Key Vault的资源标识符 var tokenRequestUri = new Uri("http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://vault.azure.net"); var response = await client.GetAsync(tokenRequestUri); response.EnsureSuccessStatusCode(); // 如果请求失败,直接抛出异常 var responseJson = await response.Content.ReadAsStringAsync(); var tokenData = JsonConvert.DeserializeAnonymousType(responseJson, new { access_token = "" }); return tokenData.access_token; } }
2. 调用Key Vault REST API获取机密
拿到令牌后,就可以调用Key Vault的REST API获取目标机密了:
public async Task<string> GetSecretFromKeyVault(string keyVaultUrl, string secretName) { var accessToken = await GetManagedIdentityAccessToken(); using (var kvClient = new HttpClient()) { // 添加Bearer令牌到请求头 kvClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {accessToken}"); // Key Vault REST API的请求地址,注意指定api-version(推荐用最新的稳定版) var secretRequestUri = new Uri($"{keyVaultUrl}/secrets/{secretName}?api-version=7.4"); var secretResponse = await kvClient.GetAsync(secretRequestUri); secretResponse.EnsureSuccessStatusCode(); var secretJson = await secretResponse.Content.ReadAsStringAsync(); var secretData = JsonConvert.DeserializeAnonymousType(secretJson, new { value = "" }); return secretData.value; } }
3. 调用示例
现在你可以直接用这个方法,不需要任何硬编码的凭据:
string keyVaultUrl = "https://your-vault-name.vault.azure.net"; string secretName = "Test"; string secretValue = await GetSecretFromKeyVault(keyVaultUrl, secretName); // 后续使用secretValue即可
三、额外说明
- 如果用的是用户分配托管身份,只需要在令牌请求Uri里加上
&client_id={你的用户分配身份的ClientID}参数即可,其他代码不变。 - 确保你的应用可以访问IMDS端点(
http://169.254.169.254),这个在Azure环境里是默认允许的,不需要额外配置网络规则。 - 相比之前的方案,这个实现完全消除了代码中的敏感凭据,所有身份验证都由Azure后台自动处理,安全性大幅提升。
备注:内容来源于stack exchange,提问作者AskMe




