使用系统托管身份在C# Azure Function中无法获取Key Vault密钥
我在Azure Function(服务总线主题触发器)中启用了系统分配托管身份,将该身份的对象(主体)ID添加到Key Vault访问策略,授予密钥、机密的Get,List权限。已在Azure Function应用设置中添加Key Vault引用,部署后运行时可正常获取密钥,引用格式为@Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/mysecret/ec96f02080254f109c51a1f14cdb1931)。
代码实现
private async Task<string> FetchSecretValueFromKeyvault(string secretName) { _logger.LogInformation($"FetchSecretValueFromKeyvault: SecretName {secretName}"); string actualSecret = string.Empty; try { string systemAssignedClientId = GetEnvironmentVariable("AzureADManagedIdentityClientId"); string azureKeyVaultUrl = GetEnvironmentVariable("AzureKeyVaultUrl"); var defaultAzureCredentialOptions = new DefaultAzureCredentialOptions(); defaultAzureCredentialOptions.ExcludeAzureCliCredential = true; defaultAzureCredentialOptions.ExcludeEnvironmentCredential = true; defaultAzureCredentialOptions.ExcludeAzurePowerShellCredential = true; defaultAzureCredentialOptions.ExcludeInteractiveBrowserCredential = true; defaultAzureCredentialOptions.ExcludeManagedIdentityCredential = false; defaultAzureCredentialOptions.ExcludeSharedTokenCacheCredential = true; defaultAzureCredentialOptions.ExcludeVisualStudioCodeCredential = true; defaultAzureCredentialOptions.ExcludeVisualStudioCredential = true; defaultAzureCredentialOptions.ManagedIdentityClientId = systemAssignedClientId; var credential = new DefaultAzureCredential(defaultAzureCredentialOptions); var client = new SecretClient(new Uri(AzureKeyVaultUrl)), credential); var secret = await client.GetSecretAsync(secretName).ConfigureAwait(false); actualSecret = secret.Value.Value; _logger.LogInformation($"FetchSecretValueFromKeyvault: Received secretValue for {secretName}"); } catch (RequestFailedException ex) { actualSecret = string.Empty; _logger.LogError($"Message: {ex.Message}. \nInnerException:{ex.InnerException}. \nStackTrace: {ex.StackTrace}. \nInnerExceptionMessage:{ex.InnerException?.Message}."); } catch (Exception ex) { actualSecret = string.Empty; _logger.LogError($"Message: {ex.Message}. \nInnerException:{ex.InnerException}. \nStackTrace: {ex.StackTrace}. \nInnerExceptionMessage:{ex.InnerException?.Message}."); } return actualSecret; }
环境配置
- 本地与Azure Function应用设置:
"AzureADManagedIdentityClientId": "xxx-123-abc-xyz-567890", "AzureKeyVaultUrl": "https://keyvaulturl.azurewebsites.net" - NuGet包版本:
- Azure.Security.KeyVault.Secrets -- 4.3.0
- Azure.Extensions.AspNetCore.Configuration.Secrets -- 1.2.2
- Azure.Identity -- 1.6.1
- Function运行时版本:.NET Core V3.1
报错信息
- 本地调试:
ManagedIdentityCredential authentication unavailable. Multiple attempts failed to obtain a token from the managed identity endpoint. - 部署后(Application Insights):
No Managed Identity found for specified ClientId/ResourceId/PrincipalId. Status: 400 (Bad Request)
已反复核对PrincipalId,确认本地和应用设置中值正确,请问哪里操作有误?
1. 系统分配托管身份无需指定ClientId
系统分配托管身份与Azure Function资源绑定,不需要手动设置ManagedIdentityClientId。你给DefaultAzureCredentialOptions.ManagedIdentityClientId赋值后,SDK会按用户分配托管身份的逻辑去查找,而你的场景是系统分配,自然会找不到对应身份,触发400错误。
解决:删除defaultAzureCredentialOptions.ManagedIdentityClientId = systemAssignedClientId;这一行代码,SDK会自动使用系统分配的托管身份。
2. 本地调试的托管身份适配
本地环境没有Azure托管身份的运行时支撑,直接用ManagedIdentityCredential必然报错。可以修改DefaultAzureCredentialOptions,允许使用Azure CLI或Visual Studio的凭据进行本地调试:
defaultAzureCredentialOptions.ExcludeAzureCliCredential = false; // 或保留Visual Studio凭据选项 defaultAzureCredentialOptions.ExcludeVisualStudioCredential = false;
调试前确保你登录Azure CLI/VS的账号已拥有Key Vault的Get,List权限。
3. Key Vault URL配置错误
你的AzureKeyVaultUrl设置为https://keyvaulturl.azurewebsites.net,这是Web App的URL格式,Key Vault的正确URL应为https://{vault-name}.vault.azure.net(例如https://myvault.vault.azure.net),错误的URL会导致SecretClient无法连接到正确服务。
4. 代码语法错误
创建SecretClient的语句存在括号配对错误,且变量名大小写不一致:
// 错误写法 var client = new SecretClient(new Uri(AzureKeyVaultUrl)), credential); // 修正后 var client = new SecretClient(new Uri(azureKeyVaultUrl), credential);
内容的提问来源于stack exchange,提问作者PavanKumar GVVS

