I have written a function app and at the start of my code I have:
var credential = new ManagedIdentityCredential();
var client = new SecretClient(vaultUri, credential);
Within Azure, I have gone to the 'Identity' section of my function app and set status to 'on' for system assigned. I have also gone to the key vault and with 'Access Control (IAM), I have added the managed identity as a Key Vaults Secrets User.
From within my function app if I go to Access Control there, I have Assigned the managed role as a contributor and managed application contributor role.
I have no idea what else I need to set to give access to the key vault from within my app for the managed user.
I also publish the function all as self-contained.
Start of the error in the invocation section of the function app
Result: Failure Exception: Azure.RequestFailedException: Caller is not authorized to perform action on resource. If role assignments, deny assignments or role definitions were changed recently, please observe propagation time. Caller: appid=61c8be63-9b5d-4c29-80ec-c839a0f0a61c;oid=849fa139-74c5-4adb-9b94-74bc444b68c0;iss=https://sts.windows.net/2f77693b-b7cd-4918-8d8a-d4f28910516f/ Action: 'Microsoft.KeyVault/vaults/secrets/getSecret/action' Resource: '/subscriptions/fb54f07b-964f-4366-88e2-
Following Ikhtesam Shots from his answer below I have:
In my Program.cs file I have:
var host = new HostBuilder()
.ConfigureFunctionsWebApplication()
.ConfigureServices((context,services) =>
{
var vaultUri = new Uri("https://{Key Vault Name Here}.vault.azure.net/");
var credential = new ManagedIdentityCredential();
var client = new SecretClient(vaultUri, credential);
services.AddSingleton(client);
services.AddTransient<ISecretService, SecretService>();
then in my function app I have:
public class GetMongoData
{
private readonly ILogger _logger;
private readonly IMySqlSession _session;
private readonly IMySqlClaimants _claimants;
private readonly IMySqlAddresses _addresses;
private readonly IMySqlClaims _claims;
private readonly IMySqlDefendants _defendants;
private readonly IMySqlDuplicateClaims _duplicateClaims;
private readonly IMySqlEvidence _evidence;
private readonly IMySqlStatuses _statuses;
private readonly ISecretService _secretService;
private readonly string _sshPath;
private readonly string _mySqlServerIp;
public GetMongoData(ILoggerFactory loggerFactory, IConfiguration
configuration, IMySqlSession mySqlSession, IMySqlClaimants mySqlClaimants,
IMySqlAddresses mySqlAddresses, IMySqlClaims mySqlClaims, IMySqlDefendants defendants, IMySqlDuplicateClaims mySqlDuplicateClaims,
IMySqlEvidence mySqlEvidence, IMySqlStatuses mySqlStatuses, ISecretService secretService)
{
_logger = loggerFactory.CreateLogger<GetMongoData>();
_session = mySqlSession;
_secretService = secretService;
_claimants = mySqlClaimants;
_addresses = mySqlAddresses;
_claims = mySqlClaims;
_defendants = defendants;
_duplicateClaims = mySqlDuplicateClaims;
_evidence = mySqlEvidence;
_statuses = mySqlStatuses;
_mySqlServerIp = _secretService.GetSecret("MySqlServerIp");
_defendants = defendants;
}
[Function("RetrieveMongoData")]
public void Run([TimerTrigger("0 0 * * * *")] TimerInfo myTimer)
{ //function set to run every hour.
_logger.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
try
{
var server = _mySqlServerIp;
var sshUserName = "forge";
var sshPassword = "";
Key vault instance -> Access Control (IAM) -> Add role assignment
as shown below.using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
namespace FunctionApp6
{
public static class Function1
{
[FunctionName("GetSecret")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
try
{
string keyVaultUrl = "https://{keyvaultName}.vault.azure.net/";
var credential = new ManagedIdentityCredential();
var client = new SecretClient(new Uri(keyVaultUrl), credential);
string secretName = "testSecret";
KeyVaultSecret secret = await client.GetSecretAsync(secretName);
string secretValue = secret.Value;
log.LogInformation($"Fetched Secret Value: {secretValue}");
return new OkObjectResult($"Secret fetched successfully. Check logs for the value.");
}
catch (Exception ex)
{
log.LogError($"Error fetching secret: {ex.Message}");
return new StatusCodeResult(StatusCodes.Status500InternalServerError);
}
}
}
}
If you intent to read the secret content then Key Vaults Secrets User role should do. Please verify if you have assigned the role correctly as I did.
I have created an isolated timer trigger function and have added below given code in program.cs file which worked successfully for me.
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
using Microsoft.Azure.Functions.Worker.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var host = new HostBuilder()
.ConfigureFunctionsWebApplication()
.ConfigureServices((context, services) =>
{
var vaultUri = new Uri("https://afreeenKv.vault.azure.net/");
var credential = new ManagedIdentityCredential();
var client = new SecretClient(vaultUri, credential);
services.AddSingleton(client);
})
.Build();
host.Run();